@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,94 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { PrimitiveProps } from 'reka-ui'
|
|
3
|
+
import type { ClassProps } from '../../lib/types'
|
|
4
|
+
import type { SidebarMenuButtonVariants } from './index'
|
|
5
|
+
import { Primitive } from 'reka-ui'
|
|
6
|
+
import { computed } from 'vue'
|
|
7
|
+
import { cn } from '../../lib/utils'
|
|
8
|
+
import Tooltip from '../tooltip/Tooltip.vue'
|
|
9
|
+
import TooltipContent from '../tooltip/TooltipContent.vue'
|
|
10
|
+
import TooltipTrigger from '../tooltip/TooltipTrigger.vue'
|
|
11
|
+
import { useSidebar } from './context'
|
|
12
|
+
import { sidebarMenuButtonVariants } from './index'
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Gốc của component là một provider KHÔNG vẽ ra DOM, nên thuộc tính rơi tự do
|
|
16
|
+
* không có chỗ đáp và biến mất hẳn. Đo được: đặt `id` lên component thì nó
|
|
17
|
+
* không xuất hiện ở bất kỳ đâu trong DOM, và `<Label for>` trỏ vào hư không.
|
|
18
|
+
*
|
|
19
|
+
* Chuyển tay xuống CẢ HAI nhánh: nhánh không có tooltip vốn đang nhận attrs
|
|
20
|
+
* nhờ fallthrough, bật `inheritAttrs: false` mà quên nó là lấy mất.
|
|
21
|
+
*/
|
|
22
|
+
defineOptions({ inheritAttrs: false })
|
|
23
|
+
|
|
24
|
+
const props = withDefaults(
|
|
25
|
+
defineProps<PrimitiveProps & ClassProps & {
|
|
26
|
+
isActive?: boolean
|
|
27
|
+
variant?: SidebarMenuButtonVariants['variant']
|
|
28
|
+
size?: SidebarMenuButtonVariants['size']
|
|
29
|
+
/** Nhãn hiện khi sidebar đã thu về cỡ icon. Bỏ trống thì không có tooltip. */
|
|
30
|
+
tooltip?: string
|
|
31
|
+
/**
|
|
32
|
+
* Hiện tooltip cả khi cột đang mở.
|
|
33
|
+
*
|
|
34
|
+
* Dành cho cột `collapsible="none"` rộng đúng cỡ icon — nó không bao giờ ở
|
|
35
|
+
* trạng thái `collapsed` nên luật mặc định sẽ giấu tooltip vĩnh viễn, trong
|
|
36
|
+
* khi nhãn thì vẫn bị cắt mất.
|
|
37
|
+
*/
|
|
38
|
+
alwaysShowTooltip?: boolean
|
|
39
|
+
}>(),
|
|
40
|
+
{ as: 'button', isActive: false, variant: 'default', size: 'default', alwaysShowTooltip: false },
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
const { isMobile, state } = useSidebar()
|
|
44
|
+
|
|
45
|
+
const nativeType = computed(() => (props.as === 'button' ? 'button' : undefined))
|
|
46
|
+
const buttonClass = computed(() => cn(sidebarMenuButtonVariants({ variant: props.variant, size: props.size }), props.class))
|
|
47
|
+
</script>
|
|
48
|
+
|
|
49
|
+
<template>
|
|
50
|
+
<!--
|
|
51
|
+
Tooltip chỉ có nghĩa khi nhãn đã bị thu mất. Ở trạng thái mở, hoặc trên
|
|
52
|
+
mobile (sidebar là ngăn kéo, luôn hiện đủ chữ), nó lặp lại đúng thứ đang
|
|
53
|
+
đọc được — và trình đọc màn hình sẽ đọc hai lần.
|
|
54
|
+
-->
|
|
55
|
+
<Tooltip v-if="tooltip">
|
|
56
|
+
<TooltipTrigger as-child>
|
|
57
|
+
<Primitive
|
|
58
|
+
v-bind="$attrs"
|
|
59
|
+
:as="as"
|
|
60
|
+
:as-child="asChild"
|
|
61
|
+
:type="nativeType"
|
|
62
|
+
data-slot="sidebar-menu-button"
|
|
63
|
+
data-sidebar="menu-button"
|
|
64
|
+
:data-size="size"
|
|
65
|
+
:data-active="isActive"
|
|
66
|
+
:class="buttonClass"
|
|
67
|
+
>
|
|
68
|
+
<slot />
|
|
69
|
+
</Primitive>
|
|
70
|
+
</TooltipTrigger>
|
|
71
|
+
<TooltipContent
|
|
72
|
+
v-if="alwaysShowTooltip || (state === 'collapsed' && !isMobile)"
|
|
73
|
+
side="right"
|
|
74
|
+
align="center"
|
|
75
|
+
>
|
|
76
|
+
{{ tooltip }}
|
|
77
|
+
</TooltipContent>
|
|
78
|
+
</Tooltip>
|
|
79
|
+
|
|
80
|
+
<Primitive
|
|
81
|
+
v-else
|
|
82
|
+
v-bind="$attrs"
|
|
83
|
+
:as="as"
|
|
84
|
+
:as-child="asChild"
|
|
85
|
+
:type="nativeType"
|
|
86
|
+
data-slot="sidebar-menu-button"
|
|
87
|
+
data-sidebar="menu-button"
|
|
88
|
+
:data-size="size"
|
|
89
|
+
:data-active="isActive"
|
|
90
|
+
:class="buttonClass"
|
|
91
|
+
>
|
|
92
|
+
<slot />
|
|
93
|
+
</Primitive>
|
|
94
|
+
</template>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { ClassProps } from '../../lib/types'
|
|
3
|
+
import { cn } from '../../lib/utils'
|
|
4
|
+
|
|
5
|
+
const props = defineProps<ClassProps>()
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<template>
|
|
9
|
+
<li
|
|
10
|
+
data-slot="sidebar-menu-item"
|
|
11
|
+
data-sidebar="menu-item"
|
|
12
|
+
:class="cn(
|
|
13
|
+
'group/menu-item relative',
|
|
14
|
+
props.class,
|
|
15
|
+
)"
|
|
16
|
+
>
|
|
17
|
+
<slot />
|
|
18
|
+
</li>
|
|
19
|
+
</template>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { CSSProperties } from 'vue'
|
|
3
|
+
import type { ClassProps } from '../../lib/types'
|
|
4
|
+
import { computed } from 'vue'
|
|
5
|
+
import { cn } from '../../lib/utils'
|
|
6
|
+
import Skeleton from '../skeleton/Skeleton.vue'
|
|
7
|
+
|
|
8
|
+
const props = withDefaults(
|
|
9
|
+
defineProps<ClassProps & { showIcon?: boolean }>(),
|
|
10
|
+
{ showIcon: false },
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Bề rộng ngẫu nhiên 50–90%.
|
|
15
|
+
*
|
|
16
|
+
* Tính một lần ở setup chứ không trong render: đọc `Math.random()` mỗi lần vẽ
|
|
17
|
+
* thì mỗi lần cha cập nhật là cả danh sách nhấp nháy đổi độ dài.
|
|
18
|
+
*/
|
|
19
|
+
const width = `${Math.floor(Math.random() * 40) + 50}%`
|
|
20
|
+
const textStyle = computed<CSSProperties>(() => ({ '--skeleton-width': width } as CSSProperties))
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<template>
|
|
24
|
+
<div
|
|
25
|
+
data-slot="sidebar-menu-skeleton"
|
|
26
|
+
data-sidebar="menu-skeleton"
|
|
27
|
+
:class="cn('flex h-8 items-center gap-2 rounded-md px-2', props.class)"
|
|
28
|
+
>
|
|
29
|
+
<Skeleton v-if="props.showIcon" data-sidebar="menu-skeleton-icon" class="size-4 rounded-md" />
|
|
30
|
+
<Skeleton
|
|
31
|
+
data-sidebar="menu-skeleton-text"
|
|
32
|
+
class="h-4 max-w-(--skeleton-width) flex-1"
|
|
33
|
+
:style="textStyle"
|
|
34
|
+
/>
|
|
35
|
+
</div>
|
|
36
|
+
</template>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { ClassProps } from '../../lib/types'
|
|
3
|
+
import { cn } from '../../lib/utils'
|
|
4
|
+
|
|
5
|
+
const props = defineProps<ClassProps>()
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<template>
|
|
9
|
+
<ul
|
|
10
|
+
data-slot="sidebar-menu-sub"
|
|
11
|
+
data-sidebar="menu-sub"
|
|
12
|
+
:class="cn(
|
|
13
|
+
[
|
|
14
|
+
'mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l border-sidebar-border px-2.5 py-0.5',
|
|
15
|
+
'group-data-[collapsible=icon]:hidden',
|
|
16
|
+
],
|
|
17
|
+
props.class,
|
|
18
|
+
)"
|
|
19
|
+
>
|
|
20
|
+
<slot />
|
|
21
|
+
</ul>
|
|
22
|
+
</template>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { PrimitiveProps } from 'reka-ui'
|
|
3
|
+
import type { ClassProps } from '../../lib/types'
|
|
4
|
+
import { Primitive } from 'reka-ui'
|
|
5
|
+
import { cn } from '../../lib/utils'
|
|
6
|
+
|
|
7
|
+
const props = withDefaults(
|
|
8
|
+
defineProps<PrimitiveProps & ClassProps & {
|
|
9
|
+
isActive?: boolean
|
|
10
|
+
size?: 'sm' | 'md'
|
|
11
|
+
}>(),
|
|
12
|
+
{ as: 'a', isActive: false, size: 'md' },
|
|
13
|
+
)
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<template>
|
|
17
|
+
<Primitive
|
|
18
|
+
:as="as"
|
|
19
|
+
:as-child="asChild"
|
|
20
|
+
data-slot="sidebar-menu-sub-button"
|
|
21
|
+
data-sidebar="menu-sub-button"
|
|
22
|
+
:data-size="size"
|
|
23
|
+
:data-active="isActive"
|
|
24
|
+
:class="cn(
|
|
25
|
+
'flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 text-sidebar-foreground outline-hidden ring-sidebar-ring',
|
|
26
|
+
'hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2',
|
|
27
|
+
'active:bg-sidebar-accent active:text-sidebar-accent-foreground',
|
|
28
|
+
'disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50',
|
|
29
|
+
'[&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0 [&>svg]:text-sidebar-accent-foreground',
|
|
30
|
+
'data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground',
|
|
31
|
+
props.size === 'sm' && 'text-xs',
|
|
32
|
+
props.size === 'md' && 'text-sm',
|
|
33
|
+
'group-data-[collapsible=icon]:hidden',
|
|
34
|
+
props.class,
|
|
35
|
+
)"
|
|
36
|
+
>
|
|
37
|
+
<slot />
|
|
38
|
+
</Primitive>
|
|
39
|
+
</template>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { ClassProps } from '../../lib/types'
|
|
3
|
+
import { cn } from '../../lib/utils'
|
|
4
|
+
|
|
5
|
+
const props = defineProps<ClassProps>()
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<template>
|
|
9
|
+
<li
|
|
10
|
+
data-slot="sidebar-menu-sub-item"
|
|
11
|
+
data-sidebar="menu-sub-item"
|
|
12
|
+
:class="cn(
|
|
13
|
+
'group/menu-sub-item relative',
|
|
14
|
+
props.class,
|
|
15
|
+
)"
|
|
16
|
+
>
|
|
17
|
+
<slot />
|
|
18
|
+
</li>
|
|
19
|
+
</template>
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { CSSProperties } from 'vue'
|
|
3
|
+
import type { ClassProps } from '../../lib/types'
|
|
4
|
+
import { computed, onBeforeUnmount, onMounted, provide, ref } from 'vue'
|
|
5
|
+
import { useIsMobile } from '../../composables/useIsMobile'
|
|
6
|
+
import { cn } from '../../lib/utils'
|
|
7
|
+
import TooltipProvider from '../tooltip/TooltipProvider.vue'
|
|
8
|
+
import {
|
|
9
|
+
SIDEBAR_INJECTION_KEY,
|
|
10
|
+
SIDEBAR_KEYBOARD_SHORTCUT,
|
|
11
|
+
SIDEBAR_WIDTH,
|
|
12
|
+
SIDEBAR_WIDTH_ICON,
|
|
13
|
+
} from './context'
|
|
14
|
+
|
|
15
|
+
const props = withDefaults(
|
|
16
|
+
defineProps<ClassProps & {
|
|
17
|
+
/** Trạng thái ban đầu khi không điều khiển từ ngoài. */
|
|
18
|
+
defaultOpen?: boolean
|
|
19
|
+
/**
|
|
20
|
+
* Điều khiển từ ngoài. Bỏ trống thì component tự giữ trạng thái.
|
|
21
|
+
*
|
|
22
|
+
* `open: undefined` trong `withDefaults` là BẮT BUỘC, không phải thừa: prop
|
|
23
|
+
* kiểu Boolean mà không khai default thì Vue ép giá trị vắng mặt thành
|
|
24
|
+
* `false` chứ không để `undefined`. Thiếu dòng đó, mọi `<SidebarProvider>`
|
|
25
|
+
* không truyền `open` đều bị coi là "đang được điều khiển và đang đóng" —
|
|
26
|
+
* sidebar dựng ra rồi nằm ngoài màn hình, không lỗi, không cảnh báo.
|
|
27
|
+
*/
|
|
28
|
+
open?: boolean
|
|
29
|
+
style?: CSSProperties
|
|
30
|
+
}>(),
|
|
31
|
+
{ defaultOpen: true, open: undefined },
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
const emit = defineEmits<{ 'update:open': [value: boolean] }>()
|
|
35
|
+
|
|
36
|
+
const isMobile = useIsMobile()
|
|
37
|
+
const openMobile = ref(false)
|
|
38
|
+
|
|
39
|
+
/*
|
|
40
|
+
* KHÔNG lưu trạng thái vào cookie như shadcn.
|
|
41
|
+
*
|
|
42
|
+
* Bên đó cookie tồn tại để `page.tsx` đọc được ở phía server và tránh nháy một
|
|
43
|
+
* nhịp lúc hydrate — một nhu cầu của Next.js mà repo này không có. Giữ lại thì
|
|
44
|
+
* nó thành một chỗ ghi mà không ai đọc, và tệ hơn: gallery block chạy 16 iframe
|
|
45
|
+
* cùng origin, một cookie dùng chung nghĩa là gập sidebar ở ô này thì 15 ô kia
|
|
46
|
+
* gập theo.
|
|
47
|
+
*/
|
|
48
|
+
const internalOpen = ref(props.defaultOpen)
|
|
49
|
+
const isControlled = computed(() => props.open !== undefined)
|
|
50
|
+
const open = computed(() => (isControlled.value ? props.open! : internalOpen.value))
|
|
51
|
+
|
|
52
|
+
function setOpen(value: boolean): void {
|
|
53
|
+
if (!isControlled.value)
|
|
54
|
+
internalOpen.value = value
|
|
55
|
+
|
|
56
|
+
emit('update:open', value)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function setOpenMobile(value: boolean): void {
|
|
60
|
+
openMobile.value = value
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function toggleSidebar(): void {
|
|
64
|
+
if (isMobile.value)
|
|
65
|
+
openMobile.value = !openMobile.value
|
|
66
|
+
else
|
|
67
|
+
setOpen(!open.value)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const state = computed(() => (open.value ? 'expanded' as const : 'collapsed' as const))
|
|
71
|
+
|
|
72
|
+
function onKeydown(event: KeyboardEvent): void {
|
|
73
|
+
if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) {
|
|
74
|
+
event.preventDefault()
|
|
75
|
+
toggleSidebar()
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
onMounted(() => window.addEventListener('keydown', onKeydown))
|
|
80
|
+
onBeforeUnmount(() => window.removeEventListener('keydown', onKeydown))
|
|
81
|
+
|
|
82
|
+
provide(SIDEBAR_INJECTION_KEY, {
|
|
83
|
+
state,
|
|
84
|
+
open,
|
|
85
|
+
setOpen,
|
|
86
|
+
openMobile,
|
|
87
|
+
setOpenMobile,
|
|
88
|
+
isMobile,
|
|
89
|
+
toggleSidebar,
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
const wrapperStyle = computed<CSSProperties>(() => ({
|
|
93
|
+
'--sidebar-width': SIDEBAR_WIDTH,
|
|
94
|
+
'--sidebar-width-icon': SIDEBAR_WIDTH_ICON,
|
|
95
|
+
...props.style,
|
|
96
|
+
} as CSSProperties))
|
|
97
|
+
</script>
|
|
98
|
+
|
|
99
|
+
<template>
|
|
100
|
+
<!-- `delayDuration: 0` — tooltip ở đây thay cho nhãn đã bị thu gọn mất, chờ
|
|
101
|
+
một nhịp là người dùng không biết mình đang trỏ vào mục nào. -->
|
|
102
|
+
<TooltipProvider :delay-duration="0">
|
|
103
|
+
<div
|
|
104
|
+
data-slot="sidebar-wrapper"
|
|
105
|
+
:style="wrapperStyle"
|
|
106
|
+
:class="cn(
|
|
107
|
+
'group/sidebar-wrapper flex min-h-svh w-full has-data-[variant=inset]:bg-sidebar',
|
|
108
|
+
props.class,
|
|
109
|
+
)"
|
|
110
|
+
>
|
|
111
|
+
<slot />
|
|
112
|
+
</div>
|
|
113
|
+
</TooltipProvider>
|
|
114
|
+
</template>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { ClassProps } from '../../lib/types'
|
|
3
|
+
import { useI18n } from '../../composables/useI18n'
|
|
4
|
+
import { cn } from '../../lib/utils'
|
|
5
|
+
import { useSidebar } from './context'
|
|
6
|
+
|
|
7
|
+
const props = defineProps<ClassProps>()
|
|
8
|
+
|
|
9
|
+
const { t } = useI18n()
|
|
10
|
+
const { toggleSidebar } = useSidebar()
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<template>
|
|
14
|
+
<!-- Dải 16px sát mép sidebar: kéo/bấm để gập. `tabindex="-1"` vì đã có
|
|
15
|
+
`SidebarTrigger` nhận focus — hai chỗ làm cùng một việc thì bàn phím phải
|
|
16
|
+
Tab hai lần qua cùng một hành động. -->
|
|
17
|
+
<button
|
|
18
|
+
type="button"
|
|
19
|
+
data-sidebar="rail"
|
|
20
|
+
data-slot="sidebar-rail"
|
|
21
|
+
:aria-label="t('ui.sidebar.toggle')"
|
|
22
|
+
:title="t('ui.sidebar.toggle')"
|
|
23
|
+
tabindex="-1"
|
|
24
|
+
:class="cn(
|
|
25
|
+
'absolute inset-y-0 z-(--z-elevated) hidden w-4 -translate-x-1/2 transition-all ease-linear sm:flex',
|
|
26
|
+
'after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] hover:after:bg-sidebar-border',
|
|
27
|
+
'group-data-[side=left]:-right-4 group-data-[side=right]:left-0',
|
|
28
|
+
'in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize',
|
|
29
|
+
'[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize',
|
|
30
|
+
'group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full hover:group-data-[collapsible=offcanvas]:bg-sidebar',
|
|
31
|
+
'[[data-side=left][data-collapsible=offcanvas]_&]:-right-2',
|
|
32
|
+
'[[data-side=right][data-collapsible=offcanvas]_&]:-left-2',
|
|
33
|
+
props.class,
|
|
34
|
+
)"
|
|
35
|
+
@click="toggleSidebar"
|
|
36
|
+
/>
|
|
37
|
+
</template>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { ClassProps } from '../../lib/types'
|
|
3
|
+
import { cn } from '../../lib/utils'
|
|
4
|
+
import Separator from '../separator/Separator.vue'
|
|
5
|
+
|
|
6
|
+
const props = defineProps<ClassProps>()
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<template>
|
|
10
|
+
<Separator
|
|
11
|
+
data-slot="sidebar-separator"
|
|
12
|
+
data-sidebar="separator"
|
|
13
|
+
:class="cn('mx-2 w-auto bg-sidebar-border', props.class)"
|
|
14
|
+
/>
|
|
15
|
+
</template>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { ClassProps } from '../../lib/types'
|
|
3
|
+
import { useI18n } from '../../composables/useI18n'
|
|
4
|
+
import { PanelLeft } from '../../lib/icons'
|
|
5
|
+
import { cn } from '../../lib/utils'
|
|
6
|
+
import Button from '../button/Button.vue'
|
|
7
|
+
import { useSidebar } from './context'
|
|
8
|
+
|
|
9
|
+
const props = defineProps<ClassProps>()
|
|
10
|
+
|
|
11
|
+
const { t } = useI18n()
|
|
12
|
+
const { toggleSidebar } = useSidebar()
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<template>
|
|
16
|
+
<Button
|
|
17
|
+
data-sidebar="trigger"
|
|
18
|
+
data-slot="sidebar-trigger"
|
|
19
|
+
variant="ghost"
|
|
20
|
+
size="icon"
|
|
21
|
+
:class="cn('size-7', props.class)"
|
|
22
|
+
@click="toggleSidebar"
|
|
23
|
+
>
|
|
24
|
+
<PanelLeft />
|
|
25
|
+
<span class="sr-only">{{ t('ui.sidebar.toggle') }}</span>
|
|
26
|
+
</Button>
|
|
27
|
+
</template>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { ComputedRef, InjectionKey, Ref } from 'vue'
|
|
2
|
+
import { inject } from 'vue'
|
|
3
|
+
|
|
4
|
+
/** Bề rộng ba trạng thái. Khai ở đây để `Sidebar` và `SidebarProvider` cùng đọc. */
|
|
5
|
+
export const SIDEBAR_WIDTH = '16rem'
|
|
6
|
+
export const SIDEBAR_WIDTH_MOBILE = '18rem'
|
|
7
|
+
export const SIDEBAR_WIDTH_ICON = '3rem'
|
|
8
|
+
|
|
9
|
+
/** Phím tắt bật/tắt, đi kèm Cmd (macOS) hoặc Ctrl. */
|
|
10
|
+
export const SIDEBAR_KEYBOARD_SHORTCUT = 'b'
|
|
11
|
+
|
|
12
|
+
export interface SidebarContext {
|
|
13
|
+
/** `expanded` hay `collapsed` — cũng là `data-state` để CSS bắt. */
|
|
14
|
+
state: ComputedRef<'expanded' | 'collapsed'>
|
|
15
|
+
open: ComputedRef<boolean>
|
|
16
|
+
setOpen: (value: boolean) => void
|
|
17
|
+
openMobile: Ref<boolean>
|
|
18
|
+
setOpenMobile: (value: boolean) => void
|
|
19
|
+
isMobile: Readonly<Ref<boolean>>
|
|
20
|
+
toggleSidebar: () => void
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const SIDEBAR_INJECTION_KEY: InjectionKey<SidebarContext> = Symbol('woodblock-sidebar')
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Đọc trạng thái sidebar từ `SidebarProvider` gần nhất.
|
|
27
|
+
*
|
|
28
|
+
* Ném lỗi thay vì trả `undefined`: mọi phần con của sidebar đều cần trạng thái
|
|
29
|
+
* này, thiếu provider thì chúng render ra một cái vỏ trông vẫn hợp lý nhưng
|
|
30
|
+
* không bấm được — đúng kiểu lỗi im lặng khó truy.
|
|
31
|
+
*/
|
|
32
|
+
export function useSidebar(): SidebarContext {
|
|
33
|
+
const context = inject(SIDEBAR_INJECTION_KEY, null)
|
|
34
|
+
|
|
35
|
+
if (!context)
|
|
36
|
+
throw new Error('useSidebar phải nằm trong một <SidebarProvider>.')
|
|
37
|
+
|
|
38
|
+
return context
|
|
39
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export { sidebarMenuButtonVariants, type SidebarMenuButtonVariants } from '../../variants/components/sidebar'
|
|
2
|
+
|
|
3
|
+
export {
|
|
4
|
+
SIDEBAR_WIDTH,
|
|
5
|
+
SIDEBAR_WIDTH_ICON,
|
|
6
|
+
SIDEBAR_WIDTH_MOBILE,
|
|
7
|
+
useSidebar,
|
|
8
|
+
} from './context'
|
|
9
|
+
|
|
10
|
+
export type { SidebarContext } from './context'
|
|
11
|
+
export { default as Sidebar } from './Sidebar.vue'
|
|
12
|
+
export { default as SidebarContent } from './SidebarContent.vue'
|
|
13
|
+
export { default as SidebarFooter } from './SidebarFooter.vue'
|
|
14
|
+
export { default as SidebarGroup } from './SidebarGroup.vue'
|
|
15
|
+
export { default as SidebarGroupAction } from './SidebarGroupAction.vue'
|
|
16
|
+
export { default as SidebarGroupContent } from './SidebarGroupContent.vue'
|
|
17
|
+
export { default as SidebarGroupLabel } from './SidebarGroupLabel.vue'
|
|
18
|
+
export { default as SidebarHeader } from './SidebarHeader.vue'
|
|
19
|
+
export { default as SidebarInput } from './SidebarInput.vue'
|
|
20
|
+
export { default as SidebarInset } from './SidebarInset.vue'
|
|
21
|
+
export { default as SidebarMenu } from './SidebarMenu.vue'
|
|
22
|
+
export { default as SidebarMenuAction } from './SidebarMenuAction.vue'
|
|
23
|
+
export { default as SidebarMenuBadge } from './SidebarMenuBadge.vue'
|
|
24
|
+
export { default as SidebarMenuButton } from './SidebarMenuButton.vue'
|
|
25
|
+
export { default as SidebarMenuItem } from './SidebarMenuItem.vue'
|
|
26
|
+
export { default as SidebarMenuSkeleton } from './SidebarMenuSkeleton.vue'
|
|
27
|
+
export { default as SidebarMenuSub } from './SidebarMenuSub.vue'
|
|
28
|
+
export { default as SidebarMenuSubButton } from './SidebarMenuSubButton.vue'
|
|
29
|
+
export { default as SidebarMenuSubItem } from './SidebarMenuSubItem.vue'
|
|
30
|
+
export { default as SidebarProvider } from './SidebarProvider.vue'
|
|
31
|
+
export { default as SidebarRail } from './SidebarRail.vue'
|
|
32
|
+
export { default as SidebarSeparator } from './SidebarSeparator.vue'
|
|
33
|
+
|
|
34
|
+
export { default as SidebarTrigger } from './SidebarTrigger.vue'
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { ClassProps } from '../../lib/types'
|
|
3
|
+
import { cn } from '../../lib/utils'
|
|
4
|
+
|
|
5
|
+
const props = defineProps<ClassProps>()
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<template>
|
|
9
|
+
<div aria-hidden="true" :class="cn('animate-pulse rounded-md bg-muted', props.class)" />
|
|
10
|
+
</template>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Skeleton } from './Skeleton.vue'
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { ClassProps } from '../../lib/types'
|
|
3
|
+
import { useI18n } from '../../composables/useI18n'
|
|
4
|
+
import { focusRing } from '../../lib/focus'
|
|
5
|
+
import { cn } from '../../lib/utils'
|
|
6
|
+
|
|
7
|
+
const props = withDefaults(
|
|
8
|
+
defineProps<ClassProps & {
|
|
9
|
+
/** Id của vùng nội dung chính, kèm dấu `#`. */
|
|
10
|
+
href?: string
|
|
11
|
+
}>(),
|
|
12
|
+
{ href: '#main' },
|
|
13
|
+
)
|
|
14
|
+
const { t } = useI18n()
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<template>
|
|
18
|
+
<!--
|
|
19
|
+
Hai yêu cầu của một skip link, và cả hai đều dễ làm hỏng:
|
|
20
|
+
|
|
21
|
+
1. **Vô hình cho tới khi được focus** — nhưng phải ẩn bằng `transform`, KHÔNG
|
|
22
|
+
phải `display:none` hay `hidden`. Hai cái đó loại phần tử khỏi chuỗi Tab
|
|
23
|
+
luôn, tức là cái link không bao giờ tới lượt để mà hiện ra.
|
|
24
|
+
`sr-only` cũng không dùng được: nó vẫn focus được nhưng lúc focus vẫn vô
|
|
25
|
+
hình, người dùng bàn phím sẽ thấy focus "biến mất" một nhịp.
|
|
26
|
+
|
|
27
|
+
2. **Là phần tử focus được ĐẦU TIÊN của trang** — đặt nó ở đâu khác thì đã
|
|
28
|
+
phải Tab qua đúng cái đống mà nó sinh ra để bỏ qua.
|
|
29
|
+
|
|
30
|
+
Đích đến phải có `tabindex="-1"`, nếu không nhảy neo chỉ cuộn màn hình chứ
|
|
31
|
+
không dời focus bàn phím — người dùng bấm xong vẫn đứng nguyên chỗ cũ.
|
|
32
|
+
-->
|
|
33
|
+
<a
|
|
34
|
+
:href="props.href"
|
|
35
|
+
:class="cn(
|
|
36
|
+
'absolute left-4 top-3 z-(--z-skip-link) -translate-y-[200%] rounded-md border border-border',
|
|
37
|
+
'bg-background px-3 py-1.5 text-sm font-medium shadow-md transition-transform',
|
|
38
|
+
'focus:translate-y-0',
|
|
39
|
+
focusRing,
|
|
40
|
+
props.class,
|
|
41
|
+
)"
|
|
42
|
+
>
|
|
43
|
+
<slot>{{ t('ui.skipLink') }}</slot>
|
|
44
|
+
</a>
|
|
45
|
+
</template>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as SkipLink } from './SkipLink.vue'
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { SliderRootEmits, SliderRootProps } from 'reka-ui'
|
|
3
|
+
import type { ClassProps } from '../../lib/types'
|
|
4
|
+
import type { SliderVariants } from './index'
|
|
5
|
+
import { SliderRange, SliderRoot, SliderThumb, SliderTrack, useForwardPropsEmits } from 'reka-ui'
|
|
6
|
+
import { computed } from 'vue'
|
|
7
|
+
import { cn } from '../../lib/utils'
|
|
8
|
+
import { sliderThumbVariants, sliderTrackVariants } from './index'
|
|
9
|
+
|
|
10
|
+
const props = withDefaults(
|
|
11
|
+
defineProps<SliderRootProps & ClassProps & {
|
|
12
|
+
size?: SliderVariants['size']
|
|
13
|
+
}>(),
|
|
14
|
+
{ size: 'md' },
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
const emits = defineEmits<SliderRootEmits>()
|
|
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
|
+
/**
|
|
27
|
+
* Số núm suy ra từ giá trị, không phải một prop riêng.
|
|
28
|
+
*
|
|
29
|
+
* Khai `:model-value="[20, 60]"` là ra thanh chọn khoảng, `[20]` là thanh một
|
|
30
|
+
* núm — không phải nhớ bật thêm cờ `range` như PrimeVue. Đọc cả `defaultValue`
|
|
31
|
+
* để bản không kiểm soát cũng đúng ngay từ lần render đầu.
|
|
32
|
+
*/
|
|
33
|
+
const thumbCount = computed(() => (props.modelValue ?? props.defaultValue ?? [0]).length)
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
<template>
|
|
37
|
+
<SliderRoot
|
|
38
|
+
v-bind="forwarded"
|
|
39
|
+
:class="cn(
|
|
40
|
+
'relative flex touch-none select-none items-center',
|
|
41
|
+
'data-[orientation=horizontal]:w-full',
|
|
42
|
+
'data-[orientation=vertical]:h-44 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col',
|
|
43
|
+
'data-[disabled]:opacity-50',
|
|
44
|
+
props.class,
|
|
45
|
+
)"
|
|
46
|
+
>
|
|
47
|
+
<SliderTrack :class="sliderTrackVariants({ size: props.size })">
|
|
48
|
+
<SliderRange class="ui-slider-range absolute bg-slider-range data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full" />
|
|
49
|
+
</SliderTrack>
|
|
50
|
+
|
|
51
|
+
<SliderThumb
|
|
52
|
+
v-for="index in thumbCount"
|
|
53
|
+
:key="index"
|
|
54
|
+
:class="sliderThumbVariants({ size: props.size })"
|
|
55
|
+
/>
|
|
56
|
+
</SliderRoot>
|
|
57
|
+
</template>
|