@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,18 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { TagsInputItemTextProps } from 'reka-ui'
|
|
3
|
+
import type { ClassProps } from '../../lib/types'
|
|
4
|
+
import { TagsInputItemText } from 'reka-ui'
|
|
5
|
+
import { computed } from 'vue'
|
|
6
|
+
import { cn } from '../../lib/utils'
|
|
7
|
+
|
|
8
|
+
const props = defineProps<TagsInputItemTextProps & ClassProps>()
|
|
9
|
+
|
|
10
|
+
const delegated = computed(() => {
|
|
11
|
+
const { class: _class, ...rest } = props
|
|
12
|
+
return rest
|
|
13
|
+
})
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<template>
|
|
17
|
+
<TagsInputItemText v-bind="delegated" :class="cn('min-w-0 truncate', props.class)" />
|
|
18
|
+
</template>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ô nhập biến từng mục thành một chip: người nhận trong ô "To:", tag của bài
|
|
3
|
+
* viết, bộ lọc đang áp.
|
|
4
|
+
*
|
|
5
|
+
* Dáng của chip lấy thẳng `badgeVariants` + `chipVariants` của `Chip`, nên hai
|
|
6
|
+
* chỗ không trôi khỏi nhau. Nhưng KHÔNG bọc chính `Chip`: nút gỡ của nó và
|
|
7
|
+
* `TagsInputItemDelete` của reka sẽ tranh nhau một việc, mà bản của reka mới là
|
|
8
|
+
* bản biết xoá khỏi model rồi trả focus về ô nhập.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export { default as InputTags } from './InputTags.vue'
|
|
12
|
+
export { default as InputTagsClear } from './InputTagsClear.vue'
|
|
13
|
+
export { default as InputTagsInput } from './InputTagsInput.vue'
|
|
14
|
+
export { default as InputTagsItem } from './InputTagsItem.vue'
|
|
15
|
+
export { default as InputTagsItemDelete } from './InputTagsItemDelete.vue'
|
|
16
|
+
export { default as InputTagsItemText } from './InputTagsItemText.vue'
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { ClassProps } from '../../lib/types'
|
|
3
|
+
import type { KbdVariants } from './index'
|
|
4
|
+
import { cn } from '../../lib/utils'
|
|
5
|
+
import { kbdVariants } from './index'
|
|
6
|
+
|
|
7
|
+
const props = defineProps<ClassProps & {
|
|
8
|
+
size?: KbdVariants['size']
|
|
9
|
+
tone?: KbdVariants['tone']
|
|
10
|
+
}>()
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<template>
|
|
14
|
+
<kbd :class="cn(kbdVariants({ size: props.size, tone: props.tone }), props.class)">
|
|
15
|
+
<slot />
|
|
16
|
+
</kbd>
|
|
17
|
+
</template>
|
|
@@ -0,0 +1,15 @@
|
|
|
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
|
+
<!-- Cũng là thẻ <kbd>, lồng đúng theo HTML spec: một tổ hợp phím là một <kbd>
|
|
10
|
+
chứa nhiều <kbd> con. Trình đọc màn hình nhờ vậy đọc ra "phím tắt" chứ
|
|
11
|
+
không phải mấy chữ rời rạc. -->
|
|
12
|
+
<kbd :class="cn('inline-flex items-center gap-1', props.class)">
|
|
13
|
+
<slot />
|
|
14
|
+
</kbd>
|
|
15
|
+
</template>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { LabelProps } from 'reka-ui'
|
|
3
|
+
import type { ClassProps } from '../../lib/types'
|
|
4
|
+
import { Label } from 'reka-ui'
|
|
5
|
+
import { cn } from '../../lib/utils'
|
|
6
|
+
|
|
7
|
+
const props = defineProps<LabelProps & ClassProps>()
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<Label
|
|
12
|
+
:for="props.for"
|
|
13
|
+
:as="props.as"
|
|
14
|
+
:as-child="props.asChild"
|
|
15
|
+
:class="cn(
|
|
16
|
+
'text-sm font-medium leading-none select-none',
|
|
17
|
+
'peer-disabled:cursor-not-allowed peer-disabled:opacity-70',
|
|
18
|
+
props.class,
|
|
19
|
+
)"
|
|
20
|
+
>
|
|
21
|
+
<slot />
|
|
22
|
+
</Label>
|
|
23
|
+
</template>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Label } from './Label.vue'
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { ListboxRootEmits, ListboxRootProps } from 'reka-ui'
|
|
3
|
+
import type { ClassProps } from '../../lib/types'
|
|
4
|
+
import { ListboxRoot, useForwardPropsEmits } from 'reka-ui'
|
|
5
|
+
import { computed } from 'vue'
|
|
6
|
+
import { cn } from '../../lib/utils'
|
|
7
|
+
|
|
8
|
+
const props = withDefaults(
|
|
9
|
+
defineProps<ListboxRootProps & ClassProps>(),
|
|
10
|
+
{ highlightOnHover: true },
|
|
11
|
+
)
|
|
12
|
+
const emits = defineEmits<ListboxRootEmits>()
|
|
13
|
+
|
|
14
|
+
const delegated = computed(() => {
|
|
15
|
+
const { class: _class, ...rest } = props
|
|
16
|
+
return rest
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
const forwarded = useForwardPropsEmits(delegated, emits)
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<template>
|
|
23
|
+
<!--
|
|
24
|
+
`highlightOnHover` bật sẵn, khác mặc định của reka.
|
|
25
|
+
|
|
26
|
+
Đây là danh sách LUÔN hiện, không phải một tấm menu vừa bung ra: con trỏ đã
|
|
27
|
+
ở trong vùng đó suốt, nên không rê chuột mà vẫn sáng theo bàn phím thì đọc
|
|
28
|
+
ra như danh sách chết. Tắt đi khi dòng nào cũng có nút riêng bên trong, vì
|
|
29
|
+
lúc đó hai vùng sáng chồng nhau.
|
|
30
|
+
-->
|
|
31
|
+
<ListboxRoot
|
|
32
|
+
v-bind="forwarded"
|
|
33
|
+
:class="cn(
|
|
34
|
+
'surface flex w-full flex-col overflow-hidden rounded-md border border-border bg-background text-sm',
|
|
35
|
+
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
|
|
36
|
+
'data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
|
37
|
+
props.class,
|
|
38
|
+
)"
|
|
39
|
+
>
|
|
40
|
+
<slot />
|
|
41
|
+
</ListboxRoot>
|
|
42
|
+
</template>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { ListboxContentProps } from 'reka-ui'
|
|
3
|
+
import type { ClassProps } from '../../lib/types'
|
|
4
|
+
import { ListboxContent } from 'reka-ui'
|
|
5
|
+
import { computed } from 'vue'
|
|
6
|
+
import { cn } from '../../lib/utils'
|
|
7
|
+
|
|
8
|
+
const props = defineProps<ListboxContentProps & ClassProps>()
|
|
9
|
+
|
|
10
|
+
const delegated = computed(() => {
|
|
11
|
+
const { class: _class, ...rest } = props
|
|
12
|
+
return rest
|
|
13
|
+
})
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<template>
|
|
17
|
+
<!-- Vùng cuộn. Chiều cao do bên gọi đặt (`max-h-*`) — danh sách dài bao nhiêu
|
|
18
|
+
thì chỉ bên gọi biết. -->
|
|
19
|
+
<ListboxContent v-bind="delegated" :class="cn('flex flex-col gap-0.5 overflow-y-auto p-1', props.class)">
|
|
20
|
+
<slot />
|
|
21
|
+
</ListboxContent>
|
|
22
|
+
</template>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { ListboxFilterEmits, ListboxFilterProps } from 'reka-ui'
|
|
3
|
+
import type { ClassProps } from '../../lib/types'
|
|
4
|
+
import { ListboxFilter, useForwardPropsEmits } from 'reka-ui'
|
|
5
|
+
import { computed } from 'vue'
|
|
6
|
+
import { Search } from '../../lib/icons'
|
|
7
|
+
import { cn } from '../../lib/utils'
|
|
8
|
+
|
|
9
|
+
const props = defineProps<ListboxFilterProps & ClassProps & { placeholder?: string }>()
|
|
10
|
+
const emits = defineEmits<ListboxFilterEmits>()
|
|
11
|
+
|
|
12
|
+
const delegated = computed(() => {
|
|
13
|
+
const { class: _class, placeholder: _placeholder, ...rest } = props
|
|
14
|
+
return rest
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
const forwarded = useForwardPropsEmits(delegated, emits)
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<template>
|
|
21
|
+
<!--
|
|
22
|
+
Ô lọc KHÔNG tự lọc gì cả — nó chỉ giữ chuỗi và chuyển phím mũi tên xuống
|
|
23
|
+
danh sách, đúng cách `Command` làm. Bên gọi tự quyết lọc thế nào; xem ghi
|
|
24
|
+
chú ở `components/command/index.ts` để biết vì sao.
|
|
25
|
+
-->
|
|
26
|
+
<div :class="cn('flex items-center gap-2 border-b border-border px-3', props.class)">
|
|
27
|
+
<Search class="size-4 shrink-0 text-muted-foreground" aria-hidden="true" />
|
|
28
|
+
<ListboxFilter
|
|
29
|
+
v-bind="forwarded"
|
|
30
|
+
:placeholder="props.placeholder"
|
|
31
|
+
class="h-9 w-full bg-transparent text-sm outline-none placeholder:text-muted-foreground"
|
|
32
|
+
/>
|
|
33
|
+
</div>
|
|
34
|
+
</template>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { ListboxGroupProps } from 'reka-ui'
|
|
3
|
+
import type { ClassProps } from '../../lib/types'
|
|
4
|
+
import { ListboxGroup, ListboxGroupLabel } from 'reka-ui'
|
|
5
|
+
import { computed } from 'vue'
|
|
6
|
+
import { cn } from '../../lib/utils'
|
|
7
|
+
|
|
8
|
+
const props = defineProps<ListboxGroupProps & ClassProps & { heading?: string }>()
|
|
9
|
+
|
|
10
|
+
const delegated = computed(() => {
|
|
11
|
+
const { class: _class, heading: _heading, ...rest } = props
|
|
12
|
+
return rest
|
|
13
|
+
})
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<template>
|
|
17
|
+
<!-- Nhãn nhóm phải là `ListboxGroupLabel` chứ không phải một `<div>` tự viết:
|
|
18
|
+
reka nối nó vào nhóm bằng `aria-labelledby`, nên trình đọc màn hình mới
|
|
19
|
+
đọc ra "Nhóm X, mục 2 trên 5". -->
|
|
20
|
+
<ListboxGroup v-bind="delegated" :class="cn('flex flex-col gap-0.5', props.class)">
|
|
21
|
+
<ListboxGroupLabel
|
|
22
|
+
v-if="props.heading || $slots.heading"
|
|
23
|
+
class="px-2 py-1.5 text-xs font-medium text-muted-foreground"
|
|
24
|
+
>
|
|
25
|
+
<slot name="heading">
|
|
26
|
+
{{ props.heading }}
|
|
27
|
+
</slot>
|
|
28
|
+
</ListboxGroupLabel>
|
|
29
|
+
<slot />
|
|
30
|
+
</ListboxGroup>
|
|
31
|
+
</template>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { ListboxItemEmits, ListboxItemProps } from 'reka-ui'
|
|
3
|
+
import type { ClassProps } from '../../lib/types'
|
|
4
|
+
import { ListboxItem, ListboxItemIndicator, 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, cùng lý do với SelectItem: generic làm TS mất thông
|
|
10
|
+
// tin "value là bắt buộc" lúc forward prop xuống primitive của reka.
|
|
11
|
+
const props = defineProps<ListboxItemProps & ClassProps>()
|
|
12
|
+
const emits = defineEmits<ListboxItemEmits>()
|
|
13
|
+
|
|
14
|
+
const delegated = computed(() => {
|
|
15
|
+
const { class: _class, ...rest } = props
|
|
16
|
+
return rest
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
const forwarded = useForwardPropsEmits(delegated, emits)
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<template>
|
|
23
|
+
<!--
|
|
24
|
+
Hai trạng thái KHÁC NHAU, và trộn chúng là lỗi hay gặp nhất ở listbox:
|
|
25
|
+
`data-highlighted` là dòng bàn phím đang đứng, `data-state=checked` là dòng
|
|
26
|
+
đã chọn. Ở chế độ nhiều lựa chọn, hai dòng đó thường không phải một.
|
|
27
|
+
-->
|
|
28
|
+
<ListboxItem
|
|
29
|
+
v-bind="forwarded"
|
|
30
|
+
:class="cn(
|
|
31
|
+
'relative flex w-full cursor-default select-none items-center gap-2 rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none transition-colors',
|
|
32
|
+
'data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground',
|
|
33
|
+
'data-[state=checked]:font-medium',
|
|
34
|
+
'data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
|
35
|
+
'[&_svg]:size-4 [&_svg]:shrink-0',
|
|
36
|
+
props.class,
|
|
37
|
+
)"
|
|
38
|
+
>
|
|
39
|
+
<slot />
|
|
40
|
+
<span class="absolute right-2 flex size-4 items-center justify-center">
|
|
41
|
+
<ListboxItemIndicator>
|
|
42
|
+
<Check class="size-4" />
|
|
43
|
+
</ListboxItemIndicator>
|
|
44
|
+
</span>
|
|
45
|
+
</ListboxItem>
|
|
46
|
+
</template>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Danh sách chọn LUÔN HIỆN. Cùng primitive với `Command`, khác cách đóng khung.
|
|
3
|
+
*
|
|
4
|
+
* | dùng khi | lấy cái nào |
|
|
5
|
+
* |---|---|
|
|
6
|
+
* | danh sách ngắn, luôn thấy, chọn một hoặc nhiều | `Listbox` |
|
|
7
|
+
* | cùng lựa chọn đó nhưng thu vào một nút | `Select` |
|
|
8
|
+
* | gõ để lọc, danh sách dài, mở bằng phím tắt | `Command` |
|
|
9
|
+
*
|
|
10
|
+
* `ListboxFilter` có ở đây cho trường hợp danh sách hơi dài nhưng vẫn muốn nó
|
|
11
|
+
* nằm nguyên trong trang. Nó **không tự lọc** — bên gọi tự quyết, cùng lý do đã
|
|
12
|
+
* ghi ở `components/command/index.ts`.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export { default as Listbox } from './Listbox.vue'
|
|
16
|
+
export { default as ListboxContent } from './ListboxContent.vue'
|
|
17
|
+
export { default as ListboxFilter } from './ListboxFilter.vue'
|
|
18
|
+
export { default as ListboxGroup } from './ListboxGroup.vue'
|
|
19
|
+
export { default as ListboxItem } from './ListboxItem.vue'
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { ClassProps } from '../../lib/types'
|
|
3
|
+
import { computed, nextTick, ref, watch } from 'vue'
|
|
4
|
+
import { focusRing, invalidRing } from '../../lib/focus'
|
|
5
|
+
import { cn } from '../../lib/utils'
|
|
6
|
+
import { dataBefore, formatMask, parseMask, toRaw } from './index'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Gốc là một `<div>` bọc ngoài, nên thuộc tính rơi tự do phải chuyển tay vào
|
|
10
|
+
* đúng cái `<input>` — cùng lý do đã ghi ở `Input.vue`.
|
|
11
|
+
*/
|
|
12
|
+
defineOptions({ inheritAttrs: false })
|
|
13
|
+
|
|
14
|
+
const props = withDefaults(
|
|
15
|
+
defineProps<ClassProps & {
|
|
16
|
+
/** `9` là chữ số, `a` là chữ cái, `*` là chữ hoặc số. Còn lại là cố định. */
|
|
17
|
+
mask: string
|
|
18
|
+
/** Ký tự giữ chỗ cho ô chưa điền. */
|
|
19
|
+
slotChar?: string
|
|
20
|
+
/** Giá trị là dữ liệu THÔ, không kèm ký tự cố định. */
|
|
21
|
+
unmask?: boolean
|
|
22
|
+
invalid?: boolean
|
|
23
|
+
disabled?: boolean
|
|
24
|
+
size?: 'sm' | 'default'
|
|
25
|
+
placeholder?: string
|
|
26
|
+
}>(),
|
|
27
|
+
{ slotChar: '_', unmask: false, size: 'default' },
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
const model = defineModel<string>({ default: '' })
|
|
31
|
+
|
|
32
|
+
const input = ref<HTMLInputElement>()
|
|
33
|
+
const focused = ref(false)
|
|
34
|
+
|
|
35
|
+
const slots = computed(() => parseMask(props.mask))
|
|
36
|
+
|
|
37
|
+
/** Dữ liệu thật, không định dạng. Đây mới là nguồn sự thật của component. */
|
|
38
|
+
const raw = ref(toRaw(model.value, slots.value))
|
|
39
|
+
|
|
40
|
+
const result = computed(() => formatMask(raw.value, slots.value, props.slotChar))
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Khuôn chỉ hiện ra khi ô ĐANG focus hoặc ĐÃ có gì đó.
|
|
44
|
+
*
|
|
45
|
+
* PrimeVue hiện `(___) ___-____` mọi lúc. Với ô rỗng thì đó là một ô trông như
|
|
46
|
+
* đã điền sẵn, và trình đọc màn hình đọc ra một tràng gạch dưới trước cả khi
|
|
47
|
+
* người dùng biết mình đang ở đâu. Placeholder làm đúng việc đó tốt hơn.
|
|
48
|
+
*/
|
|
49
|
+
const display = computed(() => {
|
|
50
|
+
if (raw.value.length === 0 && !focused.value)
|
|
51
|
+
return ''
|
|
52
|
+
return result.value.text
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
/** Đủ mọi ô dữ liệu thì mới coi là hoàn chỉnh. */
|
|
56
|
+
const complete = computed(() =>
|
|
57
|
+
raw.value.length === slots.value.filter(slot => slot.accepts !== undefined).length,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
const inputMode = computed(() =>
|
|
61
|
+
props.mask.includes('a') || props.mask.includes('*') ? undefined : 'numeric',
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
function publish(): void {
|
|
65
|
+
model.value = props.unmask ? raw.value : result.value.filled
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Ghi thẳng vào DOM rồi đặt con trỏ — Vue không kịp làm việc này giữa hai phím. */
|
|
69
|
+
function render(caret: number): void {
|
|
70
|
+
const el = input.value
|
|
71
|
+
if (el === undefined)
|
|
72
|
+
return
|
|
73
|
+
el.value = display.value
|
|
74
|
+
el.setSelectionRange(caret, caret)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function onInput(): void {
|
|
78
|
+
const el = input.value
|
|
79
|
+
if (el === undefined)
|
|
80
|
+
return
|
|
81
|
+
|
|
82
|
+
// Đếm số ký tự dữ liệu nằm TRƯỚC con trỏ, rồi đặt lại con trỏ ngay sau đúng
|
|
83
|
+
// chừng ấy ô. Nhảy thẳng về cuối chuỗi thì gõ chen vào giữa một số điện thoại
|
|
84
|
+
// đã điền dở sẽ hất con trỏ đi mất sau mỗi phím.
|
|
85
|
+
const before = toRaw(el.value.slice(0, el.selectionStart ?? 0), slots.value).length
|
|
86
|
+
|
|
87
|
+
raw.value = toRaw(el.value, slots.value)
|
|
88
|
+
publish()
|
|
89
|
+
void nextTick(() => render(caretAfter(before)))
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Backspace và Delete phải tự viết, không để trình duyệt xử lý.
|
|
94
|
+
*
|
|
95
|
+
* Mặc định nó xoá ký tự ngay trước con trỏ, mà ký tự đó thường là một ký tự CỐ
|
|
96
|
+
* ĐỊNH. Xoá xong thì `toRaw` vẫn ra đúng chuỗi cũ, khuôn dựng lại y nguyên, và
|
|
97
|
+
* người dùng thấy phím Backspace không làm gì cả — bấm bao nhiêu lần cũng vậy.
|
|
98
|
+
* Nên phím đó phải nhắm vào ô DỮ LIỆU, không nhắm vào ký tự.
|
|
99
|
+
*/
|
|
100
|
+
function onKeydown(event: KeyboardEvent): void {
|
|
101
|
+
if (event.key !== 'Backspace' && event.key !== 'Delete')
|
|
102
|
+
return
|
|
103
|
+
|
|
104
|
+
const el = input.value
|
|
105
|
+
if (el === undefined)
|
|
106
|
+
return
|
|
107
|
+
|
|
108
|
+
event.preventDefault()
|
|
109
|
+
|
|
110
|
+
const start = el.selectionStart ?? 0
|
|
111
|
+
const end = el.selectionEnd ?? start
|
|
112
|
+
|
|
113
|
+
// Kẹp vào độ dài dữ liệu THẬT. Bấm chuột vào vùng giữ chỗ rồi bấm Backspace
|
|
114
|
+
// thì `dataBefore` đếm cả những ô còn trống, ra một chỉ số nằm ngoài `raw`,
|
|
115
|
+
// và phím đó im lặng không làm gì — đúng cái mà nó sinh ra để tránh.
|
|
116
|
+
const from = Math.min(dataBefore(slots.value, start), raw.value.length)
|
|
117
|
+
|
|
118
|
+
if (end > start) {
|
|
119
|
+
// Bôi đen rồi xoá: bỏ đúng những ô dữ liệu nằm trong vùng bôi đen.
|
|
120
|
+
const to = Math.min(dataBefore(slots.value, end), raw.value.length)
|
|
121
|
+
raw.value = raw.value.slice(0, from) + raw.value.slice(to)
|
|
122
|
+
publish()
|
|
123
|
+
void nextTick(() => render(caretAfter(from)))
|
|
124
|
+
return
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const index = event.key === 'Backspace' ? from - 1 : from
|
|
128
|
+
if (index < 0 || index >= raw.value.length)
|
|
129
|
+
return
|
|
130
|
+
|
|
131
|
+
raw.value = raw.value.slice(0, index) + raw.value.slice(index + 1)
|
|
132
|
+
publish()
|
|
133
|
+
void nextTick(() => render(caretAfter(index)))
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** Vị trí con trỏ ứng với ô dữ liệu thứ `index`. */
|
|
137
|
+
function caretForIndex(index: number): number {
|
|
138
|
+
if (index <= 0)
|
|
139
|
+
return slots.value.findIndex(slot => slot.accepts !== undefined)
|
|
140
|
+
let seen = 0
|
|
141
|
+
for (const [position, slot] of slots.value.entries()) {
|
|
142
|
+
if (slot.accepts === undefined)
|
|
143
|
+
continue
|
|
144
|
+
if (seen === index)
|
|
145
|
+
return position
|
|
146
|
+
seen += 1
|
|
147
|
+
}
|
|
148
|
+
return result.value.text.length
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** Vị trí con trỏ sau khi đã điền `count` ô dữ liệu. */
|
|
152
|
+
function caretAfter(count: number): number {
|
|
153
|
+
return count <= 0 ? caretForIndex(0) : caretForIndex(count - 1) + 1
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function onFocus(): void {
|
|
157
|
+
focused.value = true
|
|
158
|
+
// Vào bằng Tab thì con trỏ đứng ngay sau ô đã điền cuối cùng. Vào bằng chuột
|
|
159
|
+
// thì KHÔNG: `mouseup` đặt lại con trỏ theo chỗ bấm, sau cả `focus`. Đó là
|
|
160
|
+
// hành vi đúng của một ô nhập, và việc gõ vẫn chèn đúng chỗ.
|
|
161
|
+
void nextTick(() => render(caretAfter(raw.value.length)))
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function onBlur(): void {
|
|
165
|
+
focused.value = false
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/** Giá trị đổi từ bên ngoài thì dựng lại — nhưng đừng đè lên thứ đang gõ. */
|
|
169
|
+
watch(model, (value) => {
|
|
170
|
+
const next = props.unmask ? value : toRaw(value, slots.value)
|
|
171
|
+
if (next !== raw.value && !focused.value)
|
|
172
|
+
raw.value = toRaw(value, slots.value)
|
|
173
|
+
})
|
|
174
|
+
</script>
|
|
175
|
+
|
|
176
|
+
<template>
|
|
177
|
+
<div class="relative w-full">
|
|
178
|
+
<input
|
|
179
|
+
ref="input"
|
|
180
|
+
v-bind="$attrs"
|
|
181
|
+
type="text"
|
|
182
|
+
:value="display"
|
|
183
|
+
:placeholder="props.placeholder"
|
|
184
|
+
:disabled="props.disabled"
|
|
185
|
+
:inputmode="inputMode"
|
|
186
|
+
:aria-invalid="props.invalid || undefined"
|
|
187
|
+
:data-invalid="props.invalid || undefined"
|
|
188
|
+
:data-complete="complete || undefined"
|
|
189
|
+
autocomplete="off"
|
|
190
|
+
:class="cn(
|
|
191
|
+
'flex w-full rounded-md border border-input bg-background py-1 shadow-xs transition-colors',
|
|
192
|
+
props.size === 'sm' ? 'h-(--ui-field-height-sm) px-(--ui-field-padding-x-sm) text-(length:--ui-field-text-sm)' : 'h-(--ui-field-height-md) px-(--ui-field-padding-x-md) text-sm',
|
|
193
|
+
'placeholder:text-muted-foreground',
|
|
194
|
+
focusRing,
|
|
195
|
+
'disabled:cursor-not-allowed disabled:opacity-50',
|
|
196
|
+
invalidRing,
|
|
197
|
+
props.class,
|
|
198
|
+
)"
|
|
199
|
+
@input="onInput"
|
|
200
|
+
@keydown="onKeydown"
|
|
201
|
+
@focus="onFocus"
|
|
202
|
+
@blur="onBlur"
|
|
203
|
+
>
|
|
204
|
+
</div>
|
|
205
|
+
</template>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bốn hàm khuôn giờ ở `src/variants/lib/mask` — logic thuần, không dính
|
|
3
|
+
* framework, nên bản React đọc CÙNG một file thay vì chép lại. Re-export ở đây
|
|
4
|
+
* để chỗ nào đang `import { toRaw } from '../mask'` không phải sửa.
|
|
5
|
+
*/
|
|
6
|
+
export {
|
|
7
|
+
dataBefore,
|
|
8
|
+
formatMask,
|
|
9
|
+
type FormatResult,
|
|
10
|
+
type MaskSlot,
|
|
11
|
+
parseMask,
|
|
12
|
+
toRaw,
|
|
13
|
+
} from '../../variants/lib/mask'
|
|
14
|
+
|
|
15
|
+
export { default as Mask } from './Mask.vue'
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { MenubarRootEmits, MenubarRootProps } from 'reka-ui'
|
|
3
|
+
import type { ClassProps } from '../../lib/types'
|
|
4
|
+
import { MenubarRoot, useForwardPropsEmits } from 'reka-ui'
|
|
5
|
+
import { computed } from 'vue'
|
|
6
|
+
import { cn } from '../../lib/utils'
|
|
7
|
+
|
|
8
|
+
const props = defineProps<MenubarRootProps & ClassProps>()
|
|
9
|
+
const emits = defineEmits<MenubarRootEmits>()
|
|
10
|
+
|
|
11
|
+
const delegated = computed(() => {
|
|
12
|
+
const { class: _class, ...rest } = props
|
|
13
|
+
return rest
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
const forwarded = useForwardPropsEmits(delegated, emits)
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<template>
|
|
20
|
+
<MenubarRoot
|
|
21
|
+
v-bind="forwarded"
|
|
22
|
+
:class="cn('flex h-9 items-center gap-1 rounded-md border border-border bg-background p-1 shadow-xs', props.class)"
|
|
23
|
+
>
|
|
24
|
+
<slot />
|
|
25
|
+
</MenubarRoot>
|
|
26
|
+
</template>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { MenubarCheckboxItemEmits, MenubarCheckboxItemProps } from 'reka-ui'
|
|
3
|
+
import type { ClassProps } from '../../lib/types'
|
|
4
|
+
import { MenubarCheckboxItem, MenubarItemIndicator, useForwardPropsEmits } from 'reka-ui'
|
|
5
|
+
import { computed } from 'vue'
|
|
6
|
+
import { Check } from '../../lib/icons'
|
|
7
|
+
import { menuIndicatorItemClass, menuIndicatorSlotClass } from '../../lib/menu-styles'
|
|
8
|
+
import { cn } from '../../lib/utils'
|
|
9
|
+
|
|
10
|
+
const props = defineProps<MenubarCheckboxItemProps & ClassProps>()
|
|
11
|
+
const emits = defineEmits<MenubarCheckboxItemEmits>()
|
|
12
|
+
|
|
13
|
+
const delegated = computed(() => {
|
|
14
|
+
const { class: _class, ...rest } = props
|
|
15
|
+
return rest
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
const forwarded = useForwardPropsEmits(delegated, emits)
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<template>
|
|
22
|
+
<MenubarCheckboxItem v-bind="forwarded" :class="cn(menuIndicatorItemClass, props.class)">
|
|
23
|
+
<span :class="menuIndicatorSlotClass">
|
|
24
|
+
<MenubarItemIndicator>
|
|
25
|
+
<Check class="size-4" />
|
|
26
|
+
</MenubarItemIndicator>
|
|
27
|
+
</span>
|
|
28
|
+
<slot />
|
|
29
|
+
</MenubarCheckboxItem>
|
|
30
|
+
</template>
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { FocusOutsideEvent, MenubarContentProps, PointerDownOutsideEvent } from 'reka-ui'
|
|
3
|
+
import type { ClassProps } from '../../lib/types'
|
|
4
|
+
import { MenubarContent, MenubarPortal, useForwardPropsEmits } from 'reka-ui'
|
|
5
|
+
import { computed } from 'vue'
|
|
6
|
+
import { menuContentClass } from '../../lib/menu-styles'
|
|
7
|
+
import { cn } from '../../lib/utils'
|
|
8
|
+
|
|
9
|
+
const props = withDefaults(
|
|
10
|
+
defineProps<MenubarContentProps & ClassProps>(),
|
|
11
|
+
{ align: 'start', sideOffset: 6, alignOffset: -4, collisionPadding: 8 },
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
/*
|
|
15
|
+
* Khai tay danh sách emit, không dùng `MenubarContentEmits`.
|
|
16
|
+
*
|
|
17
|
+
* reka chỉ export `MenubarSubContentEmits`, không có bản cho content thường —
|
|
18
|
+
* năm sự kiện dưới đây chép từ chính khai báo kiểu của component.
|
|
19
|
+
*
|
|
20
|
+
* Và không bỏ đi được: gốc của component này là `MenubarPortal`, nên listener
|
|
21
|
+
* rơi tự do sẽ dính vào portal thay vì vào tấm menu, rồi im lặng không chạy.
|
|
22
|
+
*/
|
|
23
|
+
const emits = defineEmits<{
|
|
24
|
+
escapeKeyDown: [event: KeyboardEvent]
|
|
25
|
+
pointerDownOutside: [event: PointerDownOutsideEvent]
|
|
26
|
+
focusOutside: [event: FocusOutsideEvent]
|
|
27
|
+
interactOutside: [event: PointerDownOutsideEvent | FocusOutsideEvent]
|
|
28
|
+
closeAutoFocus: [event: Event]
|
|
29
|
+
}>()
|
|
30
|
+
|
|
31
|
+
const delegated = computed(() => {
|
|
32
|
+
const { class: _class, ...rest } = props
|
|
33
|
+
return rest
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
const forwarded = useForwardPropsEmits(delegated, emits)
|
|
37
|
+
</script>
|
|
38
|
+
|
|
39
|
+
<template>
|
|
40
|
+
<MenubarPortal>
|
|
41
|
+
<MenubarContent
|
|
42
|
+
v-bind="forwarded"
|
|
43
|
+
:class="cn(
|
|
44
|
+
menuContentClass,
|
|
45
|
+
'max-h-[var(--reka-menubar-content-available-height)] min-w-[12rem] overflow-y-auto',
|
|
46
|
+
props.class,
|
|
47
|
+
)"
|
|
48
|
+
>
|
|
49
|
+
<slot />
|
|
50
|
+
</MenubarContent>
|
|
51
|
+
</MenubarPortal>
|
|
52
|
+
</template>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { MenubarGroupProps } from 'reka-ui'
|
|
3
|
+
import { MenubarGroup } from 'reka-ui'
|
|
4
|
+
|
|
5
|
+
const props = defineProps<MenubarGroupProps>()
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<template>
|
|
9
|
+
<MenubarGroup v-bind="props">
|
|
10
|
+
<slot />
|
|
11
|
+
</MenubarGroup>
|
|
12
|
+
</template>
|