@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,31 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { ClassProps } from '../../lib/types'
|
|
3
|
+
import { AlertCircle } from '../../lib/icons'
|
|
4
|
+
import { cn } from '../../lib/utils'
|
|
5
|
+
|
|
6
|
+
const props = defineProps<ClassProps & { id?: string, message?: string }>()
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<template>
|
|
10
|
+
<!--
|
|
11
|
+
Icon là bắt buộc, không phải trang trí: viền đỏ cộng chữ đỏ đều là tín hiệu
|
|
12
|
+
MÀU, mà WCAG 1.4.1 cấm mã hoá ý nghĩa chỉ bằng màu. Người bị mù màu đỏ-lục
|
|
13
|
+
thấy dòng này cùng tông với chữ thường, nên phải có một dấu hiệu không phụ
|
|
14
|
+
thuộc màu đứng cạnh.
|
|
15
|
+
|
|
16
|
+
`aria-hidden` vì chữ ngay bên cạnh đã nói đủ — trình đọc màn hình đọc thêm
|
|
17
|
+
"hình ảnh cảnh báo" chỉ làm dài thêm câu.
|
|
18
|
+
|
|
19
|
+
`mt-px` chứ không phải `items-center`: dòng lỗi có thể dài hai dòng, lúc đó
|
|
20
|
+
căn giữa sẽ đẩy icon xuống giữa khối chữ. Neo theo dòng đầu mới đúng.
|
|
21
|
+
-->
|
|
22
|
+
<p
|
|
23
|
+
v-if="props.message"
|
|
24
|
+
:id="props.id"
|
|
25
|
+
role="alert"
|
|
26
|
+
:class="cn('flex items-start gap-1.5 text-xs font-medium text-destructive', props.class)"
|
|
27
|
+
>
|
|
28
|
+
<AlertCircle class="mt-px size-3.5 shrink-0" aria-hidden="true" />
|
|
29
|
+
<span>{{ props.message }}</span>
|
|
30
|
+
</p>
|
|
31
|
+
</template>
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { AnyFormApi } from '@tanstack/vue-form'
|
|
2
|
+
import type { ComputedRef, InjectionKey, Ref } from 'vue'
|
|
3
|
+
import { inject, provide } from 'vue'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Những gì `Form` chuyền xuống cho `FormField`.
|
|
7
|
+
*
|
|
8
|
+
* TanStack Form **không có context sẵn**: `useField` bắt buộc nhận `form` qua
|
|
9
|
+
* tham số, nên khuôn dùng chính thống của nó là `<form.Field>` viết ngay trong
|
|
10
|
+
* template của màn đang dùng. Ở đây tự provide/inject để giữ nguyên API cũ —
|
|
11
|
+
* `<FormField name="email">` là một component rời, không cần biết instance form
|
|
12
|
+
* nằm ở đâu. Nhờ vậy đổi thư viện form không phải sửa dòng nào trong
|
|
13
|
+
* `apps/admin`.
|
|
14
|
+
*/
|
|
15
|
+
export interface FormContext {
|
|
16
|
+
/** Kiểu `AnyFormApi` vì `FormField` không cần biết kiểu giá trị của form bao ngoài. */
|
|
17
|
+
api: AnyFormApi
|
|
18
|
+
/**
|
|
19
|
+
* Lỗi do server trả về, giữ **ngoài** errorMap của TanStack. Xem chú thích
|
|
20
|
+
* `setErrors` trong `Form.vue` để biết vì sao không dùng khoá `onServer`.
|
|
21
|
+
*/
|
|
22
|
+
serverErrors: Ref<Record<string, string>>
|
|
23
|
+
/**
|
|
24
|
+
* Form đã bấm gửi ít nhất một lần chưa. `FormField` cần biết để hiện lỗi cho
|
|
25
|
+
* field người dùng **chưa hề chạm tới** — bỏ trống rồi bấm gửi thì vẫn phải
|
|
26
|
+
* báo.
|
|
27
|
+
*
|
|
28
|
+
* Phải chuyền xuống dưới dạng đã bọc sẵn, không để `FormField` tự đọc
|
|
29
|
+
* `form.state.submissionAttempts`: `AnyFormApi` là kiểu của core, `.state`
|
|
30
|
+
* của nó là getter trần trên store chứ **không** reactive trong Vue. Đọc
|
|
31
|
+
* thẳng thì computed không track, và bấm gửi sẽ không hiện lỗi nào — đã dính
|
|
32
|
+
* đúng lỗi đó một lần. Chỗ duy nhất lấy được bản reactive là `useSelector`
|
|
33
|
+
* của adapter Vue, mà chỉ `Form.vue` mới có.
|
|
34
|
+
*
|
|
35
|
+
* (`useField` thì khác: api nó trả về CÓ state reactive, nên `FormField` đọc
|
|
36
|
+
* `api.state.meta` trực tiếp được.)
|
|
37
|
+
*/
|
|
38
|
+
submitted: ComputedRef<boolean>
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const formContextKey = Symbol('woodblock-form') as InjectionKey<FormContext>
|
|
42
|
+
|
|
43
|
+
export function provideFormContext(context: FormContext): void {
|
|
44
|
+
provide(formContextKey, context)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function useFormContext(): FormContext {
|
|
48
|
+
const context = inject(formContextKey, null)
|
|
49
|
+
|
|
50
|
+
if (!context)
|
|
51
|
+
throw new Error('FormField phải nằm bên trong <Form>.')
|
|
52
|
+
|
|
53
|
+
return context
|
|
54
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lên `src/variants/lib/form-errors` — `form-core` là chung cho cả hai
|
|
3
|
+
* adapter, nên bản React gặp đúng hình dạng errorMap này. Hai bản là hai cơ hội
|
|
4
|
+
* để một bên quên nhánh MẢNG, mà nhánh đó hỏng âm thầm.
|
|
5
|
+
*/
|
|
6
|
+
export { type FieldErrorMap, firstErrorMessage } from '../../variants/lib/form-errors'
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { default as Form } from './Form.vue'
|
|
2
|
+
export { default as FormDescription } from './FormDescription.vue'
|
|
3
|
+
export { default as FormField } from './FormField.vue'
|
|
4
|
+
export { default as FormItem } from './FormItem.vue'
|
|
5
|
+
export { default as FormLabel } from './FormLabel.vue'
|
|
6
|
+
export { default as FormMessage } from './FormMessage.vue'
|
|
7
|
+
export type { FieldSlotProps, FormExpose } from './types'
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { Ref } from 'vue'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Props mà FormField truyền xuống control bên trong.
|
|
5
|
+
* Mục tiêu: `v-bind="field"` là đủ để một control (Input, Select, Switch...)
|
|
6
|
+
* nối dây vào form, không cần biết gì thêm.
|
|
7
|
+
*
|
|
8
|
+
* `T` mặc định là string vì phần lớn field là text input.
|
|
9
|
+
* Với kiểu khác, khai báo `:default-value` để TS suy ra:
|
|
10
|
+
*
|
|
11
|
+
* <FormField name="age" :default-value="0" /> -> T = number
|
|
12
|
+
* <FormField name="active" :default-value="false" /> -> T = boolean
|
|
13
|
+
*/
|
|
14
|
+
export interface FieldBindings<T = string> {
|
|
15
|
+
'modelValue': T
|
|
16
|
+
/**
|
|
17
|
+
* Nhận `unknown` chứ không phải `T`: tham số của hàm là contravariant,
|
|
18
|
+
* một handler chỉ nhận `string` KHÔNG gán được vào control khai báo
|
|
19
|
+
* `(value: string | number | null) => void`. `unknown` nhận được mọi control.
|
|
20
|
+
*/
|
|
21
|
+
'onUpdate:modelValue': (value: unknown) => void
|
|
22
|
+
'onBlur': (event?: Event) => void
|
|
23
|
+
'name': string
|
|
24
|
+
'id': string
|
|
25
|
+
'aria-describedby': string | undefined
|
|
26
|
+
'aria-invalid': true | undefined
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface FieldSlotProps<T = string> {
|
|
30
|
+
/** Bind thẳng vào control: <Input v-bind="field" /> */
|
|
31
|
+
field: FieldBindings<T>
|
|
32
|
+
value: T
|
|
33
|
+
setValue: (value: T) => void
|
|
34
|
+
errorMessage: string | undefined
|
|
35
|
+
invalid: boolean
|
|
36
|
+
/** id của control, dùng khi cần nối label thủ công */
|
|
37
|
+
id: string
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Những gì `<Form>` expose ra ngoài qua template ref.
|
|
42
|
+
*
|
|
43
|
+
* Khai thành interface riêng để bên gọi tự viết kiểu cho `useTemplateRef` —
|
|
44
|
+
* `Form` là generic component nên `InstanceType<typeof Form>` không dùng được.
|
|
45
|
+
*/
|
|
46
|
+
export interface FormExpose {
|
|
47
|
+
/** Về giá trị khởi tạo, xoá luôn lỗi server đang hiện. */
|
|
48
|
+
resetForm: () => void
|
|
49
|
+
/** Map lỗi của API (ModelState / ProblemDetails.errors) về từng field. */
|
|
50
|
+
setErrors: (fields: Record<string, string>) => void
|
|
51
|
+
setFieldError: (name: string, message: string) => void
|
|
52
|
+
values: Readonly<Ref<Record<string, unknown>>>
|
|
53
|
+
errors: Readonly<Ref<Record<string, string | undefined>>>
|
|
54
|
+
isSubmitting: Readonly<Ref<boolean>>
|
|
55
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { HoverCardRootEmits, HoverCardRootProps } from 'reka-ui'
|
|
3
|
+
import { HoverCardRoot, useForwardPropsEmits } from 'reka-ui'
|
|
4
|
+
|
|
5
|
+
const props = withDefaults(
|
|
6
|
+
defineProps<HoverCardRootProps>(),
|
|
7
|
+
{
|
|
8
|
+
/**
|
|
9
|
+
* Reka mặc định 700ms — quá lâu cho một thẻ xem nhanh: rê qua tên người rồi
|
|
10
|
+
* chờ gần một giây mới thấy gì thì người ta đã bỏ đi. 300ms là mức vẫn chặn
|
|
11
|
+
* được thẻ nhảy ra khi chỉ lướt chuột ngang qua.
|
|
12
|
+
*/
|
|
13
|
+
openDelay: 300,
|
|
14
|
+
/** Đóng chậm hơn mở, để còn kịp rê chuột từ trigger sang chính thẻ. */
|
|
15
|
+
closeDelay: 200,
|
|
16
|
+
},
|
|
17
|
+
)
|
|
18
|
+
const emits = defineEmits<HoverCardRootEmits>()
|
|
19
|
+
|
|
20
|
+
const forwarded = useForwardPropsEmits(props, emits)
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<template>
|
|
24
|
+
<HoverCardRoot v-bind="forwarded">
|
|
25
|
+
<slot />
|
|
26
|
+
</HoverCardRoot>
|
|
27
|
+
</template>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { HoverCardContentProps } from 'reka-ui'
|
|
3
|
+
import type { ClassProps } from '../../lib/types'
|
|
4
|
+
import { HoverCardContent, HoverCardPortal } from 'reka-ui'
|
|
5
|
+
import { computed } from 'vue'
|
|
6
|
+
import { cn } from '../../lib/utils'
|
|
7
|
+
|
|
8
|
+
const props = withDefaults(
|
|
9
|
+
defineProps<HoverCardContentProps & ClassProps>(),
|
|
10
|
+
{ sideOffset: 6, align: 'center', collisionPadding: 8 },
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
const delegated = computed(() => {
|
|
14
|
+
const { class: _class, ...rest } = props
|
|
15
|
+
return rest
|
|
16
|
+
})
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<template>
|
|
20
|
+
<HoverCardPortal>
|
|
21
|
+
<HoverCardContent
|
|
22
|
+
v-bind="delegated"
|
|
23
|
+
:class="cn(
|
|
24
|
+
'surface z-(--z-overlay) w-64 rounded-md border border-border bg-popover p-4 text-popover-foreground shadow-md outline-none',
|
|
25
|
+
'data-[state=open]:animate-in data-[state=closed]:animate-out',
|
|
26
|
+
'data-[state=open]:fade-in-0 data-[state=closed]:fade-out-0',
|
|
27
|
+
'data-[state=open]:zoom-in-95 data-[state=closed]:zoom-out-95',
|
|
28
|
+
'data-[side=bottom]:slide-in-from-top-2 data-[side=top]:slide-in-from-bottom-2',
|
|
29
|
+
'data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2',
|
|
30
|
+
props.class,
|
|
31
|
+
)"
|
|
32
|
+
>
|
|
33
|
+
<slot />
|
|
34
|
+
</HoverCardContent>
|
|
35
|
+
</HoverCardPortal>
|
|
36
|
+
</template>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { HoverCardTriggerProps } from 'reka-ui'
|
|
3
|
+
import { HoverCardTrigger } from 'reka-ui'
|
|
4
|
+
|
|
5
|
+
const props = defineProps<HoverCardTriggerProps>()
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<template>
|
|
9
|
+
<HoverCardTrigger v-bind="props">
|
|
10
|
+
<slot />
|
|
11
|
+
</HoverCardTrigger>
|
|
12
|
+
</template>
|
|
@@ -0,0 +1,26 @@
|
|
|
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
|
|
10
|
+
:class="cn(
|
|
11
|
+
'relative w-full',
|
|
12
|
+
|
|
13
|
+
// Ô cao 52px: nhãn 6..22, giá trị 24..44, chừa 8 ở đáy.
|
|
14
|
+
'[&_input]:h-13 [&_input]:pt-6 [&_input]:pb-2',
|
|
15
|
+
|
|
16
|
+
// Nhãn đứng yên một chỗ, nên không có transition nào ở đây cả.
|
|
17
|
+
'[&>label]:pointer-events-none [&>label]:absolute [&>label]:left-3 [&>label]:top-1.5 [&>label]:z-(--z-raised)',
|
|
18
|
+
'[&>label]:text-xs [&>label]:font-normal [&>label]:text-muted-foreground',
|
|
19
|
+
'has-[input:disabled]:[&>label]:opacity-50',
|
|
20
|
+
|
|
21
|
+
props.class,
|
|
22
|
+
)"
|
|
23
|
+
>
|
|
24
|
+
<slot />
|
|
25
|
+
</div>
|
|
26
|
+
</template>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as IftaLabel } from './IftaLabel.vue'
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
export * from './accordion'
|
|
2
|
+
export * from './alert'
|
|
3
|
+
export * from './avatar'
|
|
4
|
+
export * from './badge'
|
|
5
|
+
export * from './breadcrumb'
|
|
6
|
+
export * from './button'
|
|
7
|
+
export * from './button-group'
|
|
8
|
+
export * from './calendar'
|
|
9
|
+
export * from './card'
|
|
10
|
+
export * from './carousel'
|
|
11
|
+
export * from './cascade-select'
|
|
12
|
+
export * from './chart'
|
|
13
|
+
export * from './checkbox'
|
|
14
|
+
export * from './chip'
|
|
15
|
+
export * from './code-block'
|
|
16
|
+
export * from './collapsible'
|
|
17
|
+
export * from './combobox'
|
|
18
|
+
export * from './command'
|
|
19
|
+
export * from './command-block'
|
|
20
|
+
export * from './confirm-dialog'
|
|
21
|
+
export * from './confirm-popup'
|
|
22
|
+
export * from './context-menu'
|
|
23
|
+
export * from './data-table'
|
|
24
|
+
export * from './data-view'
|
|
25
|
+
export * from './date-picker'
|
|
26
|
+
export * from './deferred'
|
|
27
|
+
export * from './dialog'
|
|
28
|
+
export * from './doc-example'
|
|
29
|
+
export * from './doc-text'
|
|
30
|
+
export * from './dropdown-menu'
|
|
31
|
+
export * from './editable'
|
|
32
|
+
export * from './empty'
|
|
33
|
+
export * from './field'
|
|
34
|
+
export * from './fieldset'
|
|
35
|
+
export * from './file-upload'
|
|
36
|
+
export * from './float-label'
|
|
37
|
+
export * from './form'
|
|
38
|
+
export * from './hover-card'
|
|
39
|
+
export * from './ifta-label'
|
|
40
|
+
export * from './input'
|
|
41
|
+
export * from './input-color'
|
|
42
|
+
export * from './input-group'
|
|
43
|
+
export * from './input-number'
|
|
44
|
+
export * from './input-otp'
|
|
45
|
+
export * from './input-password'
|
|
46
|
+
export * from './input-tags'
|
|
47
|
+
export * from './kbd'
|
|
48
|
+
export * from './label'
|
|
49
|
+
export * from './listbox'
|
|
50
|
+
export * from './mask'
|
|
51
|
+
export * from './menubar'
|
|
52
|
+
export * from './navigation-menu'
|
|
53
|
+
export * from './order-list'
|
|
54
|
+
export * from './pagination'
|
|
55
|
+
export * from './panel'
|
|
56
|
+
export * from './pick-list'
|
|
57
|
+
export * from './popover'
|
|
58
|
+
export * from './progress'
|
|
59
|
+
export * from './props-table'
|
|
60
|
+
export * from './radio-group'
|
|
61
|
+
export * from './rating'
|
|
62
|
+
export * from './scroll-area'
|
|
63
|
+
export * from './search-input'
|
|
64
|
+
export * from './select'
|
|
65
|
+
export * from './separator'
|
|
66
|
+
export * from './sheet'
|
|
67
|
+
export * from './sidebar'
|
|
68
|
+
export * from './skeleton'
|
|
69
|
+
export * from './skip-link'
|
|
70
|
+
export * from './slider'
|
|
71
|
+
export * from './speed-dial'
|
|
72
|
+
export * from './spinner'
|
|
73
|
+
export * from './splitter'
|
|
74
|
+
export * from './stepper'
|
|
75
|
+
export * from './switch'
|
|
76
|
+
export * from './table'
|
|
77
|
+
export * from './tabs'
|
|
78
|
+
export * from './textarea'
|
|
79
|
+
export * from './theme-controls'
|
|
80
|
+
export * from './timeline'
|
|
81
|
+
export * from './toast'
|
|
82
|
+
export * from './toggle'
|
|
83
|
+
export * from './token-table'
|
|
84
|
+
export * from './toolbar'
|
|
85
|
+
export * from './tooltip'
|
|
86
|
+
export * from './tree'
|
|
87
|
+
export * from './tree-select'
|
|
88
|
+
export * from './tree-table'
|
|
89
|
+
export * from './video-player'
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { ClassProps } from '../../lib/types'
|
|
3
|
+
import { computed } from 'vue'
|
|
4
|
+
import { focusRing, invalidRing } from '../../lib/focus'
|
|
5
|
+
import { Check } from '../../lib/icons'
|
|
6
|
+
import { cn } from '../../lib/utils'
|
|
7
|
+
import Spinner from '../spinner/Spinner.vue'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Gốc của component là một `<div>` bọc ngoài, nên thuộc tính rơi tự do phải
|
|
11
|
+
* được chuyển tay vào đúng cái `<input>` — nếu không `id`, `name`,
|
|
12
|
+
* `aria-describedby` sẽ dính lên div và `<label for>` mất đích.
|
|
13
|
+
*/
|
|
14
|
+
defineOptions({ inheritAttrs: false })
|
|
15
|
+
|
|
16
|
+
const props = withDefaults(
|
|
17
|
+
defineProps<ClassProps & {
|
|
18
|
+
invalid?: boolean
|
|
19
|
+
/**
|
|
20
|
+
* Đã kiểm và hợp lệ. Hiện dấu tick **trong ô** — đúng chỗ mắt người dùng
|
|
21
|
+
* đang nhìn. Toast là lựa chọn sai cho việc này: nó kéo chú ý đi nơi khác
|
|
22
|
+
* rồi biến mất trước khi kịp đọc.
|
|
23
|
+
*/
|
|
24
|
+
success?: boolean
|
|
25
|
+
/** Đang kiểm bất đồng bộ (trùng email, mã giảm giá…). */
|
|
26
|
+
loading?: boolean
|
|
27
|
+
/** sm = 30px, dùng cho toolbar/bộ lọc theo mật độ compact của thiết kế. */
|
|
28
|
+
size?: 'sm' | 'default'
|
|
29
|
+
}>(),
|
|
30
|
+
{ size: 'default' },
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
// defineModel để Input dùng được với v-model và với FormField.
|
|
34
|
+
const model = defineModel<string | number | null>()
|
|
35
|
+
|
|
36
|
+
const sizeClass = computed(() =>
|
|
37
|
+
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',
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
/** Lỗi thắng tick: sai thì không còn gì để mà xác nhận là đúng. */
|
|
41
|
+
const showSuccess = computed(() => props.success && !props.invalid && !props.loading)
|
|
42
|
+
const hasAdornment = computed(() => props.loading || showSuccess.value)
|
|
43
|
+
</script>
|
|
44
|
+
|
|
45
|
+
<template>
|
|
46
|
+
<div class="relative w-full">
|
|
47
|
+
<input
|
|
48
|
+
v-bind="$attrs"
|
|
49
|
+
v-model="model"
|
|
50
|
+
:aria-invalid="props.invalid || undefined"
|
|
51
|
+
:data-invalid="props.invalid || undefined"
|
|
52
|
+
:aria-busy="props.loading || undefined"
|
|
53
|
+
:readonly="props.loading || undefined"
|
|
54
|
+
:class="cn(
|
|
55
|
+
'flex w-full rounded-md border border-input bg-background py-1 shadow-xs transition-colors',
|
|
56
|
+
sizeClass,
|
|
57
|
+
'placeholder:text-muted-foreground',
|
|
58
|
+
'file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground',
|
|
59
|
+
focusRing,
|
|
60
|
+
'disabled:cursor-not-allowed disabled:opacity-50',
|
|
61
|
+
invalidRing,
|
|
62
|
+
// Chừa chỗ cho icon, nếu không chữ chui xuống dưới nó.
|
|
63
|
+
hasAdornment && (props.size === 'sm' ? 'pr-8' : 'pr-9'),
|
|
64
|
+
props.class,
|
|
65
|
+
)"
|
|
66
|
+
>
|
|
67
|
+
|
|
68
|
+
<!--
|
|
69
|
+
`loading` khoá ô bằng `readonly`, KHÔNG bằng `disabled`.
|
|
70
|
+
|
|
71
|
+
`disabled` cướp focus khỏi phần tử người dùng đang đứng, nên giữa lúc
|
|
72
|
+
kiểm tra họ mất luôn vị trí trong form — và `disabled` còn có nghĩa "bạn
|
|
73
|
+
không được phép", khác hẳn "đang chạy". `readonly` chặn gõ mà vẫn giữ
|
|
74
|
+
focus, vẫn copy được; `aria-busy` nói phần còn lại cho trình đọc màn hình.
|
|
75
|
+
-->
|
|
76
|
+
<span
|
|
77
|
+
v-if="hasAdornment"
|
|
78
|
+
:class="cn(
|
|
79
|
+
'pointer-events-none absolute top-1/2 -translate-y-1/2',
|
|
80
|
+
props.size === 'sm' ? 'right-2.5' : 'right-3',
|
|
81
|
+
)"
|
|
82
|
+
>
|
|
83
|
+
<Spinner v-if="props.loading" class="text-muted-foreground" />
|
|
84
|
+
<Check v-else class="size-4 text-success" aria-hidden="true" />
|
|
85
|
+
</span>
|
|
86
|
+
</div>
|
|
87
|
+
</template>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Input } from './Input.vue'
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { ColorAreaRootEmits, ColorAreaRootProps } from 'reka-ui'
|
|
3
|
+
import type { ClassProps } from '../../lib/types'
|
|
4
|
+
import { ColorAreaArea, ColorAreaRoot, ColorAreaThumb, useForwardPropsEmits } from 'reka-ui'
|
|
5
|
+
import { computed } from 'vue'
|
|
6
|
+
import { cn } from '../../lib/utils'
|
|
7
|
+
|
|
8
|
+
const props = defineProps<ColorAreaRootProps & ClassProps>()
|
|
9
|
+
const emits = defineEmits<ColorAreaRootEmits>()
|
|
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
|
+
<!--
|
|
21
|
+
`ColorAreaArea` KHÔNG tự tô nền — nó chỉ đặt `touch-action: none`. Dải màu
|
|
22
|
+
nằm ở `style` mà slot của root trả về, và phải tự bind sang. Quên là ra một
|
|
23
|
+
ô xám trơn vẫn kéo được, tức hỏng mà nhìn như đang tải dở.
|
|
24
|
+
-->
|
|
25
|
+
<ColorAreaRoot
|
|
26
|
+
v-slot="{ style }"
|
|
27
|
+
v-bind="forwarded"
|
|
28
|
+
:class="cn('relative h-40 w-full touch-none select-none rounded-md border border-border', props.class)"
|
|
29
|
+
>
|
|
30
|
+
<ColorAreaArea :style="style" class="size-full rounded-[inherit]">
|
|
31
|
+
<ColorAreaThumb
|
|
32
|
+
class="size-4 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-white shadow-[0_0_0_1px_rgba(0,0,0,.35)] outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
33
|
+
/>
|
|
34
|
+
</ColorAreaArea>
|
|
35
|
+
</ColorAreaRoot>
|
|
36
|
+
</template>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { ColorFieldRootEmits, ColorFieldRootProps } from 'reka-ui'
|
|
3
|
+
import type { ClassProps } from '../../lib/types'
|
|
4
|
+
import { ColorFieldInput, ColorFieldRoot, useForwardPropsEmits } from 'reka-ui'
|
|
5
|
+
import { computed } from 'vue'
|
|
6
|
+
import { focusRing } from '../../lib/focus'
|
|
7
|
+
import { cn } from '../../lib/utils'
|
|
8
|
+
|
|
9
|
+
const props = defineProps<ColorFieldRootProps & ClassProps>()
|
|
10
|
+
const emits = defineEmits<ColorFieldRootEmits>()
|
|
11
|
+
|
|
12
|
+
const delegated = computed(() => {
|
|
13
|
+
const { class: _class, ...rest } = props
|
|
14
|
+
return rest
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
const forwarded = useForwardPropsEmits(delegated, emits)
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<template>
|
|
21
|
+
<!-- Ô nhập hex hoặc một kênh màu. `font-mono` vì đây là mã, không phải chữ —
|
|
22
|
+
và mã màu thì hay được đọc theo từng ký tự. -->
|
|
23
|
+
<ColorFieldRoot v-bind="forwarded" :class="cn('w-full', props.class)">
|
|
24
|
+
<ColorFieldInput
|
|
25
|
+
:class="cn(
|
|
26
|
+
'h-8 w-full rounded-md border border-input bg-background px-2 font-mono text-xs uppercase shadow-xs transition-colors',
|
|
27
|
+
focusRing,
|
|
28
|
+
'disabled:cursor-not-allowed disabled:opacity-50',
|
|
29
|
+
)"
|
|
30
|
+
/>
|
|
31
|
+
</ColorFieldRoot>
|
|
32
|
+
</template>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { ColorSliderRootEmits, ColorSliderRootProps } from 'reka-ui'
|
|
3
|
+
import type { ClassProps } from '../../lib/types'
|
|
4
|
+
import { ColorSliderRoot, ColorSliderThumb, ColorSliderTrack, useForwardPropsEmits } from 'reka-ui'
|
|
5
|
+
import { computed } from 'vue'
|
|
6
|
+
import { cn } from '../../lib/utils'
|
|
7
|
+
|
|
8
|
+
const props = defineProps<ColorSliderRootProps & ClassProps>()
|
|
9
|
+
const emits = defineEmits<ColorSliderRootEmits>()
|
|
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
|
+
<!-- Khác `ColorArea`: rãnh ở đây TỰ tô, reka bind nền thẳng lên `Track`. -->
|
|
21
|
+
<ColorSliderRoot
|
|
22
|
+
v-bind="forwarded"
|
|
23
|
+
:class="cn('relative flex h-4 w-full touch-none select-none items-center', props.class)"
|
|
24
|
+
>
|
|
25
|
+
<ColorSliderTrack class="h-3 w-full rounded-full border border-border">
|
|
26
|
+
<ColorSliderThumb
|
|
27
|
+
class="size-4 -translate-x-1/2 rounded-full border-2 border-white shadow-[0_0_0_1px_rgba(0,0,0,.35)] outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
28
|
+
/>
|
|
29
|
+
</ColorSliderTrack>
|
|
30
|
+
</ColorSliderRoot>
|
|
31
|
+
</template>
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { ClassProps } from '../../lib/types'
|
|
3
|
+
import { computed } from 'vue'
|
|
4
|
+
import { useI18n } from '../../composables/useI18n'
|
|
5
|
+
import { cn } from '../../lib/utils'
|
|
6
|
+
import Popover from '../popover/Popover.vue'
|
|
7
|
+
import PopoverContent from '../popover/PopoverContent.vue'
|
|
8
|
+
import PopoverTrigger from '../popover/PopoverTrigger.vue'
|
|
9
|
+
import ColorArea from './ColorArea.vue'
|
|
10
|
+
import ColorField from './ColorField.vue'
|
|
11
|
+
import ColorSlider from './ColorSlider.vue'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Gốc của component là một provider KHÔNG vẽ ra DOM, nên thuộc tính rơi tự do
|
|
15
|
+
* không có chỗ đáp và biến mất hẳn. Đo được: đặt `id` lên component thì nó
|
|
16
|
+
* không xuất hiện ở bất kỳ đâu trong DOM, và `<Label for>` trỏ vào hư không.
|
|
17
|
+
*
|
|
18
|
+
* Chuyển tay xuống chính cái trigger.
|
|
19
|
+
*/
|
|
20
|
+
defineOptions({ inheritAttrs: false })
|
|
21
|
+
|
|
22
|
+
const props = defineProps<ClassProps & {
|
|
23
|
+
/** Nhãn trợ năng cho nút mở. Bỏ trống thì lấy chuỗi của thư viện. */
|
|
24
|
+
label?: string
|
|
25
|
+
disabled?: boolean
|
|
26
|
+
}>()
|
|
27
|
+
|
|
28
|
+
const model = defineModel<string>({ default: '#2563EB' })
|
|
29
|
+
|
|
30
|
+
const { t } = useI18n()
|
|
31
|
+
|
|
32
|
+
const label = computed(() => props.label ?? t('ui.inputColor.open'))
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<template>
|
|
36
|
+
<Popover>
|
|
37
|
+
<PopoverTrigger
|
|
38
|
+
v-bind="$attrs"
|
|
39
|
+
:disabled="props.disabled"
|
|
40
|
+
:aria-label="`${label}: ${model}`"
|
|
41
|
+
:class="cn(
|
|
42
|
+
'inline-flex h-9 items-center gap-2 rounded-md border border-input bg-background px-2 pr-3 shadow-xs transition-colors',
|
|
43
|
+
'hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
|
|
44
|
+
'disabled:pointer-events-none disabled:opacity-50',
|
|
45
|
+
props.class,
|
|
46
|
+
)"
|
|
47
|
+
>
|
|
48
|
+
<!--
|
|
49
|
+
Ô màu đặt trên nền ca-rô, không phải nền trơn: màu có alpha thấp nằm
|
|
50
|
+
trên nền trắng thì trông hệt như trắng, và người dùng không có cách nào
|
|
51
|
+
biết mình vừa chọn một màu gần như trong suốt.
|
|
52
|
+
-->
|
|
53
|
+
<span class="size-5 shrink-0 overflow-hidden rounded-sm border border-border bg-[repeating-conic-gradient(theme(colors.slate.400)_0_25%,transparent_0_50%)] bg-[length:8px_8px]">
|
|
54
|
+
<span class="block size-full" :style="{ background: model }" />
|
|
55
|
+
</span>
|
|
56
|
+
<span class="font-mono text-xs uppercase">{{ model }}</span>
|
|
57
|
+
</PopoverTrigger>
|
|
58
|
+
|
|
59
|
+
<PopoverContent class="w-60 space-y-3 p-3">
|
|
60
|
+
<ColorArea v-model="model" color-space="hsb" x-channel="saturation" y-channel="brightness" />
|
|
61
|
+
<ColorSlider v-model="model" color-space="hsb" channel="hue" />
|
|
62
|
+
<ColorField v-model="model" />
|
|
63
|
+
</PopoverContent>
|
|
64
|
+
</Popover>
|
|
65
|
+
</template>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bộ chọn màu. `<InputColor v-model="brand" />` là một nút ô màu mở ra popover
|
|
3
|
+
* gồm vùng bão-hoà/độ-sáng, thanh sắc và ô nhập hex.
|
|
4
|
+
*
|
|
5
|
+
* Ba phần bên trong cũng export riêng cho lúc cần dựng bố cục khác — ví dụ một
|
|
6
|
+
* bảng màu luôn hiện trong trang cài đặt, không qua popover.
|
|
7
|
+
*
|
|
8
|
+
* Cái bẫy đáng nhớ: `ColorAreaArea` **không tự tô nền**. Dải màu nằm ở `style`
|
|
9
|
+
* mà slot của root trả về; `ColorArea.vue` bind nó sang. Còn `ColorSliderTrack`
|
|
10
|
+
* thì ngược lại, reka tô sẵn.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export { default as ColorArea } from './ColorArea.vue'
|
|
14
|
+
export { default as ColorField } from './ColorField.vue'
|
|
15
|
+
export { default as ColorSlider } from './ColorSlider.vue'
|
|
16
|
+
export { default as InputColor } from './InputColor.vue'
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { ClassProps } from '../../lib/types'
|
|
3
|
+
import type { InputGroupVariants } from './index'
|
|
4
|
+
import { computed } from 'vue'
|
|
5
|
+
import { cn } from '../../lib/utils'
|
|
6
|
+
import { inputGroupVariants, provideInputGroupContext } from './index'
|
|
7
|
+
|
|
8
|
+
const props = withDefaults(
|
|
9
|
+
defineProps<ClassProps & {
|
|
10
|
+
size?: InputGroupVariants['size']
|
|
11
|
+
invalid?: boolean
|
|
12
|
+
}>(),
|
|
13
|
+
{ size: 'default', invalid: false },
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
provideInputGroupContext({ size: computed(() => props.size) })
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<template>
|
|
20
|
+
<div
|
|
21
|
+
:data-invalid="props.invalid || undefined"
|
|
22
|
+
:class="cn(inputGroupVariants({ size: props.size }), props.class)"
|
|
23
|
+
>
|
|
24
|
+
<slot />
|
|
25
|
+
</div>
|
|
26
|
+
</template>
|