@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,55 @@
|
|
|
1
|
+
# `src/variants`
|
|
2
|
+
|
|
3
|
+
Tầng **class** của WoodBlock: bảng `cva` của từng component, vòng focus, class
|
|
4
|
+
dùng chung của menu, và `cn()`. TypeScript thuần — không import Vue, không
|
|
5
|
+
import primitive nào.
|
|
6
|
+
|
|
7
|
+
Đo lại hôm nay: **27 bảng `cva`** trong 22 file, và **0 bảng nằm trong file
|
|
8
|
+
`.vue`**.
|
|
9
|
+
|
|
10
|
+
Nó TỪNG là package riêng `src/variants`, tách ra để bản React đọc cùng
|
|
11
|
+
một quyết định thiết kế. Đợt gộp đưa nó về đây vì repo chỉ còn cây Vue; ranh
|
|
12
|
+
giới "không biết framework nào" thì giữ nguyên, và giữ vì nó vẫn có ích — một
|
|
13
|
+
bảng class không nên biết mình đang được render bằng gì.
|
|
14
|
+
|
|
15
|
+
(Tài liệu cũ ghi "18 bảng" ở sáu chỗ; đó là số FILE đeo nhãn số bảng — xem
|
|
16
|
+
`../../../../CLAUDE.md`, mục về phép đếm này, kèm một dòng để đếm lại.)
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import { buttonVariants } from '@vestow/vue/variants/components/button'
|
|
20
|
+
import { cn } from '@vestow/vue/variants/lib/utils'
|
|
21
|
+
|
|
22
|
+
cn(buttonVariants({ variant: 'destructive', tone: 'soft' }), props.class)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Package này còn sở hữu ENTRY CSS
|
|
26
|
+
|
|
27
|
+
`css/index.css` là entry dùng chung: Tailwind + token + **vùng quét của chính
|
|
28
|
+
package này** (`@source "../src"`) + các khối `@layer` không thuộc framework nào
|
|
29
|
+
(`.surface`, `.scroll-edge`, `.app-backdrop`, `.scroll-area-x`, reset base).
|
|
30
|
+
`@vestow/vue` và `@vestow/react` đều import nó rồi chỉ thêm vùng quét
|
|
31
|
+
riêng.
|
|
32
|
+
|
|
33
|
+
`@source "../src"` là BẮT BUỘC và đã có lần quên: 27 bảng `cva` chuyển sang đây
|
|
34
|
+
mà không khai vùng thì **155 class bị purge sạch** — build vẫn xanh, nút chỉ mất
|
|
35
|
+
nền khi hover. Khai ở đây chứ không khai hộ từ `packages/ui`, vì `@source` phân
|
|
36
|
+
giải tương đối theo file CSS chứa nó nên nó đúng cả khi package nằm trong
|
|
37
|
+
`node_modules`.
|
|
38
|
+
|
|
39
|
+
## Tiêu chí kết nạp
|
|
40
|
+
|
|
41
|
+
Vào đây nếu nó quyết định **class nào được gắn**, và quyết định đó phải giống
|
|
42
|
+
nhau ở mọi framework.
|
|
43
|
+
|
|
44
|
+
Không vào đây: hàm hành vi (`isMacPlatform`, `moveItem`), kiểu bám framework
|
|
45
|
+
(`ClassProps` đọc `HTMLAttributes` của Vue, `MenuActionItem.icon` là
|
|
46
|
+
`Component` của Vue). Chúng ở lại `@vestow/vue`. Cần dùng chung thì mở một
|
|
47
|
+
package khác — đừng nong package này ra khỏi đúng cái tên của nó.
|
|
48
|
+
|
|
49
|
+
## Ràng buộc
|
|
50
|
+
|
|
51
|
+
- **Chỉ CSS token, không giá trị cứng.** Class ở đây trỏ vào token của
|
|
52
|
+
`@vestow/theme`; hai package đi cùng nhau.
|
|
53
|
+
- **Không phụ thuộc package private.** `extends` trong tsconfig viết đường dẫn
|
|
54
|
+
tương đối (`../tsconfig/lib.json`), không viết `@vestow/tsconfig` — pnpm
|
|
55
|
+
đổi `workspace:*` thành `0.0.0` lúc đóng gói.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { VariantProps } from 'class-variance-authority'
|
|
2
|
+
import { cva } from 'class-variance-authority'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Hai kiểu trình bày, lấy mỗi bên một cái:
|
|
6
|
+
*
|
|
7
|
+
* - `plain` — các hàng ngăn nhau bằng một đường kẻ, không viền ngoài. Đây là
|
|
8
|
+
* kiểu của shadcn, hợp khi accordion nằm sẵn trong một Card.
|
|
9
|
+
* - `contained` — mỗi mục là một tấm riêng có viền và nền. Đây là kiểu của
|
|
10
|
+
* PrimeVue, hợp khi nó nằm thẳng trên nền trang.
|
|
11
|
+
*
|
|
12
|
+
* Hai thư viện gốc mỗi bên chỉ có một kiểu. Màn quản trị dùng cả hai chỗ nên
|
|
13
|
+
* giữ cả hai, đổi bằng prop thay vì bắt người dùng viết đè class.
|
|
14
|
+
*/
|
|
15
|
+
export const accordionVariants = cva('w-full', {
|
|
16
|
+
variants: {
|
|
17
|
+
variant: {
|
|
18
|
+
plain: '',
|
|
19
|
+
contained: 'flex flex-col gap-2',
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
defaultVariants: { variant: 'plain' },
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
export const accordionItemVariants = cva('', {
|
|
26
|
+
variants: {
|
|
27
|
+
variant: {
|
|
28
|
+
// `last:border-b-0` chứ không phải `not-last:border-b`: mục cuối vẫn cần
|
|
29
|
+
// đường kẻ khi accordion đứng trên một khối khác, chỉ bỏ khi nó là mục
|
|
30
|
+
// cuối của chính khối này.
|
|
31
|
+
plain: 'border-b border-border last:border-b-0',
|
|
32
|
+
contained: 'overflow-hidden rounded-xl border border-border bg-card',
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
defaultVariants: { variant: 'plain' },
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
export const accordionTriggerVariants = cva(
|
|
39
|
+
[
|
|
40
|
+
'group/accordion-trigger flex flex-1 items-start justify-between gap-3 py-3.5 text-left',
|
|
41
|
+
'text-sm font-medium transition-colors',
|
|
42
|
+
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background',
|
|
43
|
+
'disabled:pointer-events-none disabled:opacity-50',
|
|
44
|
+
],
|
|
45
|
+
{
|
|
46
|
+
variants: {
|
|
47
|
+
variant: {
|
|
48
|
+
plain: 'rounded-md hover:underline',
|
|
49
|
+
contained: 'rounded-xl px-4 hover:bg-accent/60',
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
defaultVariants: { variant: 'plain' },
|
|
53
|
+
},
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
export const accordionContentVariants = cva(
|
|
57
|
+
// `overflow-hidden` bắt buộc: animation chạy bằng `height`, thiếu nó thì nội
|
|
58
|
+
// dung tràn ra ngoài suốt lúc đang trượt.
|
|
59
|
+
'overflow-hidden text-sm text-muted-foreground data-[state=open]:animate-accordion-down data-[state=closed]:animate-accordion-up',
|
|
60
|
+
{
|
|
61
|
+
variants: {
|
|
62
|
+
variant: {
|
|
63
|
+
plain: '',
|
|
64
|
+
contained: '',
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
defaultVariants: { variant: 'plain' },
|
|
68
|
+
},
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
export type AccordionVariants = VariantProps<typeof accordionVariants>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { VariantProps } from 'class-variance-authority'
|
|
2
|
+
import { cva } from 'class-variance-authority'
|
|
3
|
+
|
|
4
|
+
export const alertVariants = cva(
|
|
5
|
+
'relative grid w-full grid-cols-[auto_1fr] items-start gap-x-3 gap-y-1 rounded-lg border px-4 py-3 text-sm [&>svg]:size-4 [&>svg]:translate-y-0.5',
|
|
6
|
+
{
|
|
7
|
+
variants: {
|
|
8
|
+
variant: {
|
|
9
|
+
default: 'bg-card text-card-foreground border-border [&>svg]:text-muted-foreground',
|
|
10
|
+
info: 'border-info-soft-border bg-info-soft text-foreground [&>svg]:text-info-soft-foreground',
|
|
11
|
+
success: 'border-success-soft-border bg-success-soft text-foreground [&>svg]:text-success-soft-foreground',
|
|
12
|
+
warning: 'border-warning-soft-border bg-warning-soft text-foreground [&>svg]:text-warning-soft-foreground',
|
|
13
|
+
destructive: 'border-destructive-soft-border bg-destructive-soft text-foreground [&>svg]:text-destructive-soft-foreground',
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
defaultVariants: { variant: 'default' },
|
|
17
|
+
},
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
export type AlertVariants = VariantProps<typeof alertVariants>
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { VariantProps } from 'class-variance-authority'
|
|
2
|
+
import { cva } from 'class-variance-authority'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Hai trục giống `Button`: `variant` là **màu**, `tone` là **kiểu tô**.
|
|
6
|
+
* Badge không có `glass` — chip trạng thái không nằm trên media bao giờ.
|
|
7
|
+
*/
|
|
8
|
+
export const badgeVariants = cva(
|
|
9
|
+
'inline-flex items-center gap-1 rounded-md border font-medium whitespace-nowrap [&_svg]:shrink-0',
|
|
10
|
+
{
|
|
11
|
+
variants: {
|
|
12
|
+
variant: {
|
|
13
|
+
default: 'border-transparent bg-primary text-primary-foreground',
|
|
14
|
+
secondary: 'border-transparent bg-secondary text-secondary-foreground',
|
|
15
|
+
destructive: 'border-transparent bg-destructive text-destructive-foreground',
|
|
16
|
+
success: 'border-transparent bg-success text-success-foreground',
|
|
17
|
+
warning: 'border-transparent bg-warning text-warning-foreground',
|
|
18
|
+
info: 'border-transparent bg-info text-info-foreground',
|
|
19
|
+
outline: 'border-border text-foreground',
|
|
20
|
+
},
|
|
21
|
+
// `size` phải đứng TRƯỚC `tone` — cva nối class theo đúng thứ tự key ở
|
|
22
|
+
// đây, và quy ước chung của repo là trục KIỂU TÔ luôn nối sau trục CỠ.
|
|
23
|
+
//
|
|
24
|
+
// Chỉ có hai nấc, và đó là chủ ý: `default` là toàn bộ số đo vốn nằm trong
|
|
25
|
+
// chuỗi base, nên mọi chỗ đang gọi `badgeVariants()` nhận đúng chuỗi cũ.
|
|
26
|
+
// `xs` sinh ra cho nhãn phụ 9px trong hàng nav 30px — cỡ mặc định cao 22px,
|
|
27
|
+
// tức 73% chiều cao hàng, to ngang chính cái tên nó đang chú thích.
|
|
28
|
+
//
|
|
29
|
+
// Tên nấc theo `buttonVariants` và `chipVariants`: nấc giữa gọi là
|
|
30
|
+
// `default`, KHÔNG phải `md` — ba bảng cva dùng chung một từ vựng cỡ.
|
|
31
|
+
//
|
|
32
|
+
// KHÔNG thêm `sm` cho đủ bộ: chưa có chỗ nào đọc nó. Xem mục "tiêu chí
|
|
33
|
+
// kết nạp" ở CLAUDE.md — một nấc không người dùng là một lời hứa tương
|
|
34
|
+
// thích ngược không rút lại được.
|
|
35
|
+
size: {
|
|
36
|
+
// `leading-3` KHÔNG phải chỗ trang trí, và con số 3 (12px) không tuỳ tiện:
|
|
37
|
+
// `text-[9px]` là giá trị tuỳ ý nên Tailwind chỉ đặt `font-size`, giãn dòng
|
|
38
|
+
// rơi lui về 13.5px thừa kế. Line box 13.5px không lọt nổi content box 12px
|
|
39
|
+
// (14px trừ hai đường viền) nên chữ lệch LÊN — đo được mép trên hở 0,25px
|
|
40
|
+
// còn mép dưới 1,75px.
|
|
41
|
+
//
|
|
42
|
+
// 12px là ĐÚNG BẰNG content box. Đã quét cả thang: 13.5px lệch -1,5;
|
|
43
|
+
// `leading-none` (9px) vẫn lệch -1 vì font box của Geist cao 12px và tràn
|
|
44
|
+
// ra hai đầu line box; 10px / 12px / `normal` đều cho lệch 0 (hở 1px mỗi
|
|
45
|
+
// mép, đúng bằng đường viền). Chọn 12px vì nó là nấc có sẵn và nói thẳng
|
|
46
|
+
// ra quan hệ với chiều cao.
|
|
47
|
+
xs: 'h-3.5 px-1.5 text-[9px] leading-3 [&_svg]:size-2.5',
|
|
48
|
+
default: 'px-2 py-0.5 text-xs [&_svg]:size-3',
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
tone: {
|
|
52
|
+
solid: '',
|
|
53
|
+
soft: '',
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
// Nền pha loãng, chữ giữ nguyên sắc — kiểu "soft-danger" của Bootstrap.
|
|
58
|
+
// `outline` không có bản soft: nó vốn đã không có nền.
|
|
59
|
+
compoundVariants: [
|
|
60
|
+
{ tone: 'soft', variant: 'default', class: 'border-primary-soft-border bg-primary-soft text-primary-soft-foreground' },
|
|
61
|
+
{ tone: 'soft', variant: 'secondary', class: 'border-border bg-secondary text-secondary-foreground' },
|
|
62
|
+
{ tone: 'soft', variant: 'destructive', class: 'border-destructive-soft-border bg-destructive-soft text-destructive-soft-foreground' },
|
|
63
|
+
{ tone: 'soft', variant: 'success', class: 'border-success-soft-border bg-success-soft text-success-soft-foreground' },
|
|
64
|
+
{ tone: 'soft', variant: 'warning', class: 'border-warning-soft-border bg-warning-soft text-warning-soft-foreground' },
|
|
65
|
+
{ tone: 'soft', variant: 'info', class: 'border-info-soft-border bg-info-soft text-info-soft-foreground' },
|
|
66
|
+
],
|
|
67
|
+
|
|
68
|
+
defaultVariants: {
|
|
69
|
+
variant: 'default',
|
|
70
|
+
size: 'default',
|
|
71
|
+
tone: 'solid',
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
export type BadgeVariants = VariantProps<typeof badgeVariants>
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import type { VariantProps } from 'class-variance-authority'
|
|
2
|
+
import { cva } from 'class-variance-authority'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Gộp nhiều nút thành một khối liền mạch: bỏ bo góc ở các cạnh giáp nhau và
|
|
6
|
+
* gộp viền chung.
|
|
7
|
+
*
|
|
8
|
+
* Khác shadcn ở hai chỗ, cả hai đều có lý do:
|
|
9
|
+
*
|
|
10
|
+
* 1. **Chọn con bằng `:first-child` / `:last-child`, không bằng `[data-slot]`.**
|
|
11
|
+
* shadcn đòi mọi phần tử con phải mang `data-slot`; ở đây một `<input>`,
|
|
12
|
+
* một div viết tay hay `DropdownMenuTrigger` bọc `as-child` đều nằm trong
|
|
13
|
+
* nhóm được mà không phải khai gì thêm.
|
|
14
|
+
* 2. **Chỉ TẮT bo góc ở cạnh trong, không ép lại bo góc ở cạnh ngoài.** shadcn
|
|
15
|
+
* ghi đè `rounded-r-lg!` cho con cuối, nên nhóm toàn nút `size="sm"` (vốn
|
|
16
|
+
* `rounded-md`) bị bo 8px thay vì 6px. Để nguyên thì mỗi nút giữ đúng bán
|
|
17
|
+
* kính theo cỡ của nó.
|
|
18
|
+
*
|
|
19
|
+
* ## Trục `depth` — và vì sao nó tồn tại
|
|
20
|
+
*
|
|
21
|
+
* Cây vanilla dựng `<wb-button>` / `<wb-toggle>` ở chế độ shell: host mang
|
|
22
|
+
* `display: contents` và thẻ thật nằm bên trong. Selector `>` vẫn KHỚP cái host,
|
|
23
|
+
* nhưng host không tạo hộp nên `border-radius` áp vào hư không — khai báo đúng,
|
|
24
|
+
* kết quả không có gì. `vanilla/CLAUDE.md` ghi việc này thành một ràng buộc kiến
|
|
25
|
+
* trúc còn mở, với ba lối ra và không lối nào miễn phí.
|
|
26
|
+
*
|
|
27
|
+
* `depth: 'shell'` là lối thứ hai trong ba lối đó, và chọn nó vì phép so sánh
|
|
28
|
+
* nghiêng hẳn về một phía: cái giá của nó **đo được** (vài trăm byte CSS cho mọi
|
|
29
|
+
* app nạp bộ variants), còn cái giá của việc viết bản thứ hai chỉ cho vanilla là
|
|
30
|
+
* hai bộ luật trôi khỏi nhau — thứ cả repo này sinh ra để dập, và thứ không phép
|
|
31
|
+
* đo nào bắt được.
|
|
32
|
+
*
|
|
33
|
+
* Nó phát **cả hai cấp**, không phải chỉ cấp sâu: một nhóm ở light DOM trộn được
|
|
34
|
+
* con có hộp với con `display: contents`, và bảng này không biết trước cái nào
|
|
35
|
+
* là cái nào. Luật rơi vào một host `contents` thì không vẽ gì, nên phát thừa ở
|
|
36
|
+
* đó là vô hại — còn phát thiếu thì góc không bo và không có gì báo.
|
|
37
|
+
*
|
|
38
|
+
* Giới hạn phải nói ra: nó với được **đúng một** cấp. Chuỗi `contents` lồng hai
|
|
39
|
+
* lớp (`<wb-popover-trigger>` bọc `<wb-button>`) thì hụt, và cách xử lý là đừng
|
|
40
|
+
* lồng — xem `WbSplitButton` của cây vanilla.
|
|
41
|
+
*
|
|
42
|
+
* Mặc định vẫn là `direct`, nên ba cây kia không đổi một class nào ở đầu ra.
|
|
43
|
+
* **Đừng dùng `shell` cho `SplitButton`**: ở đó con trực tiếp đã là nút, và với
|
|
44
|
+
* sâu một cấp nữa là bắt trúng nút lồng trong nút.
|
|
45
|
+
*/
|
|
46
|
+
export const buttonGroupVariants = cva(
|
|
47
|
+
[
|
|
48
|
+
'flex w-fit items-stretch',
|
|
49
|
+
// Nút đang focus phải nổi lên trên, nếu không vòng focus bị nút bên cạnh
|
|
50
|
+
// đè mất một nửa — các nút chồng viền lên nhau.
|
|
51
|
+
'[&>*]:focus-visible:relative [&>*]:focus-visible:z-(--z-raised)',
|
|
52
|
+
// Lồng ButtonGroup trong ButtonGroup thì tách hai khối ra, không dính liền.
|
|
53
|
+
'has-[>[data-slot=button-group]]:gap-2',
|
|
54
|
+
'[&>input]:flex-1',
|
|
55
|
+
],
|
|
56
|
+
{
|
|
57
|
+
variants: {
|
|
58
|
+
orientation: {
|
|
59
|
+
horizontal: '',
|
|
60
|
+
vertical: 'h-fit flex-col',
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* `direct` — con trực tiếp là thẻ có hộp (Vue, React, Angular).
|
|
65
|
+
* `shell` — con trực tiếp là một host `display: contents`, thẻ thật nằm
|
|
66
|
+
* sâu thêm một cấp (cây vanilla).
|
|
67
|
+
*/
|
|
68
|
+
depth: {
|
|
69
|
+
direct: '',
|
|
70
|
+
// Vòng focus cũng phải với sâu một cấp: tiêu điểm nằm ở thẻ thật bên
|
|
71
|
+
// trong, nên `> *:focus-visible` của phần base không bao giờ khớp và nút
|
|
72
|
+
// đang focus bị nút bên cạnh đè mất một nửa quầng.
|
|
73
|
+
shell: '[&>*>*:focus-visible]:relative [&>*>*:focus-visible]:z-(--z-raised)',
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
compoundVariants: [
|
|
79
|
+
{
|
|
80
|
+
orientation: 'horizontal',
|
|
81
|
+
depth: 'direct',
|
|
82
|
+
class: [
|
|
83
|
+
'[&>*:not(:first-child)]:rounded-l-none',
|
|
84
|
+
'[&>*:not(:last-child)]:rounded-r-none',
|
|
85
|
+
// Viền trái của con sau trùng viền phải của con trước — bỏ một cái đi
|
|
86
|
+
// thay vì kéo âm lề, để bề rộng từng nút không đổi.
|
|
87
|
+
'[&>*:not(:first-child)]:border-l-0',
|
|
88
|
+
],
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
orientation: 'vertical',
|
|
92
|
+
depth: 'direct',
|
|
93
|
+
class: [
|
|
94
|
+
'[&>*:not(:first-child)]:rounded-t-none',
|
|
95
|
+
'[&>*:not(:last-child)]:rounded-b-none',
|
|
96
|
+
'[&>*:not(:first-child)]:border-t-0',
|
|
97
|
+
],
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
orientation: 'horizontal',
|
|
101
|
+
depth: 'shell',
|
|
102
|
+
class: [
|
|
103
|
+
// CẢ HAI cấp, không phải chỉ cấp sâu: một nhóm ở light DOM trộn được
|
|
104
|
+
// con có hộp (`<input>`, nhãn) với con `display: contents` (`<wb-button>`),
|
|
105
|
+
// và bảng này không biết trước cái nào là cái nào. Luật rơi vào một
|
|
106
|
+
// host `contents` thì không vẽ gì — vô hại — nên phát cả hai là đúng.
|
|
107
|
+
'[&>*:not(:first-child)]:rounded-l-none',
|
|
108
|
+
'[&>*:not(:last-child)]:rounded-r-none',
|
|
109
|
+
'[&>*:not(:first-child)]:border-l-0',
|
|
110
|
+
'[&>*:not(:first-child)>*]:rounded-l-none',
|
|
111
|
+
'[&>*:not(:last-child)>*]:rounded-r-none',
|
|
112
|
+
'[&>*:not(:first-child)>*]:border-l-0',
|
|
113
|
+
],
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
orientation: 'vertical',
|
|
117
|
+
depth: 'shell',
|
|
118
|
+
class: [
|
|
119
|
+
'[&>*:not(:first-child)]:rounded-t-none',
|
|
120
|
+
'[&>*:not(:last-child)]:rounded-b-none',
|
|
121
|
+
'[&>*:not(:first-child)]:border-t-0',
|
|
122
|
+
'[&>*:not(:first-child)>*]:rounded-t-none',
|
|
123
|
+
'[&>*:not(:last-child)>*]:rounded-b-none',
|
|
124
|
+
'[&>*:not(:first-child)>*]:border-t-0',
|
|
125
|
+
],
|
|
126
|
+
},
|
|
127
|
+
],
|
|
128
|
+
|
|
129
|
+
defaultVariants: {
|
|
130
|
+
orientation: 'horizontal',
|
|
131
|
+
depth: 'direct',
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
export type ButtonGroupVariants = VariantProps<typeof buttonGroupVariants>
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import type { VariantProps } from 'class-variance-authority'
|
|
2
|
+
import { cva } from 'class-variance-authority'
|
|
3
|
+
import { focusRing } from '../lib/focus'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Hai trục:
|
|
7
|
+
* - `variant` là **màu** (default, destructive, success…) — không đổi so với trước.
|
|
8
|
+
* - `tone` là **kiểu tô**: `solid` đặc, `soft` nền pha loãng.
|
|
9
|
+
*
|
|
10
|
+
* KHÔNG có tone `glass`: kính là vật liệu của BỀ MẶT (`data-surface="glass"`),
|
|
11
|
+
* bật lên thì mọi nút tự thành kính — xem surfaces.css. Apple cũng khuyến nghị
|
|
12
|
+
* dùng kính dè sẻn ở lớp điều hướng chứ không rải thành biến thể của nút.
|
|
13
|
+
*
|
|
14
|
+
* BẢNG NÀY CHỈ ĐỌC `--button-*`, không đọc token ngữ nghĩa nào nữa. Tầng token
|
|
15
|
+
* riêng của Button nằm ở `@vestow/theme/css/components/button.css`, và mỗi
|
|
16
|
+
* token ở đó mặc định trỏ vào một token dùng chung — nên đổi bảng màu vẫn chảy
|
|
17
|
+
* qua như cũ, chỉ khác là giờ ghi đè được RIÊNG cái nút.
|
|
18
|
+
*
|
|
19
|
+
* Hai con số từng là literal ngay trong file này — `0.97` của phép lún và `50%`
|
|
20
|
+
* của trạng thái disabled — nay là `--button-press-scale` và
|
|
21
|
+
* `--button-disabled-opacity`. Đó đúng là loại hằng số mà tầng token sinh ra để
|
|
22
|
+
* rút: chúng là quyết định thiết kế, không phải chi tiết cài đặt.
|
|
23
|
+
*
|
|
24
|
+
* `--ui-control-*` (chiều cao, đệm ngang) CỐ Ý không nhân bản sang `--button-*`:
|
|
25
|
+
* Toggle dùng chung thang đó theo đúng chủ ý đã ghi ở `CLAUDE.md`, tách ra là
|
|
26
|
+
* dựng lại chính thứ việc gom chúng sinh ra để dập.
|
|
27
|
+
*/
|
|
28
|
+
export const buttonVariants = cva(
|
|
29
|
+
[
|
|
30
|
+
// `ui-button` là móc để surfaces.css biến MỌI nút thành kính khi bật theme
|
|
31
|
+
// glass. Ngoài theme đó nó không khớp rule nào.
|
|
32
|
+
'ui-button inline-flex items-center justify-center gap-(--button-gap) whitespace-nowrap rounded-(--button-radius)',
|
|
33
|
+
'text-(length:--button-font-size) [font-weight:var(--button-font-weight)]',
|
|
34
|
+
// Lún nhẹ khi bấm. Màu đổi trong 140ms, riêng transform 100ms cho dứt khoát
|
|
35
|
+
// — đúng nhịp bản thiết kế khai. `disabled`/`loading` đã bị chặn con trỏ nên
|
|
36
|
+
// không vào được trạng thái :active.
|
|
37
|
+
'transition-[color,background-color,border-color,opacity,transform] duration-(--button-duration)',
|
|
38
|
+
'active:scale-(--button-press-scale) active:duration-(--button-press-duration) motion-reduce:active:scale-100',
|
|
39
|
+
// Cùng vòng focus với ô nhập, không phải một kiểu riêng cho nút. Bắt buộc
|
|
40
|
+
// phải vậy: trigger của DatePicker CHÍNH LÀ một Button, để hai kiểu khác
|
|
41
|
+
// nhau thì trong cùng một form sẽ có hai kiểu focus.
|
|
42
|
+
focusRing,
|
|
43
|
+
'disabled:pointer-events-none disabled:opacity-(--button-disabled-opacity)',
|
|
44
|
+
'aria-disabled:pointer-events-none aria-disabled:opacity-(--button-disabled-opacity)',
|
|
45
|
+
'[&_svg]:pointer-events-none [&_svg]:size-(--button-icon-size) [&_svg]:shrink-0',
|
|
46
|
+
],
|
|
47
|
+
{
|
|
48
|
+
variants: {
|
|
49
|
+
variant: {
|
|
50
|
+
default: 'bg-(--button-default-bg) text-(--button-default-fg) hover:bg-(--button-default-bg-hover) active:bg-(--button-default-bg-active) [--btn-fill:var(--button-default-bg)] [--btn-fill-hover:var(--button-default-bg-hover)] [--btn-on-fill:var(--button-default-fg)] [--btn-soft:var(--button-default-soft-bg)] [--btn-soft-hover:var(--button-default-soft-bg-hover)] [--btn-on-soft:var(--button-default-soft-fg)] [--btn-on-soft-hover:var(--button-default-soft-fg-hover)] [--btn-line:var(--primary-soft-border)]',
|
|
51
|
+
secondary: 'bg-(--button-secondary-bg) text-(--button-secondary-fg) hover:bg-(--button-secondary-bg-hover) active:bg-(--button-secondary-bg-active) [--btn-fill:var(--button-secondary-bg)] [--btn-fill-hover:var(--button-secondary-bg-hover)] [--btn-on-fill:var(--button-secondary-fg)]',
|
|
52
|
+
destructive: 'bg-(--button-destructive-bg) text-(--button-destructive-fg) hover:bg-(--button-destructive-bg-hover) active:bg-(--button-destructive-bg-active) [--btn-fill:var(--button-destructive-bg)] [--btn-fill-hover:var(--button-destructive-bg-hover)] [--btn-on-fill:var(--button-destructive-fg)] [--btn-soft:var(--button-destructive-soft-bg)] [--btn-soft-hover:var(--button-destructive-soft-bg-hover)] [--btn-on-soft:var(--button-destructive-soft-fg)] [--btn-on-soft-hover:var(--button-destructive-soft-fg-hover)] [--btn-line:var(--destructive-soft-border)]',
|
|
53
|
+
success: 'bg-(--button-success-bg) text-(--button-success-fg) hover:bg-(--button-success-bg-hover) active:bg-(--button-success-bg-active) [--btn-fill:var(--button-success-bg)] [--btn-fill-hover:var(--button-success-bg-hover)] [--btn-on-fill:var(--button-success-fg)] [--btn-soft:var(--button-success-soft-bg)] [--btn-soft-hover:var(--button-success-soft-bg-hover)] [--btn-on-soft:var(--button-success-soft-fg)] [--btn-on-soft-hover:var(--button-success-soft-fg-hover)] [--btn-line:var(--success-soft-border)]',
|
|
54
|
+
warning: 'bg-(--button-warning-bg) text-(--button-warning-fg) hover:bg-(--button-warning-bg-hover) active:bg-(--button-warning-bg-active) [--btn-fill:var(--button-warning-bg)] [--btn-fill-hover:var(--button-warning-bg-hover)] [--btn-on-fill:var(--button-warning-fg)] [--btn-soft:var(--button-warning-soft-bg)] [--btn-soft-hover:var(--button-warning-soft-bg-hover)] [--btn-on-soft:var(--button-warning-soft-fg)] [--btn-on-soft-hover:var(--button-warning-soft-fg-hover)] [--btn-line:var(--warning-soft-border)]',
|
|
55
|
+
info: 'bg-(--button-info-bg) text-(--button-info-fg) hover:bg-(--button-info-bg-hover) active:bg-(--button-info-bg-active) [--btn-fill:var(--button-info-bg)] [--btn-fill-hover:var(--button-info-bg-hover)] [--btn-on-fill:var(--button-info-fg)] [--btn-soft:var(--button-info-soft-bg)] [--btn-soft-hover:var(--button-info-soft-bg-hover)] [--btn-on-soft:var(--button-info-soft-fg)] [--btn-on-soft-hover:var(--button-info-soft-fg-hover)] [--btn-line:var(--info-soft-border)]',
|
|
56
|
+
outline: 'border border-(--button-outline-border) bg-(--button-outline-bg) hover:bg-(--button-outline-bg-hover) hover:text-(--button-outline-fg-hover)',
|
|
57
|
+
ghost: 'bg-transparent hover:bg-(--button-ghost-bg-hover) hover:text-(--button-ghost-fg-hover)',
|
|
58
|
+
link: 'bg-transparent text-(--button-link-fg) underline-offset-4 hover:underline',
|
|
59
|
+
},
|
|
60
|
+
size: {
|
|
61
|
+
// Thang đo lấy đúng theo shadcn (đo trên ui.shadcn.com):
|
|
62
|
+
// xs 24px · sm 28px · default 32px · lg 36px, bo 8px cho hai cỡ nhỏ
|
|
63
|
+
// và 10px cho hai cỡ lớn. Nút chỉ có icon là ô vuông cùng chiều cao.
|
|
64
|
+
'xs': 'h-(--ui-control-height-xs) gap-(--button-gap-xs) rounded-(--button-radius-sm) px-(--ui-control-padding-x-xs) text-(length:--button-font-size-xs) [&_svg]:size-(--button-icon-size-xs)',
|
|
65
|
+
'sm': 'h-(--ui-control-height-sm) gap-(--button-gap-xs) rounded-(--button-radius-sm) px-(--ui-control-padding-x) text-(length:--button-font-size-sm)',
|
|
66
|
+
'default': 'h-(--ui-control-height-md) px-(--ui-control-padding-x)',
|
|
67
|
+
'lg': 'h-(--ui-control-height-lg) px-(--ui-control-padding-x)',
|
|
68
|
+
'icon-xs': 'size-(--ui-control-height-xs) rounded-(--button-radius-sm) [&_svg]:size-(--button-icon-size-xs)',
|
|
69
|
+
'icon-sm': 'size-(--ui-control-height-sm) rounded-(--button-radius-sm)',
|
|
70
|
+
'icon': 'size-(--ui-control-height-md)',
|
|
71
|
+
'icon-lg': 'size-(--ui-control-height-lg)',
|
|
72
|
+
},
|
|
73
|
+
tone: {
|
|
74
|
+
solid: '',
|
|
75
|
+
// KHÔNG cắt transition ở đây — xem `compoundVariants`. Trục này để rỗng
|
|
76
|
+
// vì `soft` chỉ có nghĩa với năm sắc có nhóm soft; đặt class ở tầng
|
|
77
|
+
// variant là áp cho cả chín, kể cả ba cái không có nhóm đó.
|
|
78
|
+
soft: '',
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* KIỂU TÔ — trục tách ra khỏi `variant`, theo mô hình Radix Themes.
|
|
83
|
+
*
|
|
84
|
+
* `variant` ở trên đang gộp hai thứ: sáu SẮC cộng ba KIỂU TÔ
|
|
85
|
+
* (`outline`/`ghost`/`link`). Vì vậy ô `outline × soft` không có định
|
|
86
|
+
* nghĩa, và trước đây nó im lặng không làm gì — xem mục cùng tên ở
|
|
87
|
+
* `CLAUDE.md`. Trục này đóng cái lỗ đó: sắc và kiểu tô không còn tranh
|
|
88
|
+
* nhau một prop.
|
|
89
|
+
*
|
|
90
|
+
* THÊM CHỨ KHÔNG ĐỔI. Ba giá trị cũ của `variant` giữ nguyên từng ký tự,
|
|
91
|
+
* và `fill` mặc định `solid` phát ra RỖNG — nên 456 chỗ gọi
|
|
92
|
+
* `variant="outline|ghost|link"` và 86 chỗ `tone="soft"` không phải sửa,
|
|
93
|
+
* và parity là chuyện cấu trúc chứ không phải lời hứa.
|
|
94
|
+
*
|
|
95
|
+
* Mỗi kiểu tô đọc BIẾN NGUỒN mà sáu sắc đặt ở trên, nên thêm một kiểu tô
|
|
96
|
+
* là **một dòng**, không phải 5 sắc × 4 token. Đó đúng là chỗ mô hình
|
|
97
|
+
* liệt kê tốn kém nhất.
|
|
98
|
+
*
|
|
99
|
+
* VIỀN CỦA `outline` VÀ CỦA `surface` KHÔNG cùng một token, và đó là
|
|
100
|
+
* phép đo chứ không phải thẩm mỹ. `surface` có nền nên viền chỉ là mép —
|
|
101
|
+
* `--x-soft-border` (tint 34%) hợp. `outline` KHÔNG có nền, nên viền
|
|
102
|
+
* chính là ranh giới của control và WCAG 1.4.11 đòi 3:1. Đo 100 tổ hợp
|
|
103
|
+
* (5 sắc × 5 bảng màu × sáng/tối × trên nền trang và trên card):
|
|
104
|
+
*
|
|
105
|
+
* --x-soft-border thấp nhất 1,22 — 50/100 trượt
|
|
106
|
+
* --x (màu đặc) thấp nhất 2,05 — 10/100 trượt
|
|
107
|
+
* --x-soft-foreground thấp nhất 5,32 — 0 trượt <- chọn cái này
|
|
108
|
+
*
|
|
109
|
+
* Nó cũng chính là màu chữ của nút, nên viền và chữ cùng tông.
|
|
110
|
+
*
|
|
111
|
+
* Giá trị lui trong mỗi `var()` là bắt buộc, không phải phòng xa:
|
|
112
|
+
* `secondary` KHÔNG có nhóm soft ở bất kỳ tầng nào, nên thiếu nó thì
|
|
113
|
+
* `fill="soft"` trên secondary ra nền rỗng. Và ba variant cũ không đặt
|
|
114
|
+
* biến nào, nên chúng rơi về đúng token trung tính của chính chúng.
|
|
115
|
+
*/
|
|
116
|
+
fill: {
|
|
117
|
+
solid: '',
|
|
118
|
+
|
|
119
|
+
soft: 'transition-[border-color,opacity,transform] bg-[var(--btn-soft,var(--btn-fill))] text-[var(--btn-on-soft,var(--btn-on-fill))] hover:bg-[var(--btn-soft-hover,var(--btn-fill-hover))] hover:text-[var(--btn-on-soft-hover,var(--btn-on-fill))]',
|
|
120
|
+
|
|
121
|
+
// Ô mà `outline × soft` lẽ ra phải là: nền pha loãng KÈM viền. Radix
|
|
122
|
+
// Themes gọi nó `surface`, nên lấy luôn cái tên thay vì bịa.
|
|
123
|
+
surface: 'transition-[border-color,opacity,transform] border bg-[var(--btn-soft,var(--btn-fill))] text-[var(--btn-on-soft,var(--btn-on-fill))] border-[var(--btn-line,var(--button-outline-border))] hover:bg-[var(--btn-soft-hover,var(--btn-fill-hover))] hover:text-[var(--btn-on-soft-hover,var(--btn-on-fill))]',
|
|
124
|
+
|
|
125
|
+
outline: 'border bg-transparent border-[var(--btn-on-soft,var(--button-outline-border))] text-[var(--btn-on-soft,inherit)] hover:bg-[var(--btn-soft,var(--button-outline-bg-hover))] hover:text-[var(--btn-on-soft,var(--button-outline-fg-hover))] active:bg-[var(--btn-soft,transparent)]',
|
|
126
|
+
|
|
127
|
+
ghost: 'bg-transparent text-[var(--btn-on-soft,inherit)] hover:bg-[var(--btn-soft,var(--button-ghost-bg-hover))] hover:text-[var(--btn-on-soft,var(--button-ghost-fg-hover))] active:bg-transparent',
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
|
|
131
|
+
// Nền pha loãng, chữ giữ nguyên sắc. Hover đậm thêm một nấc bằng token
|
|
132
|
+
// riêng — dùng `hover:bg-x/20` sẽ NHẠT ĐI ở chế độ tối, vì nền soft bản tối
|
|
133
|
+
// đã là 22%. Chỉ có cho các variant MÀU; outline/ghost/link vốn đã nhạt.
|
|
134
|
+
//
|
|
135
|
+
// `transition-[border-color,opacity,transform]` nằm Ở ĐÂY chứ không ở trục
|
|
136
|
+
// `tone`, và đó là một BẢN SỬA: nó bỏ `color` với `background-color` khỏi
|
|
137
|
+
// danh sách để chặn cú sập tương phản 1,09:1 giữa lúc soft chuyển sang nền
|
|
138
|
+
// đặc. Cú đó chỉ xảy ra với năm sắc dưới đây. Đặt ở tầng `tone` thì
|
|
139
|
+
// `outline`/`ghost` + `soft` cũng bị cắt — hai cái đó KHÔNG đổi diện mạo
|
|
140
|
+
// theo tone, nên chúng chỉ mất phần nội suy màu khi hover mà không được gì.
|
|
141
|
+
// Đo trước khi sửa: `outline` + `soft` ra `border-color, opacity, transform`
|
|
142
|
+
// thay vì đủ năm thuộc tính.
|
|
143
|
+
compoundVariants: [
|
|
144
|
+
{ tone: 'soft', variant: 'default', class: 'transition-[border-color,opacity,transform] bg-(--button-default-soft-bg) text-(--button-default-soft-fg) hover:bg-(--button-default-soft-bg-hover) hover:text-(--button-default-soft-fg-hover)' },
|
|
145
|
+
{ tone: 'soft', variant: 'destructive', class: 'transition-[border-color,opacity,transform] bg-(--button-destructive-soft-bg) text-(--button-destructive-soft-fg) hover:bg-(--button-destructive-soft-bg-hover) hover:text-(--button-destructive-soft-fg-hover)' },
|
|
146
|
+
{ tone: 'soft', variant: 'success', class: 'transition-[border-color,opacity,transform] bg-(--button-success-soft-bg) text-(--button-success-soft-fg) hover:bg-(--button-success-soft-bg-hover) hover:text-(--button-success-soft-fg-hover)' },
|
|
147
|
+
{ tone: 'soft', variant: 'warning', class: 'transition-[border-color,opacity,transform] bg-(--button-warning-soft-bg) text-(--button-warning-soft-fg) hover:bg-(--button-warning-soft-bg-hover) hover:text-(--button-warning-soft-fg-hover)' },
|
|
148
|
+
{ tone: 'soft', variant: 'info', class: 'transition-[border-color,opacity,transform] bg-(--button-info-soft-bg) text-(--button-info-soft-fg) hover:bg-(--button-info-soft-bg-hover) hover:text-(--button-info-soft-fg-hover)' },
|
|
149
|
+
],
|
|
150
|
+
|
|
151
|
+
defaultVariants: {
|
|
152
|
+
variant: 'default',
|
|
153
|
+
size: 'default',
|
|
154
|
+
tone: 'solid',
|
|
155
|
+
fill: 'solid',
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
export type ButtonVariants = VariantProps<typeof buttonVariants>
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { VariantProps } from 'class-variance-authority'
|
|
2
|
+
import { cva } from 'class-variance-authority'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Ô đánh dấu. Hai trục, đúng quy ước của repo:
|
|
6
|
+
*
|
|
7
|
+
* - `size` — `sm` 14px, `md` 16px (mặc định), `lg` 20px.
|
|
8
|
+
* - `tone` là **kiểu tô**: `outline` nền trong, `filled` nền xám khi chưa chọn.
|
|
9
|
+
* PrimeVue gọi cái này là `variant="filled"`; ở đây `variant` dành riêng cho
|
|
10
|
+
* **màu** (xem Button/Badge) nên phải đổi tên, không đổi ý nghĩa.
|
|
11
|
+
*
|
|
12
|
+
* Không có trục màu: một ô đánh dấu đã chọn luôn là màu primary. Trạng thái lỗi
|
|
13
|
+
* đi qua `invalid` chứ không phải qua `variant="destructive"` — nó là trạng thái
|
|
14
|
+
* xác thực, không phải một lựa chọn thiết kế.
|
|
15
|
+
*/
|
|
16
|
+
export const checkboxVariants = cva(
|
|
17
|
+
[
|
|
18
|
+
'peer inline-flex shrink-0 items-center justify-center border shadow-xs',
|
|
19
|
+
'transition-[color,background-color,border-color] duration-(--ui-control-duration)',
|
|
20
|
+
'focus-visible:outline-none',
|
|
21
|
+
'disabled:cursor-not-allowed disabled:opacity-50',
|
|
22
|
+
'[&_svg]:pointer-events-none [&_svg]:shrink-0',
|
|
23
|
+
],
|
|
24
|
+
{
|
|
25
|
+
variants: {
|
|
26
|
+
// Bán kính bo theo cỡ: 4px trên ô 16px là tỉ lệ của bản gốc, giữ nguyên
|
|
27
|
+
// con số đó cho ô 14px thì trông tròn quá, cho ô 20px thì trông vuông quá.
|
|
28
|
+
size: {
|
|
29
|
+
sm: 'size-3.5 rounded-[3px] [&_svg]:size-3',
|
|
30
|
+
md: 'size-4 rounded-[4px] [&_svg]:size-3.5',
|
|
31
|
+
lg: 'size-5 rounded-[5px] [&_svg]:size-4',
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
tone: {
|
|
35
|
+
outline: 'bg-background',
|
|
36
|
+
filled: 'bg-muted',
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Khai thành một trục của cva chứ không dùng `aria-invalid:` — lớp đã chọn
|
|
41
|
+
* và lớp lỗi cùng tô `background-color`, mà thứ tự thắng thua giữa hai
|
|
42
|
+
* variant của Tailwind do thứ tự trong stylesheet quyết định chứ không
|
|
43
|
+
* phải thứ tự mình viết. Gộp vào một nhánh thì không còn gì để đoán.
|
|
44
|
+
*/
|
|
45
|
+
invalid: {
|
|
46
|
+
false: [
|
|
47
|
+
'border-input focus-visible:shadow-focus',
|
|
48
|
+
'data-[state=checked]:border-primary data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground',
|
|
49
|
+
'data-[state=indeterminate]:border-primary data-[state=indeterminate]:bg-primary data-[state=indeterminate]:text-primary-foreground',
|
|
50
|
+
],
|
|
51
|
+
true: [
|
|
52
|
+
'border-destructive focus-visible:shadow-focus-invalid',
|
|
53
|
+
'data-[state=checked]:bg-destructive data-[state=checked]:text-destructive-foreground',
|
|
54
|
+
'data-[state=indeterminate]:bg-destructive data-[state=indeterminate]:text-destructive-foreground',
|
|
55
|
+
],
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
defaultVariants: {
|
|
60
|
+
size: 'md',
|
|
61
|
+
tone: 'outline',
|
|
62
|
+
invalid: false,
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
export type CheckboxVariants = VariantProps<typeof checkboxVariants>
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { VariantProps } from 'class-variance-authority'
|
|
2
|
+
import { cva } from 'class-variance-authority'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Chip là Badge **tương tác được**: gỡ được, cao hơn, bo tròn hẳn.
|
|
6
|
+
*
|
|
7
|
+
* Bảng này KHÔNG tham chiếu `badgeVariants` — nó chỉ khai hình dáng, còn trục
|
|
8
|
+
* màu (`variant`/`tone`) thì bên gọi lấy thẳng từ `badgeVariants` rồi ghép lại
|
|
9
|
+
* bằng `cn()`. Bốn chỗ đang làm vậy: `Chip`, `InputTagsItem` và hai bản Select.
|
|
10
|
+
*
|
|
11
|
+
* Khác biệt thật giữa Badge và Chip là **ngữ nghĩa**: Badge là nhãn tĩnh, Chip
|
|
12
|
+
* là một mục người dùng thêm vào rồi bỏ ra (bộ lọc đang áp, người nhận trong ô
|
|
13
|
+
* "To:").
|
|
14
|
+
*
|
|
15
|
+
* Từ vựng cỡ ở đây — `sm` / `default` / `lg` — khớp `buttonVariants` và
|
|
16
|
+
* `badgeVariants`; ba bảng nói chung một từ vựng.
|
|
17
|
+
*/
|
|
18
|
+
export const chipVariants = cva(
|
|
19
|
+
'inline-flex max-w-full items-center gap-1.5 rounded-full border font-medium whitespace-nowrap',
|
|
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-5 gap-1 pl-2 pr-1 text-[11px] leading-none [&_svg]:size-3',
|
|
27
|
+
default: 'h-6 pl-2.5 pr-1 text-xs [&_svg]:size-3.5',
|
|
28
|
+
lg: 'h-7 pl-3 pr-1.5 text-[13px] leading-none [&_svg]:size-4',
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
/** Không có nút gỡ thì phần đệm phải cân lại hai bên. */
|
|
32
|
+
removable: {
|
|
33
|
+
true: '',
|
|
34
|
+
false: '',
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
compoundVariants: [
|
|
39
|
+
{ removable: false, size: 'sm', class: 'pr-2' },
|
|
40
|
+
{ removable: false, size: 'default', class: 'pr-2.5' },
|
|
41
|
+
{ removable: false, size: 'lg', class: 'pr-3' },
|
|
42
|
+
],
|
|
43
|
+
|
|
44
|
+
defaultVariants: {
|
|
45
|
+
size: 'default',
|
|
46
|
+
removable: false,
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
export type ChipVariants = VariantProps<typeof chipVariants>
|