@vestow/vue 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +233 -0
- package/index.ts +8 -0
- package/package.json +68 -0
- package/src/components/accordion/Accordion.vue +45 -0
- package/src/components/accordion/AccordionContent.vue +31 -0
- package/src/components/accordion/AccordionItem.vue +26 -0
- package/src/components/accordion/AccordionTrigger.vue +39 -0
- package/src/components/accordion/index.ts +18 -0
- package/src/components/alert/Alert.vue +17 -0
- package/src/components/alert/AlertDescription.vue +12 -0
- package/src/components/alert/AlertTitle.vue +12 -0
- package/src/components/alert/index.ts +5 -0
- package/src/components/avatar/Avatar.vue +32 -0
- package/src/components/avatar/AvatarFallback.vue +23 -0
- package/src/components/avatar/AvatarImage.vue +18 -0
- package/src/components/avatar/index.ts +3 -0
- package/src/components/badge/Badge.vue +25 -0
- package/src/components/badge/index.ts +3 -0
- package/src/components/breadcrumb/Breadcrumb.vue +14 -0
- package/src/components/breadcrumb/BreadcrumbItem.vue +12 -0
- package/src/components/breadcrumb/BreadcrumbLink.vue +19 -0
- package/src/components/breadcrumb/BreadcrumbPage.vue +12 -0
- package/src/components/breadcrumb/BreadcrumbSeparator.vue +15 -0
- package/src/components/breadcrumb/index.ts +5 -0
- package/src/components/button/Button.vue +55 -0
- package/src/components/button/index.ts +3 -0
- package/src/components/button-group/ButtonGroup.vue +29 -0
- package/src/components/button-group/ButtonGroupSeparator.vue +30 -0
- package/src/components/button-group/ButtonGroupText.vue +29 -0
- package/src/components/button-group/SplitButton.vue +103 -0
- package/src/components/button-group/SplitButtonItems.vue +50 -0
- package/src/components/button-group/index.ts +34 -0
- package/src/components/calendar/Calendar.vue +120 -0
- package/src/components/calendar/RangeCalendar.vue +127 -0
- package/src/components/calendar/index.ts +2 -0
- package/src/components/card/Card.vue +12 -0
- package/src/components/card/CardAction.vue +12 -0
- package/src/components/card/CardContent.vue +12 -0
- package/src/components/card/CardDescription.vue +12 -0
- package/src/components/card/CardFooter.vue +12 -0
- package/src/components/card/CardHeader.vue +15 -0
- package/src/components/card/CardTitle.vue +12 -0
- package/src/components/card/index.ts +7 -0
- package/src/components/carousel/Carousel.vue +164 -0
- package/src/components/carousel/CarouselContent.vue +43 -0
- package/src/components/carousel/CarouselDots.vue +42 -0
- package/src/components/carousel/CarouselItem.vue +58 -0
- package/src/components/carousel/CarouselNext.vue +45 -0
- package/src/components/carousel/CarouselPrevious.vue +45 -0
- package/src/components/carousel/index.ts +44 -0
- package/src/components/cascade-select/CascadeSelect.vue +314 -0
- package/src/components/cascade-select/index.ts +11 -0
- package/src/components/chart/AreaChart.vue +201 -0
- package/src/components/chart/BarChart.vue +389 -0
- package/src/components/chart/ChartContainer.vue +127 -0
- package/src/components/chart/ChartCrosshair.vue +92 -0
- package/src/components/chart/ChartLegend.vue +63 -0
- package/src/components/chart/ChartTooltipCard.vue +49 -0
- package/src/components/chart/LineChart.vue +214 -0
- package/src/components/chart/PieChart.vue +280 -0
- package/src/components/chart/RadarChart.vue +291 -0
- package/src/components/chart/RadialChart.vue +354 -0
- package/src/components/chart/index.ts +30 -0
- package/src/components/chart/polar.ts +5 -0
- package/src/components/chart/tooltip.ts +5 -0
- package/src/components/chart/types.ts +52 -0
- package/src/components/chart/useChartSeries.ts +138 -0
- package/src/components/chart/xy-label.ts +5 -0
- package/src/components/checkbox/Checkbox.vue +81 -0
- package/src/components/checkbox/CheckboxField.vue +129 -0
- package/src/components/checkbox/CheckboxGroup.vue +62 -0
- package/src/components/checkbox/index.ts +21 -0
- package/src/components/chip/Chip.vue +73 -0
- package/src/components/chip/index.ts +3 -0
- package/src/components/code-block/CodeBlock.vue +100 -0
- package/src/components/code-block/index.ts +4 -0
- package/src/components/collapsible/Collapsible.vue +15 -0
- package/src/components/collapsible/CollapsibleContent.vue +26 -0
- package/src/components/collapsible/CollapsibleTrigger.vue +12 -0
- package/src/components/collapsible/index.ts +3 -0
- package/src/components/combobox/Combobox.vue +23 -0
- package/src/components/combobox/ComboboxAnchor.vue +20 -0
- package/src/components/combobox/ComboboxEmpty.vue +21 -0
- package/src/components/combobox/ComboboxGroup.vue +23 -0
- package/src/components/combobox/ComboboxInput.vue +32 -0
- package/src/components/combobox/ComboboxItem.vue +38 -0
- package/src/components/combobox/ComboboxList.vue +43 -0
- package/src/components/combobox/ComboboxSeparator.vue +18 -0
- package/src/components/combobox/ComboboxTrigger.vue +12 -0
- package/src/components/combobox/index.ts +9 -0
- package/src/components/command/Command.vue +54 -0
- package/src/components/command/CommandDialog.vue +41 -0
- package/src/components/command/CommandEmpty.vue +19 -0
- package/src/components/command/CommandGroup.vue +28 -0
- package/src/components/command/CommandInput.vue +25 -0
- package/src/components/command/CommandItem.vue +40 -0
- package/src/components/command/CommandList.vue +13 -0
- package/src/components/command/CommandSeparator.vue +11 -0
- package/src/components/command/CommandShortcut.vue +13 -0
- package/src/components/command/index.ts +34 -0
- package/src/components/command-block/CommandBlock.vue +90 -0
- package/src/components/command-block/index.ts +2 -0
- package/src/components/confirm-dialog/ConfirmDialog.vue +37 -0
- package/src/components/confirm-dialog/index.ts +1 -0
- package/src/components/confirm-popup/ConfirmPopup.vue +123 -0
- package/src/components/confirm-popup/index.ts +1 -0
- package/src/components/context-menu/ContextMenu.vue +15 -0
- package/src/components/context-menu/ContextMenuCheckboxItem.vue +30 -0
- package/src/components/context-menu/ContextMenuContent.vue +36 -0
- package/src/components/context-menu/ContextMenuGroup.vue +12 -0
- package/src/components/context-menu/ContextMenuItem.vue +32 -0
- package/src/components/context-menu/ContextMenuLabel.vue +21 -0
- package/src/components/context-menu/ContextMenuRadioGroup.vue +15 -0
- package/src/components/context-menu/ContextMenuRadioItem.vue +30 -0
- package/src/components/context-menu/ContextMenuSeparator.vue +19 -0
- package/src/components/context-menu/ContextMenuShortcut.vue +13 -0
- package/src/components/context-menu/ContextMenuSub.vue +15 -0
- package/src/components/context-menu/ContextMenuSubContent.vue +26 -0
- package/src/components/context-menu/ContextMenuSubTrigger.vue +26 -0
- package/src/components/context-menu/ContextMenuTrigger.vue +12 -0
- package/src/components/context-menu/index.ts +14 -0
- package/src/components/data-table/DataTable.vue +458 -0
- package/src/components/data-table/DataTableFacetedFilter.vue +97 -0
- package/src/components/data-table/DataTablePagination.vue +103 -0
- package/src/components/data-table/DataTableViewOptions.vue +69 -0
- package/src/components/data-table/features.ts +87 -0
- package/src/components/data-table/index.ts +27 -0
- package/src/components/data-table/pagination-adapter.ts +67 -0
- package/src/components/data-table/selection-column.ts +48 -0
- package/src/components/data-table/types.ts +36 -0
- package/src/components/data-view/DataView.vue +136 -0
- package/src/components/data-view/index.ts +1 -0
- package/src/components/date-picker/DatePicker.vue +117 -0
- package/src/components/date-picker/DateRangePicker.vue +122 -0
- package/src/components/date-picker/index.ts +2 -0
- package/src/components/deferred/Deferred.vue +80 -0
- package/src/components/deferred/index.ts +1 -0
- package/src/components/dialog/Dialog.vue +15 -0
- package/src/components/dialog/DialogClose.vue +12 -0
- package/src/components/dialog/DialogContent.vue +46 -0
- package/src/components/dialog/DialogDescription.vue +19 -0
- package/src/components/dialog/DialogFooter.vue +12 -0
- package/src/components/dialog/DialogHeader.vue +12 -0
- package/src/components/dialog/DialogTitle.vue +19 -0
- package/src/components/dialog/DialogTrigger.vue +12 -0
- package/src/components/dialog/index.ts +10 -0
- package/src/components/doc-example/DocExample.vue +41 -0
- package/src/components/doc-example/index.ts +1 -0
- package/src/components/doc-text/DocText.vue +64 -0
- package/src/components/doc-text/index.ts +1 -0
- package/src/components/dropdown-menu/DropdownMenu.vue +15 -0
- package/src/components/dropdown-menu/DropdownMenuCheckboxItem.vue +33 -0
- package/src/components/dropdown-menu/DropdownMenuContent.vue +36 -0
- package/src/components/dropdown-menu/DropdownMenuGroup.vue +12 -0
- package/src/components/dropdown-menu/DropdownMenuItem.vue +32 -0
- package/src/components/dropdown-menu/DropdownMenuLabel.vue +24 -0
- package/src/components/dropdown-menu/DropdownMenuRadioGroup.vue +15 -0
- package/src/components/dropdown-menu/DropdownMenuRadioItem.vue +33 -0
- package/src/components/dropdown-menu/DropdownMenuSeparator.vue +19 -0
- package/src/components/dropdown-menu/DropdownMenuShortcut.vue +13 -0
- package/src/components/dropdown-menu/DropdownMenuSub.vue +15 -0
- package/src/components/dropdown-menu/DropdownMenuSubContent.vue +29 -0
- package/src/components/dropdown-menu/DropdownMenuSubTrigger.vue +26 -0
- package/src/components/dropdown-menu/DropdownMenuTrigger.vue +12 -0
- package/src/components/dropdown-menu/index.ts +14 -0
- package/src/components/editable/Editable.vue +41 -0
- package/src/components/editable/EditableArea.vue +22 -0
- package/src/components/editable/EditableCancelTrigger.vue +40 -0
- package/src/components/editable/EditableEditTrigger.vue +40 -0
- package/src/components/editable/EditableInput.vue +28 -0
- package/src/components/editable/EditablePreview.vue +34 -0
- package/src/components/editable/EditableSubmitTrigger.vue +40 -0
- package/src/components/editable/index.ts +17 -0
- package/src/components/empty/Empty.vue +17 -0
- package/src/components/empty/EmptyActions.vue +14 -0
- package/src/components/empty/EmptyDescription.vue +12 -0
- package/src/components/empty/EmptyMedia.vue +16 -0
- package/src/components/empty/EmptyTitle.vue +17 -0
- package/src/components/empty/index.ts +7 -0
- package/src/components/field/Field.vue +22 -0
- package/src/components/field/FieldDescription.vue +20 -0
- package/src/components/field/FieldGroup.vue +22 -0
- package/src/components/field/FieldLabel.vue +27 -0
- package/src/components/field/FieldSeparator.vue +28 -0
- package/src/components/field/index.ts +7 -0
- package/src/components/fieldset/Fieldset.vue +126 -0
- package/src/components/fieldset/index.ts +1 -0
- package/src/components/file-upload/FileUpload.vue +149 -0
- package/src/components/file-upload/index.ts +8 -0
- package/src/components/float-label/FloatLabel.vue +26 -0
- package/src/components/float-label/index.ts +3 -0
- package/src/components/form/Form.vue +126 -0
- package/src/components/form/FormDescription.vue +12 -0
- package/src/components/form/FormField.vue +127 -0
- package/src/components/form/FormItem.vue +12 -0
- package/src/components/form/FormLabel.vue +14 -0
- package/src/components/form/FormMessage.vue +31 -0
- package/src/components/form/context.ts +54 -0
- package/src/components/form/errors.ts +6 -0
- package/src/components/form/index.ts +7 -0
- package/src/components/form/types.ts +55 -0
- package/src/components/hover-card/HoverCard.vue +27 -0
- package/src/components/hover-card/HoverCardContent.vue +36 -0
- package/src/components/hover-card/HoverCardTrigger.vue +12 -0
- package/src/components/hover-card/index.ts +3 -0
- package/src/components/ifta-label/IftaLabel.vue +26 -0
- package/src/components/ifta-label/index.ts +1 -0
- package/src/components/index.ts +89 -0
- package/src/components/input/Input.vue +87 -0
- package/src/components/input/index.ts +1 -0
- package/src/components/input-color/ColorArea.vue +36 -0
- package/src/components/input-color/ColorField.vue +32 -0
- package/src/components/input-color/ColorSlider.vue +31 -0
- package/src/components/input-color/InputColor.vue +65 -0
- package/src/components/input-color/index.ts +16 -0
- package/src/components/input-group/InputGroup.vue +26 -0
- package/src/components/input-group/InputGroupAddon.vue +32 -0
- package/src/components/input-group/InputGroupInput.vue +33 -0
- package/src/components/input-group/index.ts +17 -0
- package/src/components/input-number/InputNumber.vue +82 -0
- package/src/components/input-number/index.ts +1 -0
- package/src/components/input-otp/InputOtp.vue +186 -0
- package/src/components/input-otp/index.ts +1 -0
- package/src/components/input-password/InputPassword.vue +116 -0
- package/src/components/input-password/index.ts +5 -0
- package/src/components/input-tags/InputTags.vue +38 -0
- package/src/components/input-tags/InputTagsClear.vue +39 -0
- package/src/components/input-tags/InputTagsInput.vue +27 -0
- package/src/components/input-tags/InputTagsItem.vue +40 -0
- package/src/components/input-tags/InputTagsItemDelete.vue +32 -0
- package/src/components/input-tags/InputTagsItemText.vue +18 -0
- package/src/components/input-tags/index.ts +16 -0
- package/src/components/kbd/Kbd.vue +17 -0
- package/src/components/kbd/KbdGroup.vue +15 -0
- package/src/components/kbd/index.ts +4 -0
- package/src/components/label/Label.vue +23 -0
- package/src/components/label/index.ts +1 -0
- package/src/components/listbox/Listbox.vue +42 -0
- package/src/components/listbox/ListboxContent.vue +22 -0
- package/src/components/listbox/ListboxFilter.vue +34 -0
- package/src/components/listbox/ListboxGroup.vue +31 -0
- package/src/components/listbox/ListboxItem.vue +46 -0
- package/src/components/listbox/index.ts +19 -0
- package/src/components/mask/Mask.vue +205 -0
- package/src/components/mask/index.ts +15 -0
- package/src/components/menubar/Menubar.vue +26 -0
- package/src/components/menubar/MenubarCheckboxItem.vue +30 -0
- package/src/components/menubar/MenubarContent.vue +52 -0
- package/src/components/menubar/MenubarGroup.vue +12 -0
- package/src/components/menubar/MenubarItem.vue +32 -0
- package/src/components/menubar/MenubarLabel.vue +21 -0
- package/src/components/menubar/MenubarMenu.vue +12 -0
- package/src/components/menubar/MenubarRadioGroup.vue +15 -0
- package/src/components/menubar/MenubarRadioItem.vue +30 -0
- package/src/components/menubar/MenubarSeparator.vue +12 -0
- package/src/components/menubar/MenubarShortcut.vue +13 -0
- package/src/components/menubar/MenubarSub.vue +15 -0
- package/src/components/menubar/MenubarSubContent.vue +26 -0
- package/src/components/menubar/MenubarSubTrigger.vue +26 -0
- package/src/components/menubar/MenubarTrigger.vue +30 -0
- package/src/components/menubar/index.ts +29 -0
- package/src/components/navigation-menu/NavigationMenu.vue +43 -0
- package/src/components/navigation-menu/NavigationMenuContent.vue +63 -0
- package/src/components/navigation-menu/NavigationMenuIndicator.vue +31 -0
- package/src/components/navigation-menu/NavigationMenuItem.vue +20 -0
- package/src/components/navigation-menu/NavigationMenuLink.vue +34 -0
- package/src/components/navigation-menu/NavigationMenuList.vue +23 -0
- package/src/components/navigation-menu/NavigationMenuTrigger.vue +38 -0
- package/src/components/navigation-menu/NavigationMenuViewport.vue +34 -0
- package/src/components/navigation-menu/index.ts +18 -0
- package/src/components/order-list/OrderList.vue +168 -0
- package/src/components/order-list/SelectableList.vue +200 -0
- package/src/components/order-list/index.ts +1 -0
- package/src/components/pagination/Pagination.vue +133 -0
- package/src/components/pagination/index.ts +1 -0
- package/src/components/panel/Panel.vue +69 -0
- package/src/components/panel/index.ts +1 -0
- package/src/components/pick-list/PickList.vue +211 -0
- package/src/components/pick-list/index.ts +1 -0
- package/src/components/popover/Popover.vue +15 -0
- package/src/components/popover/PopoverAnchor.vue +12 -0
- package/src/components/popover/PopoverContent.vue +39 -0
- package/src/components/popover/PopoverTrigger.vue +12 -0
- package/src/components/popover/index.ts +4 -0
- package/src/components/progress/Progress.vue +39 -0
- package/src/components/progress/index.ts +1 -0
- package/src/components/props-table/PropsTable.vue +62 -0
- package/src/components/props-table/index.ts +2 -0
- package/src/components/radio-group/RadioGroup.vue +52 -0
- package/src/components/radio-group/RadioGroupItem.vue +80 -0
- package/src/components/radio-group/RadioGroupItemField.vue +128 -0
- package/src/components/radio-group/index.ts +21 -0
- package/src/components/rating/Rating.vue +70 -0
- package/src/components/rating/RatingItem.vue +26 -0
- package/src/components/rating/RatingItemIndicator.vue +28 -0
- package/src/components/rating/RatingStar.vue +16 -0
- package/src/components/rating/index.ts +13 -0
- package/src/components/scroll-area/ScrollArea.vue +52 -0
- package/src/components/scroll-area/index.ts +1 -0
- package/src/components/search-input/SearchInput.vue +46 -0
- package/src/components/search-input/index.ts +1 -0
- package/src/components/select/Select.vue +15 -0
- package/src/components/select/SelectContent.vue +67 -0
- package/src/components/select/SelectGroup.vue +20 -0
- package/src/components/select/SelectItem.vue +59 -0
- package/src/components/select/SelectLabel.vue +20 -0
- package/src/components/select/SelectSeparator.vue +18 -0
- package/src/components/select/SelectTrigger.vue +101 -0
- package/src/components/select/SelectValue.vue +46 -0
- package/src/components/select/index.ts +8 -0
- package/src/components/separator/Separator.vue +25 -0
- package/src/components/separator/index.ts +1 -0
- package/src/components/sheet/Sheet.vue +15 -0
- package/src/components/sheet/SheetClose.vue +12 -0
- package/src/components/sheet/SheetContent.vue +45 -0
- package/src/components/sheet/SheetDescription.vue +19 -0
- package/src/components/sheet/SheetFooter.vue +12 -0
- package/src/components/sheet/SheetHeader.vue +12 -0
- package/src/components/sheet/SheetTitle.vue +19 -0
- package/src/components/sheet/SheetTrigger.vue +12 -0
- package/src/components/sheet/index.ts +10 -0
- package/src/components/sidebar/Sidebar.vue +108 -0
- package/src/components/sidebar/SidebarContent.vue +19 -0
- package/src/components/sidebar/SidebarFooter.vue +19 -0
- package/src/components/sidebar/SidebarGroup.vue +19 -0
- package/src/components/sidebar/SidebarGroupAction.vue +28 -0
- package/src/components/sidebar/SidebarGroupContent.vue +19 -0
- package/src/components/sidebar/SidebarGroupLabel.vue +25 -0
- package/src/components/sidebar/SidebarHeader.vue +19 -0
- package/src/components/sidebar/SidebarInput.vue +15 -0
- package/src/components/sidebar/SidebarInset.vue +22 -0
- package/src/components/sidebar/SidebarMenu.vue +19 -0
- package/src/components/sidebar/SidebarMenuAction.vue +41 -0
- package/src/components/sidebar/SidebarMenuBadge.vue +24 -0
- package/src/components/sidebar/SidebarMenuButton.vue +94 -0
- package/src/components/sidebar/SidebarMenuItem.vue +19 -0
- package/src/components/sidebar/SidebarMenuSkeleton.vue +36 -0
- package/src/components/sidebar/SidebarMenuSub.vue +22 -0
- package/src/components/sidebar/SidebarMenuSubButton.vue +39 -0
- package/src/components/sidebar/SidebarMenuSubItem.vue +19 -0
- package/src/components/sidebar/SidebarProvider.vue +114 -0
- package/src/components/sidebar/SidebarRail.vue +37 -0
- package/src/components/sidebar/SidebarSeparator.vue +15 -0
- package/src/components/sidebar/SidebarTrigger.vue +27 -0
- package/src/components/sidebar/context.ts +39 -0
- package/src/components/sidebar/index.ts +34 -0
- package/src/components/skeleton/Skeleton.vue +10 -0
- package/src/components/skeleton/index.ts +1 -0
- package/src/components/skip-link/SkipLink.vue +45 -0
- package/src/components/skip-link/index.ts +1 -0
- package/src/components/slider/Slider.vue +57 -0
- package/src/components/slider/index.ts +3 -0
- package/src/components/speed-dial/SpeedDial.vue +362 -0
- package/src/components/speed-dial/index.ts +28 -0
- package/src/components/spinner/Spinner.vue +20 -0
- package/src/components/spinner/index.ts +1 -0
- package/src/components/splitter/Splitter.vue +24 -0
- package/src/components/splitter/SplitterHandle.vue +51 -0
- package/src/components/splitter/SplitterPanel.vue +30 -0
- package/src/components/splitter/index.ts +14 -0
- package/src/components/stepper/Stepper.vue +34 -0
- package/src/components/stepper/StepperItem.vue +113 -0
- package/src/components/stepper/index.ts +2 -0
- package/src/components/switch/Switch.vue +35 -0
- package/src/components/switch/index.ts +1 -0
- package/src/components/table/Table.vue +24 -0
- package/src/components/table/TableBody.vue +12 -0
- package/src/components/table/TableCell.vue +12 -0
- package/src/components/table/TableEmpty.vue +20 -0
- package/src/components/table/TableHead.vue +17 -0
- package/src/components/table/TableHeader.vue +12 -0
- package/src/components/table/TableRow.vue +19 -0
- package/src/components/table/index.ts +7 -0
- package/src/components/tabs/Tabs.vue +23 -0
- package/src/components/tabs/TabsContent.vue +23 -0
- package/src/components/tabs/TabsList.vue +26 -0
- package/src/components/tabs/TabsTrigger.vue +30 -0
- package/src/components/tabs/index.ts +4 -0
- package/src/components/textarea/Textarea.vue +25 -0
- package/src/components/textarea/index.ts +1 -0
- package/src/components/theme-controls/LocaleMenu.vue +95 -0
- package/src/components/theme-controls/PaletteMenu.vue +155 -0
- package/src/components/theme-controls/ThemeToggle.vue +21 -0
- package/src/components/theme-controls/index.ts +15 -0
- package/src/components/timeline/Timeline.vue +20 -0
- package/src/components/timeline/TimelineItem.vue +68 -0
- package/src/components/timeline/index.ts +15 -0
- package/src/components/toast/Toaster.vue +62 -0
- package/src/components/toast/index.ts +4 -0
- package/src/components/toast/toast.ts +57 -0
- package/src/components/toggle/Toggle.vue +32 -0
- package/src/components/toggle/ToggleGroup.vue +56 -0
- package/src/components/toggle/ToggleGroupItem.vue +33 -0
- package/src/components/toggle/index.ts +18 -0
- package/src/components/token-table/TokenTable.vue +67 -0
- package/src/components/token-table/index.ts +2 -0
- package/src/components/toolbar/Toolbar.vue +34 -0
- package/src/components/toolbar/ToolbarButton.vue +33 -0
- package/src/components/toolbar/ToolbarSeparator.vue +21 -0
- package/src/components/toolbar/index.ts +3 -0
- package/src/components/tooltip/Tooltip.vue +15 -0
- package/src/components/tooltip/TooltipContent.vue +38 -0
- package/src/components/tooltip/TooltipProvider.vue +16 -0
- package/src/components/tooltip/TooltipTrigger.vue +12 -0
- package/src/components/tooltip/index.ts +4 -0
- package/src/components/tree/Tree.vue +53 -0
- package/src/components/tree/TreeItem.vue +59 -0
- package/src/components/tree/index.ts +21 -0
- package/src/components/tree-select/TreeSelect.vue +141 -0
- package/src/components/tree-select/index.ts +1 -0
- package/src/components/tree-table/TreeTable.vue +302 -0
- package/src/components/tree-table/features.ts +49 -0
- package/src/components/tree-table/index.ts +3 -0
- package/src/components/video-player/VideoPlayer.vue +472 -0
- package/src/components/video-player/index.ts +20 -0
- package/src/composables/index.ts +15 -0
- package/src/composables/useBase.ts +32 -0
- package/src/composables/useChartPalette.ts +33 -0
- package/src/composables/useColorMode.ts +29 -0
- package/src/composables/useConfirm.ts +81 -0
- package/src/composables/useDelayedFlag.ts +62 -0
- package/src/composables/useI18n.ts +107 -0
- package/src/composables/useIsMobile.ts +34 -0
- package/src/composables/useMenuAccent.ts +32 -0
- package/src/composables/useMenuAppearance.ts +31 -0
- package/src/composables/useMenuColor.ts +31 -0
- package/src/composables/usePalette.ts +30 -0
- package/src/composables/useStyle.ts +35 -0
- package/src/composables/useSurface.ts +30 -0
- package/src/composables/useTableQuery.ts +73 -0
- package/src/composables/useThemeController.ts +48 -0
- package/src/i18n/README.md +68 -0
- package/src/i18n/controller.ts +233 -0
- package/src/i18n/dictionary.ts +43 -0
- package/src/i18n/index.ts +34 -0
- package/src/i18n/registry.ts +64 -0
- package/src/i18n/ui/en/ui.json +114 -0
- package/src/i18n/ui/en/zod.json +16 -0
- package/src/i18n/ui/index.ts +48 -0
- package/src/i18n/ui/vi/ui.json +114 -0
- package/src/i18n/ui/vi/zod.json +16 -0
- package/src/lib/date.ts +24 -0
- package/src/lib/focus.ts +12 -0
- package/src/lib/icons.ts +345 -0
- package/src/lib/menu-styles.ts +16 -0
- package/src/lib/menu.ts +20 -0
- package/src/lib/platform.ts +5 -0
- package/src/lib/types.ts +6 -0
- package/src/lib/utils.ts +9 -0
- package/src/lib/zod-messages.ts +127 -0
- package/src/styles/chart.css +30 -0
- package/src/styles/index.css +18 -0
- package/src/variants/README.md +55 -0
- package/src/variants/components/accordion.ts +71 -0
- package/src/variants/components/alert.ts +20 -0
- package/src/variants/components/badge.ts +76 -0
- package/src/variants/components/button-group.ts +136 -0
- package/src/variants/components/button.ts +160 -0
- package/src/variants/components/checkbox.ts +67 -0
- package/src/variants/components/chip.ts +51 -0
- package/src/variants/components/code-block.ts +22 -0
- package/src/variants/components/dialog.ts +28 -0
- package/src/variants/components/empty.ts +60 -0
- package/src/variants/components/field.ts +35 -0
- package/src/variants/components/float-label.ts +95 -0
- package/src/variants/components/input-group.ts +73 -0
- package/src/variants/components/input-password.ts +68 -0
- package/src/variants/components/kbd.ts +47 -0
- package/src/variants/components/picker-trigger.ts +30 -0
- package/src/variants/components/radio-group.ts +63 -0
- package/src/variants/components/sheet.ts +23 -0
- package/src/variants/components/sidebar.ts +33 -0
- package/src/variants/components/slider.ts +49 -0
- package/src/variants/components/timeline.ts +45 -0
- package/src/variants/components/toggle.ts +58 -0
- package/src/variants/index.ts +35 -0
- package/src/variants/lib/chart/polar.ts +139 -0
- package/src/variants/lib/chart/tooltip.ts +101 -0
- package/src/variants/lib/chart/types.ts +172 -0
- package/src/variants/lib/chart/xy-label.ts +42 -0
- package/src/variants/lib/focus.ts +66 -0
- package/src/variants/lib/form-errors.ts +59 -0
- package/src/variants/lib/highlight.ts +548 -0
- package/src/variants/lib/list-move.ts +63 -0
- package/src/variants/lib/mask.ts +106 -0
- package/src/variants/lib/media.ts +56 -0
- package/src/variants/lib/menu-styles.ts +71 -0
- package/src/variants/lib/platform.ts +68 -0
- package/src/variants/lib/tree.ts +119 -0
- package/src/variants/lib/upload.ts +58 -0
- package/src/variants/lib/utils.ts +11 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ComputedRef } from 'vue'
|
|
2
|
+
import type { RadioGroupItemVariants } from '../../variants/components/radio-group'
|
|
3
|
+
import { createContext } from 'reka-ui'
|
|
4
|
+
|
|
5
|
+
export { radioGroupItemVariants, type RadioGroupItemVariants } from '../../variants/components/radio-group'
|
|
6
|
+
export { default as RadioGroup } from './RadioGroup.vue'
|
|
7
|
+
export { default as RadioGroupItem } from './RadioGroupItem.vue'
|
|
8
|
+
|
|
9
|
+
/** Cỡ/kiểu tô/trạng thái lỗi mà `RadioGroup` truyền xuống từng nút con. */
|
|
10
|
+
export interface RadioGroupContext {
|
|
11
|
+
size: ComputedRef<RadioGroupItemVariants['size']>
|
|
12
|
+
tone: ComputedRef<RadioGroupItemVariants['tone']>
|
|
13
|
+
invalid: ComputedRef<boolean>
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Dùng createContext của reka thay vì tự khai InjectionKey: cùng một cơ chế với
|
|
17
|
+
// mọi context khác đang chạy trong cây component, và báo lỗi kèm tên component.
|
|
18
|
+
export const [injectRadioGroupContext, provideRadioGroupContext]
|
|
19
|
+
= createContext<RadioGroupContext>('RadioGroup')
|
|
20
|
+
|
|
21
|
+
export { default as RadioGroupItemField } from './RadioGroupItemField.vue'
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { RatingRootEmits, RatingRootProps } from 'reka-ui'
|
|
3
|
+
import type { CSSProperties } from 'vue'
|
|
4
|
+
import type { ClassProps } from '../../lib/types'
|
|
5
|
+
import { RatingItem, RatingItemIndicator, RatingRoot, useForwardPropsEmits } from 'reka-ui'
|
|
6
|
+
import { computed } from 'vue'
|
|
7
|
+
import { cn } from '../../lib/utils'
|
|
8
|
+
import RatingStar from './RatingStar.vue'
|
|
9
|
+
|
|
10
|
+
const props = withDefaults(
|
|
11
|
+
defineProps<RatingRootProps & ClassProps & {
|
|
12
|
+
/** Cỡ một ngôi sao. Đặt thành biến CSS để lớp rỗng và lớp đầy khớp nhau. */
|
|
13
|
+
size?: 'sm' | 'default' | 'lg'
|
|
14
|
+
}>(),
|
|
15
|
+
{ length: 5, hoverable: true, size: 'default' },
|
|
16
|
+
)
|
|
17
|
+
const emits = defineEmits<RatingRootEmits>()
|
|
18
|
+
|
|
19
|
+
const delegated = computed(() => {
|
|
20
|
+
const { class: _class, size: _size, ...rest } = props
|
|
21
|
+
return rest
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
const forwarded = useForwardPropsEmits(delegated, emits)
|
|
25
|
+
|
|
26
|
+
const sizes = { sm: '1rem', default: '1.25rem', lg: '1.5rem' }
|
|
27
|
+
const style = computed<CSSProperties>(() => ({ '--rating-item-size': sizes[props.size] } as CSSProperties))
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<template>
|
|
31
|
+
<!--
|
|
32
|
+
Slot mặc định dựng sẵn cả hàng sao, nên `<Rating v-model="score" />` chạy
|
|
33
|
+
được ngay. Truyền nội dung vào là thay hẳn — dùng khi cần icon khác hoặc
|
|
34
|
+
bố cục khác, và khi đó `RatingItem` / `RatingItemIndicator` vẫn export sẵn.
|
|
35
|
+
-->
|
|
36
|
+
<RatingRoot
|
|
37
|
+
v-bind="forwarded"
|
|
38
|
+
:style="style"
|
|
39
|
+
:class="cn(
|
|
40
|
+
'inline-flex items-center gap-0.5',
|
|
41
|
+
'data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
|
42
|
+
props.class,
|
|
43
|
+
)"
|
|
44
|
+
>
|
|
45
|
+
<slot>
|
|
46
|
+
<RatingItem
|
|
47
|
+
v-for="item in props.length"
|
|
48
|
+
v-slot="{ steps }"
|
|
49
|
+
:key="item"
|
|
50
|
+
:item="item"
|
|
51
|
+
class="relative block size-(--rating-item-size) cursor-pointer"
|
|
52
|
+
>
|
|
53
|
+
<RatingStar class="absolute inset-0 text-muted-foreground/35" />
|
|
54
|
+
<!--
|
|
55
|
+
Mỗi bước là một lớp phủ bị cắt theo `--reka-rating-item-step-width`
|
|
56
|
+
mà reka đặt inline. Ngôi sao bên trong giữ nguyên cỡ đầy đủ, nên nửa
|
|
57
|
+
sao là một ngôi sao bị xén chứ không phải một ngôi sao bị bóp.
|
|
58
|
+
-->
|
|
59
|
+
<RatingItemIndicator
|
|
60
|
+
v-for="step in steps"
|
|
61
|
+
:key="step"
|
|
62
|
+
:step="step"
|
|
63
|
+
class="absolute inset-y-0 left-0 block overflow-hidden outline-none w-(--reka-rating-item-step-width) opacity-(--reka-rating-item-step-opacity) z-(--reka-rating-item-step-z-index) focus-visible:outline-none"
|
|
64
|
+
>
|
|
65
|
+
<RatingStar class="text-warning" filled />
|
|
66
|
+
</RatingItemIndicator>
|
|
67
|
+
</RatingItem>
|
|
68
|
+
</slot>
|
|
69
|
+
</RatingRoot>
|
|
70
|
+
</template>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { RatingItemProps } from 'reka-ui'
|
|
3
|
+
import type { ClassProps } from '../../lib/types'
|
|
4
|
+
import { RatingItem } from 'reka-ui'
|
|
5
|
+
import { computed } from 'vue'
|
|
6
|
+
import { cn } from '../../lib/utils'
|
|
7
|
+
|
|
8
|
+
const props = defineProps<RatingItemProps & ClassProps>()
|
|
9
|
+
|
|
10
|
+
const delegated = computed(() => {
|
|
11
|
+
const { class: _class, ...rest } = props
|
|
12
|
+
return rest
|
|
13
|
+
})
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<template>
|
|
17
|
+
<!-- Slot có phạm vi trả về `steps`: một phần tử khi `step` là 1, hai khi 0.5,
|
|
18
|
+
và cứ thế. Bên gọi dựng một `RatingItemIndicator` cho mỗi bước. -->
|
|
19
|
+
<RatingItem
|
|
20
|
+
v-slot="{ steps }"
|
|
21
|
+
v-bind="delegated"
|
|
22
|
+
:class="cn('relative block size-(--rating-item-size) cursor-pointer', props.class)"
|
|
23
|
+
>
|
|
24
|
+
<slot :steps="steps" />
|
|
25
|
+
</RatingItem>
|
|
26
|
+
</template>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { RatingItemIndicatorProps } from 'reka-ui'
|
|
3
|
+
import type { ClassProps } from '../../lib/types'
|
|
4
|
+
import { RatingItemIndicator } from 'reka-ui'
|
|
5
|
+
import { computed } from 'vue'
|
|
6
|
+
import { cn } from '../../lib/utils'
|
|
7
|
+
|
|
8
|
+
const props = defineProps<RatingItemIndicatorProps & ClassProps>()
|
|
9
|
+
|
|
10
|
+
const delegated = computed(() => {
|
|
11
|
+
const { class: _class, ...rest } = props
|
|
12
|
+
return rest
|
|
13
|
+
})
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<template>
|
|
17
|
+
<!--
|
|
18
|
+
KHÔNG đặt `style` ở đây: reka đã bind inline `--reka-rating-item-step-width`,
|
|
19
|
+
`-opacity` và `-z-index` lên chính element này. Thêm style của mình vào là
|
|
20
|
+
tranh chỗ với nó, mà mấy biến đó chính là thứ vẽ ra nửa sao.
|
|
21
|
+
-->
|
|
22
|
+
<RatingItemIndicator
|
|
23
|
+
v-bind="delegated"
|
|
24
|
+
:class="cn('absolute inset-y-0 left-0 block overflow-hidden outline-none w-(--reka-rating-item-step-width) opacity-(--reka-rating-item-step-opacity) z-(--reka-rating-item-step-z-index)', props.class)"
|
|
25
|
+
>
|
|
26
|
+
<slot />
|
|
27
|
+
</RatingItemIndicator>
|
|
28
|
+
</template>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { ClassProps } from '../../lib/types'
|
|
3
|
+
import { Star } from '../../lib/icons'
|
|
4
|
+
import { cn } from '../../lib/utils'
|
|
5
|
+
|
|
6
|
+
const props = defineProps<ClassProps & { filled?: boolean }>()
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<template>
|
|
10
|
+
<!-- `max-w-none` giữ ngôi sao ở đúng cỡ ngay cả khi lớp phủ đã bị cắt hẹp —
|
|
11
|
+
thiếu nó thì nửa sao thành sao bị bóp méo thay vì sao bị xén. -->
|
|
12
|
+
<Star
|
|
13
|
+
:class="cn('size-(--rating-item-size) max-w-none', props.filled && 'fill-current', props.class)"
|
|
14
|
+
aria-hidden="true"
|
|
15
|
+
/>
|
|
16
|
+
</template>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chấm sao. `<Rating v-model="score" />` là đủ — slot mặc định dựng sẵn cả hàng.
|
|
3
|
+
*
|
|
4
|
+
* Nửa sao (`step="0.5"`) không phải một icon riêng: reka chia mỗi ngôi sao thành
|
|
5
|
+
* mấy bước, mỗi bước là một lớp phủ bị **cắt** theo bề rộng, và ngôi sao bên
|
|
6
|
+
* trong giữ nguyên cỡ đầy đủ. Vì vậy `RatingStar` khai `max-w-none` — thiếu nó
|
|
7
|
+
* thì nửa sao thành ngôi sao bị bóp méo.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export { default as Rating } from './Rating.vue'
|
|
11
|
+
export { default as RatingItem } from './RatingItem.vue'
|
|
12
|
+
export { default as RatingItemIndicator } from './RatingItemIndicator.vue'
|
|
13
|
+
export { default as RatingStar } from './RatingStar.vue'
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { ScrollAreaRootProps } from 'reka-ui'
|
|
3
|
+
import type { ClassProps } from '../../lib/types'
|
|
4
|
+
import {
|
|
5
|
+
ScrollAreaCorner,
|
|
6
|
+
ScrollAreaRoot,
|
|
7
|
+
ScrollAreaScrollbar,
|
|
8
|
+
ScrollAreaThumb,
|
|
9
|
+
ScrollAreaViewport,
|
|
10
|
+
} from 'reka-ui'
|
|
11
|
+
import { computed } from 'vue'
|
|
12
|
+
import { cn } from '../../lib/utils'
|
|
13
|
+
|
|
14
|
+
const props = withDefaults(
|
|
15
|
+
defineProps<ScrollAreaRootProps & ClassProps & {
|
|
16
|
+
orientation?: 'vertical' | 'horizontal' | 'both'
|
|
17
|
+
viewportClass?: string
|
|
18
|
+
}>(),
|
|
19
|
+
{ orientation: 'vertical' },
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
const delegated = computed(() => {
|
|
23
|
+
const { class: _class, orientation: _orientation, viewportClass: _viewportClass, ...rest } = props
|
|
24
|
+
return rest
|
|
25
|
+
})
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
<template>
|
|
29
|
+
<ScrollAreaRoot v-bind="delegated" :class="cn('relative overflow-hidden', props.class)">
|
|
30
|
+
<ScrollAreaViewport :class="cn('size-full rounded-[inherit]', props.viewportClass)">
|
|
31
|
+
<slot />
|
|
32
|
+
</ScrollAreaViewport>
|
|
33
|
+
|
|
34
|
+
<ScrollAreaScrollbar
|
|
35
|
+
v-if="props.orientation !== 'horizontal'"
|
|
36
|
+
orientation="vertical"
|
|
37
|
+
class="flex w-2 touch-none select-none border-l border-l-transparent p-px transition-colors"
|
|
38
|
+
>
|
|
39
|
+
<ScrollAreaThumb class="relative flex-1 rounded-full bg-border" />
|
|
40
|
+
</ScrollAreaScrollbar>
|
|
41
|
+
|
|
42
|
+
<ScrollAreaScrollbar
|
|
43
|
+
v-if="props.orientation !== 'vertical'"
|
|
44
|
+
orientation="horizontal"
|
|
45
|
+
class="flex h-2 touch-none select-none border-t border-t-transparent p-px transition-colors"
|
|
46
|
+
>
|
|
47
|
+
<ScrollAreaThumb class="relative flex-1 rounded-full bg-border" />
|
|
48
|
+
</ScrollAreaScrollbar>
|
|
49
|
+
|
|
50
|
+
<ScrollAreaCorner />
|
|
51
|
+
</ScrollAreaRoot>
|
|
52
|
+
</template>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as ScrollArea } from './ScrollArea.vue'
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { ClassProps } from '../../lib/types'
|
|
3
|
+
import { computed } from 'vue'
|
|
4
|
+
import { Search } from '../../lib/icons'
|
|
5
|
+
import { cn } from '../../lib/utils'
|
|
6
|
+
import Input from '../input/Input.vue'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Gốc là cái vỏ `<div class="relative">` chứ không phải ô nhập, nên thuộc tính
|
|
10
|
+
* rơi tự do (`aria-label`, `id`, `disabled`, `name`) phải chuyển tay xuống
|
|
11
|
+
* `Input` — để mặc định thì chúng đáp xuống cái div và `<Label for>` trỏ vào
|
|
12
|
+
* hư không. `class` vẫn ở vỏ vì nó là thứ đặt bề rộng.
|
|
13
|
+
*/
|
|
14
|
+
defineOptions({ inheritAttrs: false })
|
|
15
|
+
|
|
16
|
+
const props = withDefaults(
|
|
17
|
+
defineProps<ClassProps & {
|
|
18
|
+
placeholder?: string
|
|
19
|
+
size?: 'sm' | 'default'
|
|
20
|
+
}>(),
|
|
21
|
+
{ size: 'sm' },
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
const model = defineModel<string>({ default: '' })
|
|
25
|
+
|
|
26
|
+
const iconClass = computed(() =>
|
|
27
|
+
props.size === 'sm' ? 'left-2.5 size-3.5' : 'left-3 size-4',
|
|
28
|
+
)
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<template>
|
|
32
|
+
<div :class="cn('relative', props.class)">
|
|
33
|
+
<Search
|
|
34
|
+
:class="cn('pointer-events-none absolute top-1/2 -translate-y-1/2 text-muted-foreground', iconClass)"
|
|
35
|
+
aria-hidden="true"
|
|
36
|
+
/>
|
|
37
|
+
<Input
|
|
38
|
+
v-bind="$attrs"
|
|
39
|
+
v-model="model"
|
|
40
|
+
type="search"
|
|
41
|
+
:size="props.size"
|
|
42
|
+
:placeholder="props.placeholder"
|
|
43
|
+
:class="props.size === 'sm' ? 'pl-8' : 'pl-9'"
|
|
44
|
+
/>
|
|
45
|
+
</div>
|
|
46
|
+
</template>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as SearchInput } from './SearchInput.vue'
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<script setup lang="ts" generic="T extends AcceptableValue = AcceptableValue">
|
|
2
|
+
import type { AcceptableValue, SelectRootEmits, SelectRootProps } from 'reka-ui'
|
|
3
|
+
import { SelectRoot, useForwardPropsEmits } from 'reka-ui'
|
|
4
|
+
|
|
5
|
+
const props = defineProps<SelectRootProps<T>>()
|
|
6
|
+
const emits = defineEmits<SelectRootEmits<T>>()
|
|
7
|
+
|
|
8
|
+
const forwarded = useForwardPropsEmits(props, emits)
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<template>
|
|
12
|
+
<SelectRoot v-bind="forwarded">
|
|
13
|
+
<slot />
|
|
14
|
+
</SelectRoot>
|
|
15
|
+
</template>
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { SelectContentEmits, SelectContentProps } from 'reka-ui'
|
|
3
|
+
import type { ClassProps } from '../../lib/types'
|
|
4
|
+
import {
|
|
5
|
+
injectSelectRootContext,
|
|
6
|
+
SelectContent,
|
|
7
|
+
SelectPortal,
|
|
8
|
+
SelectScrollDownButton,
|
|
9
|
+
SelectScrollUpButton,
|
|
10
|
+
SelectViewport,
|
|
11
|
+
useForwardPropsEmits,
|
|
12
|
+
} from 'reka-ui'
|
|
13
|
+
import { computed } from 'vue'
|
|
14
|
+
import { ChevronDown, ChevronUp } from '../../lib/icons'
|
|
15
|
+
import { cn } from '../../lib/utils'
|
|
16
|
+
|
|
17
|
+
const props = withDefaults(
|
|
18
|
+
defineProps<SelectContentProps & ClassProps>(),
|
|
19
|
+
{ position: 'popper', sideOffset: 6 },
|
|
20
|
+
)
|
|
21
|
+
const emits = defineEmits<SelectContentEmits>()
|
|
22
|
+
|
|
23
|
+
const delegated = computed(() => {
|
|
24
|
+
const { class: _class, ...rest } = props
|
|
25
|
+
return rest
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
const forwarded = useForwardPropsEmits(delegated, emits)
|
|
29
|
+
|
|
30
|
+
// reka không đặt `aria-multiselectable` khi bật `multiple`, mà APG đòi listbox
|
|
31
|
+
// chọn nhiều phải khai — nếu không trình đọc màn hình vẫn nói "chọn một".
|
|
32
|
+
const rootContext = injectSelectRootContext()
|
|
33
|
+
const multiselectable = computed(() => rootContext.multiple.value || undefined)
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
<template>
|
|
37
|
+
<SelectPortal>
|
|
38
|
+
<SelectContent
|
|
39
|
+
v-bind="forwarded"
|
|
40
|
+
:aria-multiselectable="multiselectable"
|
|
41
|
+
:class="cn(
|
|
42
|
+
// `ui-menu` + `bg-menu-surface` cho khớp `menuContentClass`: Select là
|
|
43
|
+
// một menu, nên hai trục `data-menu-color` / `data-menu-appearance` phải
|
|
44
|
+
// với tới nó. Nó không dùng chung chuỗi class kia vì còn có nút cuộn
|
|
45
|
+
// trên/dưới và phần định vị riêng.
|
|
46
|
+
'ui-menu surface relative z-(--z-overlay) max-h-96 min-w-[8rem] overflow-hidden rounded-md border border-border bg-menu-surface text-popover-foreground shadow-md',
|
|
47
|
+
'data-[state=open]:animate-in data-[state=closed]:animate-out',
|
|
48
|
+
'data-[state=open]:fade-in-0 data-[state=closed]:fade-out-0',
|
|
49
|
+
'data-[state=open]:zoom-in-95 data-[state=closed]:zoom-out-95',
|
|
50
|
+
props.position === 'popper' && 'w-full min-w-[var(--reka-select-trigger-width)]',
|
|
51
|
+
props.class,
|
|
52
|
+
)"
|
|
53
|
+
>
|
|
54
|
+
<SelectScrollUpButton class="flex h-6 cursor-default items-center justify-center text-muted-foreground">
|
|
55
|
+
<ChevronUp class="size-4" />
|
|
56
|
+
</SelectScrollUpButton>
|
|
57
|
+
|
|
58
|
+
<SelectViewport :class="cn('p-1', props.position === 'popper' && 'max-h-[var(--reka-select-content-available-height)]')">
|
|
59
|
+
<slot />
|
|
60
|
+
</SelectViewport>
|
|
61
|
+
|
|
62
|
+
<SelectScrollDownButton class="flex h-6 cursor-default items-center justify-center text-muted-foreground">
|
|
63
|
+
<ChevronDown class="size-4" />
|
|
64
|
+
</SelectScrollDownButton>
|
|
65
|
+
</SelectContent>
|
|
66
|
+
</SelectPortal>
|
|
67
|
+
</template>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { SelectGroupProps } from 'reka-ui'
|
|
3
|
+
import type { ClassProps } from '../../lib/types'
|
|
4
|
+
import { SelectGroup } from 'reka-ui'
|
|
5
|
+
import { computed } from 'vue'
|
|
6
|
+
import { cn } from '../../lib/utils'
|
|
7
|
+
|
|
8
|
+
const props = defineProps<SelectGroupProps & ClassProps>()
|
|
9
|
+
|
|
10
|
+
const delegated = computed(() => {
|
|
11
|
+
const { class: _class, ...rest } = props
|
|
12
|
+
return rest
|
|
13
|
+
})
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<template>
|
|
17
|
+
<SelectGroup v-bind="delegated" :class="cn('p-1', props.class)">
|
|
18
|
+
<slot />
|
|
19
|
+
</SelectGroup>
|
|
20
|
+
</template>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { SelectItemEmits, SelectItemProps } from 'reka-ui'
|
|
3
|
+
import type { ClassProps } from '../../lib/types'
|
|
4
|
+
import { SelectItem, SelectItemIndicator, SelectItemText, useForwardPropsEmits } from 'reka-ui'
|
|
5
|
+
import { computed } from 'vue'
|
|
6
|
+
import { Check } from '../../lib/icons'
|
|
7
|
+
import { cn } from '../../lib/utils'
|
|
8
|
+
|
|
9
|
+
// Không đặt generic ở đây: generic làm TS mất thông tin "value là bắt buộc"
|
|
10
|
+
// khi forward prop xuống SelectItem của reka. Kiểu của value vẫn là
|
|
11
|
+
// AcceptableValue (string | number | bigint | Record | null), đủ dùng.
|
|
12
|
+
const props = defineProps<SelectItemProps & ClassProps & {
|
|
13
|
+
/**
|
|
14
|
+
* Ô đánh dấu bên trái thay cho dấu tick bên phải — dành cho chế độ nhiều,
|
|
15
|
+
* nơi "đang chọn" của từng dòng phải đọc ra như một công tắc. Trạng thái lấy
|
|
16
|
+
* từ `data-state` mà reka đặt trên chính dòng, qua `group-data-*`.
|
|
17
|
+
*/
|
|
18
|
+
checkbox?: boolean
|
|
19
|
+
}>()
|
|
20
|
+
const emits = defineEmits<SelectItemEmits>()
|
|
21
|
+
|
|
22
|
+
const delegated = computed(() => {
|
|
23
|
+
const { class: _class, checkbox: _checkbox, ...rest } = props
|
|
24
|
+
return rest
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
const forwarded = useForwardPropsEmits(delegated, emits)
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<template>
|
|
31
|
+
<SelectItem
|
|
32
|
+
v-bind="forwarded"
|
|
33
|
+
:class="cn(
|
|
34
|
+
'group relative flex w-full cursor-default select-none items-center gap-2 rounded-sm py-1.5 pl-2 text-sm outline-none transition-colors',
|
|
35
|
+
props.checkbox ? 'pr-2' : 'pr-8',
|
|
36
|
+
'focus:bg-accent focus:text-accent-foreground',
|
|
37
|
+
'data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
|
38
|
+
props.class,
|
|
39
|
+
)"
|
|
40
|
+
>
|
|
41
|
+
<span
|
|
42
|
+
v-if="props.checkbox"
|
|
43
|
+
aria-hidden="true"
|
|
44
|
+
class="flex size-4 shrink-0 items-center justify-center rounded-[4px] border border-input bg-background shadow-xs transition-colors group-data-[state=checked]:border-primary group-data-[state=checked]:bg-primary group-data-[state=checked]:text-primary-foreground"
|
|
45
|
+
>
|
|
46
|
+
<SelectItemIndicator>
|
|
47
|
+
<Check class="size-3.5" />
|
|
48
|
+
</SelectItemIndicator>
|
|
49
|
+
</span>
|
|
50
|
+
<SelectItemText>
|
|
51
|
+
<slot />
|
|
52
|
+
</SelectItemText>
|
|
53
|
+
<span v-if="!props.checkbox" class="absolute right-2 flex size-4 items-center justify-center">
|
|
54
|
+
<SelectItemIndicator>
|
|
55
|
+
<Check class="size-4" />
|
|
56
|
+
</SelectItemIndicator>
|
|
57
|
+
</span>
|
|
58
|
+
</SelectItem>
|
|
59
|
+
</template>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { SelectLabelProps } from 'reka-ui'
|
|
3
|
+
import type { ClassProps } from '../../lib/types'
|
|
4
|
+
import { SelectLabel } from 'reka-ui'
|
|
5
|
+
import { computed } from 'vue'
|
|
6
|
+
import { cn } from '../../lib/utils'
|
|
7
|
+
|
|
8
|
+
const props = defineProps<SelectLabelProps & ClassProps>()
|
|
9
|
+
|
|
10
|
+
const delegated = computed(() => {
|
|
11
|
+
const { class: _class, ...rest } = props
|
|
12
|
+
return rest
|
|
13
|
+
})
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<template>
|
|
17
|
+
<SelectLabel v-bind="delegated" :class="cn('px-2 py-1.5 text-xs font-medium text-muted-foreground', props.class)">
|
|
18
|
+
<slot />
|
|
19
|
+
</SelectLabel>
|
|
20
|
+
</template>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { SelectSeparatorProps } from 'reka-ui'
|
|
3
|
+
import type { ClassProps } from '../../lib/types'
|
|
4
|
+
import { SelectSeparator } from 'reka-ui'
|
|
5
|
+
import { computed } from 'vue'
|
|
6
|
+
import { cn } from '../../lib/utils'
|
|
7
|
+
|
|
8
|
+
const props = defineProps<SelectSeparatorProps & ClassProps>()
|
|
9
|
+
|
|
10
|
+
const delegated = computed(() => {
|
|
11
|
+
const { class: _class, ...rest } = props
|
|
12
|
+
return rest
|
|
13
|
+
})
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<template>
|
|
17
|
+
<SelectSeparator v-bind="delegated" :class="cn('-mx-1 my-1 h-px bg-border', props.class)" />
|
|
18
|
+
</template>
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { SelectTriggerProps } from 'reka-ui'
|
|
3
|
+
import type { ClassProps } from '../../lib/types'
|
|
4
|
+
import { injectSelectRootContext, SelectIcon, SelectTrigger } from 'reka-ui'
|
|
5
|
+
import { computed } from 'vue'
|
|
6
|
+
import { useI18n } from '../../composables/useI18n'
|
|
7
|
+
import { focusRing, invalidRing } from '../../lib/focus'
|
|
8
|
+
import { ChevronDown, X } from '../../lib/icons'
|
|
9
|
+
import { cn } from '../../lib/utils'
|
|
10
|
+
import Spinner from '../spinner/Spinner.vue'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Gốc là một `<div>` bọc ngoài chứ không phải chính cái nút: nút × xoá giá trị
|
|
14
|
+
* phải là `<button>` thật, mà button không được lồng trong button. Nó nằm CẠNH
|
|
15
|
+
* trigger, đặt chồng lên bằng `absolute`. Thuộc tính rơi tự do (`id`,
|
|
16
|
+
* `aria-invalid` từ FormField…) vì vậy phải chuyển tay xuống nút.
|
|
17
|
+
*/
|
|
18
|
+
defineOptions({ inheritAttrs: false })
|
|
19
|
+
|
|
20
|
+
const props = defineProps<SelectTriggerProps & ClassProps & {
|
|
21
|
+
invalid?: boolean
|
|
22
|
+
size?: 'sm' | 'default'
|
|
23
|
+
/**
|
|
24
|
+
* Nút × xoá giá trị, chỉ hiện khi đang có giá trị. Bàn phím: `Delete` hoặc
|
|
25
|
+
* `Backspace` lúc trigger đang focus — nút × để `tabindex="-1"` nên không
|
|
26
|
+
* thêm một điểm dừng Tab cho mỗi select trong form.
|
|
27
|
+
*/
|
|
28
|
+
clearable?: boolean
|
|
29
|
+
/** Thay mũi tên bằng spinner và khai `aria-busy`. Vẫn mở được. */
|
|
30
|
+
loading?: boolean
|
|
31
|
+
}>()
|
|
32
|
+
|
|
33
|
+
const { t } = useI18n()
|
|
34
|
+
const rootContext = injectSelectRootContext()
|
|
35
|
+
|
|
36
|
+
const delegated = computed(() => {
|
|
37
|
+
const { class: _class, invalid: _invalid, size: _size, clearable: _clearable, loading: _loading, ...rest } = props
|
|
38
|
+
return rest
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
const showClear = computed(() =>
|
|
42
|
+
props.clearable === true
|
|
43
|
+
&& !rootContext.isEmptyModelValue.value
|
|
44
|
+
&& !rootContext.disabled?.value,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
function clear() {
|
|
48
|
+
rootContext.modelValue.value = rootContext.multiple.value ? [] : undefined
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function onKeydown(event: KeyboardEvent) {
|
|
52
|
+
if (!showClear.value || (event.key !== 'Delete' && event.key !== 'Backspace'))
|
|
53
|
+
return
|
|
54
|
+
event.preventDefault()
|
|
55
|
+
clear()
|
|
56
|
+
}
|
|
57
|
+
</script>
|
|
58
|
+
|
|
59
|
+
<template>
|
|
60
|
+
<div :class="cn('relative', props.class)">
|
|
61
|
+
<SelectTrigger
|
|
62
|
+
v-bind="{ ...delegated, ...$attrs }"
|
|
63
|
+
:aria-invalid="props.invalid || undefined"
|
|
64
|
+
:aria-busy="props.loading || undefined"
|
|
65
|
+
:data-invalid="props.invalid || undefined"
|
|
66
|
+
:class="cn(
|
|
67
|
+
'flex w-full items-center justify-between gap-2 rounded-md border border-input bg-background px-3 py-1 text-sm shadow-xs transition-colors',
|
|
68
|
+
// `min-h` chứ không `h`: giá trị dạng chip xuống hàng thì trigger phải cao lên theo.
|
|
69
|
+
props.size === 'sm' ? 'min-h-8' : 'min-h-9',
|
|
70
|
+
'data-[placeholder]:text-muted-foreground',
|
|
71
|
+
'focus:outline-none',
|
|
72
|
+
focusRing,
|
|
73
|
+
'disabled:cursor-not-allowed disabled:opacity-50',
|
|
74
|
+
invalidRing,
|
|
75
|
+
'[&>span]:truncate [&>span]:text-left',
|
|
76
|
+
// Chừa chỗ cho nút × (16px) và khoảng cách tới nó (8px).
|
|
77
|
+
showClear && '[&>[data-slot=select-value]]:mr-6',
|
|
78
|
+
// Mũi tên xoay theo `data-state` mà reka đặt trên trigger — không JS.
|
|
79
|
+
'[&[data-state=open]>svg]:rotate-180',
|
|
80
|
+
)"
|
|
81
|
+
@keydown="onKeydown"
|
|
82
|
+
>
|
|
83
|
+
<slot />
|
|
84
|
+
<Spinner v-if="props.loading" class="shrink-0 text-muted-foreground" />
|
|
85
|
+
<SelectIcon v-else as-child>
|
|
86
|
+
<ChevronDown class="size-4 shrink-0 text-muted-foreground transition-transform duration-(--duration-base) motion-reduce:transition-none" />
|
|
87
|
+
</SelectIcon>
|
|
88
|
+
</SelectTrigger>
|
|
89
|
+
|
|
90
|
+
<button
|
|
91
|
+
v-if="showClear"
|
|
92
|
+
type="button"
|
|
93
|
+
tabindex="-1"
|
|
94
|
+
:aria-label="t('ui.select.clear')"
|
|
95
|
+
class="absolute top-1/2 right-9 grid size-4 -translate-y-1/2 place-items-center rounded-sm text-muted-foreground transition-colors hover:text-foreground"
|
|
96
|
+
@click="clear"
|
|
97
|
+
>
|
|
98
|
+
<X class="size-3.5" />
|
|
99
|
+
</button>
|
|
100
|
+
</div>
|
|
101
|
+
</template>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { SelectValueProps } from 'reka-ui'
|
|
3
|
+
import type { ClassProps } from '../../lib/types'
|
|
4
|
+
import { SelectValue } from 'reka-ui'
|
|
5
|
+
import { computed } from 'vue'
|
|
6
|
+
import { cn } from '../../lib/utils'
|
|
7
|
+
import { badgeVariants } from '../badge'
|
|
8
|
+
import { chipVariants } from '../chip'
|
|
9
|
+
|
|
10
|
+
const props = defineProps<SelectValueProps & ClassProps & {
|
|
11
|
+
/**
|
|
12
|
+
* Chế độ nhiều: mỗi nhãn đã chọn là một chip, thay vì chuỗi nối dấu phẩy.
|
|
13
|
+
* Chip chỉ để nhìn — nút gỡ trên chip sẽ là button lồng trong button.
|
|
14
|
+
*/
|
|
15
|
+
chips?: boolean
|
|
16
|
+
}>()
|
|
17
|
+
|
|
18
|
+
const delegated = computed(() => {
|
|
19
|
+
const { class: _class, chips: _chips, ...rest } = props
|
|
20
|
+
return rest
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
const chipClass = cn(badgeVariants({ variant: 'secondary' }), chipVariants({ size: 'sm', removable: false }))
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<template>
|
|
27
|
+
<!--
|
|
28
|
+
Phải chuyển tiếp slot scope: reka trả `selectedLabel` và `modelValue` qua
|
|
29
|
+
slot, viết `<slot />` trần là bên gọi nhận `undefined` mà không có gì báo.
|
|
30
|
+
|
|
31
|
+
Nhánh chip chỉ render khi CÓ giá trị; còn lại để rỗng để reka rơi về nội
|
|
32
|
+
dung mặc định của nó (nhãn nối dấu phẩy, hoặc placeholder).
|
|
33
|
+
-->
|
|
34
|
+
<SelectValue
|
|
35
|
+
v-slot="scope"
|
|
36
|
+
v-bind="delegated"
|
|
37
|
+
data-slot="select-value"
|
|
38
|
+
:class="cn('truncate', props.chips && 'flex flex-wrap gap-1', props.class)"
|
|
39
|
+
>
|
|
40
|
+
<slot v-bind="scope">
|
|
41
|
+
<template v-if="props.chips && scope.selectedLabel.length">
|
|
42
|
+
<span v-for="label in scope.selectedLabel" :key="label" :class="chipClass">{{ label }}</span>
|
|
43
|
+
</template>
|
|
44
|
+
</slot>
|
|
45
|
+
</SelectValue>
|
|
46
|
+
</template>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { default as Select } from './Select.vue'
|
|
2
|
+
export { default as SelectContent } from './SelectContent.vue'
|
|
3
|
+
export { default as SelectGroup } from './SelectGroup.vue'
|
|
4
|
+
export { default as SelectItem } from './SelectItem.vue'
|
|
5
|
+
export { default as SelectLabel } from './SelectLabel.vue'
|
|
6
|
+
export { default as SelectSeparator } from './SelectSeparator.vue'
|
|
7
|
+
export { default as SelectTrigger } from './SelectTrigger.vue'
|
|
8
|
+
export { default as SelectValue } from './SelectValue.vue'
|