From 6b62a875c499fe104e9553490183866c7f9f4c9d Mon Sep 17 00:00:00 2001 From: Thy Date: Wed, 12 Feb 2025 20:48:05 +0800 Subject: [PATCH 1/3] docs: introducting lunaria --- docs/.vitepress/{config.ts => config/en.ts} | 94 +-- docs/.vitepress/config/index.ts | 160 ++++++ .../{ => en}/docs/components/accordion.md | 0 .../{ => en}/docs/components/alert-dialog.md | 0 .../{ => en}/docs/components/aspect-ratio.md | 0 .../{ => en}/docs/components/avatar.md | 0 .../{ => en}/docs/components/calendar.md | 0 .../{ => en}/docs/components/checkbox.md | 0 .../{ => en}/docs/components/collapsible.md | 0 .../{ => en}/docs/components/combobox.md | 0 .../{ => en}/docs/components/context-menu.md | 0 .../{ => en}/docs/components/date-field.md | 0 .../{ => en}/docs/components/date-picker.md | 0 .../docs/components/date-range-field.md | 0 .../docs/components/date-range-picker.md | 0 .../{ => en}/docs/components/dialog.md | 0 .../{ => en}/docs/components/dropdown-menu.md | 0 .../{ => en}/docs/components/editable.md | 0 .../{ => en}/docs/components/hover-card.md | 0 .../content/{ => en}/docs/components/label.md | 0 .../{ => en}/docs/components/listbox.md | 0 .../{ => en}/docs/components/menubar.md | 0 .../docs/components/navigation-menu.md | 0 .../{ => en}/docs/components/number-field.md | 0 .../{ => en}/docs/components/pagination.md | 0 .../{ => en}/docs/components/pin-input.md | 0 .../{ => en}/docs/components/popover.md | 0 .../{ => en}/docs/components/progress.md | 0 .../{ => en}/docs/components/radio-group.md | 0 .../docs/components/range-calendar.md | 0 .../{ => en}/docs/components/scroll-area.md | 0 .../{ => en}/docs/components/select.md | 8 +- .../{ => en}/docs/components/separator.md | 0 .../{ => en}/docs/components/slider.md | 0 .../{ => en}/docs/components/splitter.md | 0 .../{ => en}/docs/components/stepper.md | 0 .../{ => en}/docs/components/switch.md | 0 docs/content/{ => en}/docs/components/tabs.md | 0 .../{ => en}/docs/components/tags-input.md | 0 .../{ => en}/docs/components/time-field.md | 0 .../content/{ => en}/docs/components/toast.md | 0 .../{ => en}/docs/components/toggle-group.md | 0 .../{ => en}/docs/components/toggle.md | 0 .../{ => en}/docs/components/toolbar.md | 0 .../{ => en}/docs/components/tooltip.md | 0 docs/content/{ => en}/docs/components/tree.md | 0 .../content/{ => en}/docs/guides/animation.md | 0 .../{ => en}/docs/guides/composition.md | 0 docs/content/{ => en}/docs/guides/dates.md | 0 docs/content/{ => en}/docs/guides/i18n.md | 0 .../{ => en}/docs/guides/inject-context.md | 0 .../content/{ => en}/docs/guides/migration.md | 0 .../docs/guides/namespaced-components.md | 0 .../docs/guides/server-side-rendering.md | 0 docs/content/{ => en}/docs/guides/styling.md | 0 .../{ => en}/docs/guides/virtualization.md | 0 .../{ => en}/docs/overview/accessibility.md | 0 .../{ => en}/docs/overview/getting-started.md | 2 +- .../{ => en}/docs/overview/installation.md | 0 .../{ => en}/docs/overview/introduction.md | 0 .../{ => en}/docs/overview/releases.md | 0 .../docs/utilities/config-provider.md | 0 .../{ => en}/docs/utilities/focus-scope.md | 0 .../{ => en}/docs/utilities/presence.md | 0 .../{ => en}/docs/utilities/primitive.md | 0 docs/content/{ => en}/docs/utilities/slot.md | 0 .../docs/utilities/use-date-formatter.md | 0 .../docs/utilities/use-emit-as-props.md | 0 .../docs/utilities/use-forward-expose.md | 0 .../docs/utilities/use-forward-props-emits.md | 0 .../docs/utilities/use-forward-props.md | 0 .../content/{ => en}/docs/utilities/use-id.md | 0 .../docs/utilities/visually-hidden.md | 0 docs/content/{ => en}/examples.md | 0 .../{ => en}/examples/checkbox-group.md | 0 .../{ => en}/examples/combobox-tags-input.md | 0 .../{ => en}/examples/combobox-textarea.md | 0 .../examples/date-picker-selection.md | 0 .../{ => en}/examples/dialog-command-menu.md | 0 .../{ => en}/examples/listbox-transfer.md | 0 .../{ => en}/examples/progress-circular.md | 0 .../{ => en}/examples/slider-number-field.md | 0 .../{ => en}/examples/slider-tooltip.md | 0 .../{ => en}/examples/tooltip-cursor.md | 0 docs/content/{ => en}/index.md | 0 .../content/{ => en}/meta/AccordionContent.md | 0 docs/content/{ => en}/meta/AccordionHeader.md | 0 docs/content/{ => en}/meta/AccordionItem.md | 0 docs/content/{ => en}/meta/AccordionRoot.md | 0 .../content/{ => en}/meta/AccordionTrigger.md | 0 .../{ => en}/meta/AlertDialogAction.md | 0 .../{ => en}/meta/AlertDialogCancel.md | 0 .../{ => en}/meta/AlertDialogContent.md | 0 .../{ => en}/meta/AlertDialogDescription.md | 0 .../{ => en}/meta/AlertDialogOverlay.md | 0 .../{ => en}/meta/AlertDialogPortal.md | 0 docs/content/{ => en}/meta/AlertDialogRoot.md | 0 .../content/{ => en}/meta/AlertDialogTitle.md | 0 .../{ => en}/meta/AlertDialogTrigger.md | 0 docs/content/{ => en}/meta/AspectRatio.md | 0 docs/content/{ => en}/meta/AvatarFallback.md | 0 docs/content/{ => en}/meta/AvatarImage.md | 0 docs/content/{ => en}/meta/AvatarRoot.md | 0 docs/content/{ => en}/meta/CalendarCell.md | 0 .../{ => en}/meta/CalendarCellTrigger.md | 0 docs/content/{ => en}/meta/CalendarGrid.md | 0 .../content/{ => en}/meta/CalendarGridBody.md | 0 .../content/{ => en}/meta/CalendarGridHead.md | 0 docs/content/{ => en}/meta/CalendarGridRow.md | 0 .../content/{ => en}/meta/CalendarHeadCell.md | 0 docs/content/{ => en}/meta/CalendarHeader.md | 0 docs/content/{ => en}/meta/CalendarHeading.md | 0 .../{ => en}/meta/CalendarHeadingSegment.md | 0 docs/content/{ => en}/meta/CalendarNext.md | 0 docs/content/{ => en}/meta/CalendarPrev.md | 0 docs/content/{ => en}/meta/CalendarRoot.md | 0 .../{ => en}/meta/CheckboxGroupRoot.md | 0 .../{ => en}/meta/CheckboxIndicator.md | 0 docs/content/{ => en}/meta/CheckboxRoot.md | 0 .../{ => en}/meta/CollapsibleContent.md | 0 docs/content/{ => en}/meta/CollapsibleRoot.md | 0 .../{ => en}/meta/CollapsibleTrigger.md | 0 docs/content/{ => en}/meta/ComboboxAnchor.md | 0 docs/content/{ => en}/meta/ComboboxArrow.md | 0 docs/content/{ => en}/meta/ComboboxCancel.md | 0 docs/content/{ => en}/meta/ComboboxContent.md | 0 docs/content/{ => en}/meta/ComboboxEmpty.md | 0 docs/content/{ => en}/meta/ComboboxGroup.md | 0 docs/content/{ => en}/meta/ComboboxInput.md | 0 docs/content/{ => en}/meta/ComboboxItem.md | 0 .../{ => en}/meta/ComboboxItemIndicator.md | 0 docs/content/{ => en}/meta/ComboboxLabel.md | 0 docs/content/{ => en}/meta/ComboboxPortal.md | 0 docs/content/{ => en}/meta/ComboboxRoot.md | 0 .../{ => en}/meta/ComboboxSeparator.md | 0 docs/content/{ => en}/meta/ComboboxTrigger.md | 0 .../content/{ => en}/meta/ComboboxViewport.md | 0 .../{ => en}/meta/ComboboxVirtualizer.md | 0 docs/content/{ => en}/meta/ConfigProvider.md | 0 .../content/{ => en}/meta/ContextMenuArrow.md | 0 .../{ => en}/meta/ContextMenuCheckboxItem.md | 0 .../{ => en}/meta/ContextMenuContent.md | 0 .../content/{ => en}/meta/ContextMenuGroup.md | 0 docs/content/{ => en}/meta/ContextMenuItem.md | 0 .../{ => en}/meta/ContextMenuItemIndicator.md | 0 .../content/{ => en}/meta/ContextMenuLabel.md | 0 .../{ => en}/meta/ContextMenuPortal.md | 0 .../{ => en}/meta/ContextMenuRadioGroup.md | 0 .../{ => en}/meta/ContextMenuRadioItem.md | 0 docs/content/{ => en}/meta/ContextMenuRoot.md | 0 .../{ => en}/meta/ContextMenuSeparator.md | 0 docs/content/{ => en}/meta/ContextMenuSub.md | 0 .../{ => en}/meta/ContextMenuSubContent.md | 0 .../{ => en}/meta/ContextMenuSubTrigger.md | 0 .../{ => en}/meta/ContextMenuTrigger.md | 0 docs/content/{ => en}/meta/DateFieldInput.md | 0 docs/content/{ => en}/meta/DateFieldRoot.md | 0 .../content/{ => en}/meta/DatePickerAnchor.md | 0 docs/content/{ => en}/meta/DatePickerArrow.md | 0 .../{ => en}/meta/DatePickerCalendar.md | 0 docs/content/{ => en}/meta/DatePickerCell.md | 0 .../{ => en}/meta/DatePickerCellTrigger.md | 0 docs/content/{ => en}/meta/DatePickerClose.md | 0 .../{ => en}/meta/DatePickerContent.md | 0 docs/content/{ => en}/meta/DatePickerField.md | 0 docs/content/{ => en}/meta/DatePickerGrid.md | 0 .../{ => en}/meta/DatePickerGridBody.md | 0 .../{ => en}/meta/DatePickerGridHead.md | 0 .../{ => en}/meta/DatePickerGridRow.md | 0 .../{ => en}/meta/DatePickerHeadCell.md | 0 .../content/{ => en}/meta/DatePickerHeader.md | 0 .../{ => en}/meta/DatePickerHeading.md | 0 .../{ => en}/meta/DatePickerHeadingSegment.md | 0 docs/content/{ => en}/meta/DatePickerInput.md | 0 docs/content/{ => en}/meta/DatePickerNext.md | 0 docs/content/{ => en}/meta/DatePickerPrev.md | 0 docs/content/{ => en}/meta/DatePickerRoot.md | 0 .../{ => en}/meta/DatePickerTrigger.md | 0 .../{ => en}/meta/DateRangeFieldInput.md | 0 .../{ => en}/meta/DateRangeFieldRoot.md | 0 .../{ => en}/meta/DateRangePickerAnchor.md | 0 .../{ => en}/meta/DateRangePickerArrow.md | 0 .../{ => en}/meta/DateRangePickerCalendar.md | 0 .../{ => en}/meta/DateRangePickerCell.md | 0 .../meta/DateRangePickerCellTrigger.md | 0 .../{ => en}/meta/DateRangePickerClose.md | 0 .../{ => en}/meta/DateRangePickerContent.md | 0 .../{ => en}/meta/DateRangePickerField.md | 0 .../{ => en}/meta/DateRangePickerGrid.md | 0 .../{ => en}/meta/DateRangePickerGridBody.md | 0 .../{ => en}/meta/DateRangePickerGridHead.md | 0 .../{ => en}/meta/DateRangePickerGridRow.md | 0 .../{ => en}/meta/DateRangePickerHeadCell.md | 0 .../{ => en}/meta/DateRangePickerHeader.md | 0 .../{ => en}/meta/DateRangePickerHeading.md | 0 .../meta/DateRangePickerHeadingSegment.md | 0 .../{ => en}/meta/DateRangePickerInput.md | 0 .../{ => en}/meta/DateRangePickerNext.md | 0 .../{ => en}/meta/DateRangePickerPrev.md | 0 .../{ => en}/meta/DateRangePickerRoot.md | 0 .../{ => en}/meta/DateRangePickerTrigger.md | 0 docs/content/{ => en}/meta/DialogClose.md | 0 docs/content/{ => en}/meta/DialogContent.md | 0 .../{ => en}/meta/DialogDescription.md | 0 docs/content/{ => en}/meta/DialogOverlay.md | 0 docs/content/{ => en}/meta/DialogPortal.md | 0 docs/content/{ => en}/meta/DialogRoot.md | 0 docs/content/{ => en}/meta/DialogTitle.md | 0 docs/content/{ => en}/meta/DialogTrigger.md | 0 .../{ => en}/meta/DropdownMenuArrow.md | 0 .../{ => en}/meta/DropdownMenuCheckboxItem.md | 0 .../{ => en}/meta/DropdownMenuContent.md | 0 .../{ => en}/meta/DropdownMenuGroup.md | 0 .../content/{ => en}/meta/DropdownMenuItem.md | 0 .../meta/DropdownMenuItemIndicator.md | 0 .../{ => en}/meta/DropdownMenuLabel.md | 0 .../{ => en}/meta/DropdownMenuPortal.md | 0 .../{ => en}/meta/DropdownMenuRadioGroup.md | 0 .../{ => en}/meta/DropdownMenuRadioItem.md | 0 .../content/{ => en}/meta/DropdownMenuRoot.md | 0 .../{ => en}/meta/DropdownMenuSeparator.md | 0 docs/content/{ => en}/meta/DropdownMenuSub.md | 0 .../{ => en}/meta/DropdownMenuSubContent.md | 0 .../{ => en}/meta/DropdownMenuSubTrigger.md | 0 .../{ => en}/meta/DropdownMenuTrigger.md | 0 docs/content/{ => en}/meta/EditableArea.md | 0 .../{ => en}/meta/EditableCancelTrigger.md | 0 .../{ => en}/meta/EditableEditTrigger.md | 0 docs/content/{ => en}/meta/EditableInput.md | 0 docs/content/{ => en}/meta/EditablePreview.md | 0 docs/content/{ => en}/meta/EditableRoot.md | 0 .../{ => en}/meta/EditableSubmitTrigger.md | 0 docs/content/{ => en}/meta/FocusScope.md | 0 docs/content/{ => en}/meta/HoverCardArrow.md | 0 .../content/{ => en}/meta/HoverCardContent.md | 0 docs/content/{ => en}/meta/HoverCardPortal.md | 0 docs/content/{ => en}/meta/HoverCardRoot.md | 0 .../content/{ => en}/meta/HoverCardTrigger.md | 0 docs/content/{ => en}/meta/Label.md | 0 docs/content/{ => en}/meta/ListboxContent.md | 0 docs/content/{ => en}/meta/ListboxFilter.md | 0 docs/content/{ => en}/meta/ListboxGroup.md | 0 .../{ => en}/meta/ListboxGroupLabel.md | 0 docs/content/{ => en}/meta/ListboxItem.md | 0 .../{ => en}/meta/ListboxItemIndicator.md | 0 docs/content/{ => en}/meta/ListboxRoot.md | 0 .../{ => en}/meta/ListboxVirtualizer.md | 0 docs/content/{ => en}/meta/MenubarArrow.md | 0 .../{ => en}/meta/MenubarCheckboxItem.md | 0 docs/content/{ => en}/meta/MenubarContent.md | 0 docs/content/{ => en}/meta/MenubarGroup.md | 0 docs/content/{ => en}/meta/MenubarItem.md | 0 .../{ => en}/meta/MenubarItemIndicator.md | 0 docs/content/{ => en}/meta/MenubarLabel.md | 0 docs/content/{ => en}/meta/MenubarMenu.md | 0 docs/content/{ => en}/meta/MenubarPortal.md | 0 .../{ => en}/meta/MenubarRadioGroup.md | 0 .../content/{ => en}/meta/MenubarRadioItem.md | 0 docs/content/{ => en}/meta/MenubarRoot.md | 0 .../content/{ => en}/meta/MenubarSeparator.md | 0 docs/content/{ => en}/meta/MenubarSub.md | 0 .../{ => en}/meta/MenubarSubContent.md | 0 .../{ => en}/meta/MenubarSubTrigger.md | 0 docs/content/{ => en}/meta/MenubarTrigger.md | 0 .../{ => en}/meta/NavigationMenuContent.md | 0 .../{ => en}/meta/NavigationMenuIndicator.md | 0 .../{ => en}/meta/NavigationMenuItem.md | 0 .../{ => en}/meta/NavigationMenuLink.md | 0 .../{ => en}/meta/NavigationMenuList.md | 0 .../{ => en}/meta/NavigationMenuRoot.md | 0 .../{ => en}/meta/NavigationMenuSub.md | 0 .../{ => en}/meta/NavigationMenuTrigger.md | 0 .../{ => en}/meta/NavigationMenuViewport.md | 0 .../{ => en}/meta/NumberFieldDecrement.md | 0 .../{ => en}/meta/NumberFieldIncrement.md | 0 .../content/{ => en}/meta/NumberFieldInput.md | 0 .../content/{ => en}/meta/NumberFieldLabel.md | 0 docs/content/{ => en}/meta/NumberFieldRoot.md | 0 .../{ => en}/meta/PaginationEllipsis.md | 0 docs/content/{ => en}/meta/PaginationFirst.md | 0 docs/content/{ => en}/meta/PaginationLast.md | 0 docs/content/{ => en}/meta/PaginationList.md | 0 .../{ => en}/meta/PaginationListItem.md | 0 docs/content/{ => en}/meta/PaginationNext.md | 0 docs/content/{ => en}/meta/PaginationPrev.md | 0 docs/content/{ => en}/meta/PaginationRoot.md | 0 docs/content/{ => en}/meta/PinInputInput.md | 0 docs/content/{ => en}/meta/PinInputRoot.md | 0 docs/content/{ => en}/meta/PopoverAnchor.md | 0 docs/content/{ => en}/meta/PopoverArrow.md | 0 docs/content/{ => en}/meta/PopoverClose.md | 0 docs/content/{ => en}/meta/PopoverContent.md | 0 docs/content/{ => en}/meta/PopoverPortal.md | 0 docs/content/{ => en}/meta/PopoverRoot.md | 0 docs/content/{ => en}/meta/PopoverTrigger.md | 0 .../{ => en}/meta/ProgressIndicator.md | 0 docs/content/{ => en}/meta/ProgressRoot.md | 0 .../{ => en}/meta/RadioGroupIndicator.md | 0 docs/content/{ => en}/meta/RadioGroupItem.md | 0 docs/content/{ => en}/meta/RadioGroupRoot.md | 0 .../{ => en}/meta/RangeCalendarCell.md | 0 .../{ => en}/meta/RangeCalendarCellTrigger.md | 0 .../{ => en}/meta/RangeCalendarGrid.md | 0 .../{ => en}/meta/RangeCalendarGridBody.md | 0 .../{ => en}/meta/RangeCalendarGridHead.md | 0 .../{ => en}/meta/RangeCalendarGridRow.md | 0 .../{ => en}/meta/RangeCalendarHeadCell.md | 0 .../{ => en}/meta/RangeCalendarHeader.md | 0 .../{ => en}/meta/RangeCalendarHeading.md | 0 .../meta/RangeCalendarHeadingSegment.md | 0 .../{ => en}/meta/RangeCalendarNext.md | 0 .../{ => en}/meta/RangeCalendarPrev.md | 0 .../{ => en}/meta/RangeCalendarRoot.md | 0 .../content/{ => en}/meta/ScrollAreaCorner.md | 0 docs/content/{ => en}/meta/ScrollAreaRoot.md | 0 .../{ => en}/meta/ScrollAreaScrollbar.md | 0 docs/content/{ => en}/meta/ScrollAreaThumb.md | 0 .../{ => en}/meta/ScrollAreaViewport.md | 0 docs/content/{ => en}/meta/SelectArrow.md | 0 docs/content/{ => en}/meta/SelectContent.md | 0 docs/content/{ => en}/meta/SelectGroup.md | 0 docs/content/{ => en}/meta/SelectIcon.md | 0 docs/content/{ => en}/meta/SelectItem.md | 0 .../{ => en}/meta/SelectItemIndicator.md | 0 docs/content/{ => en}/meta/SelectItemText.md | 0 docs/content/{ => en}/meta/SelectLabel.md | 0 docs/content/{ => en}/meta/SelectPortal.md | 0 docs/content/{ => en}/meta/SelectRoot.md | 0 .../{ => en}/meta/SelectScrollDownButton.md | 0 .../{ => en}/meta/SelectScrollUpButton.md | 0 docs/content/{ => en}/meta/SelectSeparator.md | 0 docs/content/{ => en}/meta/SelectTrigger.md | 0 docs/content/{ => en}/meta/SelectValue.md | 0 docs/content/{ => en}/meta/SelectViewport.md | 0 docs/content/{ => en}/meta/Separator.md | 0 docs/content/{ => en}/meta/SliderRange.md | 0 docs/content/{ => en}/meta/SliderRoot.md | 0 docs/content/{ => en}/meta/SliderThumb.md | 0 docs/content/{ => en}/meta/SliderTrack.md | 0 docs/content/{ => en}/meta/SplitterGroup.md | 0 docs/content/{ => en}/meta/SplitterPanel.md | 0 .../{ => en}/meta/SplitterResizeHandle.md | 0 .../{ => en}/meta/StepperDescription.md | 0 .../content/{ => en}/meta/StepperIndicator.md | 0 docs/content/{ => en}/meta/StepperItem.md | 0 docs/content/{ => en}/meta/StepperList.md | 0 docs/content/{ => en}/meta/StepperRoot.md | 0 .../content/{ => en}/meta/StepperSeparator.md | 0 docs/content/{ => en}/meta/StepperTitle.md | 0 docs/content/{ => en}/meta/StepperTrigger.md | 0 docs/content/{ => en}/meta/SwitchRoot.md | 0 docs/content/{ => en}/meta/SwitchThumb.md | 0 docs/content/{ => en}/meta/TabsContent.md | 0 docs/content/{ => en}/meta/TabsIndicator.md | 0 docs/content/{ => en}/meta/TabsList.md | 0 docs/content/{ => en}/meta/TabsRoot.md | 0 docs/content/{ => en}/meta/TabsTrigger.md | 0 docs/content/{ => en}/meta/TagsInputClear.md | 0 docs/content/{ => en}/meta/TagsInputInput.md | 0 docs/content/{ => en}/meta/TagsInputItem.md | 0 .../{ => en}/meta/TagsInputItemDelete.md | 0 .../{ => en}/meta/TagsInputItemText.md | 0 docs/content/{ => en}/meta/TagsInputRoot.md | 0 docs/content/{ => en}/meta/TimeFieldInput.md | 0 docs/content/{ => en}/meta/TimeFieldRoot.md | 0 docs/content/{ => en}/meta/ToastAction.md | 0 docs/content/{ => en}/meta/ToastClose.md | 0 .../content/{ => en}/meta/ToastDescription.md | 0 docs/content/{ => en}/meta/ToastPortal.md | 0 docs/content/{ => en}/meta/ToastProvider.md | 0 docs/content/{ => en}/meta/ToastRoot.md | 0 docs/content/{ => en}/meta/ToastTitle.md | 0 docs/content/{ => en}/meta/ToastViewport.md | 0 docs/content/{ => en}/meta/Toggle.md | 0 docs/content/{ => en}/meta/ToggleGroupItem.md | 0 docs/content/{ => en}/meta/ToggleGroupRoot.md | 0 docs/content/{ => en}/meta/ToolbarButton.md | 0 docs/content/{ => en}/meta/ToolbarLink.md | 0 docs/content/{ => en}/meta/ToolbarRoot.md | 0 .../content/{ => en}/meta/ToolbarSeparator.md | 0 .../{ => en}/meta/ToolbarToggleGroup.md | 0 .../{ => en}/meta/ToolbarToggleItem.md | 0 docs/content/{ => en}/meta/TooltipArrow.md | 0 docs/content/{ => en}/meta/TooltipContent.md | 0 docs/content/{ => en}/meta/TooltipPortal.md | 0 docs/content/{ => en}/meta/TooltipProvider.md | 0 docs/content/{ => en}/meta/TooltipRoot.md | 0 docs/content/{ => en}/meta/TooltipTrigger.md | 0 docs/content/{ => en}/meta/TreeItem.md | 0 docs/content/{ => en}/meta/TreeRoot.md | 0 docs/content/{ => en}/meta/TreeVirtualizer.md | 0 docs/content/{ => en}/meta/Viewport.md | 0 docs/content/{ => en}/meta/VisuallyHidden.md | 0 docs/content/{ => en}/showcase.md | 0 docs/content/public/og.jpg | Bin 159556 -> 182099 bytes docs/lunaria.config.json | 43 ++ docs/package.json | 5 +- pnpm-lock.yaml | 541 ++++++++++++++---- 398 files changed, 652 insertions(+), 201 deletions(-) rename docs/.vitepress/{config.ts => config/en.ts} (78%) create mode 100644 docs/.vitepress/config/index.ts rename docs/content/{ => en}/docs/components/accordion.md (100%) rename docs/content/{ => en}/docs/components/alert-dialog.md (100%) rename docs/content/{ => en}/docs/components/aspect-ratio.md (100%) rename docs/content/{ => en}/docs/components/avatar.md (100%) rename docs/content/{ => en}/docs/components/calendar.md (100%) rename docs/content/{ => en}/docs/components/checkbox.md (100%) rename docs/content/{ => en}/docs/components/collapsible.md (100%) rename docs/content/{ => en}/docs/components/combobox.md (100%) rename docs/content/{ => en}/docs/components/context-menu.md (100%) rename docs/content/{ => en}/docs/components/date-field.md (100%) rename docs/content/{ => en}/docs/components/date-picker.md (100%) rename docs/content/{ => en}/docs/components/date-range-field.md (100%) rename docs/content/{ => en}/docs/components/date-range-picker.md (100%) rename docs/content/{ => en}/docs/components/dialog.md (100%) rename docs/content/{ => en}/docs/components/dropdown-menu.md (100%) rename docs/content/{ => en}/docs/components/editable.md (100%) rename docs/content/{ => en}/docs/components/hover-card.md (100%) rename docs/content/{ => en}/docs/components/label.md (100%) rename docs/content/{ => en}/docs/components/listbox.md (100%) rename docs/content/{ => en}/docs/components/menubar.md (100%) rename docs/content/{ => en}/docs/components/navigation-menu.md (100%) rename docs/content/{ => en}/docs/components/number-field.md (100%) rename docs/content/{ => en}/docs/components/pagination.md (100%) rename docs/content/{ => en}/docs/components/pin-input.md (100%) rename docs/content/{ => en}/docs/components/popover.md (100%) rename docs/content/{ => en}/docs/components/progress.md (100%) rename docs/content/{ => en}/docs/components/radio-group.md (100%) rename docs/content/{ => en}/docs/components/range-calendar.md (100%) rename docs/content/{ => en}/docs/components/scroll-area.md (100%) rename docs/content/{ => en}/docs/components/select.md (97%) rename docs/content/{ => en}/docs/components/separator.md (100%) rename docs/content/{ => en}/docs/components/slider.md (100%) rename docs/content/{ => en}/docs/components/splitter.md (100%) rename docs/content/{ => en}/docs/components/stepper.md (100%) rename docs/content/{ => en}/docs/components/switch.md (100%) rename docs/content/{ => en}/docs/components/tabs.md (100%) rename docs/content/{ => en}/docs/components/tags-input.md (100%) rename docs/content/{ => en}/docs/components/time-field.md (100%) rename docs/content/{ => en}/docs/components/toast.md (100%) rename docs/content/{ => en}/docs/components/toggle-group.md (100%) rename docs/content/{ => en}/docs/components/toggle.md (100%) rename docs/content/{ => en}/docs/components/toolbar.md (100%) rename docs/content/{ => en}/docs/components/tooltip.md (100%) rename docs/content/{ => en}/docs/components/tree.md (100%) rename docs/content/{ => en}/docs/guides/animation.md (100%) rename docs/content/{ => en}/docs/guides/composition.md (100%) rename docs/content/{ => en}/docs/guides/dates.md (100%) rename docs/content/{ => en}/docs/guides/i18n.md (100%) rename docs/content/{ => en}/docs/guides/inject-context.md (100%) rename docs/content/{ => en}/docs/guides/migration.md (100%) rename docs/content/{ => en}/docs/guides/namespaced-components.md (100%) rename docs/content/{ => en}/docs/guides/server-side-rendering.md (100%) rename docs/content/{ => en}/docs/guides/styling.md (100%) rename docs/content/{ => en}/docs/guides/virtualization.md (100%) rename docs/content/{ => en}/docs/overview/accessibility.md (100%) rename docs/content/{ => en}/docs/overview/getting-started.md (98%) rename docs/content/{ => en}/docs/overview/installation.md (100%) rename docs/content/{ => en}/docs/overview/introduction.md (100%) rename docs/content/{ => en}/docs/overview/releases.md (100%) rename docs/content/{ => en}/docs/utilities/config-provider.md (100%) rename docs/content/{ => en}/docs/utilities/focus-scope.md (100%) rename docs/content/{ => en}/docs/utilities/presence.md (100%) rename docs/content/{ => en}/docs/utilities/primitive.md (100%) rename docs/content/{ => en}/docs/utilities/slot.md (100%) rename docs/content/{ => en}/docs/utilities/use-date-formatter.md (100%) rename docs/content/{ => en}/docs/utilities/use-emit-as-props.md (100%) rename docs/content/{ => en}/docs/utilities/use-forward-expose.md (100%) rename docs/content/{ => en}/docs/utilities/use-forward-props-emits.md (100%) rename docs/content/{ => en}/docs/utilities/use-forward-props.md (100%) rename docs/content/{ => en}/docs/utilities/use-id.md (100%) rename docs/content/{ => en}/docs/utilities/visually-hidden.md (100%) rename docs/content/{ => en}/examples.md (100%) rename docs/content/{ => en}/examples/checkbox-group.md (100%) rename docs/content/{ => en}/examples/combobox-tags-input.md (100%) rename docs/content/{ => en}/examples/combobox-textarea.md (100%) rename docs/content/{ => en}/examples/date-picker-selection.md (100%) rename docs/content/{ => en}/examples/dialog-command-menu.md (100%) rename docs/content/{ => en}/examples/listbox-transfer.md (100%) rename docs/content/{ => en}/examples/progress-circular.md (100%) rename docs/content/{ => en}/examples/slider-number-field.md (100%) rename docs/content/{ => en}/examples/slider-tooltip.md (100%) rename docs/content/{ => en}/examples/tooltip-cursor.md (100%) rename docs/content/{ => en}/index.md (100%) rename docs/content/{ => en}/meta/AccordionContent.md (100%) rename docs/content/{ => en}/meta/AccordionHeader.md (100%) rename docs/content/{ => en}/meta/AccordionItem.md (100%) rename docs/content/{ => en}/meta/AccordionRoot.md (100%) rename docs/content/{ => en}/meta/AccordionTrigger.md (100%) rename docs/content/{ => en}/meta/AlertDialogAction.md (100%) rename docs/content/{ => en}/meta/AlertDialogCancel.md (100%) rename docs/content/{ => en}/meta/AlertDialogContent.md (100%) rename docs/content/{ => en}/meta/AlertDialogDescription.md (100%) rename docs/content/{ => en}/meta/AlertDialogOverlay.md (100%) rename docs/content/{ => en}/meta/AlertDialogPortal.md (100%) rename docs/content/{ => en}/meta/AlertDialogRoot.md (100%) rename docs/content/{ => en}/meta/AlertDialogTitle.md (100%) rename docs/content/{ => en}/meta/AlertDialogTrigger.md (100%) rename docs/content/{ => en}/meta/AspectRatio.md (100%) rename docs/content/{ => en}/meta/AvatarFallback.md (100%) rename docs/content/{ => en}/meta/AvatarImage.md (100%) rename docs/content/{ => en}/meta/AvatarRoot.md (100%) rename docs/content/{ => en}/meta/CalendarCell.md (100%) rename docs/content/{ => en}/meta/CalendarCellTrigger.md (100%) rename docs/content/{ => en}/meta/CalendarGrid.md (100%) rename docs/content/{ => en}/meta/CalendarGridBody.md (100%) rename docs/content/{ => en}/meta/CalendarGridHead.md (100%) rename docs/content/{ => en}/meta/CalendarGridRow.md (100%) rename docs/content/{ => en}/meta/CalendarHeadCell.md (100%) rename docs/content/{ => en}/meta/CalendarHeader.md (100%) rename docs/content/{ => en}/meta/CalendarHeading.md (100%) rename docs/content/{ => en}/meta/CalendarHeadingSegment.md (100%) rename docs/content/{ => en}/meta/CalendarNext.md (100%) rename docs/content/{ => en}/meta/CalendarPrev.md (100%) rename docs/content/{ => en}/meta/CalendarRoot.md (100%) rename docs/content/{ => en}/meta/CheckboxGroupRoot.md (100%) rename docs/content/{ => en}/meta/CheckboxIndicator.md (100%) rename docs/content/{ => en}/meta/CheckboxRoot.md (100%) rename docs/content/{ => en}/meta/CollapsibleContent.md (100%) rename docs/content/{ => en}/meta/CollapsibleRoot.md (100%) rename docs/content/{ => en}/meta/CollapsibleTrigger.md (100%) rename docs/content/{ => en}/meta/ComboboxAnchor.md (100%) rename docs/content/{ => en}/meta/ComboboxArrow.md (100%) rename docs/content/{ => en}/meta/ComboboxCancel.md (100%) rename docs/content/{ => en}/meta/ComboboxContent.md (100%) rename docs/content/{ => en}/meta/ComboboxEmpty.md (100%) rename docs/content/{ => en}/meta/ComboboxGroup.md (100%) rename docs/content/{ => en}/meta/ComboboxInput.md (100%) rename docs/content/{ => en}/meta/ComboboxItem.md (100%) rename docs/content/{ => en}/meta/ComboboxItemIndicator.md (100%) rename docs/content/{ => en}/meta/ComboboxLabel.md (100%) rename docs/content/{ => en}/meta/ComboboxPortal.md (100%) rename docs/content/{ => en}/meta/ComboboxRoot.md (100%) rename docs/content/{ => en}/meta/ComboboxSeparator.md (100%) rename docs/content/{ => en}/meta/ComboboxTrigger.md (100%) rename docs/content/{ => en}/meta/ComboboxViewport.md (100%) rename docs/content/{ => en}/meta/ComboboxVirtualizer.md (100%) rename docs/content/{ => en}/meta/ConfigProvider.md (100%) rename docs/content/{ => en}/meta/ContextMenuArrow.md (100%) rename docs/content/{ => en}/meta/ContextMenuCheckboxItem.md (100%) rename docs/content/{ => en}/meta/ContextMenuContent.md (100%) rename docs/content/{ => en}/meta/ContextMenuGroup.md (100%) rename docs/content/{ => en}/meta/ContextMenuItem.md (100%) rename docs/content/{ => en}/meta/ContextMenuItemIndicator.md (100%) rename docs/content/{ => en}/meta/ContextMenuLabel.md (100%) rename docs/content/{ => en}/meta/ContextMenuPortal.md (100%) rename docs/content/{ => en}/meta/ContextMenuRadioGroup.md (100%) rename docs/content/{ => en}/meta/ContextMenuRadioItem.md (100%) rename docs/content/{ => en}/meta/ContextMenuRoot.md (100%) rename docs/content/{ => en}/meta/ContextMenuSeparator.md (100%) rename docs/content/{ => en}/meta/ContextMenuSub.md (100%) rename docs/content/{ => en}/meta/ContextMenuSubContent.md (100%) rename docs/content/{ => en}/meta/ContextMenuSubTrigger.md (100%) rename docs/content/{ => en}/meta/ContextMenuTrigger.md (100%) rename docs/content/{ => en}/meta/DateFieldInput.md (100%) rename docs/content/{ => en}/meta/DateFieldRoot.md (100%) rename docs/content/{ => en}/meta/DatePickerAnchor.md (100%) rename docs/content/{ => en}/meta/DatePickerArrow.md (100%) rename docs/content/{ => en}/meta/DatePickerCalendar.md (100%) rename docs/content/{ => en}/meta/DatePickerCell.md (100%) rename docs/content/{ => en}/meta/DatePickerCellTrigger.md (100%) rename docs/content/{ => en}/meta/DatePickerClose.md (100%) rename docs/content/{ => en}/meta/DatePickerContent.md (100%) rename docs/content/{ => en}/meta/DatePickerField.md (100%) rename docs/content/{ => en}/meta/DatePickerGrid.md (100%) rename docs/content/{ => en}/meta/DatePickerGridBody.md (100%) rename docs/content/{ => en}/meta/DatePickerGridHead.md (100%) rename docs/content/{ => en}/meta/DatePickerGridRow.md (100%) rename docs/content/{ => en}/meta/DatePickerHeadCell.md (100%) rename docs/content/{ => en}/meta/DatePickerHeader.md (100%) rename docs/content/{ => en}/meta/DatePickerHeading.md (100%) rename docs/content/{ => en}/meta/DatePickerHeadingSegment.md (100%) rename docs/content/{ => en}/meta/DatePickerInput.md (100%) rename docs/content/{ => en}/meta/DatePickerNext.md (100%) rename docs/content/{ => en}/meta/DatePickerPrev.md (100%) rename docs/content/{ => en}/meta/DatePickerRoot.md (100%) rename docs/content/{ => en}/meta/DatePickerTrigger.md (100%) rename docs/content/{ => en}/meta/DateRangeFieldInput.md (100%) rename docs/content/{ => en}/meta/DateRangeFieldRoot.md (100%) rename docs/content/{ => en}/meta/DateRangePickerAnchor.md (100%) rename docs/content/{ => en}/meta/DateRangePickerArrow.md (100%) rename docs/content/{ => en}/meta/DateRangePickerCalendar.md (100%) rename docs/content/{ => en}/meta/DateRangePickerCell.md (100%) rename docs/content/{ => en}/meta/DateRangePickerCellTrigger.md (100%) rename docs/content/{ => en}/meta/DateRangePickerClose.md (100%) rename docs/content/{ => en}/meta/DateRangePickerContent.md (100%) rename docs/content/{ => en}/meta/DateRangePickerField.md (100%) rename docs/content/{ => en}/meta/DateRangePickerGrid.md (100%) rename docs/content/{ => en}/meta/DateRangePickerGridBody.md (100%) rename docs/content/{ => en}/meta/DateRangePickerGridHead.md (100%) rename docs/content/{ => en}/meta/DateRangePickerGridRow.md (100%) rename docs/content/{ => en}/meta/DateRangePickerHeadCell.md (100%) rename docs/content/{ => en}/meta/DateRangePickerHeader.md (100%) rename docs/content/{ => en}/meta/DateRangePickerHeading.md (100%) rename docs/content/{ => en}/meta/DateRangePickerHeadingSegment.md (100%) rename docs/content/{ => en}/meta/DateRangePickerInput.md (100%) rename docs/content/{ => en}/meta/DateRangePickerNext.md (100%) rename docs/content/{ => en}/meta/DateRangePickerPrev.md (100%) rename docs/content/{ => en}/meta/DateRangePickerRoot.md (100%) rename docs/content/{ => en}/meta/DateRangePickerTrigger.md (100%) rename docs/content/{ => en}/meta/DialogClose.md (100%) rename docs/content/{ => en}/meta/DialogContent.md (100%) rename docs/content/{ => en}/meta/DialogDescription.md (100%) rename docs/content/{ => en}/meta/DialogOverlay.md (100%) rename docs/content/{ => en}/meta/DialogPortal.md (100%) rename docs/content/{ => en}/meta/DialogRoot.md (100%) rename docs/content/{ => en}/meta/DialogTitle.md (100%) rename docs/content/{ => en}/meta/DialogTrigger.md (100%) rename docs/content/{ => en}/meta/DropdownMenuArrow.md (100%) rename docs/content/{ => en}/meta/DropdownMenuCheckboxItem.md (100%) rename docs/content/{ => en}/meta/DropdownMenuContent.md (100%) rename docs/content/{ => en}/meta/DropdownMenuGroup.md (100%) rename docs/content/{ => en}/meta/DropdownMenuItem.md (100%) rename docs/content/{ => en}/meta/DropdownMenuItemIndicator.md (100%) rename docs/content/{ => en}/meta/DropdownMenuLabel.md (100%) rename docs/content/{ => en}/meta/DropdownMenuPortal.md (100%) rename docs/content/{ => en}/meta/DropdownMenuRadioGroup.md (100%) rename docs/content/{ => en}/meta/DropdownMenuRadioItem.md (100%) rename docs/content/{ => en}/meta/DropdownMenuRoot.md (100%) rename docs/content/{ => en}/meta/DropdownMenuSeparator.md (100%) rename docs/content/{ => en}/meta/DropdownMenuSub.md (100%) rename docs/content/{ => en}/meta/DropdownMenuSubContent.md (100%) rename docs/content/{ => en}/meta/DropdownMenuSubTrigger.md (100%) rename docs/content/{ => en}/meta/DropdownMenuTrigger.md (100%) rename docs/content/{ => en}/meta/EditableArea.md (100%) rename docs/content/{ => en}/meta/EditableCancelTrigger.md (100%) rename docs/content/{ => en}/meta/EditableEditTrigger.md (100%) rename docs/content/{ => en}/meta/EditableInput.md (100%) rename docs/content/{ => en}/meta/EditablePreview.md (100%) rename docs/content/{ => en}/meta/EditableRoot.md (100%) rename docs/content/{ => en}/meta/EditableSubmitTrigger.md (100%) rename docs/content/{ => en}/meta/FocusScope.md (100%) rename docs/content/{ => en}/meta/HoverCardArrow.md (100%) rename docs/content/{ => en}/meta/HoverCardContent.md (100%) rename docs/content/{ => en}/meta/HoverCardPortal.md (100%) rename docs/content/{ => en}/meta/HoverCardRoot.md (100%) rename docs/content/{ => en}/meta/HoverCardTrigger.md (100%) rename docs/content/{ => en}/meta/Label.md (100%) rename docs/content/{ => en}/meta/ListboxContent.md (100%) rename docs/content/{ => en}/meta/ListboxFilter.md (100%) rename docs/content/{ => en}/meta/ListboxGroup.md (100%) rename docs/content/{ => en}/meta/ListboxGroupLabel.md (100%) rename docs/content/{ => en}/meta/ListboxItem.md (100%) rename docs/content/{ => en}/meta/ListboxItemIndicator.md (100%) rename docs/content/{ => en}/meta/ListboxRoot.md (100%) rename docs/content/{ => en}/meta/ListboxVirtualizer.md (100%) rename docs/content/{ => en}/meta/MenubarArrow.md (100%) rename docs/content/{ => en}/meta/MenubarCheckboxItem.md (100%) rename docs/content/{ => en}/meta/MenubarContent.md (100%) rename docs/content/{ => en}/meta/MenubarGroup.md (100%) rename docs/content/{ => en}/meta/MenubarItem.md (100%) rename docs/content/{ => en}/meta/MenubarItemIndicator.md (100%) rename docs/content/{ => en}/meta/MenubarLabel.md (100%) rename docs/content/{ => en}/meta/MenubarMenu.md (100%) rename docs/content/{ => en}/meta/MenubarPortal.md (100%) rename docs/content/{ => en}/meta/MenubarRadioGroup.md (100%) rename docs/content/{ => en}/meta/MenubarRadioItem.md (100%) rename docs/content/{ => en}/meta/MenubarRoot.md (100%) rename docs/content/{ => en}/meta/MenubarSeparator.md (100%) rename docs/content/{ => en}/meta/MenubarSub.md (100%) rename docs/content/{ => en}/meta/MenubarSubContent.md (100%) rename docs/content/{ => en}/meta/MenubarSubTrigger.md (100%) rename docs/content/{ => en}/meta/MenubarTrigger.md (100%) rename docs/content/{ => en}/meta/NavigationMenuContent.md (100%) rename docs/content/{ => en}/meta/NavigationMenuIndicator.md (100%) rename docs/content/{ => en}/meta/NavigationMenuItem.md (100%) rename docs/content/{ => en}/meta/NavigationMenuLink.md (100%) rename docs/content/{ => en}/meta/NavigationMenuList.md (100%) rename docs/content/{ => en}/meta/NavigationMenuRoot.md (100%) rename docs/content/{ => en}/meta/NavigationMenuSub.md (100%) rename docs/content/{ => en}/meta/NavigationMenuTrigger.md (100%) rename docs/content/{ => en}/meta/NavigationMenuViewport.md (100%) rename docs/content/{ => en}/meta/NumberFieldDecrement.md (100%) rename docs/content/{ => en}/meta/NumberFieldIncrement.md (100%) rename docs/content/{ => en}/meta/NumberFieldInput.md (100%) rename docs/content/{ => en}/meta/NumberFieldLabel.md (100%) rename docs/content/{ => en}/meta/NumberFieldRoot.md (100%) rename docs/content/{ => en}/meta/PaginationEllipsis.md (100%) rename docs/content/{ => en}/meta/PaginationFirst.md (100%) rename docs/content/{ => en}/meta/PaginationLast.md (100%) rename docs/content/{ => en}/meta/PaginationList.md (100%) rename docs/content/{ => en}/meta/PaginationListItem.md (100%) rename docs/content/{ => en}/meta/PaginationNext.md (100%) rename docs/content/{ => en}/meta/PaginationPrev.md (100%) rename docs/content/{ => en}/meta/PaginationRoot.md (100%) rename docs/content/{ => en}/meta/PinInputInput.md (100%) rename docs/content/{ => en}/meta/PinInputRoot.md (100%) rename docs/content/{ => en}/meta/PopoverAnchor.md (100%) rename docs/content/{ => en}/meta/PopoverArrow.md (100%) rename docs/content/{ => en}/meta/PopoverClose.md (100%) rename docs/content/{ => en}/meta/PopoverContent.md (100%) rename docs/content/{ => en}/meta/PopoverPortal.md (100%) rename docs/content/{ => en}/meta/PopoverRoot.md (100%) rename docs/content/{ => en}/meta/PopoverTrigger.md (100%) rename docs/content/{ => en}/meta/ProgressIndicator.md (100%) rename docs/content/{ => en}/meta/ProgressRoot.md (100%) rename docs/content/{ => en}/meta/RadioGroupIndicator.md (100%) rename docs/content/{ => en}/meta/RadioGroupItem.md (100%) rename docs/content/{ => en}/meta/RadioGroupRoot.md (100%) rename docs/content/{ => en}/meta/RangeCalendarCell.md (100%) rename docs/content/{ => en}/meta/RangeCalendarCellTrigger.md (100%) rename docs/content/{ => en}/meta/RangeCalendarGrid.md (100%) rename docs/content/{ => en}/meta/RangeCalendarGridBody.md (100%) rename docs/content/{ => en}/meta/RangeCalendarGridHead.md (100%) rename docs/content/{ => en}/meta/RangeCalendarGridRow.md (100%) rename docs/content/{ => en}/meta/RangeCalendarHeadCell.md (100%) rename docs/content/{ => en}/meta/RangeCalendarHeader.md (100%) rename docs/content/{ => en}/meta/RangeCalendarHeading.md (100%) rename docs/content/{ => en}/meta/RangeCalendarHeadingSegment.md (100%) rename docs/content/{ => en}/meta/RangeCalendarNext.md (100%) rename docs/content/{ => en}/meta/RangeCalendarPrev.md (100%) rename docs/content/{ => en}/meta/RangeCalendarRoot.md (100%) rename docs/content/{ => en}/meta/ScrollAreaCorner.md (100%) rename docs/content/{ => en}/meta/ScrollAreaRoot.md (100%) rename docs/content/{ => en}/meta/ScrollAreaScrollbar.md (100%) rename docs/content/{ => en}/meta/ScrollAreaThumb.md (100%) rename docs/content/{ => en}/meta/ScrollAreaViewport.md (100%) rename docs/content/{ => en}/meta/SelectArrow.md (100%) rename docs/content/{ => en}/meta/SelectContent.md (100%) rename docs/content/{ => en}/meta/SelectGroup.md (100%) rename docs/content/{ => en}/meta/SelectIcon.md (100%) rename docs/content/{ => en}/meta/SelectItem.md (100%) rename docs/content/{ => en}/meta/SelectItemIndicator.md (100%) rename docs/content/{ => en}/meta/SelectItemText.md (100%) rename docs/content/{ => en}/meta/SelectLabel.md (100%) rename docs/content/{ => en}/meta/SelectPortal.md (100%) rename docs/content/{ => en}/meta/SelectRoot.md (100%) rename docs/content/{ => en}/meta/SelectScrollDownButton.md (100%) rename docs/content/{ => en}/meta/SelectScrollUpButton.md (100%) rename docs/content/{ => en}/meta/SelectSeparator.md (100%) rename docs/content/{ => en}/meta/SelectTrigger.md (100%) rename docs/content/{ => en}/meta/SelectValue.md (100%) rename docs/content/{ => en}/meta/SelectViewport.md (100%) rename docs/content/{ => en}/meta/Separator.md (100%) rename docs/content/{ => en}/meta/SliderRange.md (100%) rename docs/content/{ => en}/meta/SliderRoot.md (100%) rename docs/content/{ => en}/meta/SliderThumb.md (100%) rename docs/content/{ => en}/meta/SliderTrack.md (100%) rename docs/content/{ => en}/meta/SplitterGroup.md (100%) rename docs/content/{ => en}/meta/SplitterPanel.md (100%) rename docs/content/{ => en}/meta/SplitterResizeHandle.md (100%) rename docs/content/{ => en}/meta/StepperDescription.md (100%) rename docs/content/{ => en}/meta/StepperIndicator.md (100%) rename docs/content/{ => en}/meta/StepperItem.md (100%) rename docs/content/{ => en}/meta/StepperList.md (100%) rename docs/content/{ => en}/meta/StepperRoot.md (100%) rename docs/content/{ => en}/meta/StepperSeparator.md (100%) rename docs/content/{ => en}/meta/StepperTitle.md (100%) rename docs/content/{ => en}/meta/StepperTrigger.md (100%) rename docs/content/{ => en}/meta/SwitchRoot.md (100%) rename docs/content/{ => en}/meta/SwitchThumb.md (100%) rename docs/content/{ => en}/meta/TabsContent.md (100%) rename docs/content/{ => en}/meta/TabsIndicator.md (100%) rename docs/content/{ => en}/meta/TabsList.md (100%) rename docs/content/{ => en}/meta/TabsRoot.md (100%) rename docs/content/{ => en}/meta/TabsTrigger.md (100%) rename docs/content/{ => en}/meta/TagsInputClear.md (100%) rename docs/content/{ => en}/meta/TagsInputInput.md (100%) rename docs/content/{ => en}/meta/TagsInputItem.md (100%) rename docs/content/{ => en}/meta/TagsInputItemDelete.md (100%) rename docs/content/{ => en}/meta/TagsInputItemText.md (100%) rename docs/content/{ => en}/meta/TagsInputRoot.md (100%) rename docs/content/{ => en}/meta/TimeFieldInput.md (100%) rename docs/content/{ => en}/meta/TimeFieldRoot.md (100%) rename docs/content/{ => en}/meta/ToastAction.md (100%) rename docs/content/{ => en}/meta/ToastClose.md (100%) rename docs/content/{ => en}/meta/ToastDescription.md (100%) rename docs/content/{ => en}/meta/ToastPortal.md (100%) rename docs/content/{ => en}/meta/ToastProvider.md (100%) rename docs/content/{ => en}/meta/ToastRoot.md (100%) rename docs/content/{ => en}/meta/ToastTitle.md (100%) rename docs/content/{ => en}/meta/ToastViewport.md (100%) rename docs/content/{ => en}/meta/Toggle.md (100%) rename docs/content/{ => en}/meta/ToggleGroupItem.md (100%) rename docs/content/{ => en}/meta/ToggleGroupRoot.md (100%) rename docs/content/{ => en}/meta/ToolbarButton.md (100%) rename docs/content/{ => en}/meta/ToolbarLink.md (100%) rename docs/content/{ => en}/meta/ToolbarRoot.md (100%) rename docs/content/{ => en}/meta/ToolbarSeparator.md (100%) rename docs/content/{ => en}/meta/ToolbarToggleGroup.md (100%) rename docs/content/{ => en}/meta/ToolbarToggleItem.md (100%) rename docs/content/{ => en}/meta/TooltipArrow.md (100%) rename docs/content/{ => en}/meta/TooltipContent.md (100%) rename docs/content/{ => en}/meta/TooltipPortal.md (100%) rename docs/content/{ => en}/meta/TooltipProvider.md (100%) rename docs/content/{ => en}/meta/TooltipRoot.md (100%) rename docs/content/{ => en}/meta/TooltipTrigger.md (100%) rename docs/content/{ => en}/meta/TreeItem.md (100%) rename docs/content/{ => en}/meta/TreeRoot.md (100%) rename docs/content/{ => en}/meta/TreeVirtualizer.md (100%) rename docs/content/{ => en}/meta/Viewport.md (100%) rename docs/content/{ => en}/meta/VisuallyHidden.md (100%) rename docs/content/{ => en}/showcase.md (100%) create mode 100644 docs/lunaria.config.json diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config/en.ts similarity index 78% rename from docs/.vitepress/config.ts rename to docs/.vitepress/config/en.ts index 03d4d77a4..4123f6d48 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config/en.ts @@ -1,12 +1,7 @@ -import { defineConfig, postcssIsolateStyles } from 'vitepress' -import autoprefixer from 'autoprefixer' -import anchor from 'markdown-it-anchor' -import tailwind from 'tailwindcss' +import { defineConfig } from 'vitepress' import { version } from '../../package.json' import { - discord, font, - github, legacyLink, legacyVersion, ogImage, @@ -15,21 +10,12 @@ import { rekaName, rekaShortName, releases, -} from './meta' -import { teamMembers } from './contributors' -import ComponentPreviewPlugin from './plugins/ComponentPreview' -import InstallationTabsPlugin from './plugins/InstallationTabs' -import { createHoverTransformer } from './plugins/HoverTransformer' +} from '../meta' +import { teamMembers } from '../contributors' +import { BadgeHTML } from '.' -function BadgeHTML(text: string, translucent = false) { - return `
-${text} -
-` -} - -// https://vitepress.dev/reference/site-config export default defineConfig({ + lang: 'en', cleanUrls: true, title: rekaName, description: rekaDescription, @@ -88,10 +74,6 @@ export default defineConfig({ ], }, ], - outline: { - level: [2, 3], - }, - logo: '/logo.svg', sidebar: [ { @@ -350,79 +332,15 @@ export default defineConfig({ }, ], - socialLinks: [ - { icon: 'discord', link: discord }, - { icon: 'github', link: github }, - ], - search: { provider: 'local', }, editLink: { - pattern: 'https://github.com/unovue/reka-ui/edit/main/docs/content/:path', + pattern: 'https://github.com/unovue/reka-ui/edit/main/docs/content/en/:path', }, carbonAds: { code: 'CW7DP2JW', placement: 'reka-uicom', }, }, - srcDir: 'content', - appearance: 'dark', - markdown: { - theme: 'github-dark', - headers: { - level: [2, 3], - }, - anchor: { - callback(token) { - // set tw `group` modifier to heading element - token.attrSet( - 'class', - 'group relative border-none mb-4 lg:-ml-2 lg:pl-2 lg:pr-2 w-max', - ) - }, - permalink: anchor.permalink.linkInsideHeader({ - class: - 'header-anchor [&_span]:focus:opacity-100 [&_span_>_span]:focus:outline', - symbol: ``, - renderAttrs: (slug, state) => { - // From: https://github.com/vuejs/vitepress/blob/256d742b733bfb62d54c78168b0e867b8eb829c9/src/node/markdown/markdown.ts#L263 - // Find `heading_open` with the id identical to slug - const idx = state.tokens.findIndex((token) => { - const attrs = token.attrs - const id = attrs?.find(attr => attr[0] === 'id') - return id && slug === id[1] - }) - // Get the actual heading content - const title = state.tokens[idx + 1].content - return { - 'aria-label': `Permalink to "${title}"`, - } - }, - }), - }, - - preConfig(md) { - md.use(ComponentPreviewPlugin) - md.use(InstallationTabsPlugin) - }, - codeTransformers: [createHoverTransformer()], - }, - transformPageData(pageData) { - if (pageData.frontmatter.sidebar != null) - return - // hide sidebar on showcase page - pageData.frontmatter.sidebar = pageData.frontmatter.layout !== 'showcase' - }, - vite: { - css: { - postcss: { - plugins: [ - tailwind(), - autoprefixer(), - postcssIsolateStyles({ includeFiles: [/vp-doc\.css/] }), - ], - }, - }, - }, }) diff --git a/docs/.vitepress/config/index.ts b/docs/.vitepress/config/index.ts new file mode 100644 index 000000000..635486f9d --- /dev/null +++ b/docs/.vitepress/config/index.ts @@ -0,0 +1,160 @@ +import { defineConfig, postcssIsolateStyles } from 'vitepress' +import autoprefixer from 'autoprefixer' +import anchor from 'markdown-it-anchor' +import tailwind from 'tailwindcss' +import { + discord, + font, + github, + ogImage, + ogUrl, + rekaDescription, + rekaName, + rekaShortName, +} from '../meta' +import { teamMembers } from '../contributors' +import ComponentPreviewPlugin from '../plugins/ComponentPreview' +import InstallationTabsPlugin from '../plugins/InstallationTabs' +import { createHoverTransformer } from '../plugins/HoverTransformer' +import en from './en' + +export function BadgeHTML(text: string, translucent = false) { + return `
+${text} +
+` +} + +// https://vitepress.dev/reference/site-config +export default defineConfig({ + cleanUrls: true, + title: rekaName, + description: rekaDescription, + titleTemplate: rekaShortName, + head: [ + ['meta', { name: 'theme-color', content: '#00C38A' }], + ['link', { rel: 'icon', href: '/logo.png' }], + ['link', { rel: 'icon', href: '/logo.svg', type: 'image/svg+xml' }], + ['meta', { name: 'author', content: `${teamMembers.map(c => c.name).join(', ')} and ${rekaName} contributors` }], + ['meta', { name: 'keywords', content: 'vue, nuxt, component-library, radix, radix-vue, reka-ui, typescript' }], + ['meta', { property: 'og:title', content: rekaName }], + ['meta', { property: 'og:description', content: rekaDescription }], + ['meta', { property: 'og:url', content: ogUrl }], + ['meta', { property: 'og:image', content: ogImage }], + ['meta', { name: 'twitter:title', content: rekaName }], + ['meta', { name: 'twitter:description', content: rekaDescription }], + ['meta', { name: 'twitter:image', content: ogImage }], + ['meta', { name: 'twitter:card', content: 'summary_large_image' }], + [ + 'link', + { + rel: 'preload', + as: 'style', + onload: 'this.onload=null;this.rel=\'stylesheet\'', + href: font, + }, + ], + [ + 'noscript', + {}, + ``, + ], + ['link', { rel: 'mask-icon', href: '/logo.svg', color: '#ffffff' }], + [ + 'link', + { + rel: 'apple-touch-icon', + href: '/apple-touch-icon.png', + sizes: '180x180', + }, + ], + ], + lastUpdated: true, + sitemap: { hostname: ogUrl }, + themeConfig: { + + outline: { + level: [2, 3], + }, + logo: '/logo.svg', + + socialLinks: [ + { icon: 'discord', link: discord }, + { icon: 'github', link: github }, + ], + + search: { + provider: 'local', + }, + carbonAds: { + code: 'CW7DP2JW', + placement: 'reka-uicom', + }, + }, + srcDir: 'content', + appearance: 'dark', + markdown: { + theme: 'github-dark', + headers: { + level: [2, 3], + }, + anchor: { + callback(token) { + // set tw `group` modifier to heading element + token.attrSet( + 'class', + 'group relative border-none mb-4 lg:-ml-2 lg:pl-2 lg:pr-2 w-max', + ) + }, + permalink: anchor.permalink.linkInsideHeader({ + class: + 'header-anchor [&_span]:focus:opacity-100 [&_span_>_span]:focus:outline', + symbol: ``, + renderAttrs: (slug, state) => { + // From: https://github.com/vuejs/vitepress/blob/256d742b733bfb62d54c78168b0e867b8eb829c9/src/node/markdown/markdown.ts#L263 + // Find `heading_open` with the id identical to slug + const idx = state.tokens.findIndex((token) => { + const attrs = token.attrs + const id = attrs?.find(attr => attr[0] === 'id') + return id && slug === id[1] + }) + // Get the actual heading content + const title = state.tokens[idx + 1].content + return { + 'aria-label': `Permalink to "${title}"`, + } + }, + }), + }, + + preConfig(md) { + md.use(ComponentPreviewPlugin) + md.use(InstallationTabsPlugin) + }, + codeTransformers: [createHoverTransformer()], + }, + transformPageData(pageData) { + if (pageData.frontmatter.sidebar != null) + return + // hide sidebar on showcase page + pageData.frontmatter.sidebar = pageData.frontmatter.layout !== 'showcase' + }, + vite: { + css: { + postcss: { + plugins: [ + tailwind(), + autoprefixer(), + postcssIsolateStyles({ includeFiles: [/vp-doc\.css/] }), + ], + }, + }, + }, + rewrites: { + 'en/:rest*': ':rest*', + }, + locales: { + root: { label: 'English', ...en }, + // zh: { label: '简体中文', ...zh }, + }, +}) diff --git a/docs/content/docs/components/accordion.md b/docs/content/en/docs/components/accordion.md similarity index 100% rename from docs/content/docs/components/accordion.md rename to docs/content/en/docs/components/accordion.md diff --git a/docs/content/docs/components/alert-dialog.md b/docs/content/en/docs/components/alert-dialog.md similarity index 100% rename from docs/content/docs/components/alert-dialog.md rename to docs/content/en/docs/components/alert-dialog.md diff --git a/docs/content/docs/components/aspect-ratio.md b/docs/content/en/docs/components/aspect-ratio.md similarity index 100% rename from docs/content/docs/components/aspect-ratio.md rename to docs/content/en/docs/components/aspect-ratio.md diff --git a/docs/content/docs/components/avatar.md b/docs/content/en/docs/components/avatar.md similarity index 100% rename from docs/content/docs/components/avatar.md rename to docs/content/en/docs/components/avatar.md diff --git a/docs/content/docs/components/calendar.md b/docs/content/en/docs/components/calendar.md similarity index 100% rename from docs/content/docs/components/calendar.md rename to docs/content/en/docs/components/calendar.md diff --git a/docs/content/docs/components/checkbox.md b/docs/content/en/docs/components/checkbox.md similarity index 100% rename from docs/content/docs/components/checkbox.md rename to docs/content/en/docs/components/checkbox.md diff --git a/docs/content/docs/components/collapsible.md b/docs/content/en/docs/components/collapsible.md similarity index 100% rename from docs/content/docs/components/collapsible.md rename to docs/content/en/docs/components/collapsible.md diff --git a/docs/content/docs/components/combobox.md b/docs/content/en/docs/components/combobox.md similarity index 100% rename from docs/content/docs/components/combobox.md rename to docs/content/en/docs/components/combobox.md diff --git a/docs/content/docs/components/context-menu.md b/docs/content/en/docs/components/context-menu.md similarity index 100% rename from docs/content/docs/components/context-menu.md rename to docs/content/en/docs/components/context-menu.md diff --git a/docs/content/docs/components/date-field.md b/docs/content/en/docs/components/date-field.md similarity index 100% rename from docs/content/docs/components/date-field.md rename to docs/content/en/docs/components/date-field.md diff --git a/docs/content/docs/components/date-picker.md b/docs/content/en/docs/components/date-picker.md similarity index 100% rename from docs/content/docs/components/date-picker.md rename to docs/content/en/docs/components/date-picker.md diff --git a/docs/content/docs/components/date-range-field.md b/docs/content/en/docs/components/date-range-field.md similarity index 100% rename from docs/content/docs/components/date-range-field.md rename to docs/content/en/docs/components/date-range-field.md diff --git a/docs/content/docs/components/date-range-picker.md b/docs/content/en/docs/components/date-range-picker.md similarity index 100% rename from docs/content/docs/components/date-range-picker.md rename to docs/content/en/docs/components/date-range-picker.md diff --git a/docs/content/docs/components/dialog.md b/docs/content/en/docs/components/dialog.md similarity index 100% rename from docs/content/docs/components/dialog.md rename to docs/content/en/docs/components/dialog.md diff --git a/docs/content/docs/components/dropdown-menu.md b/docs/content/en/docs/components/dropdown-menu.md similarity index 100% rename from docs/content/docs/components/dropdown-menu.md rename to docs/content/en/docs/components/dropdown-menu.md diff --git a/docs/content/docs/components/editable.md b/docs/content/en/docs/components/editable.md similarity index 100% rename from docs/content/docs/components/editable.md rename to docs/content/en/docs/components/editable.md diff --git a/docs/content/docs/components/hover-card.md b/docs/content/en/docs/components/hover-card.md similarity index 100% rename from docs/content/docs/components/hover-card.md rename to docs/content/en/docs/components/hover-card.md diff --git a/docs/content/docs/components/label.md b/docs/content/en/docs/components/label.md similarity index 100% rename from docs/content/docs/components/label.md rename to docs/content/en/docs/components/label.md diff --git a/docs/content/docs/components/listbox.md b/docs/content/en/docs/components/listbox.md similarity index 100% rename from docs/content/docs/components/listbox.md rename to docs/content/en/docs/components/listbox.md diff --git a/docs/content/docs/components/menubar.md b/docs/content/en/docs/components/menubar.md similarity index 100% rename from docs/content/docs/components/menubar.md rename to docs/content/en/docs/components/menubar.md diff --git a/docs/content/docs/components/navigation-menu.md b/docs/content/en/docs/components/navigation-menu.md similarity index 100% rename from docs/content/docs/components/navigation-menu.md rename to docs/content/en/docs/components/navigation-menu.md diff --git a/docs/content/docs/components/number-field.md b/docs/content/en/docs/components/number-field.md similarity index 100% rename from docs/content/docs/components/number-field.md rename to docs/content/en/docs/components/number-field.md diff --git a/docs/content/docs/components/pagination.md b/docs/content/en/docs/components/pagination.md similarity index 100% rename from docs/content/docs/components/pagination.md rename to docs/content/en/docs/components/pagination.md diff --git a/docs/content/docs/components/pin-input.md b/docs/content/en/docs/components/pin-input.md similarity index 100% rename from docs/content/docs/components/pin-input.md rename to docs/content/en/docs/components/pin-input.md diff --git a/docs/content/docs/components/popover.md b/docs/content/en/docs/components/popover.md similarity index 100% rename from docs/content/docs/components/popover.md rename to docs/content/en/docs/components/popover.md diff --git a/docs/content/docs/components/progress.md b/docs/content/en/docs/components/progress.md similarity index 100% rename from docs/content/docs/components/progress.md rename to docs/content/en/docs/components/progress.md diff --git a/docs/content/docs/components/radio-group.md b/docs/content/en/docs/components/radio-group.md similarity index 100% rename from docs/content/docs/components/radio-group.md rename to docs/content/en/docs/components/radio-group.md diff --git a/docs/content/docs/components/range-calendar.md b/docs/content/en/docs/components/range-calendar.md similarity index 100% rename from docs/content/docs/components/range-calendar.md rename to docs/content/en/docs/components/range-calendar.md diff --git a/docs/content/docs/components/scroll-area.md b/docs/content/en/docs/components/scroll-area.md similarity index 100% rename from docs/content/docs/components/scroll-area.md rename to docs/content/en/docs/components/scroll-area.md diff --git a/docs/content/docs/components/select.md b/docs/content/en/docs/components/select.md similarity index 97% rename from docs/content/docs/components/select.md rename to docs/content/en/docs/components/select.md index 099eb78a7..f493afd3c 100644 --- a/docs/content/docs/components/select.md +++ b/docs/content/en/docs/components/select.md @@ -528,11 +528,11 @@ import { ### Controlling the value displayed in the trigger -By default the trigger will automatically display the selected item `ItemText`'s content. You can control what appears by choosing to put things inside/outside the `ItemText` part. +By default the trigger display the selected item's text (no longer automatically render `ItemText`'s content like in v1). -If you need more flexibility, you can control the component using `v-model` props and passing `slot` to `SelectValue`. Remember to make sure what you put in there is accessible. +If you need to render other than plain text, you can control the component using `v-model` props (or accessing `SelectValue`'s slotProps) and passing `slot` to `SelectValue`. Remember to make sure what you put in there is accessible. -```vue line=2,4,8 +```vue line=2,4,10-12 @@ -32,6 +33,7 @@ defineProps<{ @@ -39,6 +41,7 @@ defineProps<{ diff --git a/docs/.vitepress/components/DocSidebarItem.vue b/docs/.vitepress/components/DocSidebarItem.vue index 2eaf7b89b..a3d0d0699 100644 --- a/docs/.vitepress/components/DocSidebarItem.vue +++ b/docs/.vitepress/components/DocSidebarItem.vue @@ -2,8 +2,10 @@ import { computed, watch } from 'vue' import { type SidebarItem, useSidebarControl } from '../composables/sidebar' import { useCurrentElement } from '@vueuse/core' +import { withBase } from 'ufo' const props = defineProps<{ + base?: string item: SidebarItem }>() const { isActiveLink } = useSidebarControl(computed(() => props.item)) @@ -25,8 +27,8 @@ watch(isActiveLink, () => { :class="{ 'is-active !bg-primary/10 !text-primary font-semibold': isActiveLink }" > diff --git a/docs/.vitepress/components/DocTopbar.vue b/docs/.vitepress/components/DocTopbar.vue index 1763d9cbc..de45652de 100644 --- a/docs/.vitepress/components/DocTopbar.vue +++ b/docs/.vitepress/components/DocTopbar.vue @@ -4,6 +4,7 @@ import { type DefaultTheme, useData, useRoute } from 'vitepress' import { computed, ref, toRefs, watch } from 'vue' import { Icon } from '@iconify/vue' import { DialogContent, DialogDescription, DialogOverlay, DialogPortal, DialogRoot, DialogTitle, DialogTrigger } from 'reka-ui' +import { withBase } from 'ufo' import { flatten } from '../functions/flatten' import DocSidebarItem from '../components/DocSidebarItem.vue' @@ -13,7 +14,10 @@ const { page, theme } = useData() const isSidebarOpen = ref(false) const sidebar = computed(() => (theme.value.sidebar as DefaultTheme.SidebarItem[])) -const sectionTabs = computed(() => sidebar.value.map(val => ({ label: val.text, link: flatten(val.items ?? [], 'items').filter(i => !!i.link)?.[0].link, icon: val.icon }))) +const sectionTabs = computed(() => sidebar.value.map((val) => { + const _link = flatten(val.items ?? [], 'items').filter(i => !!i.link)?.[0].link + return { label: val.text, link: val.base ? withBase(_link, val.base) : _link, icon: val.icon } +})) const { arrivedState } = useScroll(globalThis.window) const { top } = toRefs(arrivedState) diff --git a/docs/.vitepress/components/DropdownMenu.vue b/docs/.vitepress/components/DropdownMenu.vue index 7ca2a0894..2f19280b5 100644 --- a/docs/.vitepress/components/DropdownMenu.vue +++ b/docs/.vitepress/components/DropdownMenu.vue @@ -1,9 +1,11 @@ + + + { + + + + + + + + + + + + {{ item.text }} + + + + + + ({ + label: site.value.locales[localeIndex.value]?.label, + link: + site.value.locales[localeIndex.value]?.link + || (localeIndex.value === 'root' ? '/' : `/${localeIndex.value}/`), + })) + + const localeLinks = computed(() => + Object.entries(site.value.locales).flatMap(([key, value]) => + currentLang.value.label === value.label + ? [] + : { + text: value.label, + link: + normalizeLink( + value.link || (key === 'root' ? '/' : `/${key}/`), + theme.value.i18nRouting !== false && correspondingLink, + page.value.relativePath.slice( + currentLang.value.link.length - 1, + ), + !site.value.cleanUrls, + ) + hash.value, + }, + ), + ) + + return { localeLinks, currentLang } +} + +function normalizeLink( + link: string, + addPath: boolean, + path: string, + addExt: boolean, +) { + return addPath + ? link.replace(/\/$/, '') + + ensureStartingSlash( + path + .replace(/(^|\/)index\.md$/, '$1') + .replace(/\.md$/, addExt ? '.html' : ''), + ) + : link +} diff --git a/docs/.vitepress/config/en.ts b/docs/.vitepress/config/en.ts index 4123f6d48..bd45cf05e 100644 --- a/docs/.vitepress/config/en.ts +++ b/docs/.vitepress/config/en.ts @@ -1,65 +1,21 @@ import { defineConfig } from 'vitepress' import { version } from '../../package.json' import { - font, legacyLink, legacyVersion, - ogImage, - ogUrl, rekaDescription, rekaName, rekaShortName, releases, } from '../meta' -import { teamMembers } from '../contributors' import { BadgeHTML } from '.' export default defineConfig({ lang: 'en', - cleanUrls: true, title: rekaName, description: rekaDescription, titleTemplate: rekaShortName, - head: [ - ['meta', { name: 'theme-color', content: '#00C38A' }], - ['link', { rel: 'icon', href: '/logo.png' }], - ['link', { rel: 'icon', href: '/logo.svg', type: 'image/svg+xml' }], - ['meta', { name: 'author', content: `${teamMembers.map(c => c.name).join(', ')} and ${rekaName} contributors` }], - ['meta', { name: 'keywords', content: 'vue, nuxt, component-library, radix, radix-vue, reka-ui, typescript' }], - ['meta', { property: 'og:title', content: rekaName }], - ['meta', { property: 'og:description', content: rekaDescription }], - ['meta', { property: 'og:url', content: ogUrl }], - ['meta', { property: 'og:image', content: ogImage }], - ['meta', { name: 'twitter:title', content: rekaName }], - ['meta', { name: 'twitter:description', content: rekaDescription }], - ['meta', { name: 'twitter:image', content: ogImage }], - ['meta', { name: 'twitter:card', content: 'summary_large_image' }], - [ - 'link', - { - rel: 'preload', - as: 'style', - onload: 'this.onload=null;this.rel=\'stylesheet\'', - href: font, - }, - ], - [ - 'noscript', - {}, - ``, - ], - ['link', { rel: 'mask-icon', href: '/logo.svg', color: '#ffffff' }], - [ - 'link', - { - rel: 'apple-touch-icon', - href: '/apple-touch-icon.png', - sizes: '180x180', - }, - ], - ], lastUpdated: true, - sitemap: { hostname: ogUrl }, themeConfig: { // https://vitepress.dev/reference/default-theme-config nav: [ @@ -336,7 +292,7 @@ export default defineConfig({ provider: 'local', }, editLink: { - pattern: 'https://github.com/unovue/reka-ui/edit/main/docs/content/en/:path', + pattern: 'https://github.com/unovue/radix-vue/edit/main/docs/content/:path', }, carbonAds: { code: 'CW7DP2JW', diff --git a/docs/.vitepress/config/index.ts b/docs/.vitepress/config/index.ts index 635486f9d..3d95ba0ce 100644 --- a/docs/.vitepress/config/index.ts +++ b/docs/.vitepress/config/index.ts @@ -16,7 +16,11 @@ import { teamMembers } from '../contributors' import ComponentPreviewPlugin from '../plugins/ComponentPreview' import InstallationTabsPlugin from '../plugins/InstallationTabs' import { createHoverTransformer } from '../plugins/HoverTransformer' +import { dirname, resolve } from 'node:path' +import { fileURLToPath } from 'node:url' +import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite' import en from './en' +import zh from './zh' export function BadgeHTML(text: string, translucent = false) { return `
@@ -149,12 +153,19 @@ export default defineConfig({ ], }, }, + plugins: [ + VueI18nPlugin({ + // locale messages resource pre-compile option + include: resolve(dirname(fileURLToPath(import.meta.url)), '../../locales/**'), + ssr: true, + }), + ], }, rewrites: { 'en/:rest*': ':rest*', }, locales: { root: { label: 'English', ...en }, - // zh: { label: '简体中文', ...zh }, + zh: { label: '简体中文', ...zh }, }, }) diff --git a/docs/.vitepress/config/zh.ts b/docs/.vitepress/config/zh.ts new file mode 100644 index 000000000..61b8696bf --- /dev/null +++ b/docs/.vitepress/config/zh.ts @@ -0,0 +1,338 @@ +import { defineConfig } from 'vitepress' +import { version } from '../../package.json' +import { + legacyLink, + legacyVersion, + releases, +} from '../meta' +import { BadgeHTML } from '.' + +export default defineConfig({ + lang: 'zh', + description: '使用 Vue 构建高质量设计系统和 Web 应用程序的无样式、可访问的组件', + themeConfig: { + nav: [ + { text: '文档', link: '/zh/docs/overview/getting-started' }, + { text: '示例', link: '/zh/examples/checkbox-group' }, + { text: '样例', link: '/zh/showcase' }, + { + text: `v${version}`, + items: [ + { text: '发布日志 ', link: releases }, + { text: legacyVersion, link: legacyLink }, + ], + }, + ], + + sidebar: [ + { + text: '总览', + icon: 'lucide:rocket', + base: '/zh/docs/overview/', + items: [ + { text: '介绍', link: '/introduction' }, + { text: '开始', link: '/getting-started' }, + { text: '安装', link: '/installation' }, + { text: '可访问性', link: '/accessibility' }, + { text: '发布物', link: '/releases' }, + ], + }, + { + text: '指南', + icon: 'lucide:book-open', + base: '/zh/docs/guides/', + items: [ + { text: '样式', link: '/styling' }, + { text: '动画/渐变', link: '/animation' }, + { text: '组合式', link: '/composition' }, + { text: '服务端渲染', link: '/server-side-rendering' }, + { text: '命名空间', link: '/namespaced-components' }, + { text: '日期处理', link: '/dates' }, + { text: '国际化 (RTL)', link: '/i18n' }, + { + text: `注入上下文 ${BadgeHTML('New')}`, + link: '/guides/inject-context', + }, + { + text: `可视化 ${BadgeHTML('New')}`, + link: '/guides/virtualization', + }, + { + text: `迁移 ${BadgeHTML('New')}`, + link: '/guides/migration', + }, + ], + }, + { + text: '组件', + icon: 'lucide:box', + base: '/zh/docs/components/', + items: [ + { + text: '表单', + items: [ + { text: 'Checkbox 复选框', link: '/checkbox' }, + { text: 'Combobox 组合框', link: '/combobox' }, + { text: `Editable 可编辑的`, link: '/editable' }, + { text: `Listbox 列表框`, link: '/listbox' }, + { text: `Number Field 数字字段`, link: '/number-field' }, + { text: 'Label 标签', link: '/label' }, + { text: 'Pin Input Pin 输入', link: '/pin-input' }, + { text: 'Radio Group 单选按钮组', link: '/radio-group' }, + { text: 'Select 选择', link: '/select' }, + { text: 'Slider 滑块', link: '/slider' }, + { text: 'Switch 开关', link: '/switch' }, + { text: 'Tags Input 标签输入', link: '/tags-input' }, + { text: 'Toggle 切换', link: '/toggle' }, + { text: 'Toggle Group 切换组', link: '/toggle-group' }, + ], + }, + { + text: '时间', + items: [ + { + text: `Calendar 日历 ${BadgeHTML('Alpha', true)}`, + link: '/calendar', + }, + { + text: `Date Field 日期字段 ${BadgeHTML('Alpha', true)}`, + link: '/date-field', + }, + { + text: `Date Picker 日期选择器 ${BadgeHTML('Alpha', true)}`, + link: '/date-picker', + }, + { + text: `Date Range Field 日期范围字段 ${BadgeHTML('Alpha', true)}`, + link: '/date-range-field', + }, + { + text: `Date Range Picker 日期范围选择器 ${BadgeHTML('Alpha', true)}`, + link: '/date-range-picker', + }, + { + text: `Range Calendar 范围日历 ${BadgeHTML('Alpha', true)}`, + link: '/range-calendar', + }, + { + text: `Time Field 时间字段 ${BadgeHTML('Alpha', true)}`, + link: '/time-field', + }, + ], + }, + { + text: '通用', + items: [ + { text: 'Accordion 手风琴面板', link: '/accordion' }, + { text: 'Alert Dialog 警报对话框', link: '/alert-dialog' }, + { text: 'Aspect Ratio 横纵比', link: '/aspect-ratio' }, + { text: 'Avatar 头像', link: '/avatar' }, + { text: 'Collapsible 折叠面板', link: '/collapsible' }, + { text: 'Context Menu 上下文菜单', link: '/context-menu' }, + { text: 'Dialog 对话框', link: '/dialog' }, + { text: 'Dropdown Menu 下拉菜单', link: '/dropdown-menu' }, + { text: 'Hover Card 悬浮卡片', link: '/hover-card' }, + { text: 'Menubar 菜单栏', link: '/menubar' }, + { + text: 'Navigation Menu 导航菜单', + link: '/navigation-menu', + }, + { text: 'Pagination 分页', link: '/pagination' }, + { text: 'Popover 弹出面板', link: '/popover' }, + { text: 'Progress 进度条', link: '/progress' }, + { text: 'Scroll Area 滚动区域', link: '/scroll-area' }, + { text: 'Separator 分割线', link: '/separator' }, + { text: 'Splitter 分隔条', link: '/splitter' }, + { + text: `Stepper 步骤 ${BadgeHTML('Alpha', true)}`, + link: '/stepper', + }, + { text: 'Tabs 标签页', link: '/tabs' }, + { text: 'Toast 通知', link: '/toast' }, + { text: 'Toolbar 工具栏', link: '/toolbar' }, + { text: 'Tooltip 工具提示', link: '/tooltip' }, + { + text: `Tree 树 ${BadgeHTML('Alpha', true)}`, + link: '/tree', + }, + ], + }, + ], + }, + { + text: '实用工具', + icon: 'lucide:wrench', + base: '/zh/docs/utilities/', + items: [ + { + text: '组件', + items: [ + { text: 'Config Provider 配置下发', link: '/config-provider' }, + { text: 'Focus Scope 焦点范围', link: '/focus-scope' }, + { text: 'Presence 存在性', link: '/presence' }, + { text: 'Primitive 原始', link: '/primitive' }, + { text: 'Slot 插槽', link: '/slot' }, + { text: 'Visually Hidden 视觉隐藏', link: '/visually-hidden' }, + ], + }, + { + text: '组合式', + items: [ + { text: 'useId', link: '/use-id' }, + { + text: 'useDateFormatter', + link: '/use-date-formatter', + }, + { + text: 'useEmitAsProps', + link: '/use-emit-as-props', + }, + { + text: 'useForwardExpose', + link: '/use-forward-expose', + }, + { + text: 'useForwardProps', + link: '/use-forward-props', + }, + { + text: 'useForwardPropsEmits', + link: '/use-forward-props-emits', + }, + ], + }, + ], + }, + { + text: '示例', + icon: 'lucide:square-dashed-mouse-pointer', + link: '/zh/examples/checkbox-group', + base: '/zh/examples/', + items: [ + { + text: '复选框', + items: [ + { text: '复选框组', link: '/checkbox-group' }, + ], + }, + { + text: '组合框', + items: [ + { + text: '标签输入的组合框', + link: '/combobox-tags-input', + }, + { + text: '组合框文本域', + link: '/combobox-textarea', + }, + ], + }, + { + text: '日期', + items: [ + { + text: '日期范围选择器', + link: '/date-picker-selection', + }, + ], + }, + { + text: '对话框', + items: [ + { + text: '对话框命令菜单', + link: '/dialog-command-menu', + }, + ], + }, + { + text: '列表框', + items: [ + { text: '穿梭框', link: '/listbox-transfer' }, + ], + }, + { + text: '滑块', + items: [ + { + text: '带数字字段的滑块', + link: '/slider-number-field', + }, + { text: '滑块提示', link: '/slider-tooltip' }, + ], + }, + { + text: '工具提示', + items: [ + { text: '光标提示', link: '/tooltip-cursor' }, + ], + }, + { + text: '进度条', + items: [ + { + text: '圆形进度条', + link: '/progress-circular', + }, + ], + }, + ], + }, + ], + + search: { + provider: 'local', + options: { + translations: { + button: { + buttonAriaLabel: '搜索', + buttonText: '搜索', + }, + modal: { + displayDetails: '显示细节列表', + resetButtonTitle: '重置搜索', + backButtonTitle: '关闭搜索', + noResultsText: '没有找到结果', + footer: { + selectText: '选择', + selectKeyAriaLabel: '回车', + navigateText: '跳转', + navigateUpKeyAriaLabel: '上', + navigateDownKeyAriaLabel: '下', + closeText: '关闭', + }, + }, + }, + }, + }, + editLink: { + pattern: 'https://github.com/radix-vue/radix-vue/edit/main/docs/content/:path', + text: '在 GitHub 上编辑此页面', + }, + docFooter: { + prev: '上一页', + next: '下一页', + }, + + outline: { + level: [2, 3], + label: '页面导航', + }, + + lastUpdated: { + text: '最后更新于', + formatOptions: { + dateStyle: 'short', + timeStyle: 'medium', + }, + }, + + langMenuLabel: '多语言', + returnToTopLabel: '回到顶部', + sidebarMenuLabel: '菜单', + darkModeSwitchLabel: '主题', + lightModeSwitchTitle: '切换到浅色模式', + darkModeSwitchTitle: '切换到深色模式', + }, +}) diff --git a/docs/.vitepress/custom/Docs.vue b/docs/.vitepress/custom/Docs.vue index f4f696d6b..6d6fbb1b7 100644 --- a/docs/.vitepress/custom/Docs.vue +++ b/docs/.vitepress/custom/Docs.vue @@ -1,6 +1,7 @@ @@ -43,7 +44,10 @@ const isExamplePage = computed(() => path.value.includes('examples')) v-if="activeSection" class="h-full" > - +
diff --git a/docs/.vitepress/custom/Layout.vue b/docs/.vitepress/custom/Layout.vue index 72df7dece..dd8a6d40e 100644 --- a/docs/.vitepress/custom/Layout.vue +++ b/docs/.vitepress/custom/Layout.vue @@ -6,11 +6,23 @@ import Navbar from '../components/Navbar.vue' // import HomePageDemo from '../components/HomePageDemo.vue' import Home from '../components/Home.vue' import { useScroll } from '@vueuse/core' -import { toRefs } from 'vue' +import { toRefs, watch } from 'vue' import { TooltipProvider } from 'reka-ui' import Showcase from './Showcase.vue' +import { useI18n } from 'vue-i18n' +import { normalizeLink } from '../functions/utils' +import { useLangs } from '../composables/langs' + +const { locale } = useI18n() +const { site, theme, frontmatter, lang } = useData() +const { currentLang } = useLangs() + +watch(lang, (newLang) => { + locale.value = newLang +}, { + immediate: true, +}) -const { site, theme, frontmatter } = useData() const { path } = toRefs(useRoute()) const { arrivedState } = useScroll(globalThis.window) const { top } = toRefs(arrivedState) @@ -26,7 +38,7 @@ const { top } = toRefs(arrivedState)
KNOWN_EXTENSIONS.add(ext)) + } + + const ext = filename.split('.').pop() + + return ext == null || !KNOWN_EXTENSIONS.has(ext.toLowerCase()) +} diff --git a/docs/.vitepress/plugins/ComponentPreview.ts b/docs/.vitepress/plugins/ComponentPreview.ts index c62bfebdb..0d4f4154e 100644 --- a/docs/.vitepress/plugins/ComponentPreview.ts +++ b/docs/.vitepress/plugins/ComponentPreview.ts @@ -56,7 +56,7 @@ export default function (md: MarkdownRenderer) { props[propName] = propValue } - const pathName = props.type === 'example' ? `../../components/examples/${props.name}` : `../../../components/demo/${props.name}` + const pathName = props.type === 'example' ? `../../../components/examples/${props.name}` : `../../../../components/demo/${props.name}` insertComponentImport(props.type === 'example' ? `import ${props.name} from '${pathName}/index.vue'` : `import ${props.name} from '${pathName}/tailwind/index.vue'`) const index = state.tokens.findIndex(i => i.content.match(regex)) diff --git a/docs/.vitepress/theme/index.ts b/docs/.vitepress/theme/index.ts index fd7c59b66..4da6d65f2 100644 --- a/docs/.vitepress/theme/index.ts +++ b/docs/.vitepress/theme/index.ts @@ -3,17 +3,25 @@ import ComponentPreview from '../components/ComponentPreview.vue' import InstallationTabs from '../components/InstallationTabs.vue' import './style.css' import type { Theme } from 'vitepress' +import { createI18n } from 'vue-i18n' +import messages from '@intlify/unplugin-vue-i18n/messages' import Layout from '../custom/Layout.vue' const regex = /\/(\w+)\.vue/ const baseModules = import.meta.glob('../../components/*.vue', { eager: true }) const tableModules = import.meta.glob('../../components/tables/*.vue', { eager: true }) +const i18n = createI18n({ + legacy: false, + locale: 'en', + messages, +}) export default { // extends: DefaultTheme, Layout, enhanceApp({ app }) { + app.use(i18n) for (const path in baseModules) app.component(path.match(regex)?.[1] ?? '', (baseModules[path] as any)?.default) diff --git a/docs/content/en/docs/overview/introduction.md b/docs/content/en/docs/overview/introduction.md index e3c6861ea..b1acfef95 100644 --- a/docs/content/en/docs/overview/introduction.md +++ b/docs/content/en/docs/overview/introduction.md @@ -4,7 +4,7 @@ description: An open-source UI component library for building high-quality, acce --- # Introduction diff --git a/docs/content/en/examples.md b/docs/content/en/examples.md index f356c6c5f..89dd94597 100644 --- a/docs/content/en/examples.md +++ b/docs/content/en/examples.md @@ -1,5 +1,5 @@ diff --git a/docs/content/zh/docs/components/accordion.md b/docs/content/zh/docs/components/accordion.md new file mode 100644 index 000000000..854eabdcf --- /dev/null +++ b/docs/content/zh/docs/components/accordion.md @@ -0,0 +1,398 @@ +--- +title: Accordion +description: A vertically stacked set of interactive headings that each reveal an associated section of content. +name: accordion +aria: https://www.w3.org/WAI/ARIA/apg/patterns/accordion +--- + +# Accordion + + +A vertically stacked set of interactive headings that each reveal an +associated section of content. + + + + +## Features + + + +## Installation + +Install the component from your command line. + + + +## Anatomy + +Import all parts and piece them together. + +```vue + + + +``` + +## API Reference + +### Root + +Contains all the parts of an Accordion + + + + + +### Item + +Contains all the parts of a collapsible section. + + + + + +### Header + +Wraps an `AccordionTrigger`. Use the `asChild` prop to update it to the appropriate heading level for your page. + + + + + +### Trigger + +Toggles the collapsed state of its associated item. It should be nested inside of an `AccordionHeader`. + + + + + +### Content + +Contains the collapsible content for an item. + + + + + + + +## Examples + +### Expanded by default + +Use the `defaultValue` prop to define the open item by default. + +```vue line=2 + +``` + +### Allow collapsing all items + +Use the `collapsible` prop to allow all items to close. + +```vue line=2 + +``` + +### Multiple items open at the same time + +Set the `type` prop to `multiple` to enable opening multiple items at once. + +```vue line=2 + +``` + +### Rotated icon when open + +You can add extra decorative elements, such as chevrons, and rotate it when the item is open. + +```vue line=14 +// index.vue + + + +``` + +```css line=5-7 +/* styles.css */ +.AccordionChevron { + transition: transform 300ms; +} +.AccordionTrigger[data-state="open"] > .AccordionChevron { + transform: rotate(180deg); +} +``` + +### Horizontal orientation + +Use the `orientation` prop to create a horizontal Accordion + +```vue line=2 + +``` + +### Animating content size + +Use the `--reka-accordion-content-width` and/or `--reka-accordion-content-height` CSS variables to animate the size of the content when it opens/closes: + +```vue line=11 +// index.vue + + + +``` + +```css line=17,23 +/* styles.css */ +.AccordionContent { + overflow: hidden; +} +.AccordionContent[data-state="open"] { + animation: slideDown 300ms ease-out; +} +.AccordionContent[data-state="closed"] { + animation: slideUp 300ms ease-out; +} + +@keyframes slideDown { + from { + height: 0; + } + to { + height: var(--reka-accordion-content-height); + } +} + +@keyframes slideUp { + from { + height: var(--reka-accordion-content-height); + } + to { + height: 0; + } +} +``` + +### Render content even when closed + +By default hidden content will be removed, use `:unmountOnHide="false"` to keep the content always available. + +This will also allow browser to search the hidden text, and open the accordion. + +```vue line=2 + +``` + +## Accessibility + +Adheres to the [Accordion WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/accordion). + +### Keyboard Interactions + + diff --git a/docs/content/zh/docs/components/alert-dialog.md b/docs/content/zh/docs/components/alert-dialog.md new file mode 100644 index 000000000..860b211d4 --- /dev/null +++ b/docs/content/zh/docs/components/alert-dialog.md @@ -0,0 +1,249 @@ +--- +title: Alert Dialog +description: A modal dialog that interrupts the user with important content and expects a response. +name: alert-dialog +aria: https://www.w3.org/WAI/ARIA/apg/patterns/alertdialog +--- + +# Alert Dialog + + +A modal dialog that interrupts the user with important content and expects a +response. + + + + +## Features + + + +## Installation + +Install the component from your command line. + + + +## Anatomy + +Import all parts and piece them together. + +```vue + + + +``` + +## API Reference + +### Root + +Contains all the parts of an alert dialog. + + + +### Trigger + +A button that opens the dialog. + + + + + +### Portal + +When used, portals your overlay and content parts into the body. + + + +### Overlay + +A layer that covers the inert portion of the view when the dialog is open. + + + + + +### Content + +Contains content to be rendered when the dialog is open. + + + + + +### Cancel + +A button that closes the dialog. This button should be distinguished visually from `AlertDialogAction` buttons. + + + +### Action + +A button that closes the dialog. These buttons should be distinguished visually from the `AlertDialogCancel` button. + + + +### Title + +An accessible name to be announced when the dialog is opened. Alternatively, you can provide `aria-label` or `aria-labelledby` to `AlertDialogContent` and exclude this component. + + + +### Description + +An accessible description to be announced when the dialog is opened. Alternatively, you can provide `aria-describedby` to `AlertDialogContent` and exclude this component. + + + +## Examples + +### Close after asynchronous form submission + +Use the controlled props to programmatically close the Alert Dialog after an async operation has completed. + +```vue line=14,15,19,25-29 + + + +``` + +
+ +### Custom portal container + +Customise the element that your alert dialog portals into. + +```vue line=4,17 + + + +``` + +## Accessibility + +Adheres to the [Alert and Message Dialogs WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/alertdialog). + +### Keyboard Interactions + + diff --git a/docs/content/zh/docs/components/aspect-ratio.md b/docs/content/zh/docs/components/aspect-ratio.md new file mode 100644 index 000000000..ca8f09505 --- /dev/null +++ b/docs/content/zh/docs/components/aspect-ratio.md @@ -0,0 +1,50 @@ +--- + +title: Aspect Ratio +description: Displays content within a desired ratio. +name: aspect-ratio +--- + +# Aspect Ratio + + +Displays content within a desired ratio. + + + + +## Features + + + +## Installation + +Install the component from your command line. + + + +## Anatomy + +Import the component. + +```vue + + + +``` + +## API Reference + +### Root + +Contains the content you want to constrain to a given ratio. + + diff --git a/docs/content/zh/docs/components/avatar.md b/docs/content/zh/docs/components/avatar.md new file mode 100644 index 000000000..74fb4870d --- /dev/null +++ b/docs/content/zh/docs/components/avatar.md @@ -0,0 +1,92 @@ +--- + +title: Avatar +description: An image element with a fallback for representing the user. +name: avatar +--- + +# Avatar + + +An image element with a fallback for representing the user. + + + + +## Features + + + +## Installation + +Install the component from your command line. + + + +## Anatomy + +Import all parts and piece them together. + +```vue + + + +``` + +## API Reference + +### Root + +Contains all the parts of an avatar + + + +### Image + +The image to render. By default it will only render when it has loaded. You can use the `@loadingStatusChange` handler if you need more control. + + + +### Fallback + +An element that renders when the image hasn't loaded. This means whilst it's loading, or if there was an error. If you notice a flash during loading, you can provide a `delayMs` prop to delay its rendering so it only renders for those with slower connections. For more control, use the `@loadingStatusChange` emit on `AvatarImage`. + + + +## Examples + +### Clickable Avatar with tooltip + +You can compose the Avatar with a [Tooltip](/docs/components/tooltip) to display extra information. + +```vue line=6-7,9,11-15 + + + +``` diff --git a/docs/content/zh/docs/components/calendar.md b/docs/content/zh/docs/components/calendar.md new file mode 100644 index 000000000..a0757fc78 --- /dev/null +++ b/docs/content/zh/docs/components/calendar.md @@ -0,0 +1,318 @@ +--- + +title: Calendar +description: Displays dates and days of the week, facilitating date-related interactions. +name: calendar +--- + +# Calendar + +Alpha + + +Displays dates and days of the week, facilitating date-related interactions. + + + + +## Features + + + +## Preface + +The component depends on the [@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/index.html) package, which solves a lot of the problems that come with working with dates and times in JavaScript. + +We highly recommend reading through the documentation for the package to get a solid feel for how it works, and you'll need to install it in your project to use the date-related components. + +## Installation + +Install the date package. + + + +Install the component from your command line. + + + +## Anatomy + +Import all parts and piece them together. + +```vue + + + +``` + +## API Reference + +### Root + +Contains all the parts of a calendar + + + + + +### Header + +Contains the navigation buttons and the heading segments. + + + +### Prev Button + +Calendar navigation button. It navigates the calendar one month/year/decade in the past based on the current calendar view. + + + + + +### Next Button + +Calendar navigation button. It navigates the calendar one month/year/decade in the future based on the current calendar view. + + + + + +### Heading + +Heading for displaying the current month and year + + + + + +### Grid + +Container for wrapping the calendar grid. + + + + + +### Grid Head + +Container for wrapping the grid head. + + + +### Grid Body + +Container for wrapping the grid body. + + + +### Grid Row + +Container for wrapping the grid row. + + + +### Head Cell + +Container for wrapping the head cell. Used for displaying the week days. + + + +### Cell + +Container for wrapping the calendar cells. + + + + + +### Cell Trigger + +Interactable container for displaying the cell dates. Clicking it selects the date. + + + + + +## Examples + +### Calendar with Year Incrementation + +This example showcases a calendar which allows incrementing the year. + + + +### Calendar with Locale and Calendar System Selection + +This example showcases some of the available locales and how the calendar systems are displayed. + + + +## Accessibility + +### Keyboard Interactions + + diff --git a/docs/content/zh/docs/components/checkbox.md b/docs/content/zh/docs/components/checkbox.md new file mode 100644 index 000000000..eb51c8701 --- /dev/null +++ b/docs/content/zh/docs/components/checkbox.md @@ -0,0 +1,154 @@ +--- + +title: Checkbox +description: A control that allows the user to toggle between checked and not checked. +name: checkbox +aria: https://www.w3.org/WAI/ARIA/apg/patterns/checkbox +--- + +# Checkbox + + +A control that allows the user to toggle between checked and not checked. + + + + +## Features + + + +## Installation + +Install the component from your command line. + + + +## Anatomy + +Import all parts and piece them together. + +```vue + + + +``` + +## API Reference + +### Root + +Contains all the parts of a checkbox. An `input` will also render when used within a `form` to ensure events propagate correctly. + + + + + +### Indicator + +Renders when the checkbox is in a checked or indeterminate state. You can style this element directly, or you can use it as a wrapper to put an icon into, or both. + + + + + + + +### CheckboxGroupRoot + +Wrapper around `CheckboxRoot` to support array of `modelValue` + + + +## Examples + +### Indeterminate + +You can set the checkbox to `indeterminate` by taking control of its state. + +```vue line=5,9-14,16-18 + + + +``` + +## Accessibility + +Adheres to the [tri-state Checkbox WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/checkbox). + +### Keyboard Interactions + + diff --git a/docs/content/zh/docs/components/collapsible.md b/docs/content/zh/docs/components/collapsible.md new file mode 100644 index 000000000..e48ecb972 --- /dev/null +++ b/docs/content/zh/docs/components/collapsible.md @@ -0,0 +1,212 @@ +--- + +title: Collapsible +description: An interactive component which expands/collapses a panel. +name: collapsible +aria: https://www.w3.org/WAI/ARIA/apg/patterns/disclosure +--- + +# Collapsible + + +An interactive component which expands/collapses a panel. + + + + +## Features + + + +## Installation + +Install the component from your command line. + + + +## Anatomy + +Import the components and piece the parts together. + +```vue + + + +``` + +## API Reference + +### Root + +Contains all the parts of a collapsible + + + + + +### Trigger + +The button that toggles the collapsible + + + + + +### Content + +The component that contains the collapsible content. + + + + + + + + + +## Examples + +### Animating content size + +Use the `--reka-collapsible-content-width` and/or `--reka-collapsible-content-height` CSS variables to animate the size of the content when it opens/closes. Here's a demo: + +```vue line=10 +// index.vue + + + +``` + +```css line=17,23 +/* styles.css */ +.CollapsibleContent { + overflow: hidden; +} +.CollapsibleContent[data-state="open"] { + animation: slideDown 300ms ease-out; +} +.CollapsibleContent[data-state="closed"] { + animation: slideUp 300ms ease-out; +} + +@keyframes slideDown { + from { + height: 0; + } + to { + height: var(--reka-collapsible-content-height); + } +} + +@keyframes slideUp { + from { + height: var(--reka-collapsible-content-height); + } + to { + height: 0; + } +} +``` + +### Render content even when collapsed + +By default hidden content will be removed, use `:unmountOnHide="false"` to keep the content always available. + +This will also allow browser to search the hidden text, and open the collapsible. + +```vue line=6 + + + +``` + +## Accessibility + +Adheres to the [Disclosure WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/disclosure). + +### Keyboard Interactions + + diff --git a/docs/content/zh/docs/components/combobox.md b/docs/content/zh/docs/components/combobox.md new file mode 100644 index 000000000..42e9aaa39 --- /dev/null +++ b/docs/content/zh/docs/components/combobox.md @@ -0,0 +1,748 @@ +--- + +title: Combobox +description: Choose from a list of suggested values with full keyboard support. +name: combobox +aria: https://www.w3.org/WAI/ARIA/apg/patterns/listbox +--- + +# Combobox + + +Choose from a list of suggested values with full keyboard support. + + + + +## Features + + + +## Installation + +Install the component from your command line. + + + +## Anatomy + +Import all parts and piece them together. + +```vue + + + +``` + +## API Reference + +### Root + +Contains all the parts of a Combobox + + + +### Anchor + +Used as an anchor if you set `ComboboxContent`'s position to `popper`. + + + +### Input + +The input component to search through the combobox items. + + + +### Trigger + +The button that toggles the Combobox Content. + + + + + +### Cancel + +The button that clears the search term. + + + +### Empty + +Shown when none of the items match the query. + + + +### Portal + +When used, portals the content part into the `body`. + +You need to set `position="popper"` for `ComboboxContent` to make sure the position was automatically computed similar to `Popover` or `DropdownMenu`. + + + +### Content + +The component that pops out when the combobox is open. + + + + + + + + + +### Viewport + +The scrolling viewport that contains all of the items. + + + +### Item + +The component that contains the combobox items. + + + + + +### ItemIndicator + +Renders when the item is selected. You can style this element directly, or you can use it as a wrapper to put an icon into, or both. + + + +### Group + +Used to group multiple items. use in conjunction with `ComboboxLabel` to ensure good accessibility via automatic labelling. + + + +### Label + +Used to render the label of a group. It won't be focusable using arrow keys. + + + +### Separator + +Used to visually separate items in the Combobox + + + +### Arrow + +An optional arrow element to render alongside the content. This can be used to help visually link the trigger with the `ComboboxContent`. Must be rendered inside `ComboboxContent`. Only available when `position` is set to `popper`. + + + +### Virtualizer + +Virtual container to achieve list virtualization. + + + +Combobox items **must** be filtered manually before passing them over to the virtualizer. See [example below](#virtualized-combobox-with-working-filtering). + + + +See the [virtualization guide](../guides/virtualization.md) for more general info on virtualization. + + + +## Examples + +### Binding objects as values + +Unlike native HTML form controls which only allow you to provide strings as values, `reka-ui` supports binding complex objects as well. + +Make sure to set the `displayValue` prop to set the input value on item selection. + +```vue line=12,17,26 + + + +``` + +### Selecting multiple values + +The `Combobox` component allows you to select multiple values. You can enable this by providing an array of values instead of a single value. + +```vue line=12,16 + + + +``` + +### Custom filtering + +Internally, `ComboboxRoot` will filter the item based on the rendered text. + +However, you may also provide your own custom filtering logic together with setting `ignoreFilter="false"`. + +```vue line=15,16,22,28 + + + +``` + +### Custom label + +By default the `Combobox` will use the input contents as the label for screenreaders. If you'd like more control over what is announced to assistive technologies, use the [Label](/docs/components/label) component. + +```vue line=8,9 + + + +``` + +### With disabled items + + You can add special styles to disabled items via the `data-disabled` attribute. + +```vue line=17 + + + +``` + +```css line=2 +/* styles.css */ +.ComboboxItem[data-disabled] { + color: "gainsboro"; +} +``` + +### With separators + +Use the `Separator` part to add a separator between items. + +```vue line=21 + + + +``` + +### With grouped items + +Use the `Group` and `Label` parts to group items in a section. + +```vue line=19,20,24 + + + +``` + +### With complex items + +You can use custom content in your items. + +```vue line=21 + + + +``` + +### Prevent select behavior + +By default, selecting `ComboboxItem` would close the content, and update the `modelValue` with the provided value. +You can prevent this behavior by preventing default `@select.prevent`. + +```vue line=11 + + + +``` + +### Virtualized combobox with working filtering + +Combobox items **must** be filtered manually before passing them over to the virtualizer. + +See the [virtualization guide](../guides/virtualization.md) for more general info on virtualization. + +```vue line=9-10,17,19-28 + + + +``` + +## Accessibility + +Adheres to the [Combobox WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/combobox/). + +See the W3C [Combobox Autocomplete List](https://www.w3.org/WAI/ARIA/apg/patterns/combobox/examples/combobox-autocomplete-list/) example for more information. + +### Keyboard Interactions + + + +## Custom APIs + +Create your own API by abstracting the primitive parts into your own component. + +### Command Menu + +Combobox can be use to build your own Command Menu. + +#### Usage + +```vue + + + +``` + +#### Implementation + +```ts +// your-command.ts +export { default as Command } from 'Command.vue' +export { default as CommandItem } from 'CommandItem.vue' +``` + +```vue + + + + +``` + +```vue + + + + +``` diff --git a/docs/content/zh/docs/components/context-menu.md b/docs/content/zh/docs/components/context-menu.md new file mode 100644 index 000000000..034424173 --- /dev/null +++ b/docs/content/zh/docs/components/context-menu.md @@ -0,0 +1,812 @@ +--- + +title: Context Menu +description: Displays a menu located at the pointer, triggered by a right-click or a long-press. +name: context-menu +aria: https://www.w3.org/WAI/ARIA/apg/patterns/menu +--- + +# Context Menu + + +Displays a menu located at the pointer, triggered by a right-click or a long-press. + + + + +## Features + + + +## Installation + +Install the component from your command line. + + + +## Anatomy + +Import all parts and piece them together. + +```vue + + + +``` + +## API Reference + +Adheres to the [Menu WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/menu) and uses [roving tabindex](https://www.w3.org/TR/wai-aria-practices-1.2/examples/menu-button/menu-button-actions.html) to manage focus movement among menu items. + +### Root + +Contains all the parts of a context menu. + + + +### Trigger + +The area that opens the context menu. Wrap it around the target you want the context menu to open from when right-clicking (or using the relevant keyboard shortcuts). + + + + + +### Portal + +When used, portals the content part into the `body`. + + + +### Content + +The component that pops out in an open context menu. + + + + + + + +### Arrow + +An optional arrow element to render alongside a submenu. This can be used to help visually link the trigger item with the `ContextMenu.Content`. Must be rendered inside `ContextMenu.Content`. + + + +### Item + +The component that contains the context menu items. + + + + + +### Group + +Used to group multiple `ContextMenu.Item`s. + + + +### Label + +Used to render a label. It won't be focusable using arrow keys. + + + +### CheckboxItem + +An item that can be controlled and rendered like a checkbox. + + + + + +### RadioGroup + +Used to group multiple `ContextMenu.RadioItem`s. + + + +### RadioItem + +An item that can be controlled and rendered like a radio. + + + + + +### ItemIndicator + +Renders when the parent `ContextMenu.CheckboxItem` or `ContextMenu.RadioItem` is checked. You can style this element directly, or you can use it as a wrapper to put an icon into, or both. + + + + + +### Separator + +Used to visually separate items in the context menu. + + + +### Sub + +Contains all the parts of a submenu. + + + +### SubTrigger + +An item that opens a submenu. Must be rendered inside `ContextMenu.Sub`. + + + + + +### SubContent + +The component that pops out when a submenu is open. Must be rendered inside `ContextMenu.Sub`. + + + + + + + +## Examples + +### With submenus + +You can create submenus by using `ContextMenuSub` in combination with its parts. + +```vue line=24-33 + + + +``` + +### With disabled items + +You can add special styles to disabled items via the `data-disabled` attribute. + +```vue line=10 + + + +``` + +```css line=2 +/* styles.css */ +.ContextMenuItem[data-disabled] { + color: gainsboro; +} +``` + +### With separators + +Use the `Separator` part to add a separator between items. + +```vue line=8,18,20 + + + +``` + +### With labels + +Use the `Label` part to help label a section. + +```vue line=5,17 + + + +``` + +### With checkbox items + +Use the `CheckboxItem` part to add an item that can be checked. + +```vue line=3,25-30 + + + +``` + +### With radio items + +Use the `RadioGroup` and `RadioItem` parts to add an item that can be checked amongst others. + +```vue line=8,9,24-43 + + + +``` + +### With complex items + +You can add extra decorative elements in the `Item` parts, such as images. + +```vue line=11,15 + + + +``` + +### Constrain the content/sub-content size + +You may want to constrain the width of the content (or sub-content) so that it matches the trigger (or sub-trigger) width. You may also want to constrain its height to not exceed the viewport. + +We expose several CSS custom properties such as `--reka-context-menu-trigger-width` and `--reka-context-menu-content-available-height` to support this. Use them to constrain the content dimensions. + +```vue line=9 + + + +``` + +```css +/* styles.css */ +.ContextMenuContent { + width: var(--reka-context-menu-trigger-width); + max-height: var(--reka-context-menu-content-available-height); +} +``` + +### Origin-aware animations + +We expose a CSS custom property `--reka-context-menu-content-transform-origin`. Use it to animate the content from its computed origin based on `side`, `sideOffset`, `align`, `alignOffset` and any collisions. + +```vue line=9 + + + +``` + +```css line=3 +/* styles.css */ +.ContextMenuContent { + transform-origin: var(--reka-context-menu-content-transform-origin); + animation: scaleIn 0.5s ease-out; +} + +@keyframes scaleIn { + from { + opacity: 0; + transform: scale(0); + } + to { + opacity: 1; + transform: scale(1); + } +} +``` + +### Collision-aware animations + +We expose `data-side` and `data-align` attributes. Their values will change at runtime to reflect collisions. Use them to create collision and direction-aware animations. + +```vue line=9 + + + +``` + +```css line=6-11 +/* styles.css */ +.ContextMenuContent { + animation-duration: 0.6s; + animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1); +} +.ContextMenuContent[data-side="top"] { + animation-name: slideUp; +} +.ContextMenuContent[data-side="bottom"] { + animation-name: slideDown; +} + +@keyframes slideUp { + from { + opacity: 0; + transform: translateY(10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes slideDown { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} +``` + +## Accessibility + +Uses [roving tabindex](https://www.w3.org/WAI/ARIA/apg/patterns/kbd_roving_tabindex) to manage focus movement among menu items. + +### Keyboard Interactions + + diff --git a/docs/content/zh/docs/components/date-field.md b/docs/content/zh/docs/components/date-field.md new file mode 100644 index 000000000..bda4d79d8 --- /dev/null +++ b/docs/content/zh/docs/components/date-field.md @@ -0,0 +1,150 @@ +--- +title: Date Field +description: Enables users to input specific dates within a designated field. +name: date-field +--- + +# Date Field + +Alpha + + +Enables users to input specific dates within a designated field. + + + + +## Features + + + +## Preface + +The component depends on the [@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/index.html) package, which solves a lot of the problems that come with working with dates and times in JavaScript. + +We highly recommend reading through the documentation for the package to get a solid feel for how it works, and you'll need to install it in your project to use the date-related components. + +## Installation + +Install the date package. + + + +Install the component from your command line. + + + +## Anatomy + +Import all parts and piece them together. + +```vue + + + +``` + +## API Reference + +### Root + +Contains all the parts of a date field + + + + + +### Input + +Contains the date field segments + + + + + +## Accessibility + +### Keyboard Interactions + + diff --git a/docs/content/zh/docs/components/date-picker.md b/docs/content/zh/docs/components/date-picker.md new file mode 100644 index 000000000..9e56c04fa --- /dev/null +++ b/docs/content/zh/docs/components/date-picker.md @@ -0,0 +1,418 @@ +--- +title: Date Picker +description: Facilitates the selection of dates through an input and calendar-based interface. +name: date-picker +--- + +# Date Picker + +Alpha + + +Facilitates the selection of dates through an input and calendar-based interface. + + + + +## Features + + + +## Preface + +The component depends on the [@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/index.html) package, which solves a lot of the problems that come with working with dates and times in JavaScript. + +We highly recommend reading through the documentation for the package to get a solid feel for how it works, and you'll need to install it in your project to use the date-related components. + +## Installation + +Install the date package. + + + +Install the component from your command line. + + + +## Anatomy + +Import all parts and piece them together. + +```vue + + + +``` + +## API Reference + +### Root + +Contains all the parts of a date picker + + + +### Field + +Contains the date picker date field segments and trigger + + + + + +### Input + +Contains the date picker date field segments + + + + + +### Trigger + +The button that toggles the popover. By default, the `DatePickerContent` will position itself against the trigger. + + + +### Content + +The component that pops out when the popover is open. + + + +### Arrow + +An optional arrow element to render alongside the popover. This can be used to help visually link the anchor with the `DatePickerContent`. Must be rendered inside `DatePickerContent`. + + + +### Close + +The button that closes an open date picker. + + + +### Anchor + +An optional element to position the `DatePickerContent` against. If this part is not used, the content will position alongside the `DatePickerTrigger`. + + + +### Calendar + +Contains all the parts of a calendar + + + + + +### Header + +Contains the navigation buttons and the heading segments. + + + +### Prev Button + +Calendar navigation button. It navigates the calendar one month/year/decade in the past based on the current calendar view. + + + + + +### Next Button + +Calendar navigation button. It navigates the calendar one month/year/decade in the future based on the current calendar view. + + + + + +### Heading + +Heading for displaying the current month and year/ + + + +### Grid + +Container for wrapping the calendar grid. + + + + + +### Grid Head + +Container for wrapping the grid head. + + + +### Grid Body + +Container for wrapping the grid body. + + + +### Grid Row + +Container for wrapping the grid row. + + + +### Head Cell + +Container for wrapping the head cell. Used for displaying the week days. + + + +### Cell + +Container for wrapping the calendar cells. + + + + + +### Cell Trigger + +Interactable container for displaying the cell dates. Clicking it selects the date. + + + + + +## Accessibility + +### Keyboard Interactions + + diff --git a/docs/content/zh/docs/components/date-range-field.md b/docs/content/zh/docs/components/date-range-field.md new file mode 100644 index 000000000..289182aa2 --- /dev/null +++ b/docs/content/zh/docs/components/date-range-field.md @@ -0,0 +1,150 @@ +--- +title: Date Range Field +description: Allows users to input a range of dates within a designated field. +name: date-range-field +--- + +# Date Range Field + +Alpha + + +Allows users to input a range of dates within a designated field. + + + + +## Features + + + +## Preface + +The component depends on the [@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/index.html) package, which solves a lot of the problems that come with working with dates and times in JavaScript. + +We highly recommend reading through the documentation for the package to get a solid feel for how it works, and you'll need to install it in your project to use the date-related components. + +## Installation + +Install the date package. + + + +Install the component from your command line. + + + +## Anatomy + +Import all parts and piece them together. + +```vue + + + +``` + +## API Reference + +### Root + +Contains all the parts of a date field + + + + + +### Input + +Contains the date field segments + + + + + +## Accessibility + +### Keyboard Interactions + + diff --git a/docs/content/zh/docs/components/date-range-picker.md b/docs/content/zh/docs/components/date-range-picker.md new file mode 100644 index 000000000..6a7ed0d1e --- /dev/null +++ b/docs/content/zh/docs/components/date-range-picker.md @@ -0,0 +1,448 @@ +--- +title: Date Range Picker +description: Facilitates the selection of date ranges through an input and calendar-based interface. +name: date-range-picker +--- + +# Date Range Picker + +Alpha + + +Facilitates the selection of date ranges through an input and calendar-based interface. + + + + +## Features + + + +## Preface + +The component depends on the [@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/index.html) package, which solves a lot of the problems that come with working with dates and times in JavaScript. + +We highly recommend reading through the documentation for the package to get a solid feel for how it works, and you'll need to install it in your project to use the date-related components. + +## Installation + +Install the date package. + + + +Install the component from your command line. + + + +## Anatomy + +Import all parts and piece them together. + +```vue + + + +``` + +## API Reference + +### Root + +Contains all the parts of a date picker + + + +### Field + +Contains the date picker date field segments and trigger + + + + + +### Input + +Contains the date picker date field segments + + + + + +### Trigger + +The button that toggles the popover. By default, the `DateRangePickerContent` will position itself against the trigger. + + + +### Content + +The component that pops out when the popover is open. + + + +### Arrow + +An optional arrow element to render alongside the popover. This can be used to help visually link the anchor with the `DateRangePickerContent`. Must be rendered inside `DateRangePickerContent`. + + + +### Close + +The button that closes an open date picker. + + + +### Anchor + +An optional element to position the `DateRangePickerContent` against. If this part is not used, the content will position alongside the `DateRangePickerTrigger`. + + + +### Calendar + +Contains all the parts of a calendar + + + + + +### Header + +Contains the navigation buttons and the heading segments. + + + +### Prev Button + +Calendar navigation button. It navigates the calendar one month/year/decade in the past based on the current calendar view. + + + + + +### Next Button + +Calendar navigation button. It navigates the calendar one month/year/decade in the future based on the current calendar view. + + + + + +### Heading + +Heading for displaying the current month and year + + + + + +### Grid + +Container for wrapping the calendar grid. + + + + + +### Grid Head + +Container for wrapping the grid head. + + + +### Grid Body + +Container for wrapping the grid body. + + + +### Grid Row + +Container for wrapping the grid row. + + + +### Head Cell + +Container for wrapping the head cell. Used for displaying the week days. + + + +### Cell + +Container for wrapping the calendar cells. + + + + + +### Cell Trigger + +Interactable container for displaying the cell dates. Clicking it selects the date. + + + + + +## Accessibility + +### Keyboard Interactions + + diff --git a/docs/content/zh/docs/components/dialog.md b/docs/content/zh/docs/components/dialog.md new file mode 100644 index 000000000..ec4139c06 --- /dev/null +++ b/docs/content/zh/docs/components/dialog.md @@ -0,0 +1,397 @@ +--- + +title: Dialog +description: A window overlaid on either the primary window or another dialog window, rendering the content underneath inert. +name: dialog +aria: https://www.w3.org/WAI/ARIA/apg/patterns/dialogmodal +--- + +# Dialog + + +A window overlaid on either the primary window or another dialog window, rendering the content underneath inert. + + + + +## Features + + + +## Installation + +Install the component from your command line. + + + +## Anatomy + +Import all parts and piece them together. + +```vue + + + +``` + +## API Reference + +### Root + +Contains all the parts of a dialog + + + +### Trigger + +The button that opens the dialog + + + + + +### Portal + +When used, portals your overlay and content parts into the `body`. + + + +### Overlay + +A layer that covers the inert portion of the view when the dialog is open. + + + + + + + +### Content + +Contains content to be rendered in the open dialog + + + + + + + +### Close + +The button that closes the dialog + + + +### Title + +An accessible title to be announced when the dialog is opened. + +If you want to hide the title, wrap it inside our Visually Hidden utility like this ``. + + + +### Description + +An optional accessible description to be announced when the dialog is opened. + +If you want to hide the description, wrap it inside our Visually Hidden utility like this ``. If you want to remove the description entirely, remove this part and pass `:aria-describedby="undefined"` to `DialogContent`. + + + +## Examples + +### Nested dialog + +You can nest multiple layers of dialogs. + + + +### Close after asynchronous form submission + +Use the controlled props to programmatically close the Dialog after an async operation has completed. + +```vue line=4,5,15-19,22-24 + + + +``` + +### Scrollable overlay + +Move the content inside the overlay to render a dialog with overflow. + +```vue +// index.vue + + + +``` + +```css +/* styles.css */ +.DialogOverlay { + background: rgba(0 0 0 / 0.5); + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + display: grid; + place-items: center; + overflow-y: auto; +} + +.DialogContent { + min-width: 300px; + background: white; + padding: 30px; + border-radius: 4px; +} +``` + +However, there's a caveat to this approach, where user might click on the scrollbar and close the dialog unintentionally. There's no universal solution that would fix this issue for now, however you can add the following snippet to `DialogContent` to prevent closing of modal when clicking on scrollbar. + +```vue + +``` + +### Custom portal container + +Customise the element that your dialog portals into. + +```vue line=4,11,17 + + + +``` + +### Disable close on Interaction outside + +For example, if you have some global Toaster component that should not close the Dialog when clicking on it. + + + +## Accessibility + +Adheres to the [Dialog WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/). + +### Close icon button + +When providing an icon (or font icon), remember to label it correctly for screen reader users. + +```html line=8-9 + + + + + + + + + + + + + +``` + +### Keyboard Interactions + + + +## Custom APIs + +Create your own API by abstracting the primitive parts into your own component. + +### Abstract the overlay and the close button + +This example abstracts the `DialogOverlay` and `DialogClose` parts. + +#### Usage + +```vue + + + +``` + +#### Implementation + +```ts +// your-dialog.ts +export { default as DialogContent } from 'DialogContent.vue' +export { DialogRoot as Dialog, DialogTrigger } from 'reka-ui' +``` + +```vue + + + + +``` diff --git a/docs/content/zh/docs/components/dropdown-menu.md b/docs/content/zh/docs/components/dropdown-menu.md new file mode 100644 index 000000000..8ea751d54 --- /dev/null +++ b/docs/content/zh/docs/components/dropdown-menu.md @@ -0,0 +1,996 @@ +--- + +title: Dropdown Menu +description: Displays a menu to the user—such as a set of actions or functions—triggered by a button. +name: dropdown-menu +aria: https://www.w3.org/WAI/ARIA/apg/patterns/menubutton +--- + +# DropdownMenu + + +Displays a menu to the user—such as a set of actions or functions—triggered by a button. + + + + +## Features + + + +## Installation + +Install the component from your command line. + + + +## Anatomy + +Import all parts and piece them together. + +```vue + + + +``` + +## API Reference + +### Root + +Contains all the parts of a dropdown menu. + + + +### Trigger + +The button that toggles the dropdown menu. By default, the `DropdownMenuContent` will position itself against the trigger. + + + + + +### Portal + +When used, portals the content part into the `body`. + + + +### Content + +The component that pops out when the dropdown menu is open. + + + + + + + +### Arrow + +An optional arrow element to render alongside the dropdown menu. This can be used to help visually link the trigger with the `DropdownMenuContent`. Must be rendered inside `DropdownMenuContent`. + + + +### Item + +The component that contains the dropdown menu items. + + + + + +### Group + +Used to group multiple `DropdownMenuItem`s. + + + +### Label + +Used to render a label. It won't be focusable using arrow keys. + + + +### CheckboxItem + +An item that can be controlled and rendered like a checkbox. + + + + + +### RadioGroup + +Used to group multiple `DropdownMenuRadioItem`s. + + + +### RadioItem + +An item that can be controlled and rendered like a radio. + + + + + +### ItemIndicator + +Renders when the parent `DropdownMenuCheckboxItem` or `DropdownMenuRadioItem` is checked. You can style this element directly, or you can use it as a wrapper to put an icon into, or both. + + + + + +### Separator + +Used to visually separate items in the dropdown menu. + + + +### Sub + +Contains all the parts of a submenu. + + + +### SubTrigger + +An item that opens a submenu. Must be rendered inside `DropdownMenuSub`. + + + + + + + +### SubContent + +The component that pops out when a submenu is open. Must be rendered inside `DropdownMenuSub`. + + + + + +## Examples + +### With submenus + +You can create submenus by using `DropdownMenuSub` in combination with its parts. + +```vue line=9-11,24-33 + + + +``` + +### With disabled items + +You can add special styles to disabled items via the `data-disabled` attribute. + +```vue line=16 + + + +``` + +```css line=2 +/* styles.css */ +.DropdownMenuItem[data-disabled] { + color: gainsboro; +} +``` + +### With separators + +Use the `Separator` part to add a separator between items. + +```vue line=7 ,18,20 + + + +``` + +### With labels + +Use the `Label` part to help label a section. + +```vue line=5,17 + + + +``` + +### With checkbox items + +Use the `CheckboxItem` part to add an item that can be checked. + +```vue line=5 ,26-31 + + + +``` + +### With radio items + +Use the `RadioGroup` and `RadioItem` parts to add an item that can be checked amongst others. + +```vue line=8-9,22-41 + + + +``` + +### With complex items + +You can add extra decorative elements in the `Item` parts, such as images. + +```vue line=17,21 + + + +``` + +### Constrain the content/sub-content size + +You may want to constrain the width of the content (or sub-content) so that it matches the trigger (or sub-trigger) width. You may also want to constrain its height to not exceed the viewport. + +We expose several CSS custom properties such as `--reka-dropdown-menu-trigger-width` and `--reka-dropdown-menu-content-available-height` to support this. Use them to constrain the content dimensions. + +```vue line=9 + + + +``` + +```css line=3-4 +/* styles.css */ +.DropdownMenuContent { + width: var(--reka-dropdown-menu-trigger-width); + max-height: var(--reka-dropdown-menu-content-available-height); +} +``` + +### Origin-aware animations + +We expose a CSS custom property `--reka-dropdown-menu-content-transform-origin`. Use it to animate the content from its computed origin based on `side`, `sideOffset`, `align`, `alignOffset` and any collisions. + +```vue line=9 + + + +``` + +```css line=3 +/* styles.css */ +.DropdownMenuContent { + transform-origin: var(--reka-dropdown-menu-content-transform-origin); + animation: scaleIn 0.5s ease-out; +} + +@keyframes scaleIn { + from { + opacity: 0; + transform: scale(0); + } + to { + opacity: 1; + transform: scale(1); + } +} +``` + +### Collision-aware animations + +We expose `data-side` and `data-align` attributes. Their values will change at runtime to reflect collisions. Use them to create collision and direction-aware animations. + +```vue line=9 + + + +``` + +```css line=6-11 +/* styles.css */ +.DropdownMenuContent { + animation-duration: 0.6s; + animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1); +} +.DropdownMenuContent[data-side="top"] { + animation-name: slideUp; +} +.DropdownMenuContent[data-side="bottom"] { + animation-name: slideDown; +} + +@keyframes slideUp { + from { + opacity: 0; + transform: translateY(10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes slideDown { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} +``` + +## Accessibility + +Adheres to the [Menu Button WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/menubutton) and uses [roving tabindex](https://www.w3.org/WAI/ARIA/apg/patterns/kbd_roving_tabindex) to manage focus movement among menu items. + +### Keyboard Interactions + + + +## Custom APIs + +Create your own API by abstracting the primitive parts into your own component. + +### Abstract the arrow and item indicators + +This example abstracts the `DropdownMenuArrow` and `DropdownMenuItemIndicator` parts. It also wraps implementation details for `CheckboxItem` and `RadioItem`. + +#### Usage + +```vue + + + +``` + +#### Implementation + +```ts +// your-dropdown-menu.ts +export { default as DropdownMenuContent } from 'DropdownMenuContent.vue' +export { default as DropdownMenuCheckboxItem } from 'DropdownMenuCheckboxItem.vue' +export { default as DropdownMenuRadioItem } from 'DropdownMenuRadioItem.vue' + +export { + DropdownMenuRoot as DropdownMenu, + DropdownMenuTrigger, + DropdownMenuLabel, + DropdownMenuItem, + DropdownMenuGroup, + DropdownMenuRadioGroup, + DropdownMenuSeparator +} from 'reka-ui' +``` + +```vue + + + + +``` + +```vue + + + + +``` + +```vue + + + + +``` diff --git a/docs/content/zh/docs/components/editable.md b/docs/content/zh/docs/components/editable.md new file mode 100644 index 000000000..a6625cfeb --- /dev/null +++ b/docs/content/zh/docs/components/editable.md @@ -0,0 +1,194 @@ +--- +title: Editable +description: Displays an input field used for editing a single line of text, rendering as static text on load. +name: editable +--- + +# Editable + + +Displays an input field used for editing a single line of text, rendering as static text on load. It transforms into a text input field when the edit interaction is triggered. + + + + +## Features + + + +## Installation + +Install the component from your command line. + + + +## Anatomy + +Import all parts and piece them together. + +```vue + + + +``` + +## API Reference + +### Root + +Contains all the parts of an editable component. + + + +### Area + +Contains the text parts of an editable component. + + + + + +### Input + +Contains the input of an editable component. + + + + + +### Preview + +Contains the preview of the editable component. + + + +### Edit Trigger + +Contains the edit trigger of the editable component. + + + +### Submit Trigger + +Contains the submit trigger of the editable component. + + + +### Cancel Trigger + +Contains the cancel trigger of the editable component. + + + +## Examples + +### Change only on submit + +By default the component will submit when `blur` event triggers. We can modify the `submit-mode` prop to alter this behavior. +In this case, we want to submit only when user click on `EditableSubmitTrigger`, so we change the submit mode to `none`. + +```vue line=2,8 + +``` + +## Accessibility + +### Keyboard Interactions + + diff --git a/docs/content/zh/docs/components/hover-card.md b/docs/content/zh/docs/components/hover-card.md new file mode 100644 index 000000000..fdb46ada5 --- /dev/null +++ b/docs/content/zh/docs/components/hover-card.md @@ -0,0 +1,309 @@ +--- + +title: Hover Card +description: For sighted users to preview content available behind a link. +name: hover-card +--- + +# HoverCard + + +For sighted users to preview content available behind a link. + + + + +## Features + + + +## Installation + +Install the component from your command line. + + + +## Anatomy + +Import all parts and piece them together. + +```vue + + + +``` + +## API Reference + +### Root + +Contains all the parts of a hover card. + + + +### Trigger + +The link that opens the hover card when hovered. + + + + + +### Portal + +When used, portals the content part into the `body`. + + + +### Content + +The component that pops out when the hover card is open. + + + + + + + + + +### Arrow + +An optional arrow element to render alongside the hover card. This can be used to help visually link the trigger with the `HoverCardContent`. Must be rendered inside `HoverCardContent`. + + + +## Examples + +### Show instantly + +Use the `openDelay` prop to control the time it takes for the hover card to open. + +```vue line=12 + + + +```` + +### Constrain the content size + +You may want to constrain the width of the content so that it matches the trigger width. You may also want to constrain its height to not exceed the viewport. + +We expose several CSS custom properties such as `--reka-hover-card-trigger-width` and `--reka-hover-card-content-available-height` to support this. Use them to constrain the content dimensions. + +```vue line=10 +// index.vue + + + +``` + +```css line=3-4 +/* styles.css */ +.HoverCardContent { + width: var(--reka-hover-card-trigger-width); + max-height: var(--reka-hover-card-content-available-height); +} +``` + +### Origin-aware animations + +We expose a CSS custom property `--reka-hover-card-content-transform-origin`. Use it to animate the content from its computed origin based on `side`, `sideOffset`, `align`, `alignOffset` and any collisions. + +```vue line=9 +// index.vue + + + +``` + +```css line=3 +/* styles.css */ +.HoverCardContent { + transform-origin: var(--reka-hover-card-content-transform-origin); + animation: scaleIn 0.5s ease-out; +} + +@keyframes scaleIn { + from { + opacity: 0; + transform: scale(0); + } + to { + opacity: 1; + transform: scale(1); + } +} +``` + +### Collision-aware animations + +We expose `data-side` and `data-align` attributes. Their values will change at runtime to reflect collisions. Use them to create collision and direction-aware animations. + +```vue line=9 +// index.vue + + + +``` + +```css line=6-11 +/* styles.css */ +.HoverCardContent { + animation-duration: 0.6s; + animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1); +} +.HoverCardContent[data-side="top"] { + animation-name: slideUp; +} +.HoverCardContent[data-side="bottom"] { + animation-name: slideDown; +} + +@keyframes slideUp { + from { + opacity: 0; + transform: translateY(10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes slideDown { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} +``` + +## Accessibility + +The hover card is intended for sighted users only, the content will be inaccessible to keyboard users. + +### Keyboard Interactions + + diff --git a/docs/content/zh/docs/components/label.md b/docs/content/zh/docs/components/label.md new file mode 100644 index 000000000..b0b176759 --- /dev/null +++ b/docs/content/zh/docs/components/label.md @@ -0,0 +1,55 @@ +--- + +title: Label +description: Renders an accessible label associated with controls. +name: label +--- + +# Label + + +Renders an accessible label associated with controls. + + + + +## Features + + + +## Installation + +Install the component from your command line. + + + +## Anatomy + +Import the component. + +```vue + + + +``` + +## API Reference + +### Root + +Contains the content for the label. + + + +## Accessibility + +This component is based on the native `label` element, it will automatically apply the correct labelling when wrapping controls or using the `for` attribute. For your own custom controls to work correctly, ensure they use native elements such as `button` or `input` as a base. diff --git a/docs/content/zh/docs/components/listbox.md b/docs/content/zh/docs/components/listbox.md new file mode 100644 index 000000000..cd6d98980 --- /dev/null +++ b/docs/content/zh/docs/components/listbox.md @@ -0,0 +1,331 @@ +--- + +title: Listbox +description: A control that allows the user to toggle between checked and not checked. +name: listbox +aria: https://www.w3.org/WAI/ARIA/apg/patterns/listbox +--- + +# Listbox + + +A control that allows the user to toggle between checked and not checked. + + + + +## Features + + + +## Installation + +Install the component from your command line. + + + +## Anatomy + +Import all parts and piece them together. + +```vue + + + +``` + +## API Reference + +### Root + +Contains all the parts of a listbox. An `input` will also render when used within a `form` to ensure events propagate correctly. + + + + + +### Filter + +Input element to perform filtering. + + + + + +### Content + +Contains all the listbox group and items. + + + +### Item + +The item component. + + + + + +### ItemIndicator + +Renders when the item is selected. You can style this element directly, or you can use it as a wrapper to put an icon into, or both. + + + +### Group + +Used to group multiple items. use in conjunction with `ListboxGroupLabel` to ensure good accessibility via automatic labelling. + + + +### GroupLabel + +Used to render the label of a group. It won't be focusable using arrow keys. + + + +### Virtualizer + +Virtual container to achieve list virtualization. + + + +## Examples + +### Binding objects as values + +Unlike native HTML form controls which only allow you to provide strings as values, `reka-ui` supports binding complex objects as well. + +```vue line=12,16,21 + + + +``` + +### Selecting multiple values + +The `Listbox` component allows you to select multiple values. You can enable this by providing an array of values instead of a single value. + +```vue line=12,18 + + + +``` + +### Custom filtering + +```vue line=13,15-16,21,24 + + + +``` + +### Virtual List + +Rendering a long list of item can slow down the app, thus using virtualization would significantly improve the performance. + +```vue line=19-23,24 + + + +``` + +## Accessibility + +Adheres to the [Listbox WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/listbox/). + +### Keyboard Interactions + + diff --git a/docs/content/zh/docs/components/menubar.md b/docs/content/zh/docs/components/menubar.md new file mode 100644 index 000000000..b37a7b94c --- /dev/null +++ b/docs/content/zh/docs/components/menubar.md @@ -0,0 +1,868 @@ +--- + +title: Menubar +description: A visually persistent menu common in desktop applications that provides quick + access to a consistent set of commands. +name: menubar +aria: https://www.w3.org/WAI/ARIA/apg/patterns/menu/ +--- + +# Menubar + + +A visually persistent menu common in desktop applications that provides quick access to a consistent set of commands. + + + + +## Features + + + +## Installation + +Install the component from your command line. + + + +## Anatomy + +Import all parts and piece them together. + +```vue + + + +``` + +## API Reference + +### Root + +Contains all the parts of a menubar + + + +### Menu + +A top level menu item, contains a trigger with content combination. + + + +### Trigger + +The button that toggles the content. By default, the `MenubarContent` will position itself against the trigger. + + + + + +### Portal + +When used, portals the content part into the `body`. + + + +### Content + +The component that pops out when a menu is open. + + + + + + + +### Arrow + +An optional arrow element to render alongside a menubar menu. This can be used to help visually link the trigger with the `MenubarContent`. Must be rendered inside `MenubarContent`. + + + +### Item + +The component that contains the menubar items. + + + + + +### Group + +Used to group multiple `MenubarItem`s. + + + +### Label + +Used to render a label. It won't be focusable using arrow keys. + + + +### CheckboxItem + +An item that can be controlled and rendered like a checkbox. + + + + + +### RadioGroup + +Used to group multiple `MenubarRadioItem`s. + + + +### RadioItem + +An item that can be controlled and rendered like a radio. + + + + + +### ItemIndicator + +Renders when the parent `MenubarCheckboxItem` or `MenubarRadioItem` is checked. You can style this element directly, or you can use it as a wrapper to put an icon into, or both. + + + + + +### Separator + +Used to visually separate items in a menubar menu. + + + +### Sub + +Contains all the parts of a submenu. + + + +### SubTrigger + +An item that opens a submenu. Must be rendered inside `MenubarSub`. + + + + + +### SubContent + +The component that pops out when a submenu is open. Must be rendered inside `MenubarSub`. + + + + + + + +## Examples + +### With submenus + +You can create submenus by using `MenubarSub` in combination with its parts. + +```vue line=9-11,25-34 + + + +``` + +### With disabled items + +You can add special styles to disabled items via the `data-disabled` attribute. + +```vue line=11 + + + +``` + +```css line=2 +/* styles.css */ +.MenubarItem[data-disabled] { + color: gainsboro; +} +``` + +### With separators + +Use the `Separator` part to add a separator between items. + +```vue line=8,20,22 + + + +``` + +### With labels + +Use the `Label` part to help label a section. + +```vue line=5,19 + + + +``` + +### With checkbox items + +Use the `CheckboxItem` part to add an item that can be checked. + +```vue line=3,27-32 + + + +``` + +### With radio items + +Use the `RadioGroup` and `RadioItem` parts to add an item that can be checked amongst others. + +```vue line=9-10,26-39 + + + +``` + +### With complex items + +You can add extra decorative elements in the `Item` parts, such as images. + +```vue line=12,16 + + + +``` + +### Constrain the content/sub-content size + +You may want to constrain the width of the content (or sub-content) so that it matches the trigger (or sub-trigger) width. You may also want to constrain its height to not exceed the viewport. + +We expose several CSS custom properties such as `--reka-menubar-trigger-width` and `--reka-menubar-content-available-height` to support this. Use them to constrain the content dimensions. + +```vue line=10 + + + +``` + +```css line=3-4 +/* styles.css */ +.MenubarContent { + width: var(--reka-menubar-trigger-width); + max-height: var(--reka-menubar-content-available-height); +} +``` + +### Origin-aware animations + +We expose a CSS custom property `--reka-menubar-content-transform-origin`. Use it to animate the content from its computed origin based on `side`, `sideOffset`, `align`, `alignOffset` and any collisions. + +```vue line=10 + + + +``` + +```css line=3 +/* styles.css */ +.MenubarContent { + transform-origin: var(--reka-menubar-content-transform-origin); + animation: scaleIn 0.5s ease-out; +} + +@keyframes scaleIn { + from { + opacity: 0; + transform: scale(0); + } + to { + opacity: 1; + transform: scale(1); + } +} +``` + +### Collision-aware animations + +We expose `data-side` and `data-align` attributes. Their values will change at runtime to reflect collisions. Use them to create collision and direction-aware animations. + +```vue line=10 + + + +``` + +```css line=6-11 +/* styles.css */ +.MenubarContent { + animation-duration: 0.6s; + animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1); +} +.MenubarContent[data-side="top"] { + animation-name: slideUp; +} +.MenubarContent[data-side="bottom"] { + animation-name: slideDown; +} + +@keyframes slideUp { + from { + opacity: 0; + transform: translateY(10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes slideDown { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} +``` + +## Accessibility + +Adheres to the [Menu Button WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/menubutton) and uses [roving tabindex](https://www.w3.org/WAI/ARIA/apg/patterns/kbd_roving_tabindex) to manage focus movement among menu items. + +### Keyboard Interactions + + diff --git a/docs/content/zh/docs/components/navigation-menu.md b/docs/content/zh/docs/components/navigation-menu.md new file mode 100644 index 000000000..4715e2dc8 --- /dev/null +++ b/docs/content/zh/docs/components/navigation-menu.md @@ -0,0 +1,681 @@ +--- +title: Navigation Menu +description: A collection of links for navigating websites. +name: navigation-menu +aria: https://www.w3.org/TR/wai-aria/#navigation +--- + +# Navigation Menu + + +A collection of links for navigating websites. + + + + +## Features + + + +## Installation + +Install the component from your command line. + + + +## Anatomy + +Import all parts and piece them together. + +```vue + + + +``` + +## API Reference + +### Root + +Contains all the parts of a navigation menu. + + + + + +### Sub + +Signifies a submenu. Use it in place of the root part when nested to create a submenu. + + + + + +### List + +Contains the top level menu items. + + + + + +### Item + +A top level menu item, contains a link or trigger with content combination. + + + +### Trigger + +The button that toggles the content. + + + + + +### Content + +Contains the content associated with each trigger. + + + + + + + +### Link + +A navigational link. + + + + + +### Indicator + +An optional indicator element that renders below the list, is used to highlight the currently active trigger. + + + + + + + + + +### Viewport + +An optional viewport element that is used to render active content outside of the list. + + + + + + + + + +## Examples + +### Vertical + +You can create a vertical menu by using the `orientation` prop. + +```vue line=16 + + + +``` + +### Flexible layouts + +Use the `Viewport` part when you need extra control over where `Content` is rendered. This can be helpful when your design +requires an adjusted DOM structure or if you need flexibility to achieve [advanced animation](/docs/components/navigation-menu#advanced-animation). +Tab focus will be maintained automatically. + +```vue line=26 + + + +``` + +### With indicator + +You can use the optional `Indicator` part to highlight the currently active `Trigger`, this is useful when you want to provide +an animated visual cue such as an arrow or highlight to accompany the `Viewport`. + +```vue line=24 + + + +``` + +```css +/* styles.css */ +.NavigationMenuIndicator { + background-color: grey; + position: absolute; + transition: width, transform, 250ms ease; +} + +.NavigationMenuIndicator[data-orientation="horizontal"] { + left: 0; + height: 3px; + transform: translateX(var(--reka-navigation-menu-indicator-position)); + width: var(--reka-navigation-menu-indicator-size); +} +``` + +### With submenus + +Create a submenu by nesting your `NavigationMenu` and using the `Sub` part in place of its `Root`. +Submenus work differently to `Root` navigation menus and are similar to [`Tabs`](/docs/components/tabs) in that one item should always be active, so be +sure to assign and set a `defaultValue`. + +```vue line=7,23-34 + + + +``` + +### With client side routing + +If you need to use the `RouterLink` component provided by your routing package then we recommend adding `asChild="true"` to `NavigationMenuLink`, or setting `as="RouterLink"`. +This will ensure accessibility and consistent keyboard control is maintained: + +```vue line=12-14,19-21 + + + +``` + +### Advanced animation + +We expose `--reka-navigation-menu-viewport-[width|height]` and `data-motion['from-start'|'to-start'|'from-end'|'to-end']` attributes to allow you to animate `Viewport` size and `Content` position based on the enter/exit direction. + +Combining these with `position: absolute;` allows you to create smooth overlapping animation effects when moving between items. + +```vue line=17,23,29 + + + +``` + +```css line=9-20,24,25 +/* styles.css */ +.NavigationMenuContent { + position: absolute; + top: 0; + left: 0; + animation-duration: 250ms; + animation-timing-function: ease; +} +.NavigationMenuContent[data-motion="from-start"] { + animation-name: enterFromLeft; +} +.NavigationMenuContent[data-motion="from-end"] { + animation-name: enterFromRight; +} +.NavigationMenuContent[data-motion="to-start"] { + animation-name: exitToLeft; +} +.NavigationMenuContent[data-motion="to-end"] { + animation-name: exitToRight; +} + +.NavigationMenuViewport { + position: relative; + width: var(--reka-navigation-menu-viewport-width); + height: var(--reka-navigation-menu-viewport-height); + transition: width, height, 250ms ease; +} + +@keyframes enterFromRight { + from { + opacity: 0; + transform: translateX(200px); + } + to { + opacity: 1; + transform: translateX(0); + } +} + +@keyframes enterFromLeft { + from { + opacity: 0; + transform: translateX(-200px); + } + to { + opacity: 1; + transform: translateX(0); + } +} + +@keyframes exitToRight { + from { + opacity: 1; + transform: translateX(0); + } + to { + opacity: 0; + transform: translateX(200px); + } +} + +@keyframes exitToLeft { + from { + opacity: 1; + transform: translateX(0); + } + to { + opacity: 0; + transform: translateX(-200px); + } +} +``` + +## Accessibility + +Adheres to the [`navigation` role requirements](https://www.w3.org/TR/wai-aria-1.2/#navigation). + +### Differences to menubar + +`NavigationMenu` should not be confused with `menubar`, although this primitive shares the name `menu` in the colloquial sense to refer to a set of navigation links, it does not use the WAI-ARIA `menu` role. +This is because `menu` and `menubars` behave like native operating system menus most commonly found in desktop application windows, as such they feature complex functionality like composite focus management and first-character navigation. + +These features are often considered [unnecessary for website navigation](https://github.com/w3c/aria-practices/issues/353) and at worst can confuse users who are familiar with established website patterns. + +See the W3C [Disclosure Navigation Menu](https://w3c.github.io/aria-practices/examples/disclosure/disclosure-navigation.html) example for more information. + +### Link usage and aria-current + +It's important to use `NavigationMenuLink` for all navigational links within a menu, this not only applies to the main list +but also within any content rendered via `NavigationMenuContent`. This will ensure consistent keyboard interactions and accessibility +while also giving access to the `active` prop for setting `aria-current` and the active styles. +See [this example](/docs/components/navigation-menu#with-client-side-routing) for more information on usage with third party routing components. + +### Keyboard Interactions + + diff --git a/docs/content/zh/docs/components/number-field.md b/docs/content/zh/docs/components/number-field.md new file mode 100644 index 000000000..9d14cdc83 --- /dev/null +++ b/docs/content/zh/docs/components/number-field.md @@ -0,0 +1,222 @@ +--- + +title: Number Field +description: A number field allows a user to enter a number and increment or decrement the value using stepper buttons. +name: number field +aria: https://www.w3.org/WAI/ARIA/apg/patterns/spinbutton +--- + +# Number Field + + +A number field allows a user to enter a number and increment or decrement the value using stepper buttons. + + + + +## Features + + + +## Installation + +Install the number package. + + + +Install the component from your command line. + + + +## Anatomy + +Import all parts and piece them together. + +```vue + + + +``` + +## API Reference + +### Root + +Contains all the parts of a number field. An `input` will also render when used within a `form` to ensure events propagate correctly. + + + + + +### Input + +Input + +The input component that renders the text value based on value and format options. + + + + + +### Increment + +The button that increases the value. + + + + + +### Decrement + +The button that decreases the value. + + + + + +## Example + +### Decimal + +All options supported by `Intl.NumberFormat` are supported, including configuration of minimum and maximum fraction digits, sign display, grouping separators, etc. + +```vue line=3-7 + +``` + +### Percentage + +You can set `formatOptions.style` to `percent` to treat the value as a percentage. You need to set the step to 0.01 manually to allow an appropriate step size in this mode. + +```vue line=3-7 + +``` + +### Currency + +You can set `formatOptions.style` to `currency` to treat the value as a currency value. The currency option must also be passed to set the currency code (e.g., USD). + +If you need to allow the user to change the currency, you should include a separate dropdown next to the number field. The number field itself will not determine the currency from the user input. + +```vue line=4-9 + +``` + +## Accessibility + +Adheres to the [Spinbutton WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/spinbutton). + +### Keyboard Interactions + + diff --git a/docs/content/zh/docs/components/pagination.md b/docs/content/zh/docs/components/pagination.md new file mode 100644 index 000000000..aee6e6849 --- /dev/null +++ b/docs/content/zh/docs/components/pagination.md @@ -0,0 +1,232 @@ +--- +title: Pagination +description: Displays data in paged format and provides navigation between pages. +name: pagination +--- + +# Pagination + + +Displays data in paged format and provides navigation between pages. + + + + +## Features + + + +## Installation + +Install the component from your command line. + + + +### Anatomy + +Import all parts and piece them together. + +```vue + + + +``` + +## API Reference + +### Root + +Contains all of the paginations parts. + + + +### List + +Used to show the list of pages. It also makes pagination accessible to assistive technologies. + + + +### Item + +Used to render the button that changes the current page. + + + + + +### Ellipsis + +Placeholder element when the list is long, and only a small amount of `siblingCount` was set and `showEdges` was set to `true`. + + + + + +### First + +Triggers that set the page value to 1 + + + +### Prev + +Triggers that set the page value to the previous page + + + +### Next + +Triggers that set the page value to the next page + + + +### Last + +Triggers that set the page value to the last page + + + +## Examples + +### With ellipsis + +You can add `PaginationEllipsis` as a visual cue for more previous and after items. + +```vue line=10-12 + + + +``` + +### With first/last button + +You can add `PaginationFirst` to allow user to navigate to first page, or `PaginationLast` to navigate to last page. + +```vue line=8,10 + + + +``` + +### Control page programmatically + +You can control the current page by passing it a reactive value. + +```vue line=6,10,11 + + + +``` + +## Keyboard Interactions + + diff --git a/docs/content/zh/docs/components/pin-input.md b/docs/content/zh/docs/components/pin-input.md new file mode 100644 index 000000000..644d8705c --- /dev/null +++ b/docs/content/zh/docs/components/pin-input.md @@ -0,0 +1,159 @@ +--- + +title: Pin Input +description: A sequence of one-character alphanumeric inputs. +name: pin-input +--- + +# Pin Input + + +A sequence of one-character alphanumeric inputs. + + + + +## Features + + + +## Installation + +Install the component from your command line. + + + +## Anatomy + +Import all parts and piece them together. + +```vue + + + +``` + +## API Reference + +### Root + +Contains all the parts of a checkbox. An `input` will also render when used within a `form` to ensure events propagate correctly. + + + + + +### Input + +Input field for Pin Input. You can add as many input as you like. + + + + + +## Examples + +### OTP mode + +You can set the pin input to `otp` mode by setting otp to `true`. + +```vue{6} + + + +``` + +### Numeric mode + +You can set the pin input to only accept `number` type by setting type to `number`. + +```vue{6} + + + +``` + +## Accessibility + +### Keyboard Interactions + + diff --git a/docs/content/zh/docs/components/popover.md b/docs/content/zh/docs/components/popover.md new file mode 100644 index 000000000..af6ebc642 --- /dev/null +++ b/docs/content/zh/docs/components/popover.md @@ -0,0 +1,406 @@ +--- + +title: Popover +description: Displays rich content in a portal, triggered by a button. +name: popover +aria: https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/ +--- + +# Popover + + +Displays rich content in a portal, triggered by a button. + + + + +## Features + + + +## Installation + +Install the component from your command line. + + + +## Anatomy + +Import all parts and piece them together. + +```vue + + + +``` + +## API Reference + +### Root + +Contains all the parts of a popover. + + + +### Trigger + +The button that toggles the popover. By default, the `PopoverContent` will position itself against the trigger. + + + + + +### Anchor + +An optional element to position the `PopoverContent` against. If this part is not used, the content will position alongside the PopoverTrigger. + + + +### Portal + +When used, portals the content part into the `body`. + + + +### Content + +The component that pops out when the popover is open. + + + + + + + + + +### Arrow + +An optional arrow element to render alongside the popover. This can be used to help visually link the anchor with the `PopoverContent`. Must be rendered inside `PopoverContent`. + + + +### Close + +The button that closes an open popover. + + + +## Examples + +### Constrain the content size + +You may want to constrain the width of the content so that it matches the trigger width. You may also want to constrain its height to not exceed the viewport. + +We expose several CSS custom properties such as `--reka-popover-trigger-width` and `--reka-popover-content-available-height` to support this. Use them to constrain the content dimensions. + +```vue line=10 +// index.vue + + + +``` + +```css line=3,4 +/* styles.css */ +.PopoverContent { + width: var(--reka-popover-trigger-width); + max-height: var(--reka-popover-content-available-height); +} +``` + +### Origin-aware animations + +We expose a CSS custom property `--reka-popover-content-transform-origin`. Use it to animate the content from its computed origin based on `side`, `sideOffset`, `align`, `alignOffset` and any collisions. + +```vue line=l10 +// index.vue + + + +``` + +```css line=3 +/* styles.css */ +.PopoverContent { + transform-origin: var(--reka-popover-content-transform-origin); + animation: scaleIn 0.5s ease-out; +} + +@keyframes scaleIn { + from { + opacity: 0; + transform: scale(0); + } + to { + opacity: 1; + transform: scale(1); + } +} +``` + +### Collision-aware animations + +We expose `data-side` and `data-align` attributes. Their values will change at runtime to reflect collisions. Use them to create collision and direction-aware animations. + +```vue line=10 +// index.vue + + + +``` + +```css line=6-11 +/* styles.css */ +.PopoverContent { + animation-duration: 0.6s; + animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1); +} +.PopoverContent[data-side="top"] { + animation-name: slideUp; +} +.PopoverContent[data-side="bottom"] { + animation-name: slideDown; +} + +@keyframes slideDown { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes slideUp { + from { + opacity: 0; + transform: translateY(10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} +``` + +### With custom anchor + +You can anchor the content to another element if you do not want to use the trigger as the anchor. + +```vue line=8-12 +// index.vue + + + +``` + +```css +/* styles.css */ +.Row { + background-color: gainsboro; + padding: 20px; +} +``` + +## Accessibility + +Adheres to the [Dialog WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/). + +### Keyboard Interactions + + + +## Custom APIs + +Create your own API by abstracting the primitive parts into your own component. + +#### Abstract the arrow and set default configuration + +This example abstracts the `PopoverArrow` part and sets a default `sideOffset` configuration. + +#### Usage + +```vue + + + +``` + +#### Implementation + +```ts +// your-popover.ts +export { default as PopoverContent } from 'PopoverContent.vue' + +export { PopoverRoot as Popover, PopoverTrigger } from 'reka-ui' +``` + +```vue + + + + +``` diff --git a/docs/content/zh/docs/components/progress.md b/docs/content/zh/docs/components/progress.md new file mode 100644 index 000000000..7abf0ffef --- /dev/null +++ b/docs/content/zh/docs/components/progress.md @@ -0,0 +1,97 @@ +--- + +title: Progress +description: Displays an indicator showing the completion progress of a task, typically displayed as a progress bar. +name: progress +aria: https://www.w3.org/WAI/ARIA/apg/patterns/meter +--- + +# Progress + + +Displays an indicator showing the completion progress of a task, typically displayed as a progress bar. + + + + +## Features + + + +## Installation + +Install the component from your command line. + + + +### Anatomy + +Import all parts and piece them together. + +```vue + + + +``` + +## Accessibility + +Adheres to the [`progressbar` role requirements](https://www.w3.org/WAI/ARIA/apg/patterns/meter). + +## API Reference + +### Root + +Contains all of the progress parts. + + + + + +### Indicator + +Used to show the progress visually. It also makes progress accessible to assistive technologies. + + + + diff --git a/docs/content/zh/docs/components/radio-group.md b/docs/content/zh/docs/components/radio-group.md new file mode 100644 index 000000000..510b82e26 --- /dev/null +++ b/docs/content/zh/docs/components/radio-group.md @@ -0,0 +1,141 @@ +--- + +title: Radio Group +description: A set of checkable buttons—known as radio buttons—where no more than one of the buttons can be checked at a time. +name: radio-group +aria: https://www.w3.org/WAI/ARIA/apg/patterns/radiobutton +--- + +# RadioGroup + + +A set of checkable buttons—known as radio buttons—where no more than one of the buttons can be checked at a time. + + + + +## Features + + + +## Installation + +Install the component from your command line. + + + +## Anatomy + +Import all parts and piece them together. + +```vue + + + +``` + +## API Reference + +### Root + +Contains all the parts of a radio group. + + + + + +### Item + +An item in the group that can be checked. An `input` will also render when used within a `form` to ensure events propagate correctly. + + + + + +### Indicator + +Renders when the radio item is in a checked state. You can style this element directly, or you can use it as a wrapper to put an icon into, or both. + + + + + + + +## Accessibility + +Adheres to the [Radio Group WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/radiobutton) and uses [roving tabindex](https://www.w3.org/TR/wai-aria-practices-1.2/examples/radio/radio.html) to manage focus movement among radio items. + +### Keyboard Interactions + + diff --git a/docs/content/zh/docs/components/range-calendar.md b/docs/content/zh/docs/components/range-calendar.md new file mode 100644 index 000000000..b2e8f02f8 --- /dev/null +++ b/docs/content/zh/docs/components/range-calendar.md @@ -0,0 +1,324 @@ +--- + +title: RangeCalendar +description: Presents a calendar view tailored for selecting date ranges. +name: range-calendar +--- + +# Range Calendar + +Alpha + + +Presents a calendar view tailored for selecting date ranges. + + + + +## Features + + + +## Preface + +The component depends on the [@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/index.html) package, which solves a lot of the problems that come with working with dates and times in JavaScript. + +We highly recommend reading through the documentation for the package to get a solid feel for how it works, and you'll need to install it in your project to use the date-related components. + +## Installation + +Install the date package. + + + +Install the component from your command line. + + + +## Anatomy + +Import all parts and piece them together. + +```vue + + + +``` + +## API Reference + +### Root + +Contains all the parts of a calendar + + + + + +### Header + +Contains the navigation buttons and the heading segments. + + + +### Prev Button + +Calendar navigation button. It navigates the calendar one month/year/decade in the past based on the current calendar view. + + + + + +### Next Button + +Calendar navigation button. It navigates the calendar one month/year/decade in the future based on the current calendar view. + + + + + +### Heading + +Heading for displaying the current month and year. + + + + + +### Grid + +Container for wrapping the calendar grid. + + + + + +### Grid Head + +Container for wrapping the grid head. + + + +### Grid Body + +Container for wrapping the grid body. + + + +### Grid Row + +Container for wrapping the grid row. + + + +### Head Cell + +Container for wrapping the head cell. Used for displaying the week days. + + + +### Cell + +Container for wrapping the calendar cells. + + + + + +### Cell Trigger + +Interactable container for displaying the cell dates. Clicking it selects the date. + + + + + +## Accessibility + +### Keyboard Interactions + + diff --git a/docs/content/zh/docs/components/scroll-area.md b/docs/content/zh/docs/components/scroll-area.md new file mode 100644 index 000000000..5eacc96c4 --- /dev/null +++ b/docs/content/zh/docs/components/scroll-area.md @@ -0,0 +1,118 @@ +--- + +title: Scroll Area +description: Augments native scroll functionality for custom, cross-browser styling. +name: scroll-area +--- + +# ScrollArea + + +Augments native scroll functionality for custom, cross-browser styling. + + + + +## Features + + + +## Installation + +Install the component from your command line. + + + +## Anatomy + +Import all parts and piece them together. + +```vue + + + +``` + +## API Reference + +### Root + +Contains all the parts of a scroll area. + + + +### Viewport + +The viewport area of the scroll area. + + + +### Scrollbar + +The vertical scrollbar. Add a second `Scrollbar` with an `orientation` prop to enable horizontal scrolling. + + + + + + + +### Thumb + +The thumb to be used in `ScrollAreaScrollbar`. + + + + + +### Corner + +The corner where both vertical and horizontal scrollbars meet. + + + +## Accessibility + +In most cases, it's best to rely on native scrolling and work with the customization options available in CSS. When that isn't enough, `ScrollArea` provides additional customizability while maintaining the browser's native scroll behavior (as well as accessibility features, like keyboard scrolling). + +### Keyboard Interactions + +Scrolling via keyboard is supported by default because the component relies on native scrolling. Specific keyboard interactions may differ between platforms, so we do not specify them here or add specific event listeners to handle scrolling via key events. diff --git a/docs/content/zh/docs/components/select.md b/docs/content/zh/docs/components/select.md new file mode 100644 index 000000000..f493afd3c --- /dev/null +++ b/docs/content/zh/docs/components/select.md @@ -0,0 +1,818 @@ +--- + +title: Select +description: Displays a list of options for the user to pick from—triggered by a button. +name: select +aria: https://www.w3.org/WAI/ARIA/apg/patterns/listbox +--- + +# Select + + +Displays a list of options for the user to pick from—triggered by a button. + + + + +## Features + + + +## Installation + +Install the component from your command line. + + + +## Anatomy + +Import all parts and piece them together. + +```vue + + + +``` + +## API Reference + +### Root + +Contains all the parts of a Select + + + +### Trigger + +The button that toggles the Select The `SelectContent` will position itself by aligning over the trigger. + + + + + +### Value + +The part that reflects the selected value. By default the selected item's text will be rendered. if you require more control, you can instead control the select and pass your own `children`. It should not be styled to ensure correct positioning. An optional `placeholder` prop is also available for when the select has no value. + + + +### Icon + +A small icon often displayed next to the value as a visual affordance for the fact it can be open. By default renders ▼ but you can use your own icon via `asChild` or use `children`. + + + +### Portal + +When used, portals the content part into the `body`. + + + +### Content + +The component that pops out when the select is open. + + + + + + + + + +### Viewport + +The scrolling viewport that contains all of the items. + + + +### Item + +The component that contains the select items. + + + + + +### ItemText + +The textual part of the item. It should only contain the text you want to see in the trigger when that item is selected. It should not be styled to ensure correct positioning. + + + +### ItemIndicator + +Renders when the item is selected. You can style this element directly, or you can use it as a wrapper to put an icon into, or both. + + + +### ScrollUpButton + +An optional button used as an affordance to show the viewport overflow as well as functionally enable scrolling upwards. + + + +### ScrollDownButton + +An optional button used as an affordance to show the viewport overflow as well as functionally enable scrolling downwards. + + + +### Group + +Used to group multiple items. use in conjunction with `SelectLabel` to ensure good accessibility via automatic labelling. + + + +### Label + +Used to render the label of a group. It won't be focusable using arrow keys. + + + +### Separator + +Used to visually separate items in the Select + + +### Arrow + +An optional arrow element to render alongside the content. This can be used to help visually link the trigger with the `SelectContent`. Must be rendered inside `SelectContent`. Only available when `position` is set to `popper`. + + + +## Examples + +### Change the positioning mode + +By default, `Select` will behave similarly to a native MacOS menu by positioning `SelectContent` relative to the active item. If you would prefer an alternative positioning approach similar to `Popover` or `DropdownMenu` then you can set `position` to `popper` and make use of additional alignment options such as `side`, `sideOffset` and more. + +```vue line=20 +// index.vue + + + +``` + +### Constrain the content size + +When using `position="popper"` on `SelectContent`, you may want to constrain the width of the content so that it matches the trigger width. You may also want to constrain its height to not exceed the viewport. + +We expose several CSS custom properties such as `--reka-select-trigger-width` and `--reka-select-content-available-height` to support this. Use them to constrain the content dimensions. + +```vue line=20 +// index.vue + + + +``` + +```css line=3,4 +/* styles.css */ +.SelectContent { + width: var(--reka-select-trigger-width); + max-height: var(--reka-select-content-available-height); +} +``` + +### With disabled items + +You can add special styles to disabled items via the `data-disabled` attribute. + +```vue line=22 +// index.vue + + + +``` + +```css line=2 +/* styles.css */ +.SelectItem[data-disabled] { + color: "gainsboro"; +} +``` + +### With a placeholder + +You can use the `placeholder` prop on `Value` for when the select has no value. There's also a `data-placeholder` attribute on `Trigger` to help with styling. + +```vue line=19,20 +// index.vue + + + +``` + +```css line=2 +/* styles.css */ +.SelectTrigger[data-placeholder] { + color: "gainsboro"; +} +``` + +### With separators + +Use the `Separator` part to add a separator between items. + +```vue line=10 + +``` + +### With grouped items + +Use the `Group` and `Label` parts to group items in a section. + +```vue line=7,8,12 + +``` + +### With complex items + +You can use custom content in your items. + +```vue line=23 + + + +``` + +### Controlling the value displayed in the trigger + +By default the trigger display the selected item's text (no longer automatically render `ItemText`'s content like in v1). + +If you need to render other than plain text, you can control the component using `v-model` props (or accessing `SelectValue`'s slotProps) and passing `slot` to `SelectValue`. Remember to make sure what you put in there is accessible. + +```vue line=2,4,10-12 + + + +``` + +### With custom scrollbar + +The native scrollbar is hidden by default as we recommend using the `ScrollUpButton` and `ScrollDownButton` parts for the best UX. If you do not want to use these parts, compose your select with our [Scroll Area](scroll-area) primitive. + +```vue line=25,27,32-34 +// index.vue + + + +``` + +```css +/* styles.css */ +.ScrollAreaRoot { + width: 100%; + height: 100%; +} + +.ScrollAreaViewport { + width: 100%; + height: 100%; +} + +.ScrollAreaScrollbar { + width: 4px; + padding: 5px 2px; +} + +.ScrollAreaThumb { + background: rgba(0, 0, 0, 0.3); + borderradius: 3px; +} +``` + +## Accessibility + +Adheres to the [ListBox WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/listbox). + +See the W3C [Select-Only Combobox](https://www.w3.org/TR/wai-aria-practices/examples/combobox/combobox-select-only.html) example for more information. + +### Keyboard Interactions + + + +### Labelling + +Use our [Label](label) component in order to offer a visual and accessible label for the Select + +```vue line=19,22,26,28 + + + +``` + +## Custom APIs + +Create your own API by abstracting the primitive parts into your own component. + +### Abstract down to `Select` and `SelectItem` + +This example abstracts most of the parts. + +#### Usage + +```vue + + + +``` + +#### Implementation + +```ts +// your-select.ts +export { default as Select } from 'Select.vue' +export { default as SelectItem } from 'SelectItem.vue' +``` + +```vue + + + + +``` + +```vue + + + + +``` diff --git a/docs/content/zh/docs/components/separator.md b/docs/content/zh/docs/components/separator.md new file mode 100644 index 000000000..ff09b185a --- /dev/null +++ b/docs/content/zh/docs/components/separator.md @@ -0,0 +1,60 @@ +--- + +title: Separator +description: Visually or semantically separates content. +name: separator +aria: https://www.w3.org/TR/wai-aria-1.2/#separator +--- + +# Separator + + +Visually or semantically separates content. + + + + +## Features + + + +## Installation + +Install the component from your command line. + + + +## Anatomy + +Import all parts and piece them together. + +```vue + + + +``` + +## API Reference + +### Root + +The separator. + + + + + +## Accessibility + +Adheres to the [`separator` role requirements](https://www.w3.org/TR/wai-aria-1.2/#separator). diff --git a/docs/content/zh/docs/components/slider.md b/docs/content/zh/docs/components/slider.md new file mode 100644 index 000000000..16e17d49b --- /dev/null +++ b/docs/content/zh/docs/components/slider.md @@ -0,0 +1,384 @@ +--- + +title: Slider +description: An input where the user selects a value from within a given range. +name: slider +aria: https://www.w3.org/WAI/ARIA/apg/patterns/slidertwothumb +--- + +# Slider + + +An input where the user selects a value from within a given range. + + + + +## Features + + + +## Installation + +Install the component from your command line. + + + +## Anatomy + +Import all parts and piece them together. + +```vue + + + +``` + +## API Reference + +### Root + +Contains all the parts of a slider. It will render an `input` for each thumb when used within a `form` to ensure events propagate correctly. + + + + + +### Track + +The track that contains the `SliderRange`. + + + + + +### Range + +The range part. Must live inside `SliderTrack`. + + + + + +### Thumb + +A draggable thumb. You can render multiple thumbs. + + + + + +## Examples + +### Vertical orientation + +Use the `orientation` prop to create a vertical slider. + +```vue line=7 +// index.vue + + + +``` + +```css line=7,18,26 +/* styles.css */ +.SliderRoot { + position: relative; + display: flex; + align-items: center; +} +.SliderRoot[data-orientation="vertical"] { + flex-direction: column; + width: 20px; + height: 100px; +} + +.SliderTrack { + position: relative; + flex-grow: 1; + background-color: grey; +} +.SliderTrack[data-orientation="vertical"] { + width: 3px; +} + +.SliderRange { + position: absolute; + background-color: black; +} +.SliderRange[data-orientation="vertical"] { + width: 100%; +} + +.SliderThumb { + display: block; + width: 20px; + height: 20px; + background-color: black; +} +``` + +### Create a range + +Add multiple thumbs and values to create a range slider. + +```vue line=7,11-12 +// index.vue + + + +``` + +### Define step size + +Use the `step` prop to increase the stepping interval. + +```vue line=7 +// index.vue + + + +``` + +### Prevent thumb overlap + +Use `minStepsBetweenThumbs` to avoid thumbs with equal values. + +```vue line=10 +// index.vue + + + +``` + +## Accessibility + +Adheres to the [Slider WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/slidertwothumb). + +### Keyboard Interactions + + + +## Custom APIs + +Create your own API by abstracting the primitive parts into your own component. + +### Abstract all parts + +This example abstracts all of the `Slider` parts so it can be used as a self closing element. + +#### Usage + +```vue + + + +``` + +#### Implementation + + ```ts +// your-slider.ts +export { default as Slider } from 'Slider.vue' +``` + +```vue + + + + +``` + +## Caveats + +### Mouse events are not fired + +Because of [a limitation](https://github.com/unovue/reka-ui/blob/main/packages/core/src/Slider/SliderImpl.vue#L48-L49) we faced during implementation, the following example won't work as expected and the `@mousedown` and `@mousedown` event handlers won't be fired: + +```vue + + … + +``` + +We recommend using pointer events instead (eg. `@pointerdown`, `@pointerup`). Regardless of the above limitation, these events are better suited for cross-platform/device handling as they are fired for all pointer input types (mouse, touch, pen, etc.). diff --git a/docs/content/zh/docs/components/splitter.md b/docs/content/zh/docs/components/splitter.md new file mode 100644 index 000000000..adf4e9ffa --- /dev/null +++ b/docs/content/zh/docs/components/splitter.md @@ -0,0 +1,275 @@ +--- +title: Splitter +description: A component that divides your layout into resizable sections. +name: splitter +aria: https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/ +--- + +# Splitter + + +A component that divides your layout into resizable sections. + + + + +## Features + + + +## Installation + +Install the component from your command line. + + + +## Anatomy + +Import all parts and piece them together. + +```vue + + + +``` + +## API Reference + +### Group + +Contains all the parts of a Splitter. + + + + + +### Panel + +A collapsible section. + + + +### Resize Handle + +Handle that use for resizing. + + + + + +## Examples + +### Collapsible + +Use the `collapsible` prop to allow the panel to collapse into `collapsedSize` when `minSize` is reached. + +(`collapsedSize` and `minSize` props are required.) + +```vue line=2 + +``` + +### Persist in localStorage + +Use the `autoSaveId` prop to save the layout data into `localStorage`. + +```vue line=2 + +``` + +### Persist layout with SSR + +By default, Splitter uses `localStorage` to persist layouts. With server rendering, this can cause a flicker when the default layout (rendered on the server) is replaced with the persisted layout (in `localStorage`). The way to avoid this flicker is to also persist the layout with a cookie like so: + +```vue line=3,7,8,12 + + + + +``` + +### Collapse/Expand programmatically + +Sometimes panels need to resize or collapse/expand in response to user actions. `SplitterPanel` exposes the `collapse` and `expand` methods to achieve this. + +```vue line=2,7,14 + + + +``` + +### Custom handle + +Customize the handle by passing any element as the slot. + + ```vue line=6-8 + +``` + +### SSR + +Splitter component heavily relies on unique `id`, however for Vue<3.4 we don't have a reliable way of generating [SSR-friendly `id`](https://github.com/vuejs/rfcs/discussions/557). + +Thus, if you are using Nuxt or other SSR framework, you are required to manually add the `id` for all Splitter components. Alternatively, you can wrap the component with ``. + +```vue + +``` + +## Accessibility + +Adheres to the [Window Splitter WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter). + +### Keyboard Interactions + + diff --git a/docs/content/zh/docs/components/stepper.md b/docs/content/zh/docs/components/stepper.md new file mode 100644 index 000000000..767188678 --- /dev/null +++ b/docs/content/zh/docs/components/stepper.md @@ -0,0 +1,208 @@ +--- +title: Stepper +description: A set of steps that are used to indicate progress through a multi-step process. +name: stepper +--- + +# Stepper + + +A set of steps that are used to indicate progress through a multi-step process. + + + + +## Features + + + +## Installation + +Install the component from your command line. + + + +## Anatomy + +Import all parts and piece them together. + +```vue + + + +``` + +## API Reference + +### Root + +Contains all the stepper component parts. + + + + + +### Item + +The step item component. + + + + + +### Trigger + +The trigger that toggles the step. + + + + + +### Indicator + +The indicator for the step. + + + +### Title + +An accessible title to be announced when the stepper trigger is focused. + +If you want to hide the title, wrap it inside our Visually Hidden utility like this ``. + + + +### Description + +An optional accessible description to be announced when the stepper trigger is focused. + +If you want to hide the description, wrap it inside our Visually Hidden utility like this ``. If you want to remove the description entirely, remove this part and pass `aria-describedby="undefined"` to `StepperTrigger`. + + + +## Examples + +### Vertical + +You can create vertical steps by using the `orientation` prop. + +```vue line=8 + + + +``` + +## Accessibility + +### Keyboard Interactions + + diff --git a/docs/content/zh/docs/components/switch.md b/docs/content/zh/docs/components/switch.md new file mode 100644 index 000000000..16b399332 --- /dev/null +++ b/docs/content/zh/docs/components/switch.md @@ -0,0 +1,102 @@ +--- + +title: Switch +description: A control that allows the user to toggle between checked and not checked. +name: switch +aria: https://www.w3.org/WAI/ARIA/apg/patterns/switch +--- + +# Switch + + +A control that allows the user to toggle between checked and not checked. + + + + +## Features + + + +## Installation + +Install the component from your command line. + + + +## Anatomy + +Import all parts and piece them together. + +```vue + + + +``` + +## API Reference + +### Root + +Contains all the parts of a switch. An `input` will also render when used within a `form` to ensure events propagate correctly. + + + + + +### Thumb + +The thumb that is used to visually indicate whether the switch is on or off. + + + + + +## Accessibility + +Adheres to the [`switch` role requirements](https://www.w3.org/WAI/ARIA/apg/patterns/switch). + +### Keyboard Interactions + + diff --git a/docs/content/zh/docs/components/tabs.md b/docs/content/zh/docs/components/tabs.md new file mode 100644 index 000000000..3fe078bfb --- /dev/null +++ b/docs/content/zh/docs/components/tabs.md @@ -0,0 +1,226 @@ +--- + +title: Tabs +description: A set of layered sections of content—known as tab panels—that are displayed one at a time. +name: tabs +aria: https://www.w3.org/WAI/ARIA/apg/patterns/tabpanel +--- + +# Tabs + + +A set of layered sections of content—known as tab panels—that are displayed one at a time. + + + + +## Features + + + +## Installation + +Install the component from your command line. + + + +## Anatomy + +Import all parts and piece them together. + +```vue + + + +``` + +## API Reference + +### Root + +Contains all the tabs component parts. + + + + + +### List + +Contains the triggers that are aligned along the edge of the active content. + + + + + +### Trigger + +The button that activates its associated content. + + + + + +### Indicator + +The indicator that highlights the current active tab. + + + + + +### Content + +Contains the content associated with each trigger. + + + + + + + +## Examples + +### Vertical + +You can create vertical tabs by using the `orientation` prop. + +```vue line=6 + + + +``` + +## Accessibility + +Adheres to the [Tabs WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/tabpanel). + +### Keyboard Interactions + + diff --git a/docs/content/zh/docs/components/tags-input.md b/docs/content/zh/docs/components/tags-input.md new file mode 100644 index 000000000..6dcd65e9b --- /dev/null +++ b/docs/content/zh/docs/components/tags-input.md @@ -0,0 +1,235 @@ +--- +title: Tags Input +description: Tags input render tags inside an input, followed by an actual text input. +name: tags-input +--- + +# Tags Input + + +Tag inputs render tags inside an input, followed by an actual text input. + + + + +## Features + + + +## Installation + +Install the component from your command line. + + + +## Anatomy + +Import all parts and piece them together. + +```vue + + + +``` + +## API Reference + +### Root + +Contains all the tags input component parts. + + + + + +### Item + +The component that contains the tag. + + + + + +### ItemText + +The textual part of the tag. Important for accessibility. + + + +### ItemDelete + +The button that delete the associate tag. + + + + + +### Input + +The input element for the tags input. + + + + + +### Clear + +The button that remove all tags. + + + + + +## Examples + +### With Combobox + +You can compose Tags input together with [Combobox](../components/combobox.html). + + + +### Paste behavior + +You can automatically add tags on paste by passing the `add-on-paste` prop. + +```vue line=8 + + + +``` + +### Multiple delimiters + +You can pass `RegExp` as `delimiter` to allow multiple characters to trigger addition of a new tag. When `add-on-paste` is passed it will be also used to split tags for `@paste` event. + +```vue line=4-5,11 + + + +``` + +## Accessibility + +### Keyboard Interactions + + diff --git a/docs/content/zh/docs/components/time-field.md b/docs/content/zh/docs/components/time-field.md new file mode 100644 index 000000000..77e2c3bba --- /dev/null +++ b/docs/content/zh/docs/components/time-field.md @@ -0,0 +1,149 @@ +--- +title: Time Field +description: Enables users to input specific times within a designated field. +name: time-field +--- + +# Time Field + +Alpha + + +Enables users to input specific times within a designated field. + + + + +## Features + + + +## Preface + +The component depends on the [@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/index.html) package, which solves a lot of the problems that come with working with dates and times in JavaScript. + +We highly recommend reading through the documentation for the package to get a solid feel for how it works, and you'll need to install it in your project to use the date-related components. + +## Installation + +Install the date package. + + + +Install the component from your command line. + + + +## Anatomy + +Import all parts and piece them together. + +```vue + + + +``` + +## API Reference + +### Root + +Contains all the parts of a time field + + + + + +### Input + +Contains the time field segments + + + + + +## Accessibility + +### Keyboard Interactions + + diff --git a/docs/content/zh/docs/components/toast.md b/docs/content/zh/docs/components/toast.md new file mode 100644 index 000000000..efd7c7ffc --- /dev/null +++ b/docs/content/zh/docs/components/toast.md @@ -0,0 +1,446 @@ +--- +title: Toast +description: A succinct message that is displayed temporarily. +name: toast +aria: https://www.w3.org/TR/wai-aria/#aria-live +--- + +# Toast + + +A succinct message that is displayed temporarily. + + + + + + +## Installation + +Install the component from your command line. + + + +## Anatomy + +Import the component. + +```vue + + + +``` + +## API Reference + +### Provider + +The provider that wraps your toasts and toast viewport. It usually wraps the application. + + + +### Viewport + +The fixed area where toasts appear. Users can jump to the viewport by pressing a hotkey. It is up to you to ensure the discoverability of the hotkey for keyboard users. + + + +### Root + +The toast that automatically closes. It should not be held open to [acquire a user response](/docs/components/toast#action). + + + + + + + + + +### Portal + +When used, portals the content part into the `body`. + + + +### Title + +An optional title for the toast + + + +### Description + +The toast message. + + + +### Action + +An action that is safe to ignore to ensure users are not expected to complete tasks with unexpected side effects as a result of a [time limit](https://www.w3.org/TR/UNDERSTANDING-WCAG20/time-limits-required-behaviors.html). + +When obtaining a user response is necessary, portal an ["AlertDialog"](/docs/components/alert-dialog) styled as a toast into the viewport instead. + + + +### Close + +A button that allows users to dismiss the toast before its duration has elapsed. + + + +## Examples + +### Custom hotkey + +Override the default hotkey using the `event.code` value for each key from [keycode.info](https://keycode.info/). + +```html line=3 + + ... + + +``` + +### Custom duration + +Customise the duration of a toast to override the provider value. + +```vue line=1 + + Saved! + +``` + +### Duplicate toasts + +When a toast must appear every time a user clicks a button, use state to render multiple instances of the same toast (see below). Alternatively, you can abstract the parts to create your own [imperative API](/docs/components/toast#imperative-api). + +```html line=2,7 +
+
+ ... + +
+ + + Saved! + +
+``` + +### Animating swipe gesture + +Combine `--reka-toast-swipe-move-[x|y]` and `--reka-toast-swipe-end-[x|y]` CSS variables with `data-swipe="[start|move|cancel|end]"` attributes to animate a swipe to close gesture. Here's an example: + +```html line=2 + + ... + + +``` + +```css line=2,3,5,9,15 +/* styles.css */ +.ToastRoot[data-swipe='move'] { + transform: translateX(var(--reka-toast-swipe-move-x)); +} +.ToastRoot[data-swipe='cancel'] { + transform: translateX(0); + transition: transform 200ms ease-out; +} +.ToastRoot[data-swipe='end'] { + animation: slideRight 100ms ease-out; +} + +@keyframes slideRight { + from { + transform: translateX(var(--reka-toast-swipe-end-x)); + } + to { + transform: translateX(100%); + } +} +``` + +## Accessibility + +Adheres to the [`aria-live` requirements](https://www.w3.org/TR/wai-aria/#aria-live). + +### Sensitivity + +Control the sensitivity of the toast for screen readers using the `type` prop. + +For toasts that are the result of a user action, choose `foreground`. Toasts generated from background tasks should use `background`. + +#### Foreground + +Foreground toasts are announced immediately. Assistive technologies may choose to clear previously queued messages when a foreground toast appears. Try to avoid stacking distinct foreground toasts at the same time. + +#### Background + +Background toasts are announced at the next graceful opportunity, for example, when the screen reader has finished reading its current sentence. They do not clear queued messages so overusing them can be perceived as a laggy user experience for screen reader users when used in response to a user interaction. + +```html line=1,6 + + File removed successfully. + Dismiss + + + + We've just released Radix 1.0. + Dismiss + +``` + +### Alternative action + +Use the `altText` prop on the `Action` to instruct an alternative way of actioning the toast to screen reader users. + +You can direct the user to a permanent place in your application where they can action it or implement your own custom hotkey logic. If implementing the latter, use `foreground` type to announce immediately and increase the duration to give the user ample time. + +```html line=4,10,12 + + Upgrade Available! + We've just released Radix 1.0. + + Upgrade + + Dismiss + + + + File removed successfully. + + Undo Alt+U + + Dismiss + +``` + +### Close icon button + +When providing an icon (or font icon), remember to label it correctly for screen reader users. + +```html line=3-4 + + Saved! + + + + +``` + +### Keyboard Interactions + + + +## Custom APIs + +### Abstract parts + +Create your own API by abstracting the primitive parts into your own component. + +#### Usage + +```vue + + + +``` + +#### Implementation + +```vue +// your-toast.vue + + + +``` + +### Imperative API + +Create your own imperative API to allow [toast duplication](/docs/components/toast#duplicate-toasts) if preferred. + +#### Usage + +```vue + + + +``` + +#### Implementation + +```vue +// your-toast.vue + + + +``` diff --git a/docs/content/zh/docs/components/toggle-group.md b/docs/content/zh/docs/components/toggle-group.md new file mode 100644 index 000000000..c7bc8899e --- /dev/null +++ b/docs/content/zh/docs/components/toggle-group.md @@ -0,0 +1,170 @@ +--- + +title: Toggle Group +description: A set of two-state buttons that can be toggled on or off. +name: toggle-group +aria: https://www.w3.org/WAI/ARIA/apg/patterns/button +--- + +# ToggleGroup + + +A set of two-state buttons that can be toggled on or off. + + + + +## Features + + + +## Installation + +Install the component from your command line. + + + +## Anatomy + +Import the component. + +```vue + + + +``` + +## API Reference + +### Root + +Contains all the parts of a toggle group. + + + + + +### Item + +An item in the group. + + + + + +## Examples + +### Ensuring there is always a value + +You can control the component to ensure a value. + +```vue line=5,10-13 + + + +``` + +## Accessibility + +Uses [roving tabindex](https://www.w3.org/TR/wai-aria-practices-1.2/examples/radio/radio.html) to manage focus movement among items. + +### Keyboard Interactions + + diff --git a/docs/content/zh/docs/components/toggle.md b/docs/content/zh/docs/components/toggle.md new file mode 100644 index 000000000..45414cb17 --- /dev/null +++ b/docs/content/zh/docs/components/toggle.md @@ -0,0 +1,79 @@ +--- + +title: Toggle +description: A two-state button that can be either on or off. +name: toggle +aria: https://www.w3.org/WAI/ARIA/apg/patterns/button +--- + +# Toggle + + +A two-state button that can be either on or off. + + + + +## Features + + + +## Installation + +Install the component from your command line. + + + +## Anatomy + +Import the component. + +```vue + + + +``` + +## API Reference + +### Root + +The toggle. + + + + + +## Accessibility + +### Keyboard Interactions + + diff --git a/docs/content/zh/docs/components/toolbar.md b/docs/content/zh/docs/components/toolbar.md new file mode 100644 index 000000000..ad061fdd3 --- /dev/null +++ b/docs/content/zh/docs/components/toolbar.md @@ -0,0 +1,229 @@ +--- + +title: Toolbar +description: A container for grouping a set of controls, such as buttons, toggle groups or dropdown menus. +name: toolbar +aria: https://www.w3.org/WAI/ARIA/apg/patterns/toolbar +--- + +# Toolbar + + +A container for grouping a set of controls, such as buttons, Toolbar groups or +dropdown menus. + + + + +## Features + + + +## Installation + +Install the component from your command line. + + + +## Anatomy + +Import the component. + +```vue + + + +``` + +## API Reference + +### Root + +Contains all the toolbar component parts. + + + + + +### Button + +A button item. + + + + + +### Link + +A link item. + + + +### ToggleGroup + +A set of two-state buttons that can be toggled on or off. + + + + + +### ToggleItem + +An item in the group. + + + + + +### Separator + +Used to visually separate items in the toolbar + + + + + +## Examples + +### Use with other primitives + +All our primitives which expose a `Trigger` part, such as `Dialog`, `AlertDialog`, `Popover`, `DropdownMenu` can be composed within a toolbar by using the [`asChild` prop](/docs/guides/composition). + +Here is an example using our `DropdownMenu` primitive. + +```vue line=20-22 + + + +``` + +## Accessibility + +Uses [roving tabindex](https://www.w3.org/TR/wai-aria-practices-1.2/examples/radio/radio.html) to manage focus movement among items. + +### Keyboard Interactions + + diff --git a/docs/content/zh/docs/components/tooltip.md b/docs/content/zh/docs/components/tooltip.md new file mode 100644 index 000000000..041e4658e --- /dev/null +++ b/docs/content/zh/docs/components/tooltip.md @@ -0,0 +1,421 @@ +--- +title: Tooltip +description: A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it. +name: tooltip +aria: https://www.w3.org/WAI/ARIA/apg/patterns/tooltip +--- + +# Tooltip + + +A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it. + + + + +## Features + + + +## Anatomy + +Import all parts and piece them together. + +```vue + + + +``` + +## API Reference + +### Provider + +Wraps your app to provide global functionality to your tooltips. + + + +### Root + +Contains all the parts of a tooltip. + + + +### Trigger + +The button that toggles the tooltip. By default, the `TooltipContent` will position itself against the trigger. + + + + + +### Portal + +When used, portals the content part into the `body`. + + + +### Content + +The component that pops out when the tooltip is open. + + + + + + + + + +### Arrow + +An optional arrow element to render alongside the tooltip. This can be used to help visually link the trigger with the `TooltipContent`. Must be rendered inside `TooltipContent`. + + + +## Examples + +### Configure globally + +Use the `Provider` to control `delayDuration` and `skipDelayDuration` globally. + +```vue line=6 + + + +``` + +### Show instantly + +Use the `delayDuration` prop to control the time it takes for the tooltip to open. + +```vue line=6 + + + +``` + +### Displaying a tooltip from a disabled button + +Since disabled buttons don't fire events, you need to: + +- Render the `Trigger` as `span`. +- Ensure the `button` has no `pointerEvents`. + +```vue line=7-11 + + + +``` + +### Constrain the content size + +You may want to constrain the width of the content so that it matches the trigger width. You may also want to constrain its height to not exceed the viewport. + +We expose several CSS custom properties such as `--reka-tooltip-trigger-width` and `--reka-tooltip-content-available-height` to support this. Use them to constrain the content dimensions. + +```vue line=10 + + + + +``` + +```css line=3,4 +/* styles.css */ +.TooltipContent { + width: var(--reka-tooltip-trigger-width); + max-height: var(--reka-tooltip-content-available-height); +} +``` + +### Origin-aware animations + +We expose a CSS custom property `--reka-tooltip-content-transform-origin`. Use it to animate the content from its computed origin based on `side`, `sideOffset`, `align`, `alignOffset` and any collisions. + +```vue line=9 + + + + +``` + +```css line=3-4 +/* styles.css */ +.TooltipContent { + transform-origin: var(--reka-tooltip-content-transform-origin); + animation: scaleIn 0.5s ease-out; +} + +@keyframes scaleIn { + from { + opacity: 0; + transform: scale(0); + } + to { + opacity: 1; + transform: scale(1); + } +} +``` + +### Collision-aware animations + +We expose `data-side` and `data-align` attributes. Their values will change at runtime to reflect collisions. Use them to create collision and direction-aware animations. + +```vue line=9 + + + + +``` + +```css line=6,9 +/* styles.css */ +.TooltipContent { + animation-duration: 0.6s; + animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1); +} +.TooltipContent[data-side="top"] { + animation-name: slideUp; +} +.TooltipContent[data-side="bottom"] { + animation-name: slideDown; +} + +@keyframes slideDown { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes slideUp { + from { + opacity: 0; + transform: translateY(10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} +``` + +## Accessibility + +### Keyboard Interactions + + + +## Custom APIs + +Create your own API by abstracting the primitive parts into your own component. + +### Abstract parts and introduce a content prop + +This example abstracts all of the `Tooltip` parts and introduces a new `content` prop. + +#### Usage + +```vue + + + +``` + +#### Implementation + +Use the [`asChild` prop](/docs/guides/composition) to convert the trigger part into a slottable area. It will replace the trigger with the child that gets passed to it. + +```vue line=13-15 + + + + +``` diff --git a/docs/content/zh/docs/components/tree.md b/docs/content/zh/docs/components/tree.md new file mode 100644 index 000000000..0dd73f5fb --- /dev/null +++ b/docs/content/zh/docs/components/tree.md @@ -0,0 +1,358 @@ +--- + +title: Tree +description: A tree view widget displays a hierarchical list of items that can be expanded or collapsed to show or hide their child items, such as in a file system navigator. +name: tree +aria: https://www.w3.org/WAI/ARIA/apg/patterns/treeview/ +--- + +# Tree + +Alpha + + +A tree view widget displays a hierarchical list of items that can be expanded or collapsed to show or hide their child items, such as in a file system navigator. + + + + +## Features + + + +## Installation + +Install the component from your command line. + + + +## Anatomy + +Import all parts and piece them together. + +```vue + + + +``` + +## API Reference + +### Root + +Contains all the parts of a tree. + + + +### Item + +The item component. + + + + + +### Virtualizer + +Virtual container to achieve list virtualization. + + + +## Examples + +### Selecting multiple items + +The `Tree` component allows you to select multiple items. You can enable this by providing an array of values instead of a single value. + +```vue line=12,16 + + + +``` + +### Virtual List + +Rendering a long list of item can slow down the app, thus using virtualization would significantly improve the performance. + +```vue line=9-16 + + + +``` + +### With Checkbox + +Some `Tree` component might want to show `toggled/indeterminate` checkbox. We can change the behavior of the `Tree` component by using a few props and `preventDefault` event. + +We set `propagateSelect` to `true` because we want the parent checkbox to select/deselect it's descendants. Then, we add a checkbox that triggers `select` event. + +```vue line=10-11,17-25,29-33 + + + +``` + +### Nested Tree Node + +The default example shows flatten tree items and nodes, this enables [Virtualization](/docs/components/tree.html#virtual-list) and custom feature such as Drag & Drop easier. However, you can also build it to have nested DOM node. + +In `Tree.vue`, + +```vue + + + +``` + +In `CustomTree.vue` + +```vue + +``` + +### Custom children schema + +By default, `` expects you to provide the list of node's children by passing a list of `children` for every node. You can override that by providing the `getChildren` prop. + + + +If the node doesn't have any children, `getChildren` should return `undefined` instead of an empty array. + + + +```vue line=22 + + + +``` + +### Draggable/Sortable Tree + +For more complex draggable `Tree` component, in this example we will be using [pragmatic-drag-and-drop](https://github.com/atlassian/pragmatic-drag-and-drop), as the core package for handling dnd. + +[Stackblitz Demo](https://stackblitz.com/edit/github-8f3fzs?file=src%2FTreeDND.vue) + +## Accessibility + +Adheres to the [Tree WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/treeview/). + +### Keyboard Interactions + + diff --git a/docs/content/zh/docs/guides/animation.md b/docs/content/zh/docs/guides/animation.md new file mode 100644 index 000000000..bb79a7d63 --- /dev/null +++ b/docs/content/zh/docs/guides/animation.md @@ -0,0 +1,203 @@ +--- +title: Animation/Transition +description: Animate Reka UI with CSS keyframes, native Vue Transition or JavaScript animation library of your choice. +--- + +# Animation + + +Animate Reka UI with CSS keyframes, native Vue Transition or JavaScript animation library of your choice. + + +Adding animation to Reka UI should feel similar to any other component, but there are some caveats noted here in regards to exiting animations with JS animation libraries. + +## Animating with CSS animation + +The simplest way to animate Primitives is with CSS. + +You can use CSS animation to animate both mount and unmount phases. The latter is possible because the Reka UI will suspend unmount while your animation plays out. + +```css +@keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +@keyframes fadeOut { + from { + opacity: 1; + } + to { + opacity: 0; + } +} + +.DialogOverlay[data-state="open"], +.DialogContent[data-state="open"] { + animation: fadeIn 300ms ease-out; +} + +.DialogOverlay[data-state="closed"], +.DialogContent[data-state="closed"] { + animation: fadeOut 300ms ease-in; +} +``` + +## Animating with Vue Transition + +Other than using CSS animation, you might prefer to use the native Vue ``. Great news! It should be as easy as wrapping component (that has `forceMount` prop), and you are done! + +```vue line=11,13,14,19,25-33 + + + + + +``` + +## ⭐️ Animating with Motion Vue + +[Motion Vue](https://motion.unovue.com/) is the recommended animation library for Reka UI. This lightweight, powerful library integrates seamlessly with components and offers extensive flexibility for creating smooth, performant animations. + +```vue line=3,12,14-18,22-26,29,31 + + + +``` + + + +Check out this [Stackblitz Demo](https://stackblitz.com/edit/x7y44ngl?file=src%2FApp.vue) 🤩 + + + +## Delegating unmounting for JavaScript Animation + +When many stateful Primitives are hidden from view, they are actually removed from the DOM. JavaScript animation libraries need control of the unmounting phase, so we provide the `forceMount` prop on many components to allow consumers to delegate the mounting and unmounting of children based on the animation state determined by those libraries. + +For example, if you want to use [@vueuse/motion](https://motion.vueuse.org/) to animate a `Dialog`, you would do so by conditionally rendering the dialog `Overlay` and `Content` parts based on the animation state from one of its composable like `useSpring`: + +```vue line=32,34,41 + + + +``` + + + +Check out this [Stackblitz Demo](https://stackblitz.com/edit/macsaz-xuwbw3im?file=src%2FApp.vue) + + diff --git a/docs/content/zh/docs/guides/composition.md b/docs/content/zh/docs/guides/composition.md new file mode 100644 index 000000000..43e0e4fd4 --- /dev/null +++ b/docs/content/zh/docs/guides/composition.md @@ -0,0 +1,71 @@ +--- + +title: Composition +description: Use the `asChild` prop to compose Radix's functionality onto alternative element types or your own Vue components. +--- + +# Composition + + +Use the `asChild` prop to compose Radix's functionality onto alternative +element types or your own Vue components. + + +All Reka UI parts that render a DOM element accept an `asChild` prop. When `asChild` is set to `true`, Reka UI will not render a default DOM element, instead passing the props and behavior required to make it functional to the first child of the slots. + +## Changing the element type + +In the majority of cases you shouldn’t need to modify the element type as Radix has been designed to provide the most appropriate defaults. However, there are cases where it is helpful to do so. + +A good example is with `TooltipTrigger`. By default this part is rendered as a `button`, though you may want to add a tooltip to a link (`a` tag) as well. Let's see how you can achieve this using `asChild`: + +```vue{7} + + + +``` + +> If you do decide to change the underlying element type, it is your responsibility to ensure it remains accessible and functional. In the case of `TooltipTrigger` for example, it must be a focusable element that can respond to pointer and keyboard events. If you were to switch it to a `div`, it would no longer be accessible. + +In reality, you will rarely modify the underlying DOM element like we've seen above. Instead it's more common to use your own Vue components. This is especially true for most `Trigger` parts, as you usually want to compose the functionality with the custom buttons and links in your design system. + +## Composing with your own Vue components + +This works exactly the same as above, you pass `asChild` to the part and then wrap your own component with it. +However, there are a few gotchas to be aware of. + +## Composing multiple primitives + +`asChild` can be used as deeply as you need to. This means it is a great way to compose multiple primitive's behavior together. +Here is an example of how you can compose `TooltipTrigger` and `DialogTrigger` together with your own button: + +```vue{9,10} + + + +``` diff --git a/docs/content/zh/docs/guides/dates.md b/docs/content/zh/docs/guides/dates.md new file mode 100644 index 000000000..a29a07cf6 --- /dev/null +++ b/docs/content/zh/docs/guides/dates.md @@ -0,0 +1,97 @@ +--- +title: Dates & Times +description: How to work with dates and times in Reka UI. +--- + +# Dates & Times + + +How to work with dates and times in Reka UI. + + + + +The inner-workings of our date-related components are heavily inspired by the research and work done +by the [React Aria](https://react-spectrum.adobe.com/react-aria/) team at Adobe, who have created +robust date components that excel in terms of accessibility, user experience, and flexibility. + + + +The component depends on the [@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/index.html) package, which solves a lot of the problems that come with working with dates and times in JavaScript. + +We highly recommend reading through the documentation for the package to get a solid feel for how it +works, and you'll need to install it in your project to use the date-related components. + + + +## Date Objects + +We use the `DateValue` objects provided by `@internationalized/date` to +represent dates in the various components. These objects are immutable, and provide information about +the type of date they represent: + +- `CalendarDate`: A date with no time component, such as `2023-10-11`. +- `CalendarDateTime`: A date with a time component, but without a timezone, such as + `2023-10-11T12:30:00`. +- `ZonedDateTime`: A date with a time component and a timezone, such as + `2023-10-11T21:00:00:00-04:00[America/New_York]`. + +The benefit of using these objects is that we can be very specific about the type of date we want, +and the behavior of the builder will adapt to that type. + +Additionally, you don't have to worry about wrangling timezones, daylight savings time, or any other +date-related nuance. + +## Utility Functions + +This package also provides a number of utility functions which solves a lot of the problems that come with working with dates and times in JavaScript. + +Specially designed to work well with [@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/index.html). + +### How to use? + +```ts +import { + createDateRange, + createDecade, + createMonth, + createYear, + createYearRange, + getDaysInMonth, + hasTime, + isAfter, + isAfterOrSame, + isBefore, + isBeforeOrSame, + isBetween, + isBetweenInclusive, + isCalendarDateTime, + isZonedDateTime, + parseStringToDateValue, + toDate, +} from 'reka-ui/date' + +import { CalendarDate, type DateValue } from '@internationalized/date' + +const date = new CalendarDate(1995, 8, 18) +const minDate = new CalendarDate(1995, 8, 1) +const maxDate = new CalendarDate(1995, 8, 31) + +parseStringToDateValue('1995-08-18', date) // returns a DateValue object +toDate(date) // returns a Date object +isCalendarDateTime(date) // returns false +isZonedDateTime(date) // returns false +hasTime(date) // returns false +getDaysInMonth(date) // returns 31 +isAfter(date, minDate) // returns true +isBeforeOrSame(date, maxDate) // returns true +isAfterOrSame(date, minDate) // returns true +isBefore(date, maxDate) // returns true +isBetweenInclusive(date, minDate, maxDate) // returns true +isBetween(date, minDate, maxDate) // returns true +createMonth({ dateObj: new CalendarDate(1995, 8, 18), weekStartsOn: 0, locale: 'en', fixedWeeks: true }) // returns a grid of days as DateValue for the month, also containing the dateObj, plus an array of days for the month +createYear({ dateObj: new CalendarDate(1995, 8, 18), numberOfMonths: 2, pagedNavigation: true }) // returns an array of months as DateValue, centered around the dateObj taking into account the numberOfMonths and pagedNavigation when returning the months +createDecade({ dateObj: new CalendarDate(1995, 8, 18), startIndex: -10, endIndex: 10 }) // returns a decade centered around the dateObj +createDateRange({ start: new CalendarDate(1995, 8, 18), end: new CalendarDate(2005, 8, 18) }) // returns an array of dates as DateValue between the start and end date +createYearRange({ start: new CalendarDate(1995, 8, 18), end: new CalendarDate(2005, 8, 18) }) // returns an array of years as DateValue between the start and end date +``` diff --git a/docs/content/zh/docs/guides/i18n.md b/docs/content/zh/docs/guides/i18n.md new file mode 100644 index 000000000..cc074ba99 --- /dev/null +++ b/docs/content/zh/docs/guides/i18n.md @@ -0,0 +1,255 @@ +--- +title: Internationalization (RTL) +description: Reka UI support both LTR/RTL directions. Learn more about how to integrate internationalization with Radix. +--- + +# Internationalization & RTL + + +Reka UI support both LTR/RTL directions. Learn more about how to integrate internationalization with Radix. + + +## Multi-Direction Support + +### Introduction + +This documentation provides guidance on how to utilize multi-directional support in Reka UI with SSR support. Reka UI rely on [`Floating UI`](https://floating-ui.com/) to position floating elements, which requires to be fed the current direction of the web app. + +Radix components are LTR by default, but you are in control of what direction (only LTR, RTL, or both) you want to support. This section provides best practices to easily support RTL direction. + +### RTL + +[`ConfigProvider`](/docs/utilities/config-provider) is a wrapper component to provide global configurations, including the directionality of the web app. + +When creating localized apps that require right-to-left (RTL) reading direction, you need to wrap your application with the `ConfigProvider` component to ensure all of the primitives adjust their behavior based on the `dir` prop. + +To make all Reka UI RTL, wrap your entire App in `ConfigProvider` and pass the `dir` prop with the value `rtl`. + +Add the following code to your `app.vue` or main layout component: + +```vue + + + +``` + +All Radix components that are wrapped in the provider inherit the `dir` attribute. + +### Dynamic Direction + +To dynamically change the direction of Reka UI, we could leverage the [`useTextDirection`](https://vueuse.org/core/useTextDirection/) composable and combine it with our `ConfigProvider`. + +But first, we need to install the [`@vueuse/core`](https://vueuse.org/) package. + + + +Then in your root Vue file: + +```vue + + + +``` + +To support SSR - when the server has no access to the `html` and its direction, set `initialValue` in `useTextDirection`. + +```vue{5} + + + +``` + + + +The `dir` prop doesn't support `auto` as a value, so we need an intermediate Ref to explicitly define the direction. + + + +`textDirection` is a [`Ref`](https://vuejs.org/api/reactivity-core.html#ref), and by changing the value of it to either "ltr" or "rtl", the `dir` attribute on the `html` tag changes as well. + +## Internationalization + +Some languages are written from LTR and others are written in RTL. In a multi-language web app, you need to configure directionality alongside the translations. This is a simplified guide on how to achieve that using `reka-ui` primitives. + +But first, let's install some required packages. + +### Dependencies + +We rely on [`VueI18n`](https://vue-i18n.intlify.dev/) to manage different translations we want to support. + + + +Go ahead and add some translations for the word "hello" in different languages at `main.ts`. + +```ts{4-26,29} +import { createApp } from 'vue' +import './style.css' +import App from './App.vue' +import { createI18n } from 'vue-i18n' + +const messages = { + en: { + hello: 'Hello', + }, + fa: { + hello: 'درود', + }, + ar: { + hello: 'مرحبا', + }, + ja: { + hello: 'こんにちは', + } +} + +const i18n = createI18n({ + legacy: false, // you must set `false` to use the Composition API + locale: 'en', // set default locale + availableLocales: ['en', 'fa', 'ar', 'ja'], + messages, +}) + +createApp(App) + .use(i18n) + .mount('#app') +``` + +### Language Selector + +After setting the translations and adding the `vue-i18n` plugin, we need a language selector in your `app.vue`. By changing the language using this `radix` select primitive: +1. The translations are reactive to the new language +2. The direction of the web app is reactive to the new language + +```vue + + + +``` diff --git a/docs/content/zh/docs/guides/inject-context.md b/docs/content/zh/docs/guides/inject-context.md new file mode 100644 index 000000000..0057da29a --- /dev/null +++ b/docs/content/zh/docs/guides/inject-context.md @@ -0,0 +1,66 @@ +--- +title: Inject Context +description: Utilize `injectContext` to enhances component composition in Reka UI, enabling powerful and flexible UI development. +--- + +# Inject Context + + + +Utilize `injectContext` to enhances component composition in Reka UI, enabling powerful and flexible UI development. + + + + + +Reka UI exposes internal `injectContext` to further extend the ability to compose and construct complex components. However, this API was primarily designed to be internal use. Thus the API might change without notice. + + + +## Introduction to `injectContext` + +In Reka UI, all root component, and some other component exports an `injectContext` function, which is a key feature for managing component state and enabling seamless composition. This guide will show you how to craft your own child component based on the provided context. + +## What is `injectContext`? + +`injectContext` is a function provided by each Reka UI component that allows you to access the internal state and methods of that component. + +It leverages Vue's [Provide / Inject](https://vuejs.org/guide/components/provide-inject) to provide a powerful way of extending and customizing component behavior. + +## Basic Usage + +Here's a simple example of how to use `injectContext` with a Reka UI Accordion component: + +```vue + + + + +``` + +## Common Use Cases + +1. **Custom Styling**: Access internal state to apply dynamic styles based on component state. +2. **Extended Functionality**: Build upon existing component logic to add new features. +3. **Complex Layouts**: Create intricate UI patterns by composing multiple components and sharing state between them. +4. **Accessibility Enhancements**: Utilize internal methods and state to improve keyboard navigation or screen reader support. + +## Best Practices + +1. Use `injectContext` in child components or composables, not in the component itself. +2. Always check if the injected context exists before using it, as it may be `undefined` if used outside the component's scope. +3. Prefer using provided props and events when possible, and use `injectContext` for more advanced scenarios. +4. When using TypeScript, leverage the type information provided by `injectContext` for better code quality. diff --git a/docs/content/zh/docs/guides/migration.md b/docs/content/zh/docs/guides/migration.md new file mode 100644 index 000000000..5c55ce712 --- /dev/null +++ b/docs/content/zh/docs/guides/migration.md @@ -0,0 +1,126 @@ +--- +title: Migration - Radix Vue to Reka UI +description: This guide provides step-by-step instructions for developers transitioning their projects from Radix Vue to Reka UI. +--- + +# Migration - Radix Vue to Reka UI + + +This guide provides step-by-step instructions for developers transitioning their projects from Radix Vue to Reka UI. + + +## Installation + +First and foremost, you need to install the latest `reka-ui`. + + + +Congratulation! 🎉 Now that you've installed the above package, let's perform the migration! The first 2 steps are relatively simple. Just do a global search and replace for the following changes. + +## Import Statement Changes + +The primary change in imports is replacing `radix-vue` with `reka-ui`. + +```vue + +``` + +## Naming Convention Changes + +CSS variable and data attributes names have been updated to use the `reka` prefix instead of `radix`. + +```css + --radix-accordion-content-width: 300px; /* [!code --] */ + --reka-accordion-content-width: 300px; /* [!code ++] */ + + [data-radix-collection-item] {} /* [!code --] */ + [data-reka-collection-item] {} /* [!code ++] */ +``` + +## Component Breaking Changes + +### Combobox + +- [Remove `filter-function` props](https://github.com/unovue/reka-ui/commit/ee8a3f2366a5c27c2bf1cc0a1ecbb0fea559a9f7) - `Combobox` has been refactored and improve to support better custom filtering. Read more. + + ```vue + + ``` + +- [Replace `searchTerm` props of Root to Input's `v-model`](https://github.com/unovue/reka-ui/commit/e1bab6598c3533dfbf6a86ad26b471ab826df069#diff-833593a5ce28a8c3fabc7d77462b116405e25df2b93bcab449798b5799e73474) +- [Move `displayValue` props from Root to Input](https://github.com/unovue/reka-ui/commit/e1bab6598c3533dfbf6a86ad26b471ab826df069#diff-833593a5ce28a8c3fabc7d77462b116405e25df2b93bcab449798b5799e73474) + + ```vue + + ``` + +### Arrow + +- [Improve arrow polygon](https://github.com/unovue/reka-ui/commit/ac8f3c34760f4c9c0f952ecd027b32951b9c416c) - Change the svg polygon to allow better styling. + +### Form component + +- [Rename controlled state to `v-model`](https://github.com/unovue/reka-ui/commit/87aa5ba6016fa7a98f02ea43062212906b2633a0) - Replace `v-model:checked`, `v-model:pressed` with more familiar API for form component. + + ```vue + + ``` + +- [Reposition `VisuallyHidden`](https://github.com/unovue/reka-ui/commit/107389a9c230d2c94232887b9cbe2710222564aa) - Previously `VisuallyHidden` were position at the root node, causing style scoped to not be applied. + +### Pagination + +- [Required `itemsPerPage` prop](https://github.com/unovue/reka-ui/commit/37bba0c26a3cbe7e7e3e4ac36770be3ef5224f0c) - Instead of default `itemsPerPage` value, now it is required as to provide a more explicit hint about the page size. + + ```vue + + ``` + +### Calendar + +- [Remove deprecated step prop](https://github.com/unovue/reka-ui/commit/ec146dd8fa0f95f64baf0b29c3424ee31cfb9666) - Use `prevPage/nextPage` props for greater control. + + ```vue + + + + ``` + +### Select + +- [`SelectValue` no longer render teleported element](https://github.com/unovue/reka-ui/commit/6a623484d610cc3b7c1a23a77c253c8e95cef518) - Previous implmenentation of `SelectValue` will render the selected `SelectItem` via teleporting fragment. This causes SSR flickering, and it is unnecessarily computation. + + ```vue + + ``` diff --git a/docs/content/zh/docs/guides/namespaced-components.md b/docs/content/zh/docs/guides/namespaced-components.md new file mode 100644 index 000000000..d3542a09f --- /dev/null +++ b/docs/content/zh/docs/guides/namespaced-components.md @@ -0,0 +1,38 @@ +# Namespaced components + +Reka UI design pattern is to create primitives for each component, and allow user to construct or [compose](./composition) components however they want. + +However, importing all the necessary components 1-by-1 can be quite an effort, and the user might sometimes accidentally leave out an important component. + +## How to use? + +First, you need to import the namespaced components via `reka-ui/namespaced` in your Vue component. + +```vue line=2 + +``` + +Then, you can use all the relevant components within the namespace. + +```vue line=6-17 + + + +``` diff --git a/docs/content/zh/docs/guides/server-side-rendering.md b/docs/content/zh/docs/guides/server-side-rendering.md new file mode 100644 index 000000000..96a67fe82 --- /dev/null +++ b/docs/content/zh/docs/guides/server-side-rendering.md @@ -0,0 +1,26 @@ +--- +title: Server side rendering +description: Reka UI can be rendered on the server. +--- + +# Server side rendering + + +Reka UI can be rendered on the server. + + +## Overview + +Server side rendering or `SSR`, is a technique used to render components to HTML on the server, as opposed to rendering them only on the client. + +Static rendering is another similar approach. Instead it pre-renders pages to HTML at build time rather than on each request. + +You should be able to use all of our primitives with both approaches, for example with [Nuxt.js](https://nuxt.com/). + +## Nuxt Hydration issue (Vue < 3.5) + +Reka UI offers a [Nuxt module](/docs/overview/installation.html#nuxt-modules) that supports auto importing components. However, if you are using Vue < 3.5, minor hydration issues might arise because as of vue <= 3.4 there is [currently no way](https://github.com/vuejs/rfcs/discussions/557) to ensure consistent DOM element `id` between the client and server renders. This is something that Reka UI relies on. + +As a temporary workaround, we expose a way to allow Nuxt (with version > `3.10`) inject it's `useId` implementation to `reka-ui`. + +To provide a custom `useId` implementation, please follow this [guide](/docs/utilities/config-provider.html#hydration-issue-vue-3-5). diff --git a/docs/content/zh/docs/guides/styling.md b/docs/content/zh/docs/guides/styling.md new file mode 100644 index 000000000..efcfd698a --- /dev/null +++ b/docs/content/zh/docs/guides/styling.md @@ -0,0 +1,169 @@ +--- + +title: Styling +description: Reka UI are unstyled—and compatible with any styling solution—giving you complete control over styling. +--- + +# Styling + + +Reka UI are unstyled and compatible with any styling solution giving you complete control over styling. + + +## Styling overview + +### Functional styles + +You are in control of all aspects of styling, including functional styles. For example, by default, a [Dialog Overlay](../components/dialog) won't cover the entire viewport. You're responsible for adding those styles, plus any presentation styles. + +### Classes + +All components accept `class` attributes, just like normal component. This class will be passed through to the DOM element. You can use it in CSS as expected. + +#### Teleported elements + +Some elements, such as modals or popovers, are teleported to the `body`. When using scoped style to apply CSS, you will need to use [deep selectors](https://vuejs.org/api/sfc-css-features.html#deep-selectors) to target them. + +### Data attributes + +When components are stateful, their state will be exposed in a `data-state` attribute. For example, when an [Accordion Item](../components/accordion) is opened, it includes a `data-state="open"` attribute. + +## Styling with CSS + +### Styling a part + +You can style a component part by targeting the `class` that you provide. + +```vue{7} + + + + + +``` + +### Styling a state + +You can style a component state by targeting its `data-state` attribute. + +```css +.AccordionItem { + border-bottom: 1px solid gainsboro; +} + +.AccordionItem[data-state="open"] { + border-bottom-width: 2px; +} +``` + +### Scoped style + +You can style a component using scoped style. Be wary of teleported elements, as they require the use of [deep selectors](https://vuejs.org/api/sfc-css-features.html#deep-selectors) to be targeted. + +```vue{7} + + + + + +``` + +## Styling with Tailwind CSS + +The examples below are using [Tailwind CSS](https://tailwindcss.com/), but you can use any library of your choice. + +### Styling a part + +You can style a component part by targeting the `class`. + +```vue{7} + + + +``` + +### Styling a state + +With Tailwind CSS's powerful variant selector, you can style a component state by targeting its `data-state` attribute. + +```vue{10} + + + +``` + +## Extending a primitive + +Extending a primitive is done the same way you extend any Vue component. + +```vue[CustomAccordion.vue] + + + +``` + +## Summary + +Reka UI were designed to encapsulate accessibility concerns and other complex functionalities, while ensuring you retain complete control over styling. + +For convenience, stateful components include a `data-state` attribute. diff --git a/docs/content/zh/docs/guides/virtualization.md b/docs/content/zh/docs/guides/virtualization.md new file mode 100644 index 000000000..32f23593f --- /dev/null +++ b/docs/content/zh/docs/guides/virtualization.md @@ -0,0 +1,100 @@ +--- +title: Virtualization +description: Learn how to efficiently render large datasets with Reka UI, powered by `@tanstack/virtual`. +--- + +# Virtualization + + + +Learn how to efficiently render large datasets with Reka UI, powered by `@tanstack/virtual`. + + + + + +Virtualization is a technique used to efficiently render large lists or tree structures by only rendering the items currently visible in the viewport. This approach significantly improves performance and reduces memory usage, especially when dealing with thousands of items. + + + +## Benefits of Using Virtualization + + + +## Customization Options + +All virtualizer ([Combobox](/docs/components/combobox#virtualizer), [Listbox](/docs/components/listbox#virtualizer), and [Tree](/docs/components/tree#virtualizer)) components offer the following props and customization: + +- Custom item rendering: Flexibility to render complex item structures +- `estimateSize`: Set estimate item heights for static or dynamic item +- `overscan`: Control the number of items rendered outside the visible area +- `textContent`: Text content for each item to achieve type-ahead feature + +## Usage + +Here's a few important note to make sure virtualization works! + +1. A fixed height/max-height wrapping ``. +2. Consistent item height, and set the `estimateSize` props appropriately. +3. Set `textContent` props to make sure type-ahead acceessibility. + +## Example + +```vue + + + +``` + +## Common issue + +### Virtualization is not working + +Do ensure that ``'s parent element has a defined height! + +```vue line=6 + +``` diff --git a/docs/content/zh/docs/overview/accessibility.md b/docs/content/zh/docs/overview/accessibility.md new file mode 100644 index 000000000..d3118ed74 --- /dev/null +++ b/docs/content/zh/docs/overview/accessibility.md @@ -0,0 +1,36 @@ +--- + +title: Accessibility +description: Reka UI follow the WAI-ARIA authoring practices guidelines and are tested in a wide selection of modern browsers and commonly used assistive technologies. +--- + +# Accessibility + +Reka UI follow the WAI-ARIA authoring practices guidelines and are +tested in a wide selection of modern browsers and commonly used assistive +technologies. + + +We take care of many of the difficult implementation details related to accessibility, including `aria` and `role` attributes, focus management, and keyboard navigation. That means that users should be able to use our components as-is in most contexts and rely on functionality to follow the expected accessibility design patterns. + +## WAI-ARIA + +[WAI-ARIA](https://www.w3.org/TR/wai-aria-1.2/), published and maintained by the W3C, specifies the semantics for many common UI patterns that show up in Reka UI. This is designed to provide meaning for controls that aren't built using elements provided by the browser. For example, if you use a `div` instead of a `button` element to create a button, there are attributes you need to add to the `div` in order to convey that it's a button for screen readers or voice recognition tools. + +In addition to semantics, there are behaviors that are expected from different types of components. A `button` element is going to respond to certain interactions in ways that a `div` will not, so it's up to the developer to reimplement those interactions with JavaScript. The [WAI-ARIA authoring practices](https://www.w3.org/TR/wai-aria-practices-1.2/) provide additional guidance for implementing behaviors for various controls that come with Reka UI. + +## Accessible Labels + +With many built-in form controls, the native HTML `label` element is designed to provide semantic meaning and context for corresponding `input` elements. For non-form control elements, or for custom controls like those provided by Reka UI, [WAI-ARIA provides a specification](https://www.w3.org/TR/wai-aria-1.2/#namecalculation) for how to provide accessible names and descriptions to those controls. + +Where possible, Reka UI include abstractions to make labelling our controls simple. The [`Label`](../components/label) primitive is designed to work with many of our controls. Ultimately it's up to you to provide those labels so that users have the proper context when navigating your application. + +## Keyboard Navigation + +Many complex components, like [`Tabs`](../components/tabs) and [`Dialog`](../components/dialog), come with expectations from users on how to interact with their content using a keyboard or other non-mouse input modalities. Reka UI provide basic keyboard support in accordance with the [WAI-ARIA authoring practices](https://www.w3.org/TR/wai-aria-practices-1.2/). + +## Focus Management + +Proper keyboard navigation and good labelling often go hand-in-hand with managing focus. When a user interacts with an element and something changes as a result, it's often helpful to move focus with the interaction so that the next tab stop is logical depending on the new context of the app. And for screen reader users, moving focus often results in an announcement to convey this new context, which relies on proper labelling. + +In many Reka UI, we move focus based on the interactions a user normally takes in a given component. For example, in [`AlertDialog`](../components/alert-dialog), when the modal is opened, focus is programmatically moved to a `Cancel` button element to anticipate a response to the prompt. diff --git a/docs/content/zh/docs/overview/getting-started.md b/docs/content/zh/docs/overview/getting-started.md new file mode 100644 index 000000000..03232f7f9 --- /dev/null +++ b/docs/content/zh/docs/overview/getting-started.md @@ -0,0 +1,106 @@ +--- + +title: Getting started +description: A quick tutorial to get you up and running with Reka UI. +name: popover +--- + +# Getting started + + +A quick tutorial to get you up and running with Reka UI. + + +## Implementing a Popover + +In this quick tutorial, we will install and style the [Popover](../components/popover) component. + +### 1. Install the library + +Install the component from your command line. + + + +### 2. Import the parts + +Import and structure the parts. + +```vue twoslash + + + + +``` + +### 3. Add your styles + +Add styles where desired. + +```vue + + + +``` + +### Demo + +Here's a complete demo. + + + +## Summary + +The steps above outline briefly what's involved in using a Reka UI in your application. + +These components are low-level enough to give you control over how you want to wrap them. You're free to introduce your own high-level API to better suit the needs of your team and product. + +In a few simple steps, we've implemented a fully accessible Popover component, without having to worry about many of its complexities. + +- Adheres to [WAI-ARIA](https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/) design pattern. +- Can be controlled or uncontrolled. +- Customize side, alignment, offsets, collision handling. +- Optionally render a pointing arrow. +- Focus is fully managed and customizable. +- Dismissing and layering behavior is highly customizable. diff --git a/docs/content/zh/docs/overview/installation.md b/docs/content/zh/docs/overview/installation.md new file mode 100644 index 000000000..7d4f0f20a --- /dev/null +++ b/docs/content/zh/docs/overview/installation.md @@ -0,0 +1,48 @@ +# Installation + +A quick tutorial to walk through installing the packages, as well as the supported plugins. + +## Installing the package + +
NPM Downloads + + + +## Nuxt modules + +Reka UI offers Nuxt modules support. + +In `nuxt.config.ts`, simply add `reka-ui/nuxt` into the modules, and it will auto-imports all the components for you. + +```ts +export default defineNuxtConfig({ + modules: ['reka-ui/nuxt'], +}) +``` + +## unplugin-vue-components + +Reka UI also has resolver for the popular [unplugin-vue-components](https://github.com/antfu/unplugin-vue-components). + +In `vite.config.ts`, import `reka-ui/resolver`, and configure as such and it will auto-imports all the components from Reka UI. + +```ts{2,10 } +import Components from 'unplugin-vue-components/vite' +import RekaResolver from 'reka-ui/resolver' + +export default defineConfig({ + plugins: [ + vue(), + Components({ + dts: true, + resolvers: [ + RekaResolver() + + // RekaResolver({ + // prefix: '' // use the prefix option to add Prefix to the imported components + // }) + ], + }), + ], +}) +``` diff --git a/docs/content/zh/docs/overview/introduction.md b/docs/content/zh/docs/overview/introduction.md new file mode 100644 index 000000000..b1acfef95 --- /dev/null +++ b/docs/content/zh/docs/overview/introduction.md @@ -0,0 +1,81 @@ +--- +title: Introduction +description: An open-source UI component library for building high-quality, accessible design systems and web apps using Vue. +--- + + + +# Introduction + + + +An open-source UI component library for building high-quality, accessible +design systems and web apps using Vue.js. + + + +## ✨ Rebrand: Reka UI ✨ + +Presenting **Reka UI**, the new identity of [Radix Vue](https://www.radix-vue.com/) in its v2 evolution. + +**Reka** (pronounced `/ree·kuh/`) means "design" in [Malay](https://translate.google.com/?hl=en&sl=ms&tl=en&text=reka&op=translate), and also evokes "Eureka." + +Reka UI strives to deliver a low-level UI component library centered on accessibility, customization, and developer experience. Use these components as the foundation of your design system or integrate them progressively. + +Check out the release note [here](/docs/overview/releases#_2-0-changes) + + + +Curious about the rebrand? See the announcement in [this discussion](https://github.com/unovue/radix-vue/issues/908). + + + +## Our Principles + +### Accessibility-First + +Accessibility is at the heart of Reka UI. Our components align with [WAI-ARIA design patterns](https://www.w3.org/TR/wai-aria-practices-1.2) to ensure that all users, regardless of abilities, can interact with your UI effectively. We handle intricate accessibility details like aria attributes, keyboard navigation, and focus management to simplify the developer's work. + +### Customizable & Unstyled + +Reka UI components come unstyled, providing developers the freedom to style them however they choose, using any CSS solution (vanilla CSS, preprocessors, or CSS-in-JS libraries). Our open component architecture allows you to wrap, extend, or modify each component as needed. Explore more in our [styling guide](../guides/styling). + +### Open & Modular + +Our components are designed to be open and adaptable, allowing you to customize each element to fit your needs. Whether adding event listeners, props, or refs, Reka UI provides granular access to each component's inner workings. + +### Flexible State Management + +Reka UI components are, by default, uncontrolled but can also be fully controlled when needed. This approach allows developers to decide on the level of state management required, offering a balance between flexibility and ease of use. + +### Developer-Centric Experience + +We prioritize developer experience by maintaining a consistent and predictable API. Reka UI is fully-typed and structured with simplicity in mind, ensuring that components are easy to use and integrate. Our `asChild` prop allows full control over rendered elements, enhancing flexibility. + +### Performance & Tree-Shaking + +Our library is designed with performance in mind. All components are compiled into a single package, making installation straightforward and ensuring that any unused components won’t add to your bundle size thanks to tree-shaking. + + + +Reka UI is inspired by the principles and goals of [Radix UI](https://www.radix-ui.com/), sharing a commitment to accessibility, customization, and developer-friendly design. + + + +--- + +# Built by Vue lovers 💚 + + + +# Credits + +All credits go to these open-source works and resources + +- Radix UI - https://radix-ui.com +- React Aria - https://react-spectrum.adobe.com/react-aria +- Floating UI - https://floating-ui.com +- VueUse - https://vueuse.org +- HeadlessUI - https://headlessui.com diff --git a/docs/content/zh/docs/overview/releases.md b/docs/content/zh/docs/overview/releases.md new file mode 100644 index 000000000..2a9925064 --- /dev/null +++ b/docs/content/zh/docs/overview/releases.md @@ -0,0 +1,83 @@ +--- +title: Releases +description: Discover the latest release of Reka UI. +--- + +# Releases + + +Discover the latest release of Reka UI. + + +[Latest releases on github](https://github.com/unovue/radix-vue/releases) + +--- + +## 2.0 Changes + +### ✨ New Features + +#### Components +- **TimeField**: Implement new TimeField component +- **Presence**: Expose component +- **ConfigProvider**: Add global config for locale + +#### Functionality +- **Checkbox**: + - Support multiple values and more types + - Add roving focus props to group +- **ToggleGroup**: Support more types +- **RadioGroup**: + - Support more types + - Emit 'select' event when user clicks on item +- **Select**: Support different modelValue and option types +- **Listbox/Combobox**: + - Expose highlight methods + - Highlight first item when filter changes +- **NavigationMenu**: + - Add additional CSS variables for better positioning + - Add SSR support +- **Collapsible/Accordion**: Add `unmount` prop to help SEO for hidden content + +#### Developer Experience +- **Types**: + - Expose useful types + - Allow type inference in usePrimitiveElement +- **Filtering**: New `useFilter` composable for easy filtering +- **Bundle**: Bundle with preserveModules, rollup types dts + +### 🔧 Refactors + +- **Form Components**: + - Move visually hidden input element inside root node +- **Combobox**: + - Use Listbox as base component + - Remove ComboboxEmpty +- **Popper**: + - Allow custom reference el or virtual el + - Add position strategy and updateOnLayoutShift props + - Rename props for better clarity + +### 🐛 Bug Fixes + +- **NavigationMenu**: Reset position after animation +- **Accordion**: Fix SSR animation causing flickers +- **Listbox**: Prevent scroll when using pointermove +- **Combobox**: + - Fix empty state based on search value + - Fix initial search not working and virtualizer issues +- **Select**: Fix arrow throwing content context injection error +- **VisuallyHidden**: Fix not focusable after native form validation + +### 🚨 Breaking Changes + +- **Form Components**: + - Rename controlled state to `v-model` +- **Popover**: Update aria attributes and remove messy attributes +- **Select**: + - Fix SSR support + - Refactor SelectValue rendering mechanism +- **Arrow**: Improve polygon implementation +- **Calendar**: Remove deprecated `step` prop + +We recommend reviewing the [migration guide](/docs/guides/migration) to make transitioning from v1 to v2 smooth. diff --git a/docs/content/zh/docs/utilities/config-provider.md b/docs/content/zh/docs/utilities/config-provider.md new file mode 100644 index 000000000..e0eec4654 --- /dev/null +++ b/docs/content/zh/docs/utilities/config-provider.md @@ -0,0 +1,86 @@ +--- +title: Config Provider +description: Wraps your app to provide global configurations. +--- + +# Config Provider + + +Wraps your app to provide global configurations. + + + + +## Anatomy + +Import the component. + +```vue + + + +``` + +## API Reference + +### Config Provider + +When creating localized apps that require right-to-left (RTL) reading direction, you need to wrap your application with the `ConfigProvider` component to ensure all of the primitives adjust their behavior based on the `dir` prop. + +You can also change the global behavior of `bodylock` for components such as `Alert`, `DropdownMenu` and etc to fit your layout to prevent any [content shifts](https://github.com/unovue/radix-vue/issues/385). + + + +## Example + +Use the config provider. + +Set global direction to `rtl`, and scroll body behavior to `false` (will not set any padding/margin). + +```vue + + + +``` + +## Hydration issue (Vue < 3.5) + +We expose a temporary workaround to allow current Nuxt (with version >3.10) project fix the current hydration issue by using [`useId`](https://nuxt.com/docs/api/composables/use-id) provided by Nuxt. + +> Inspired by [Headless UI](https://github.com/tailwindlabs/headlessui/pull/2959) + + ```vue + + + + +``` diff --git a/docs/content/zh/docs/utilities/focus-scope.md b/docs/content/zh/docs/utilities/focus-scope.md new file mode 100644 index 000000000..8a04e4f64 --- /dev/null +++ b/docs/content/zh/docs/utilities/focus-scope.md @@ -0,0 +1,78 @@ +--- +title: Focus Scope +description: Manages focus within a component boundary with support for trapping and looping focus navigation. +--- + +# Focus Scope + + + Manages focus within a component boundary with support for trapping and looping focus navigation. + + +Focus Scope provides enhanced control over keyboard focus management within component boundaries. It can trap focus within its container and optionally loop focus navigation, making it ideal for modal interfaces and other interactive components that need to manage focus states. + +## API Reference + + + +## Example + +Basic usage with focus trapping + +```vue line=2 + +``` + +### With Focus Looping + +Enable both trapping and looping for complete focus management: + +```vue line=2 + +``` + +### Handling Focus Event + +```vue line=2-5 + + + +``` + +
+ + + +When using trapped mode, ensure there is always at least one focusable element within the scope to prevent focus from being trapped in an inaccessible state. + + diff --git a/docs/content/zh/docs/utilities/presence.md b/docs/content/zh/docs/utilities/presence.md new file mode 100644 index 000000000..f3555f648 --- /dev/null +++ b/docs/content/zh/docs/utilities/presence.md @@ -0,0 +1,100 @@ +--- +title: Presence +description: Manages mounting and unmounting of element with transition support. +--- + +# Presence + + +Manages mounting and unmounting of element with transition support. + + + + +How is this component different from [Vue Transition](https://vuejs.org/guide/built-ins/transition.html#transition)? + +A: The biggest difference is it accepts css animation, and control the visibility of element. + + + +Presence component provides enhanced control over element mounting/unmounting. It ensures animations and transitions complete before removing elements from the DOM, making it perfect for animated UI components. + +## API Reference + + + + + + + +Read our [Animation Guide](/docs/guides/animation) to learn more about implementing animations with Presence component. + + + +## Example + +```vue line=2,4,5 + +``` + +### Force Mount + +When you need to ensure content is always rendered regardless of the present state: + +```vue + +``` diff --git a/docs/content/zh/docs/utilities/primitive.md b/docs/content/zh/docs/utilities/primitive.md new file mode 100644 index 000000000..4413b45ac --- /dev/null +++ b/docs/content/zh/docs/utilities/primitive.md @@ -0,0 +1,60 @@ +--- +title: Primitive +description: Compose Radix's functionality onto alternative element types or your own Vue components. +--- + +# Primitive + + +Compose Radix's functionality onto alternative element types or your own Vue components. + + +When you are building a component, in some cases you might want to allow user to compose some functionalities onto the underlying element, or alternative element. This is where `Primitive` comes in handy as it expose this capability to the user. + +## API Reference + + + +## Usage + +### Changing `as` value + +If you want to change the default element or component being render, you can set the default `as` when defining the props. + +```vue + + + +``` + +### Render `asChild` + +Change the default rendered element for the one passed as a child, merging their props and behavior.

Read our Composition guide for more details. diff --git a/docs/content/zh/docs/utilities/slot.md b/docs/content/zh/docs/utilities/slot.md new file mode 100644 index 000000000..7c77c4746 --- /dev/null +++ b/docs/content/zh/docs/utilities/slot.md @@ -0,0 +1,73 @@ +--- +title: Slot +description: Merges its props onto its immediate child. +--- + +# Slot + + +Merges its props onto its immediate child. + + + + +How is this component different from [Vue native slot](https://vuejs.org/guide/components/slots.html)? + +A: The biggest different is how it handles the `attributes` assigned to it. + + + +Native slot treat any binded value as [Scoped Slots](https://vuejs.org/guide/components/slots.html#scoped-slots), where the values will be exposed to the parent template and be consumed. + +But Reka UI's slot behave differently, it would merge all the assigned attributes onto it's immediate child. + +## Example + +Say we want to assign an `id` attribute to whatever component/element that was rendered, but Native slot will convert it into a scoped slot, and you will need to assign that id manually. + +```vue + + + + + +