@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,22 @@
|
|
|
1
|
+
import type { TokenKind } from '../lib/highlight'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Bảng class cho từng loại token của bộ tô cú pháp.
|
|
5
|
+
*
|
|
6
|
+
* Nằm ở đây chứ không ở component vì **cả hai cây đều vẽ cùng một bảng màu
|
|
7
|
+
* code**: nó là một bảng class, và luật của repo là bảng class thì thuộc
|
|
8
|
+
* `src/variants`. Trước đó nó nằm trong `CodeBlock.vue`, nên port sang
|
|
9
|
+
* React là chép lần thứ hai — đúng lớp lỗi mà package này sinh ra để dập.
|
|
10
|
+
*
|
|
11
|
+
* `text` và `punctuation` cố ý không khai màu: chúng lấy màu chữ của khối.
|
|
12
|
+
*/
|
|
13
|
+
export const codeTokenClass: Partial<Record<TokenKind, string>> = {
|
|
14
|
+
comment: 'text-code-comment italic',
|
|
15
|
+
keyword: 'text-code-keyword',
|
|
16
|
+
string: 'text-code-string',
|
|
17
|
+
number: 'text-code-number',
|
|
18
|
+
tag: 'text-code-tag',
|
|
19
|
+
component: 'text-code-component',
|
|
20
|
+
attr: 'text-code-entity',
|
|
21
|
+
function: 'text-code-entity',
|
|
22
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { VariantProps } from 'class-variance-authority'
|
|
2
|
+
import { cva } from 'class-variance-authority'
|
|
3
|
+
|
|
4
|
+
export const dialogContentVariants = cva(
|
|
5
|
+
[
|
|
6
|
+
'fixed left-1/2 top-1/2 z-(--z-overlay) flex w-full -translate-x-1/2 -translate-y-1/2 flex-col',
|
|
7
|
+
'surface max-h-[calc(100dvh-2rem)] gap-0 overflow-hidden rounded-lg border border-border bg-background shadow-lg',
|
|
8
|
+
// Reka expose data-state -> transition do CSS lo, không cần JS
|
|
9
|
+
'data-[state=open]:animate-in data-[state=closed]:animate-out',
|
|
10
|
+
'data-[state=open]:fade-in-0 data-[state=closed]:fade-out-0',
|
|
11
|
+
'data-[state=open]:zoom-in-95 data-[state=closed]:zoom-out-95',
|
|
12
|
+
'duration-(--duration-base)',
|
|
13
|
+
],
|
|
14
|
+
{
|
|
15
|
+
variants: {
|
|
16
|
+
size: {
|
|
17
|
+
sm: 'max-w-sm',
|
|
18
|
+
default: 'max-w-lg',
|
|
19
|
+
lg: 'max-w-2xl',
|
|
20
|
+
xl: 'max-w-4xl',
|
|
21
|
+
full: 'max-w-[calc(100vw-2rem)]',
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
defaultVariants: { size: 'default' },
|
|
25
|
+
},
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
export type DialogContentVariants = VariantProps<typeof dialogContentVariants>
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { VariantProps } from 'class-variance-authority'
|
|
2
|
+
import { cva } from 'class-variance-authority'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Trạng thái rỗng: bảng chưa có dữ liệu, bộ lọc không khớp gì, tìm kiếm không
|
|
6
|
+
* ra kết quả.
|
|
7
|
+
*
|
|
8
|
+
* `variant` quyết định **khung**, không phải màu:
|
|
9
|
+
* - `plain` — không viền, dùng khi nó nằm sẵn trong một Card hoặc trong thân bảng.
|
|
10
|
+
* - `dashed` — viền đứt, dùng khi nó là cả một vùng trống trên trang, kiểu "thả
|
|
11
|
+
* file vào đây" hoặc "chưa tạo mục nào".
|
|
12
|
+
*
|
|
13
|
+
* S chỉ có `dashed`; đặt nó vào trong `<tbody>` của một bảng đã có viền là ra
|
|
14
|
+
* hai lớp viền lồng nhau.
|
|
15
|
+
*/
|
|
16
|
+
export const emptyVariants = cva(
|
|
17
|
+
'flex w-full min-w-0 flex-col items-center justify-center gap-4 text-balance text-center',
|
|
18
|
+
{
|
|
19
|
+
variants: {
|
|
20
|
+
variant: {
|
|
21
|
+
plain: 'px-6 py-10',
|
|
22
|
+
dashed: 'rounded-xl border border-dashed border-border p-10',
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
size: {
|
|
26
|
+
sm: 'gap-3 py-8',
|
|
27
|
+
default: '',
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
defaultVariants: {
|
|
32
|
+
variant: 'plain',
|
|
33
|
+
size: 'default',
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Khung tròn bọc icon. Tách khỏi `Empty` để icon nào cũng ra cùng một cỡ mà
|
|
40
|
+
* không phải nhớ đặt class ở chỗ gọi.
|
|
41
|
+
*/
|
|
42
|
+
export const emptyMediaVariants = cva(
|
|
43
|
+
'flex shrink-0 items-center justify-center [&_svg]:shrink-0',
|
|
44
|
+
{
|
|
45
|
+
variants: {
|
|
46
|
+
variant: {
|
|
47
|
+
// Vòng tròn có nền — icon đọc ra như một biểu tượng trạng thái.
|
|
48
|
+
muted: 'size-11 rounded-full bg-muted text-muted-foreground [&_svg]:size-5',
|
|
49
|
+
// Không nền, icon to hơn — dùng khi đã có viền đứt bao quanh, thêm một
|
|
50
|
+
// vòng tròn nữa thành hai hình lồng nhau.
|
|
51
|
+
plain: 'text-muted-foreground [&_svg]:size-8',
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
defaultVariants: { variant: 'muted' },
|
|
55
|
+
},
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
export type EmptyVariants = VariantProps<typeof emptyVariants>
|
|
59
|
+
|
|
60
|
+
export type EmptyMediaVariants = VariantProps<typeof emptyMediaVariants>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { VariantProps } from 'class-variance-authority'
|
|
2
|
+
import { cva } from 'class-variance-authority'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Một ô nhập cùng nhãn và phần mô tả của nó.
|
|
6
|
+
*
|
|
7
|
+
* Khác `FormField`: `FormField` nối vào TanStack Form (giá trị, lỗi, chạm chưa),
|
|
8
|
+
* còn `Field` chỉ lo bố cục. Form thật thì lồng cái này trong cái kia.
|
|
9
|
+
*
|
|
10
|
+
* `responsive` xếp dọc rồi chuyển sang ngang khi NHÓM đủ rộng — container query,
|
|
11
|
+
* không phải media query, nên nó đúng cả khi form nằm trong một cột hẹp.
|
|
12
|
+
*/
|
|
13
|
+
export const fieldVariants = cva(
|
|
14
|
+
'group/field flex w-full gap-3 data-[invalid=true]:text-destructive',
|
|
15
|
+
{
|
|
16
|
+
variants: {
|
|
17
|
+
orientation: {
|
|
18
|
+
vertical: '[&>*]:w-full [&>.sr-only]:w-auto flex-col',
|
|
19
|
+
horizontal: [
|
|
20
|
+
'flex-row items-center',
|
|
21
|
+
'[&>[data-slot=field-label]]:flex-auto',
|
|
22
|
+
'has-[>[data-slot=field-content]]:items-start has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px',
|
|
23
|
+
],
|
|
24
|
+
responsive: [
|
|
25
|
+
'flex-col @md/field-group:flex-row @md/field-group:items-center [&>*]:w-full @md/field-group:[&>*]:w-auto [&>.sr-only]:w-auto',
|
|
26
|
+
'@md/field-group:[&>[data-slot=field-label]]:flex-auto',
|
|
27
|
+
'@md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px',
|
|
28
|
+
],
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
defaultVariants: { orientation: 'vertical' },
|
|
32
|
+
},
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
export type FieldVariants = VariantProps<typeof fieldVariants>
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { VariantProps } from 'class-variance-authority'
|
|
2
|
+
import { cva } from 'class-variance-authority'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Nhãn nằm trong ô, rồi trôi lên khi ô có nội dung.
|
|
6
|
+
*
|
|
7
|
+
* Toàn bộ là CSS, không một dòng JS: `:has()` trên cái vỏ đọc trạng thái của ô
|
|
8
|
+
* nhập bên trong, và `[&>label]` chọn ra cái nhãn để dời nó. Đổi lại, **ô nhập
|
|
9
|
+
* bắt buộc phải có `placeholder`** — thường là một dấu cách — vì thứ CSS dùng
|
|
10
|
+
* để biết ô còn rỗng hay không chính là `:placeholder-shown`.
|
|
11
|
+
*
|
|
12
|
+
* Quên nó thì nhãn đứng nguyên ở vị trí đã trôi ngay từ đầu: không lỗi, không
|
|
13
|
+
* cảnh báo, chỉ là hiệu ứng không bao giờ chạy và ô trông như đang có sẵn giá trị.
|
|
14
|
+
*
|
|
15
|
+
* ## Hai selector, hai luật khác nhau — và đó không phải sơ suất
|
|
16
|
+
*
|
|
17
|
+
* | thứ | selector | vì sao |
|
|
18
|
+
* |---|---|---|
|
|
19
|
+
* | nhãn | `[&>label]` — CON TRỰC TIẾP | `Label` render ra `<label>` ở gốc |
|
|
20
|
+
* | ô nhập | `[&_input]` — HẬU DUỆ | `Input` bọc `<input>` trong một `<div class="relative">` |
|
|
21
|
+
*
|
|
22
|
+
* Viết `[&>input]` cho vế thứ hai là không khớp gì cả, mà cũng chẳng có gì báo.
|
|
23
|
+
*
|
|
24
|
+
* ## Không dùng cho textarea hay select
|
|
25
|
+
*
|
|
26
|
+
* `over` và `on` để nhãn nằm ĐÚNG hàng của giá trị lúc ô còn rỗng, nên với ô
|
|
27
|
+
* nhiều dòng thì nhãn rơi vào giữa vùng chữ. Còn select thì không có
|
|
28
|
+
* `:placeholder-shown` để mà đọc — trigger của nó là một cái nút. Cả hai trường
|
|
29
|
+
* hợp dùng `IftaLabel`, nơi nhãn không bao giờ chiếm hàng giá trị.
|
|
30
|
+
*/
|
|
31
|
+
export const floatLabelVariants = cva(
|
|
32
|
+
[
|
|
33
|
+
'relative w-full',
|
|
34
|
+
|
|
35
|
+
// Trạng thái nghỉ: nhãn nằm giữa ô, cùng cỡ chữ với giá trị.
|
|
36
|
+
'[&>label]:pointer-events-none [&>label]:absolute [&>label]:left-3 [&>label]:z-(--z-raised)',
|
|
37
|
+
'[&>label]:origin-left [&>label]:text-muted-foreground [&>label]:font-normal',
|
|
38
|
+
'[&>label]:transition-all [&>label]:duration-(--duration-base)',
|
|
39
|
+
'[&>label]:top-1/2 [&>label]:-translate-y-1/2 [&>label]:text-sm',
|
|
40
|
+
|
|
41
|
+
// Ô bị khoá thì nhãn phải mờ theo, nếu không nó đọc ra như một ô còn dùng được.
|
|
42
|
+
'has-[input:disabled]:[&>label]:opacity-50',
|
|
43
|
+
|
|
44
|
+
// Chuyển động phải tắt được — nhãn trôi là chuyển động, không phải trang trí.
|
|
45
|
+
'motion-reduce:[&>label]:transition-none',
|
|
46
|
+
],
|
|
47
|
+
{
|
|
48
|
+
variants: {
|
|
49
|
+
variant: {
|
|
50
|
+
/** Trôi hẳn LÊN TRÊN ô. Mặc định, và là cái ít va chạm nhất. */
|
|
51
|
+
over: [
|
|
52
|
+
'has-[input:focus]:[&>label]:top-0 has-[input:focus]:[&>label]:-translate-y-[calc(100%_+_0.25rem)] has-[input:focus]:[&>label]:text-xs',
|
|
53
|
+
'has-[input:not(:placeholder-shown)]:[&>label]:top-0 has-[input:not(:placeholder-shown)]:[&>label]:-translate-y-[calc(100%_+_0.25rem)] has-[input:not(:placeholder-shown)]:[&>label]:text-xs',
|
|
54
|
+
],
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Trôi lên NẰM TRÊN đường viền, có một miếng nền che đoạn viền bên dưới.
|
|
58
|
+
*
|
|
59
|
+
* Miếng che đang giả vờ là một khoảng trống trên đường viền, nên nó phải
|
|
60
|
+
* đúng bằng màu của mặt nền phía sau. Mặc định là `--background`, và
|
|
61
|
+
* điều đó chỉ đúng khi ô nằm thẳng trên nền trang. Đo hai mặt nền trên
|
|
62
|
+
* cả năm bảng màu:
|
|
63
|
+
*
|
|
64
|
+
* | | `--background` | `--card` |
|
|
65
|
+
* |---|---|---|
|
|
66
|
+
* | sáng, bốn bảng | trắng | trắng — trùng, không thấy gì |
|
|
67
|
+
* | Solar sáng | 98,5% | trắng — lệch một chút |
|
|
68
|
+
* | **tối, cả năm bảng** | ~14,5% | ~21% — **lệch rõ** |
|
|
69
|
+
* | **kính** | đục | trong mờ — **lệch hẳn** |
|
|
70
|
+
*
|
|
71
|
+
* Nghĩa là lỗi này ẩn mình ở chế độ sáng rồi hiện ra thành một vệt tối
|
|
72
|
+
* ngay khi ai đó bật theme tối. Đổi màu bằng BIẾN, đừng bằng class:
|
|
73
|
+
* chuỗi gốc nằm sau `has-[…]` nên `[&>label]:bg-card` viết thêm vào
|
|
74
|
+
* `class` thua về specificity, còn `[--float-label-patch:var(--card)]`
|
|
75
|
+
* thì nằm trên chính cái vỏ nên thắng.
|
|
76
|
+
*/
|
|
77
|
+
on: [
|
|
78
|
+
'[--float-label-patch:var(--background)]',
|
|
79
|
+
'has-[input:focus]:[&>label]:top-0 has-[input:focus]:[&>label]:-translate-y-1/2 has-[input:focus]:[&>label]:text-xs has-[input:focus]:[&>label]:bg-(--float-label-patch) has-[input:focus]:[&>label]:px-1',
|
|
80
|
+
'has-[input:not(:placeholder-shown)]:[&>label]:top-0 has-[input:not(:placeholder-shown)]:[&>label]:-translate-y-1/2 has-[input:not(:placeholder-shown)]:[&>label]:text-xs has-[input:not(:placeholder-shown)]:[&>label]:bg-(--float-label-patch) has-[input:not(:placeholder-shown)]:[&>label]:px-1',
|
|
81
|
+
],
|
|
82
|
+
|
|
83
|
+
/** Trôi lên nhưng Ở LẠI TRONG ô — nên ô phải cao thêm để có chỗ. */
|
|
84
|
+
in: [
|
|
85
|
+
'[&_input]:h-13 [&_input]:pt-6 [&_input]:pb-2',
|
|
86
|
+
'has-[input:focus]:[&>label]:top-1.5 has-[input:focus]:[&>label]:translate-y-0 has-[input:focus]:[&>label]:text-xs',
|
|
87
|
+
'has-[input:not(:placeholder-shown)]:[&>label]:top-1.5 has-[input:not(:placeholder-shown)]:[&>label]:translate-y-0 has-[input:not(:placeholder-shown)]:[&>label]:text-xs',
|
|
88
|
+
],
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
defaultVariants: { variant: 'over' },
|
|
92
|
+
},
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
export type FloatLabelVariants = VariantProps<typeof floatLabelVariants>
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { VariantProps } from 'class-variance-authority'
|
|
2
|
+
import { cva } from 'class-variance-authority'
|
|
3
|
+
import { focusRingWithin, invalidRingWithin } from '../lib/focus'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Ghép ô nhập với phần phụ ở hai đầu: tiền tố `https://`, đơn vị `kg`, một icon,
|
|
7
|
+
* hay một nút.
|
|
8
|
+
*
|
|
9
|
+
* **Khác `ButtonGroup` ở chỗ cốt lõi**: nhóm nút giữ viền của từng nút rồi gộp
|
|
10
|
+
* lại; nhóm nhập thì **cả nhóm** sở hữu viền và vòng focus, còn ô nhập bên
|
|
11
|
+
* trong bị lột sạch viền/nền/ring. Nếu để ô nhập giữ ring của nó thì lúc gõ chỉ
|
|
12
|
+
* một mảnh giữa control sáng lên, phần phụ hai bên đứng ngoài — đọc ra thành hai
|
|
13
|
+
* thứ rời nhau chứ không phải một control.
|
|
14
|
+
*/
|
|
15
|
+
export const inputGroupVariants = cva(
|
|
16
|
+
[
|
|
17
|
+
'flex w-full items-stretch overflow-hidden rounded-md border border-input bg-background shadow-xs',
|
|
18
|
+
'transition-colors',
|
|
19
|
+
focusRingWithin,
|
|
20
|
+
'has-[input:disabled]:cursor-not-allowed has-[input:disabled]:opacity-50',
|
|
21
|
+
invalidRingWithin,
|
|
22
|
+
],
|
|
23
|
+
{
|
|
24
|
+
variants: {
|
|
25
|
+
size: {
|
|
26
|
+
sm: 'h-(--ui-field-height-sm) text-(length:--ui-field-text-sm)',
|
|
27
|
+
default: 'h-(--ui-field-height-md) text-sm',
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
defaultVariants: { size: 'default' },
|
|
31
|
+
},
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
export const inputGroupAddonVariants = cva(
|
|
35
|
+
'flex shrink-0 select-none items-center gap-1.5 whitespace-nowrap text-muted-foreground [&_svg]:shrink-0',
|
|
36
|
+
{
|
|
37
|
+
variants: {
|
|
38
|
+
variant: {
|
|
39
|
+
/** Nhãn chữ có nền xám, ngăn với ô nhập bằng một đường kẻ. */
|
|
40
|
+
text: 'bg-muted',
|
|
41
|
+
/** Chỉ có phần đệm — dùng cho icon nằm trong ô, hoặc để nhét nút vào. */
|
|
42
|
+
plain: 'bg-transparent',
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
align: {
|
|
46
|
+
start: '',
|
|
47
|
+
end: '',
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
size: {
|
|
51
|
+
sm: 'px-2 text-[12px] [&_svg]:size-3.5',
|
|
52
|
+
default: 'px-2.5 text-sm [&_svg]:size-4',
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
// Đường kẻ chỉ vẽ ở CẠNH GIÁP ô nhập, và chỉ khi phần phụ có nền — icon
|
|
57
|
+
// trong ô mà kẻ thêm một vạch thì thành cái nhóm hai ngăn.
|
|
58
|
+
compoundVariants: [
|
|
59
|
+
{ variant: 'text', align: 'start', class: 'border-r border-input' },
|
|
60
|
+
{ variant: 'text', align: 'end', class: 'border-l border-input' },
|
|
61
|
+
],
|
|
62
|
+
|
|
63
|
+
defaultVariants: {
|
|
64
|
+
variant: 'text',
|
|
65
|
+
align: 'start',
|
|
66
|
+
size: 'default',
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
export type InputGroupVariants = VariantProps<typeof inputGroupVariants>
|
|
72
|
+
|
|
73
|
+
export type InputGroupAddonVariants = VariantProps<typeof inputGroupAddonVariants>
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thang đo độ mạnh mật khẩu: bảng class của từng nấc, và hàm chấm điểm.
|
|
3
|
+
*
|
|
4
|
+
* Nằm ở đây vì `STRENGTH_LEVELS` **là một bảng class** — `bg-destructive`,
|
|
5
|
+
* `text-warning-soft-foreground` — và luật của repo là bảng class thì thuộc
|
|
6
|
+
* `src/variants`. Hai cây đọc chung một bảng nên thanh đo của bản Vue và
|
|
7
|
+
* bản React không thể trôi khỏi nhau.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Một nấc của thanh đo: màu thanh, màu chữ, và khoá chuỗi.
|
|
12
|
+
*
|
|
13
|
+
* Nấc 0 là ô rỗng — nó có mặt trong mảng để `STRENGTH_LEVELS[score]` không phải
|
|
14
|
+
* cộng trừ chỉ số ở chỗ đọc, nhưng chữ của nó không bao giờ hiện ra.
|
|
15
|
+
*/
|
|
16
|
+
export interface StrengthLevel {
|
|
17
|
+
key: string
|
|
18
|
+
bar: string
|
|
19
|
+
text: string
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const STRENGTH_LEVELS: readonly StrengthLevel[] = [
|
|
23
|
+
{ key: 'ui.inputPassword.weak', bar: 'bg-muted', text: 'text-muted-foreground' },
|
|
24
|
+
{ key: 'ui.inputPassword.weak', bar: 'bg-destructive', text: 'text-destructive-soft-foreground' },
|
|
25
|
+
{ key: 'ui.inputPassword.fair', bar: 'bg-warning', text: 'text-warning-soft-foreground' },
|
|
26
|
+
{ key: 'ui.inputPassword.good', bar: 'bg-info', text: 'text-info-soft-foreground' },
|
|
27
|
+
{ key: 'ui.inputPassword.strong', bar: 'bg-success', text: 'text-success-soft-foreground' },
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Chấm mật khẩu ra một nấc từ 0 tới 4, theo ĐỘ DÀI và SỐ NHÓM KÝ TỰ.
|
|
32
|
+
*
|
|
33
|
+
* Đây là một lời nhắc, không phải một phép đo an toàn. Nó không biết
|
|
34
|
+
* `Password1!` nằm trong mọi bộ từ điển rò rỉ, cũng không biết `correct horse
|
|
35
|
+
* battery staple` mạnh hơn hẳn dù chỉ có đúng một nhóm ký tự. Chấm cho đúng cần
|
|
36
|
+
* một bộ từ điển và một mô hình entropy — tức một dependency, mà repo này phải
|
|
37
|
+
* hỏi trước khi thêm.
|
|
38
|
+
*
|
|
39
|
+
* Vì vậy đừng bao giờ CHẶN theo nấc này. Nó chỉ có việc nói cho người đang gõ
|
|
40
|
+
* biết họ vừa làm mật khẩu dài thêm hay đa dạng thêm; luật thật thì đặt ở
|
|
41
|
+
* schema, và đặt ở server.
|
|
42
|
+
*/
|
|
43
|
+
export function scoreOf(value: string): number {
|
|
44
|
+
if (value.length === 0)
|
|
45
|
+
return 0
|
|
46
|
+
|
|
47
|
+
let groups = 0
|
|
48
|
+
if (/[a-z]/.test(value))
|
|
49
|
+
groups += 1
|
|
50
|
+
if (/[A-Z]/.test(value))
|
|
51
|
+
groups += 1
|
|
52
|
+
if (/\d/.test(value))
|
|
53
|
+
groups += 1
|
|
54
|
+
// `\W` coi `_` là ký tự chữ, nên một mật khẩu chỉ thêm dấu gạch dưới sẽ không
|
|
55
|
+
// được tính là có nhóm ký hiệu. Liệt kê thẳng hai nhóm kia rồi phủ định.
|
|
56
|
+
if (/[^a-z0-9]/i.test(value))
|
|
57
|
+
groups += 1
|
|
58
|
+
|
|
59
|
+
let score = 1
|
|
60
|
+
if (value.length >= 8 && groups >= 2)
|
|
61
|
+
score = 2
|
|
62
|
+
if (value.length >= 10 && groups >= 3)
|
|
63
|
+
score = 3
|
|
64
|
+
if (value.length >= 12 && groups >= 4)
|
|
65
|
+
score = 4
|
|
66
|
+
|
|
67
|
+
return score
|
|
68
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { VariantProps } from 'class-variance-authority'
|
|
2
|
+
import { cva } from 'class-variance-authority'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Một phím trên bàn phím.
|
|
6
|
+
*
|
|
7
|
+
* Dùng **font chữ thường, không phải font mono** — giống S, và có lý do: các
|
|
8
|
+
* glyph ⌘ ⇧ ⌥ ⌃ trong font mono thường thiếu hoặc lệch chiều rộng ô, nên hàng
|
|
9
|
+
* phím trông so le. Geist có đủ bộ đó.
|
|
10
|
+
*
|
|
11
|
+
* `min-w` bằng đúng chiều cao nên phím một ký tự ra hình vuông, phím nhiều ký
|
|
12
|
+
* tự thì giãn ra — không phải khai riêng biến thể "phím rộng".
|
|
13
|
+
*/
|
|
14
|
+
export const kbdVariants = cva(
|
|
15
|
+
[
|
|
16
|
+
'pointer-events-none inline-flex w-fit select-none items-center justify-center gap-1',
|
|
17
|
+
'rounded font-sans font-medium text-muted-foreground',
|
|
18
|
+
'[&_svg]:size-3 [&_svg]:shrink-0',
|
|
19
|
+
],
|
|
20
|
+
{
|
|
21
|
+
variants: {
|
|
22
|
+
size: {
|
|
23
|
+
// Giãn dòng phải khai TƯỜNG MINH bên cạnh mọi `text-[Npx]`: cỡ chữ tuỳ ý
|
|
24
|
+
// chỉ đặt `font-size`, nên line box rơi lui về giá trị thừa kế và chữ lệch
|
|
25
|
+
// trong một hộp CAO CỐ ĐỊNH. Cùng lỗi đã đo ở `badge.ts` — xem ghi chú ở đó.
|
|
26
|
+
sm: 'h-4 min-w-4 px-1 text-[10px] leading-none',
|
|
27
|
+
default: 'h-5 min-w-5 px-1 text-xs',
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
tone: {
|
|
31
|
+
// Nền xám, dùng khi phím nằm trên nền trang hoặc trong menu.
|
|
32
|
+
muted: 'bg-muted',
|
|
33
|
+
// Trong suốt có viền, dùng khi phím nằm trên một mặt đã có nền xám —
|
|
34
|
+
// ví dụ ô tìm kiếm ở header, nơi `bg-muted` chồng lên `bg-secondary`
|
|
35
|
+
// gần như biến mất.
|
|
36
|
+
outline: 'border border-border bg-transparent',
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
defaultVariants: {
|
|
41
|
+
size: 'default',
|
|
42
|
+
tone: 'muted',
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
export type KbdVariants = VariantProps<typeof kbdVariants>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { cva } from 'class-variance-authority'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Nút mở của những ô chọn dựng trên `Popover` — `TreeSelect` và `CascadeSelect`.
|
|
5
|
+
*
|
|
6
|
+
* Chuỗi này trước đó được chép nguyên văn ở hai component bản Vue, và bản React
|
|
7
|
+
* sẽ là bản thứ ba với thứ tư. Cùng lớp lỗi với `lib/focus`: mười ba chỗ chép
|
|
8
|
+
* một chuỗi thì mười ba chỗ tự do trôi khỏi nhau.
|
|
9
|
+
*
|
|
10
|
+
* **`Select` cố ý ĐỨNG NGOÀI.** Nó dùng `min-h-8` / `min-h-9` chứ không `h-8` /
|
|
11
|
+
* `h-9`, vì một giá trị dài phải đẩy nút cao lên thay vì bị cắt — mà hai ô chọn
|
|
12
|
+
* ở đây luôn hiện đúng một dòng đã cắt bớt. Gộp là đổi hành vi của `Select`.
|
|
13
|
+
* Xem mục "cỡ `sm` của ô nhập đã trôi thành BA số" trong CLAUDE.md.
|
|
14
|
+
*/
|
|
15
|
+
export const pickerTriggerVariants = cva(
|
|
16
|
+
[
|
|
17
|
+
'flex w-full items-center justify-between gap-2 rounded-md border border-input bg-background px-3 py-1 text-sm shadow-xs transition-colors',
|
|
18
|
+
'data-[placeholder]:text-muted-foreground',
|
|
19
|
+
'disabled:cursor-not-allowed disabled:opacity-50',
|
|
20
|
+
],
|
|
21
|
+
{
|
|
22
|
+
variants: {
|
|
23
|
+
size: {
|
|
24
|
+
sm: 'h-8',
|
|
25
|
+
default: 'h-9',
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
defaultVariants: { size: 'default' },
|
|
29
|
+
},
|
|
30
|
+
)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { VariantProps } from 'class-variance-authority'
|
|
2
|
+
import { cva } from 'class-variance-authority'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Nút chọn một trong nhiều. Hai trục **giống hệt Checkbox** — cùng thang cỡ,
|
|
6
|
+
* cùng tên kiểu tô — vì hai control này luôn đứng cạnh nhau trong một biểu mẫu,
|
|
7
|
+
* lệch nhau một pixel là thấy ngay.
|
|
8
|
+
*
|
|
9
|
+
* - `size` — `sm` 14px, `md` 16px (mặc định), `lg` 20px.
|
|
10
|
+
* - `tone` — `outline` nền trong, `filled` nền xám khi chưa chọn.
|
|
11
|
+
*
|
|
12
|
+
* Không có trục màu: đã chọn thì luôn là primary. Lỗi đi qua `invalid` vì nó là
|
|
13
|
+
* trạng thái xác thực, không phải một lựa chọn thiết kế.
|
|
14
|
+
*/
|
|
15
|
+
export const radioGroupItemVariants = cva(
|
|
16
|
+
[
|
|
17
|
+
'peer inline-flex shrink-0 items-center justify-center rounded-full border shadow-xs',
|
|
18
|
+
'transition-[color,background-color,border-color] duration-(--ui-control-duration)',
|
|
19
|
+
'focus-visible:outline-none',
|
|
20
|
+
'disabled:cursor-not-allowed disabled:opacity-50',
|
|
21
|
+
],
|
|
22
|
+
{
|
|
23
|
+
variants: {
|
|
24
|
+
// Chấm bên trong tô bằng selector con chứ không phải một cva riêng: nó
|
|
25
|
+
// không bao giờ đứng một mình, và để chung thì đổi cỡ chỉ sửa một dòng.
|
|
26
|
+
size: {
|
|
27
|
+
sm: 'size-3.5 [&_[data-dot]]:size-1.5',
|
|
28
|
+
md: 'size-4 [&_[data-dot]]:size-2',
|
|
29
|
+
lg: 'size-5 [&_[data-dot]]:size-2.5',
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
tone: {
|
|
33
|
+
outline: 'bg-background',
|
|
34
|
+
filled: 'bg-muted',
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Khai thành một trục của cva chứ không dùng `aria-invalid:` — lớp đã chọn
|
|
39
|
+
* và lớp lỗi cùng tô `background-color`, mà thứ tự thắng thua giữa hai
|
|
40
|
+
* variant của Tailwind do thứ tự trong stylesheet quyết định chứ không
|
|
41
|
+
* phải thứ tự mình viết. Gộp vào một nhánh thì không còn gì để đoán.
|
|
42
|
+
*/
|
|
43
|
+
invalid: {
|
|
44
|
+
false: [
|
|
45
|
+
'border-input focus-visible:shadow-focus',
|
|
46
|
+
'data-[state=checked]:border-primary data-[state=checked]:bg-primary',
|
|
47
|
+
],
|
|
48
|
+
true: [
|
|
49
|
+
'border-destructive focus-visible:shadow-focus-invalid',
|
|
50
|
+
'data-[state=checked]:border-destructive data-[state=checked]:bg-destructive',
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
defaultVariants: {
|
|
56
|
+
size: 'md',
|
|
57
|
+
tone: 'outline',
|
|
58
|
+
invalid: false,
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
export type RadioGroupItemVariants = VariantProps<typeof radioGroupItemVariants>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { VariantProps } from 'class-variance-authority'
|
|
2
|
+
import { cva } from 'class-variance-authority'
|
|
3
|
+
|
|
4
|
+
export const sheetContentVariants = cva(
|
|
5
|
+
[
|
|
6
|
+
'fixed z-(--z-overlay) flex flex-col gap-0 bg-background shadow-lg transition ease-in-out',
|
|
7
|
+
'data-[state=open]:animate-in data-[state=closed]:animate-out',
|
|
8
|
+
'data-[state=open]:duration-(--duration-slow) data-[state=closed]:duration-(--duration-base)',
|
|
9
|
+
],
|
|
10
|
+
{
|
|
11
|
+
variants: {
|
|
12
|
+
side: {
|
|
13
|
+
top: 'inset-x-0 top-0 h-auto max-h-[80dvh] border-b border-border data-[state=open]:slide-in-from-top data-[state=closed]:slide-out-to-top',
|
|
14
|
+
bottom: 'inset-x-0 bottom-0 h-auto max-h-[80dvh] border-t border-border data-[state=open]:slide-in-from-bottom data-[state=closed]:slide-out-to-bottom',
|
|
15
|
+
left: 'inset-y-0 left-0 h-full w-3/4 max-w-sm border-r border-border data-[state=open]:slide-in-from-left data-[state=closed]:slide-out-to-left',
|
|
16
|
+
right: 'inset-y-0 right-0 h-full w-3/4 max-w-sm border-l border-border data-[state=open]:slide-in-from-right data-[state=closed]:slide-out-to-right',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
defaultVariants: { side: 'right' },
|
|
20
|
+
},
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
export type SheetContentVariants = VariantProps<typeof sheetContentVariants>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { VariantProps } from 'class-variance-authority'
|
|
2
|
+
import { cva } from 'class-variance-authority'
|
|
3
|
+
|
|
4
|
+
export const sidebarMenuButtonVariants = cva(
|
|
5
|
+
[
|
|
6
|
+
'peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-hidden ring-sidebar-ring',
|
|
7
|
+
'transition-[width,height,padding]',
|
|
8
|
+
'group-has-data-[sidebar=menu-action]/menu-item:pr-8',
|
|
9
|
+
'group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2!',
|
|
10
|
+
'hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2',
|
|
11
|
+
'active:bg-sidebar-accent active:text-sidebar-accent-foreground',
|
|
12
|
+
'disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50',
|
|
13
|
+
'data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground',
|
|
14
|
+
'data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground',
|
|
15
|
+
'[&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0',
|
|
16
|
+
],
|
|
17
|
+
{
|
|
18
|
+
variants: {
|
|
19
|
+
variant: {
|
|
20
|
+
default: 'hover:bg-sidebar-accent hover:text-sidebar-accent-foreground',
|
|
21
|
+
outline: 'bg-background shadow-[0_0_0_1px_var(--sidebar-border)] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_var(--sidebar-accent)]',
|
|
22
|
+
},
|
|
23
|
+
size: {
|
|
24
|
+
default: 'h-8 text-sm',
|
|
25
|
+
sm: 'h-7 text-xs',
|
|
26
|
+
lg: 'h-12 text-sm group-data-[collapsible=icon]:p-0!',
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
defaultVariants: { variant: 'default', size: 'default' },
|
|
30
|
+
},
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
export type SidebarMenuButtonVariants = VariantProps<typeof sidebarMenuButtonVariants>
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { VariantProps } from 'class-variance-authority'
|
|
2
|
+
import { cva } from 'class-variance-authority'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Ba cỡ. S chỉ có một (rãnh 4px / núm 12px); P có `small` và `large` nhưng đổi
|
|
6
|
+
* cả hai chiều theo một hệ số. Ở đây tách rõ: rãnh dày lên chậm hơn núm, vì
|
|
7
|
+
* rãnh quá dày trông như thanh tiến độ chứ không còn ra thanh kéo.
|
|
8
|
+
*
|
|
9
|
+
* Cỡ khai ở `Slider`, hai lớp con đọc lại qua cva chứ không truyền prop.
|
|
10
|
+
*/
|
|
11
|
+
export const sliderTrackVariants = cva(
|
|
12
|
+
// `ui-slider-track` / `ui-slider-thumb` là móc để surfaces.css dựng ba mặt
|
|
13
|
+
// kính (rãnh lõm, phần đã chọn, núm nổi). Ngoài theme glass không khớp rule nào.
|
|
14
|
+
'ui-slider-track relative grow overflow-hidden rounded-full bg-slider-track select-none',
|
|
15
|
+
{
|
|
16
|
+
variants: {
|
|
17
|
+
size: {
|
|
18
|
+
sm: 'data-[orientation=horizontal]:h-1 data-[orientation=vertical]:w-1',
|
|
19
|
+
md: 'data-[orientation=horizontal]:h-1.5 data-[orientation=vertical]:w-1.5',
|
|
20
|
+
lg: 'data-[orientation=horizontal]:h-2 data-[orientation=vertical]:w-2',
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
defaultVariants: { size: 'md' },
|
|
24
|
+
},
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
export const sliderThumbVariants = cva(
|
|
28
|
+
[
|
|
29
|
+
'ui-slider-thumb block shrink-0 rounded-full border border-slider-thumb-border bg-slider-thumb shadow-sm transition-[box-shadow,transform]',
|
|
30
|
+
// Vùng bấm nới rộng ra ngoài mà không đổi kích thước hình vẽ — núm 12px là
|
|
31
|
+
// quá nhỏ so với mục tiêu chạm 24px mà WCAG khuyến nghị.
|
|
32
|
+
'relative after:absolute after:-inset-2',
|
|
33
|
+
'hover:ring-4 hover:ring-ring/20',
|
|
34
|
+
'focus-visible:outline-none focus-visible:border-ring focus-visible:ring-0 focus-visible:shadow-focus',
|
|
35
|
+
'disabled:pointer-events-none',
|
|
36
|
+
],
|
|
37
|
+
{
|
|
38
|
+
variants: {
|
|
39
|
+
size: {
|
|
40
|
+
sm: 'size-3',
|
|
41
|
+
md: 'size-4',
|
|
42
|
+
lg: 'size-5',
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
defaultVariants: { size: 'md' },
|
|
46
|
+
},
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
export type SliderVariants = VariantProps<typeof sliderTrackVariants>
|