@aleph-alpha/ui-library 1.9.0 → 1.11.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 +14 -0
- package/dist/system/index-CkH7HQaa.js +7 -0
- package/dist/system/index-CuHwEAQ_.js +7 -0
- package/dist/system/index.d.ts +1322 -318
- package/dist/system/lib.js +8839 -6993
- package/package.json +2 -1
- package/src/@types/shims-vue.d.ts +5 -0
- package/src/__tests__/placeholder.test.ts +7 -0
- package/src/compositions/UiCompositionPlaceholder/UiCompositionPlaceholder.vue +9 -0
- package/src/compositions/UiCompositionPlaceholder/index.ts +1 -0
- package/src/compositions/UiCompositionPlaceholder/types.ts +8 -0
- package/src/compositions/UiDataTable/UiDataTable.mock.ts +104 -0
- package/src/compositions/UiDataTable/UiDataTable.stories.ts +1575 -0
- package/src/compositions/UiDataTable/UiDataTable.vue +129 -0
- package/src/compositions/UiDataTable/UiDataTableColumnHeader.vue +97 -0
- package/src/compositions/UiDataTable/UiDataTablePagination.vue +147 -0
- package/src/compositions/UiDataTable/UiDataTableToolbar.vue +85 -0
- package/src/compositions/UiDataTable/__tests__/UiDataTable.test.ts +372 -0
- package/src/compositions/UiDataTable/__tests__/UiDataTableColumnHeader.test.ts +217 -0
- package/src/compositions/UiDataTable/__tests__/UiDataTablePagination.test.ts +274 -0
- package/src/compositions/UiDataTable/__tests__/UiDataTableToolbar.test.ts +198 -0
- package/src/compositions/UiDataTable/constants.ts +77 -0
- package/src/compositions/UiDataTable/index.ts +6 -0
- package/src/compositions/UiDataTable/types.ts +39 -0
- package/src/compositions/UiDatePicker/UiDatePicker.stories.ts +976 -0
- package/src/compositions/UiDatePicker/UiDatePicker.vue +193 -0
- package/src/compositions/UiDatePicker/__tests__/UiDatePicker.test.ts +325 -0
- package/src/compositions/UiDatePicker/index.ts +14 -0
- package/src/compositions/UiDatePicker/types.ts +220 -0
- package/src/compositions/index.ts +8 -0
- package/src/foundations/UiPlaceholder/UiPlaceholder.vue +9 -0
- package/src/foundations/UiPlaceholder/index.ts +1 -0
- package/src/foundations/UiPlaceholder/types.ts +8 -0
- package/src/foundations/index.ts +6 -0
- package/src/index.ts +27 -0
- package/src/lib/utils.ts +6 -0
- package/src/primitives/UiAccordion/UiAccordion.stories.ts +476 -0
- package/src/primitives/UiAccordion/UiAccordion.vue +31 -0
- package/src/primitives/UiAccordion/UiAccordionContent.vue +16 -0
- package/src/primitives/UiAccordion/UiAccordionItem.vue +16 -0
- package/src/primitives/UiAccordion/UiAccordionTrigger.vue +23 -0
- package/src/primitives/UiAccordion/__tests__/UiAccordion.test.ts +198 -0
- package/src/primitives/UiAccordion/index.ts +6 -0
- package/src/primitives/UiAccordion/types.ts +95 -0
- package/src/primitives/UiAlert/UiAlert.stories.ts +199 -0
- package/src/primitives/UiAlert/UiAlert.vue +27 -0
- package/src/primitives/UiAlert/UiAlertDescription.vue +13 -0
- package/src/primitives/UiAlert/UiAlertTitle.vue +13 -0
- package/src/primitives/UiAlert/__tests__/UiAlert.test.ts +20 -0
- package/src/primitives/UiAlert/constants.ts +3 -0
- package/src/primitives/UiAlert/index.ts +5 -0
- package/src/primitives/UiAlert/types.ts +14 -0
- package/src/primitives/UiAlertDialog/UiAlertDialog.stories.ts +186 -0
- package/src/primitives/UiAlertDialog/UiAlertDialog.vue +18 -0
- package/src/primitives/UiAlertDialog/UiAlertDialogAction.vue +16 -0
- package/src/primitives/UiAlertDialog/UiAlertDialogCancel.vue +16 -0
- package/src/primitives/UiAlertDialog/UiAlertDialogContent.vue +26 -0
- package/src/primitives/UiAlertDialog/UiAlertDialogDescription.vue +16 -0
- package/src/primitives/UiAlertDialog/UiAlertDialogFooter.vue +13 -0
- package/src/primitives/UiAlertDialog/UiAlertDialogHeader.vue +16 -0
- package/src/primitives/UiAlertDialog/UiAlertDialogTitle.vue +16 -0
- package/src/primitives/UiAlertDialog/UiAlertDialogTrigger.vue +17 -0
- package/src/primitives/UiAlertDialog/__tests__/UiAlertDialog.test.ts +184 -0
- package/src/primitives/UiAlertDialog/index.ts +9 -0
- package/src/primitives/UiAlertDialog/types.ts +83 -0
- package/src/primitives/UiAvatar/UiAvatar.stories.ts +194 -0
- package/src/primitives/UiAvatar/UiAvatar.vue +13 -0
- package/src/primitives/UiAvatar/UiAvatarFallback.vue +13 -0
- package/src/primitives/UiAvatar/UiAvatarImage.vue +14 -0
- package/src/primitives/UiAvatar/__tests__/UiAvatar.test.ts +36 -0
- package/src/primitives/UiAvatar/index.ts +3 -0
- package/src/primitives/UiAvatar/types.ts +17 -0
- package/src/primitives/UiBadge/UiBadge.stories.ts +373 -0
- package/src/primitives/UiBadge/UiBadge.vue +21 -0
- package/src/primitives/UiBadge/__tests__/UiBadge.test.ts +44 -0
- package/src/primitives/UiBadge/constants.ts +3 -0
- package/src/primitives/UiBadge/index.ts +2 -0
- package/src/primitives/UiBadge/types.ts +48 -0
- package/src/primitives/UiButton/UiButton.stories.ts +537 -0
- package/src/primitives/UiButton/UiButton.vue +72 -0
- package/src/primitives/UiButton/__tests__/UiButton.test.ts +133 -0
- package/src/primitives/UiButton/index.ts +2 -0
- package/src/primitives/UiButton/types.ts +87 -0
- package/src/primitives/UiCalendar/UiCalendar.stories.ts +797 -0
- package/src/primitives/UiCalendar/UiCalendar.vue +67 -0
- package/src/primitives/UiCalendar/__tests__/UiCalendar.test.ts +45 -0
- package/src/primitives/UiCalendar/index.ts +15 -0
- package/src/primitives/UiCalendar/types.ts +236 -0
- package/src/primitives/UiCard/UiCard.stories.ts +197 -0
- package/src/primitives/UiCard/UiCard.vue +13 -0
- package/src/primitives/UiCard/UiCardAction.vue +13 -0
- package/src/primitives/UiCard/UiCardContent.vue +13 -0
- package/src/primitives/UiCard/UiCardDescription.vue +13 -0
- package/src/primitives/UiCard/UiCardFooter.vue +13 -0
- package/src/primitives/UiCard/UiCardHeader.vue +13 -0
- package/src/primitives/UiCard/UiCardTitle.vue +13 -0
- package/src/primitives/UiCard/__tests__/UiCard.test.ts +19 -0
- package/src/primitives/UiCard/__tests__/UiCardAction.test.ts +19 -0
- package/src/primitives/UiCard/__tests__/UiCardContent.test.ts +19 -0
- package/src/primitives/UiCard/__tests__/UiCardDescription.test.ts +19 -0
- package/src/primitives/UiCard/__tests__/UiCardFooter.test.ts +19 -0
- package/src/primitives/UiCard/__tests__/UiCardHeader.test.ts +19 -0
- package/src/primitives/UiCard/__tests__/UiCardTitle.test.ts +19 -0
- package/src/primitives/UiCard/index.ts +7 -0
- package/src/primitives/UiCard/types.ts +10 -0
- package/src/primitives/UiCheckbox/UiCheckbox.stories.ts +231 -0
- package/src/primitives/UiCheckbox/UiCheckbox.vue +19 -0
- package/src/primitives/UiCheckbox/__tests__/UiCheckbox.test.ts +29 -0
- package/src/primitives/UiCheckbox/index.ts +2 -0
- package/src/primitives/UiCheckbox/types.ts +30 -0
- package/src/primitives/UiDrawer/UiDrawer.stories.ts +602 -0
- package/src/primitives/UiDrawer/UiDrawer.vue +19 -0
- package/src/primitives/UiDrawer/UiDrawerClose.vue +16 -0
- package/src/primitives/UiDrawer/UiDrawerContent.vue +29 -0
- package/src/primitives/UiDrawer/UiDrawerDescription.vue +16 -0
- package/src/primitives/UiDrawer/UiDrawerFooter.vue +16 -0
- package/src/primitives/UiDrawer/UiDrawerHeader.vue +16 -0
- package/src/primitives/UiDrawer/UiDrawerTitle.vue +16 -0
- package/src/primitives/UiDrawer/UiDrawerTrigger.vue +16 -0
- package/src/primitives/UiDrawer/__tests__/UiDrawer.test.ts +229 -0
- package/src/primitives/UiDrawer/index.ts +8 -0
- package/src/primitives/UiDrawer/types.ts +96 -0
- package/src/primitives/UiDropdownMenu/UiDropdownMenu.stories.ts +760 -0
- package/src/primitives/UiDropdownMenu/UiDropdownMenu.vue +25 -0
- package/src/primitives/UiDropdownMenu/UiDropdownMenuCheckboxItem.vue +29 -0
- package/src/primitives/UiDropdownMenu/UiDropdownMenuContent.vue +27 -0
- package/src/primitives/UiDropdownMenu/UiDropdownMenuGroup.vue +13 -0
- package/src/primitives/UiDropdownMenu/UiDropdownMenuItem.vue +26 -0
- package/src/primitives/UiDropdownMenu/UiDropdownMenuLabel.vue +18 -0
- package/src/primitives/UiDropdownMenu/UiDropdownMenuRadioGroup.vue +20 -0
- package/src/primitives/UiDropdownMenu/UiDropdownMenuRadioItem.vue +26 -0
- package/src/primitives/UiDropdownMenu/UiDropdownMenuSeparator.vue +11 -0
- package/src/primitives/UiDropdownMenu/UiDropdownMenuShortcut.vue +13 -0
- package/src/primitives/UiDropdownMenu/UiDropdownMenuSub.vue +26 -0
- package/src/primitives/UiDropdownMenu/UiDropdownMenuSubContent.vue +23 -0
- package/src/primitives/UiDropdownMenu/UiDropdownMenuSubTrigger.vue +24 -0
- package/src/primitives/UiDropdownMenu/UiDropdownMenuTrigger.vue +24 -0
- package/src/primitives/UiDropdownMenu/__tests__/UiDropdownMenu.test.ts +557 -0
- package/src/primitives/UiDropdownMenu/index.ts +16 -0
- package/src/primitives/UiDropdownMenu/types.ts +219 -0
- package/src/primitives/UiField/UiField.stories.ts +1496 -0
- package/src/primitives/UiField/UiField.vue +18 -0
- package/src/primitives/UiField/UiFieldContent.vue +13 -0
- package/src/primitives/UiField/UiFieldDescription.vue +13 -0
- package/src/primitives/UiField/UiFieldError.vue +20 -0
- package/src/primitives/UiField/UiFieldGroup.vue +13 -0
- package/src/primitives/UiField/UiFieldLabel.vue +16 -0
- package/src/primitives/UiField/UiFieldLegend.vue +13 -0
- package/src/primitives/UiField/UiFieldSeparator.vue +13 -0
- package/src/primitives/UiField/UiFieldSet.vue +13 -0
- package/src/primitives/UiField/UiFieldTitle.vue +13 -0
- package/src/primitives/UiField/__tests__/UiFieldError.test.ts +35 -0
- package/src/primitives/UiField/index.ts +10 -0
- package/src/primitives/UiField/types.ts +47 -0
- package/src/primitives/UiIcon/UiIcon.stories.ts +95 -0
- package/src/primitives/UiIcon/UiIcon.vue +14 -0
- package/src/primitives/UiIcon/__tests__/UiIcon.test.ts +24 -0
- package/src/primitives/UiIcon/index.ts +1 -0
- package/src/primitives/UiIcon/types.ts +23 -0
- package/src/primitives/UiIconButton/UiIconButton.stories.ts +446 -0
- package/src/primitives/UiIconButton/UiIconButton.vue +63 -0
- package/src/primitives/UiIconButton/__tests__/UiIconButton.test.ts +102 -0
- package/src/primitives/UiIconButton/index.ts +2 -0
- package/src/primitives/UiIconButton/types.ts +67 -0
- package/src/primitives/UiInput/UiInput.stories.ts +193 -0
- package/src/primitives/UiInput/UiInput.vue +19 -0
- package/src/primitives/UiInput/__tests__/UiInput.test.ts +38 -0
- package/src/primitives/UiInput/index.ts +2 -0
- package/src/primitives/UiInput/types.ts +31 -0
- package/src/primitives/UiPopover/UiPopover.stories.ts +394 -0
- package/src/primitives/UiPopover/UiPopover.vue +17 -0
- package/src/primitives/UiPopover/UiPopoverContent.vue +27 -0
- package/src/primitives/UiPopover/UiPopoverTrigger.vue +16 -0
- package/src/primitives/UiPopover/__tests__/UiPopover.test.ts +87 -0
- package/src/primitives/UiPopover/index.ts +5 -0
- package/src/primitives/UiPopover/types.ts +86 -0
- package/src/primitives/UiProgress/UiProgress.stories.ts +92 -0
- package/src/primitives/UiProgress/UiProgress.vue +25 -0
- package/src/primitives/UiProgress/__tests__/UiProgress.test.ts +46 -0
- package/src/primitives/UiProgress/index.ts +2 -0
- package/src/primitives/UiProgress/types.ts +16 -0
- package/src/primitives/UiRadioGroup/UiRadioGroup.stories.ts +291 -0
- package/src/primitives/UiRadioGroup/UiRadioGroup.vue +43 -0
- package/src/primitives/UiRadioGroup/UiRadioGroupItem.vue +18 -0
- package/src/primitives/UiRadioGroup/__tests__/UiRadioGroup.test.ts +404 -0
- package/src/primitives/UiRadioGroup/index.ts +4 -0
- package/src/primitives/UiRadioGroup/types.ts +66 -0
- package/src/primitives/UiRangeCalendar/UiRangeCalendar.stories.ts +609 -0
- package/src/primitives/UiRangeCalendar/UiRangeCalendar.vue +50 -0
- package/src/primitives/UiRangeCalendar/__tests__/UiRangeCalendar.test.ts +35 -0
- package/src/primitives/UiRangeCalendar/index.ts +13 -0
- package/src/primitives/UiRangeCalendar/types.ts +184 -0
- package/src/primitives/UiSelect/UiSelect.stories.ts +425 -0
- package/src/primitives/UiSelect/UiSelect.vue +47 -0
- package/src/primitives/UiSelect/UiSelectContent.vue +30 -0
- package/src/primitives/UiSelect/UiSelectGroup.vue +13 -0
- package/src/primitives/UiSelect/UiSelectItem.vue +19 -0
- package/src/primitives/UiSelect/UiSelectLabel.vue +13 -0
- package/src/primitives/UiSelect/UiSelectSeparator.vue +11 -0
- package/src/primitives/UiSelect/UiSelectTrigger.vue +30 -0
- package/src/primitives/UiSelect/UiSelectValue.vue +18 -0
- package/src/primitives/UiSelect/__tests__/UiSelect.test.ts +211 -0
- package/src/primitives/UiSelect/__tests__/UiSelectContent.test.ts +30 -0
- package/src/primitives/UiSelect/__tests__/UiSelectGroup.test.ts +85 -0
- package/src/primitives/UiSelect/__tests__/UiSelectItem.test.ts +79 -0
- package/src/primitives/UiSelect/__tests__/UiSelectLabel.test.ts +83 -0
- package/src/primitives/UiSelect/__tests__/UiSelectSeparator.test.ts +82 -0
- package/src/primitives/UiSelect/__tests__/UiSelectTrigger.test.ts +54 -0
- package/src/primitives/UiSelect/__tests__/UiSelectValue.test.ts +39 -0
- package/src/primitives/UiSelect/index.ts +10 -0
- package/src/primitives/UiSelect/types.ts +93 -0
- package/src/primitives/UiSlider/UiSlider.stories.ts +226 -0
- package/src/primitives/UiSlider/UiSlider.vue +44 -0
- package/src/primitives/UiSlider/__tests__/UiSlider.test.ts +76 -0
- package/src/primitives/UiSlider/index.ts +1 -0
- package/src/primitives/UiSlider/types.ts +101 -0
- package/src/primitives/UiSpinner/UiSpinner.stories.ts +143 -0
- package/src/primitives/UiSpinner/UiSpinner.vue +16 -0
- package/src/primitives/UiSpinner/__tests__/UiSpinner.test.ts +19 -0
- package/src/primitives/UiSpinner/index.ts +2 -0
- package/src/primitives/UiSpinner/types.ts +16 -0
- package/src/primitives/UiSwitch/UiSwitch.stories.ts +120 -0
- package/src/primitives/UiSwitch/UiSwitch.vue +21 -0
- package/src/primitives/UiSwitch/__tests__/UiSwitch.test.ts +47 -0
- package/src/primitives/UiSwitch/index.ts +2 -0
- package/src/primitives/UiSwitch/types.ts +25 -0
- package/src/primitives/UiTable/UiTable.stories.ts +505 -0
- package/src/primitives/UiTable/UiTable.vue +13 -0
- package/src/primitives/UiTable/UiTableBody.vue +13 -0
- package/src/primitives/UiTable/UiTableCaption.vue +13 -0
- package/src/primitives/UiTable/UiTableCell.vue +16 -0
- package/src/primitives/UiTable/UiTableEmpty.vue +18 -0
- package/src/primitives/UiTable/UiTableFooter.vue +13 -0
- package/src/primitives/UiTable/UiTableHead.vue +18 -0
- package/src/primitives/UiTable/UiTableHeader.vue +13 -0
- package/src/primitives/UiTable/UiTableRow.vue +18 -0
- package/src/primitives/UiTable/__tests__/UiTable.test.ts +19 -0
- package/src/primitives/UiTable/__tests__/UiTableBody.test.ts +19 -0
- package/src/primitives/UiTable/__tests__/UiTableCaption.test.ts +19 -0
- package/src/primitives/UiTable/__tests__/UiTableCell.test.ts +26 -0
- package/src/primitives/UiTable/__tests__/UiTableEmpty.test.ts +32 -0
- package/src/primitives/UiTable/__tests__/UiTableFooter.test.ts +19 -0
- package/src/primitives/UiTable/__tests__/UiTableHead.test.ts +43 -0
- package/src/primitives/UiTable/__tests__/UiTableHeader.test.ts +19 -0
- package/src/primitives/UiTable/__tests__/UiTableRow.test.ts +32 -0
- package/src/primitives/UiTable/index.ts +16 -0
- package/src/primitives/UiTable/types.ts +68 -0
- package/src/primitives/UiTabs/UiTabs.stories.ts +456 -0
- package/src/primitives/UiTabs/UiTabs.vue +31 -0
- package/src/primitives/UiTabs/UiTabsContent.vue +16 -0
- package/src/primitives/UiTabs/UiTabsList.vue +16 -0
- package/src/primitives/UiTabs/UiTabsTrigger.vue +16 -0
- package/src/primitives/UiTabs/__tests__/UiTabs.test.ts +122 -0
- package/src/primitives/UiTabs/index.ts +6 -0
- package/src/primitives/UiTabs/types.ts +68 -0
- package/src/primitives/UiTextarea/UiTextarea.stories.ts +107 -0
- package/src/primitives/UiTextarea/UiTextarea.vue +19 -0
- package/src/primitives/UiTextarea/__tests__/UiTextarea.test.ts +40 -0
- package/src/primitives/UiTextarea/index.ts +2 -0
- package/src/primitives/UiTextarea/types.ts +30 -0
- package/src/primitives/UiTooltip/UiTooltip.stories.ts +550 -0
- package/src/primitives/UiTooltip/UiTooltip.vue +42 -0
- package/src/primitives/UiTooltip/__tests__/UiTooltip.test.ts +78 -0
- package/src/primitives/UiTooltip/index.ts +2 -0
- package/src/primitives/UiTooltip/types.ts +53 -0
- package/src/primitives/index.ts +33 -0
- package/src/primitives/shadcn/accordion/Accordion.vue +15 -0
- package/src/primitives/shadcn/accordion/AccordionContent.vue +23 -0
- package/src/primitives/shadcn/accordion/AccordionItem.vue +24 -0
- package/src/primitives/shadcn/accordion/AccordionTrigger.vue +35 -0
- package/src/primitives/shadcn/accordion/index.ts +4 -0
- package/src/primitives/shadcn/alert/Alert.vue +17 -0
- package/src/primitives/shadcn/alert/AlertDescription.vue +22 -0
- package/src/primitives/shadcn/alert/AlertTitle.vue +17 -0
- package/src/primitives/shadcn/alert/index.ts +24 -0
- package/src/primitives/shadcn/alert-dialog/AlertDialog.vue +15 -0
- package/src/primitives/shadcn/alert-dialog/AlertDialogAction.vue +18 -0
- package/src/primitives/shadcn/alert-dialog/AlertDialogCancel.vue +21 -0
- package/src/primitives/shadcn/alert-dialog/AlertDialogContent.vue +44 -0
- package/src/primitives/shadcn/alert-dialog/AlertDialogDescription.vue +21 -0
- package/src/primitives/shadcn/alert-dialog/AlertDialogFooter.vue +17 -0
- package/src/primitives/shadcn/alert-dialog/AlertDialogHeader.vue +17 -0
- package/src/primitives/shadcn/alert-dialog/AlertDialogTitle.vue +21 -0
- package/src/primitives/shadcn/alert-dialog/AlertDialogTrigger.vue +12 -0
- package/src/primitives/shadcn/alert-dialog/index.ts +9 -0
- package/src/primitives/shadcn/avatar/Avatar.vue +18 -0
- package/src/primitives/shadcn/avatar/AvatarFallback.vue +21 -0
- package/src/primitives/shadcn/avatar/AvatarImage.vue +12 -0
- package/src/primitives/shadcn/avatar/index.ts +3 -0
- package/src/primitives/shadcn/badge/Badge.vue +28 -0
- package/src/primitives/shadcn/badge/index.ts +24 -0
- package/src/primitives/shadcn/button/Button.vue +29 -0
- package/src/primitives/shadcn/button/index.ts +36 -0
- package/src/primitives/shadcn/calendar/Calendar.vue +206 -0
- package/src/primitives/shadcn/calendar/CalendarCell.vue +28 -0
- package/src/primitives/shadcn/calendar/CalendarCellTrigger.vue +44 -0
- package/src/primitives/shadcn/calendar/CalendarGrid.vue +23 -0
- package/src/primitives/shadcn/calendar/CalendarGridBody.vue +12 -0
- package/src/primitives/shadcn/calendar/CalendarGridHead.vue +13 -0
- package/src/primitives/shadcn/calendar/CalendarGridRow.vue +23 -0
- package/src/primitives/shadcn/calendar/CalendarHeadCell.vue +23 -0
- package/src/primitives/shadcn/calendar/CalendarHeader.vue +23 -0
- package/src/primitives/shadcn/calendar/CalendarHeading.vue +30 -0
- package/src/primitives/shadcn/calendar/CalendarNextButton.vue +33 -0
- package/src/primitives/shadcn/calendar/CalendarPrevButton.vue +33 -0
- package/src/primitives/shadcn/calendar/index.ts +14 -0
- package/src/primitives/shadcn/card/Card.vue +22 -0
- package/src/primitives/shadcn/card/CardAction.vue +17 -0
- package/src/primitives/shadcn/card/CardContent.vue +14 -0
- package/src/primitives/shadcn/card/CardDescription.vue +14 -0
- package/src/primitives/shadcn/card/CardFooter.vue +14 -0
- package/src/primitives/shadcn/card/CardHeader.vue +22 -0
- package/src/primitives/shadcn/card/CardTitle.vue +14 -0
- package/src/primitives/shadcn/card/index.ts +7 -0
- package/src/primitives/shadcn/checkbox/Checkbox.vue +38 -0
- package/src/primitives/shadcn/checkbox/index.ts +1 -0
- package/src/primitives/shadcn/drawer/Drawer.vue +15 -0
- package/src/primitives/shadcn/drawer/DrawerClose.vue +12 -0
- package/src/primitives/shadcn/drawer/DrawerContent.vue +52 -0
- package/src/primitives/shadcn/drawer/DrawerDescription.vue +20 -0
- package/src/primitives/shadcn/drawer/DrawerFooter.vue +17 -0
- package/src/primitives/shadcn/drawer/DrawerHeader.vue +17 -0
- package/src/primitives/shadcn/drawer/DrawerTitle.vue +20 -0
- package/src/primitives/shadcn/drawer/DrawerTrigger.vue +12 -0
- package/src/primitives/shadcn/drawer/index.ts +8 -0
- package/src/primitives/shadcn/dropdown-menu/DropdownMenu.vue +15 -0
- package/src/primitives/shadcn/dropdown-menu/DropdownMenuCheckboxItem.vue +41 -0
- package/src/primitives/shadcn/dropdown-menu/DropdownMenuContent.vue +40 -0
- package/src/primitives/shadcn/dropdown-menu/DropdownMenuGroup.vue +12 -0
- package/src/primitives/shadcn/dropdown-menu/DropdownMenuItem.vue +41 -0
- package/src/primitives/shadcn/dropdown-menu/DropdownMenuLabel.vue +25 -0
- package/src/primitives/shadcn/dropdown-menu/DropdownMenuRadioGroup.vue +15 -0
- package/src/primitives/shadcn/dropdown-menu/DropdownMenuRadioItem.vue +38 -0
- package/src/primitives/shadcn/dropdown-menu/DropdownMenuSeparator.vue +23 -0
- package/src/primitives/shadcn/dropdown-menu/DropdownMenuShortcut.vue +17 -0
- package/src/primitives/shadcn/dropdown-menu/DropdownMenuSub.vue +15 -0
- package/src/primitives/shadcn/dropdown-menu/DropdownMenuSubContent.vue +29 -0
- package/src/primitives/shadcn/dropdown-menu/DropdownMenuSubTrigger.vue +31 -0
- package/src/primitives/shadcn/dropdown-menu/DropdownMenuTrigger.vue +14 -0
- package/src/primitives/shadcn/dropdown-menu/index.ts +16 -0
- package/src/primitives/shadcn/field/Field.vue +22 -0
- package/src/primitives/shadcn/field/FieldContent.vue +17 -0
- package/src/primitives/shadcn/field/FieldDescription.vue +24 -0
- package/src/primitives/shadcn/field/FieldError.vue +69 -0
- package/src/primitives/shadcn/field/FieldGroup.vue +22 -0
- package/src/primitives/shadcn/field/FieldLabel.vue +28 -0
- package/src/primitives/shadcn/field/FieldLegend.vue +26 -0
- package/src/primitives/shadcn/field/FieldSeparator.vue +28 -0
- package/src/primitives/shadcn/field/FieldSet.vue +23 -0
- package/src/primitives/shadcn/field/FieldTitle.vue +22 -0
- package/src/primitives/shadcn/field/index.ts +39 -0
- package/src/primitives/shadcn/icon/Icon.vue +38 -0
- package/src/primitives/shadcn/icon/index.ts +1 -0
- package/src/primitives/shadcn/index.ts +3 -0
- package/src/primitives/shadcn/input/Input.vue +35 -0
- package/src/primitives/shadcn/input/index.ts +1 -0
- package/src/primitives/shadcn/label/Label.vue +28 -0
- package/src/primitives/shadcn/label/index.ts +1 -0
- package/src/primitives/shadcn/native-select/NativeSelect.vue +56 -0
- package/src/primitives/shadcn/native-select/NativeSelectOptGroup.vue +18 -0
- package/src/primitives/shadcn/native-select/NativeSelectOption.vue +18 -0
- package/src/primitives/shadcn/native-select/index.ts +3 -0
- package/src/primitives/shadcn/popover/Popover.vue +19 -0
- package/src/primitives/shadcn/popover/PopoverContent.vue +41 -0
- package/src/primitives/shadcn/popover/PopoverTrigger.vue +11 -0
- package/src/primitives/shadcn/popover/index.ts +4 -0
- package/src/primitives/shadcn/progress/Progress.vue +30 -0
- package/src/primitives/shadcn/progress/index.ts +1 -0
- package/src/primitives/shadcn/radio-group/RadioGroup.vue +25 -0
- package/src/primitives/shadcn/radio-group/RadioGroupItem.vue +38 -0
- package/src/primitives/shadcn/radio-group/index.ts +2 -0
- package/src/primitives/shadcn/range-calendar/RangeCalendar.vue +73 -0
- package/src/primitives/shadcn/range-calendar/RangeCalendarCell.vue +28 -0
- package/src/primitives/shadcn/range-calendar/RangeCalendarCellTrigger.vue +46 -0
- package/src/primitives/shadcn/range-calendar/RangeCalendarGrid.vue +23 -0
- package/src/primitives/shadcn/range-calendar/RangeCalendarGridBody.vue +12 -0
- package/src/primitives/shadcn/range-calendar/RangeCalendarGridHead.vue +12 -0
- package/src/primitives/shadcn/range-calendar/RangeCalendarGridRow.vue +23 -0
- package/src/primitives/shadcn/range-calendar/RangeCalendarHeadCell.vue +23 -0
- package/src/primitives/shadcn/range-calendar/RangeCalendarHeader.vue +23 -0
- package/src/primitives/shadcn/range-calendar/RangeCalendarHeading.vue +30 -0
- package/src/primitives/shadcn/range-calendar/RangeCalendarNextButton.vue +34 -0
- package/src/primitives/shadcn/range-calendar/RangeCalendarPrevButton.vue +34 -0
- package/src/primitives/shadcn/range-calendar/index.ts +12 -0
- package/src/primitives/shadcn/select/Select.vue +15 -0
- package/src/primitives/shadcn/select/SelectContent.vue +55 -0
- package/src/primitives/shadcn/select/SelectGroup.vue +12 -0
- package/src/primitives/shadcn/select/SelectItem.vue +39 -0
- package/src/primitives/shadcn/select/SelectItemText.vue +12 -0
- package/src/primitives/shadcn/select/SelectLabel.vue +17 -0
- package/src/primitives/shadcn/select/SelectScrollDownButton.vue +26 -0
- package/src/primitives/shadcn/select/SelectScrollUpButton.vue +26 -0
- package/src/primitives/shadcn/select/SelectSeparator.vue +19 -0
- package/src/primitives/shadcn/select/SelectTrigger.vue +37 -0
- package/src/primitives/shadcn/select/SelectValue.vue +12 -0
- package/src/primitives/shadcn/select/index.ts +11 -0
- package/src/primitives/shadcn/separator/Separator.vue +27 -0
- package/src/primitives/shadcn/separator/index.ts +1 -0
- package/src/primitives/shadcn/slider/Slider.vue +45 -0
- package/src/primitives/shadcn/slider/index.ts +1 -0
- package/src/primitives/shadcn/spinner/Spinner.vue +18 -0
- package/src/primitives/shadcn/spinner/index.ts +1 -0
- package/src/primitives/shadcn/switch/Switch.vue +40 -0
- package/src/primitives/shadcn/switch/index.ts +1 -0
- package/src/primitives/shadcn/table/Table.vue +16 -0
- package/src/primitives/shadcn/table/TableBody.vue +14 -0
- package/src/primitives/shadcn/table/TableCaption.vue +14 -0
- package/src/primitives/shadcn/table/TableCell.vue +26 -0
- package/src/primitives/shadcn/table/TableEmpty.vue +29 -0
- package/src/primitives/shadcn/table/TableFooter.vue +17 -0
- package/src/primitives/shadcn/table/TableHead.vue +28 -0
- package/src/primitives/shadcn/table/TableHeader.vue +14 -0
- package/src/primitives/shadcn/table/TableRow.vue +21 -0
- package/src/primitives/shadcn/table/index.ts +9 -0
- package/src/primitives/shadcn/table/utils.ts +8 -0
- package/src/primitives/shadcn/tabs/Tabs.vue +24 -0
- package/src/primitives/shadcn/tabs/TabsContent.vue +21 -0
- package/src/primitives/shadcn/tabs/TabsList.vue +26 -0
- package/src/primitives/shadcn/tabs/TabsTrigger.vue +28 -0
- package/src/primitives/shadcn/tabs/index.ts +4 -0
- package/src/primitives/shadcn/textarea/Textarea.vue +33 -0
- package/src/primitives/shadcn/textarea/index.ts +1 -0
- package/src/primitives/shadcn/tooltip/Tooltip.vue +15 -0
- package/src/primitives/shadcn/tooltip/TooltipContent.vue +40 -0
- package/src/primitives/shadcn/tooltip/TooltipProvider.vue +12 -0
- package/src/primitives/shadcn/tooltip/TooltipTrigger.vue +12 -0
- package/src/primitives/shadcn/tooltip/index.ts +4 -0
- package/src/styles/global.css +1 -0
- package/src/templates/UiTemplatePlaceholder/UiTemplatePlaceholder.vue +9 -0
- package/src/templates/UiTemplatePlaceholder/index.ts +1 -0
- package/src/templates/UiTemplatePlaceholder/types.ts +8 -0
- package/src/templates/index.ts +6 -0
|
@@ -0,0 +1,1575 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite';
|
|
2
|
+
import type { ColumnDef } from '@tanstack/vue-table';
|
|
3
|
+
import { computed, h, ref } from 'vue';
|
|
4
|
+
import { Ban, MoreHorizontal } from 'lucide-vue-next';
|
|
5
|
+
import {
|
|
6
|
+
UiDataTable,
|
|
7
|
+
UiDataTableColumnHeader,
|
|
8
|
+
UiDataTablePagination,
|
|
9
|
+
UiDataTableToolbar,
|
|
10
|
+
} from './index';
|
|
11
|
+
import { UiCheckbox } from '@/primitives/UiCheckbox';
|
|
12
|
+
import { UiButton } from '@/primitives/UiButton';
|
|
13
|
+
import {
|
|
14
|
+
UiDropdownMenu,
|
|
15
|
+
UiDropdownMenuContent,
|
|
16
|
+
UiDropdownMenuItem,
|
|
17
|
+
UiDropdownMenuLabel,
|
|
18
|
+
UiDropdownMenuSeparator,
|
|
19
|
+
UiDropdownMenuTrigger,
|
|
20
|
+
} from '@/primitives/UiDropdownMenu';
|
|
21
|
+
import { payments, paymentsMedium, datasetOptions, type Payment } from './UiDataTable.mock';
|
|
22
|
+
|
|
23
|
+
// Basic columns
|
|
24
|
+
const basicColumns: ColumnDef<Payment>[] = [
|
|
25
|
+
{
|
|
26
|
+
accessorKey: 'status',
|
|
27
|
+
header: 'Status',
|
|
28
|
+
cell: ({ row }) => h('div', { class: 'capitalize' }, row.getValue('status')),
|
|
29
|
+
size: 120,
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
accessorKey: 'email',
|
|
33
|
+
header: 'Email',
|
|
34
|
+
cell: ({ row }) => h('div', { class: 'lowercase' }, row.getValue('email')),
|
|
35
|
+
size: 250,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
accessorKey: 'amount',
|
|
39
|
+
header: () => h('div', { class: 'text-right' }, 'Amount'),
|
|
40
|
+
cell: ({ row }) => {
|
|
41
|
+
const amount = Number.parseFloat(row.getValue('amount'));
|
|
42
|
+
const formatted = new Intl.NumberFormat('de-DE', {
|
|
43
|
+
style: 'currency',
|
|
44
|
+
currency: 'EUR',
|
|
45
|
+
}).format(amount);
|
|
46
|
+
return h('div', { class: 'text-right font-medium' }, formatted);
|
|
47
|
+
},
|
|
48
|
+
size: 120,
|
|
49
|
+
},
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
// Sortable columns using UiDataTableColumnHeader
|
|
53
|
+
const sortableColumns: ColumnDef<Payment>[] = [
|
|
54
|
+
{
|
|
55
|
+
accessorKey: 'status',
|
|
56
|
+
header: ({ column }) => h(UiDataTableColumnHeader, { column, title: 'Status' }),
|
|
57
|
+
cell: ({ row }) => h('div', { class: 'capitalize' }, row.getValue('status')),
|
|
58
|
+
size: 120,
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
accessorKey: 'email',
|
|
62
|
+
header: ({ column }) => h(UiDataTableColumnHeader, { column, title: 'Email' }),
|
|
63
|
+
cell: ({ row }) => h('div', { class: 'lowercase' }, row.getValue('email')),
|
|
64
|
+
size: 250,
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
accessorKey: 'amount',
|
|
68
|
+
header: ({ column }) =>
|
|
69
|
+
h(UiDataTableColumnHeader, { column, title: 'Amount', class: 'justify-end' }),
|
|
70
|
+
cell: ({ row }) => {
|
|
71
|
+
const amount = Number.parseFloat(row.getValue('amount'));
|
|
72
|
+
const formatted = new Intl.NumberFormat('de-DE', {
|
|
73
|
+
style: 'currency',
|
|
74
|
+
currency: 'EUR',
|
|
75
|
+
}).format(amount);
|
|
76
|
+
return h('div', { class: 'text-right font-medium' }, formatted);
|
|
77
|
+
},
|
|
78
|
+
size: 120,
|
|
79
|
+
},
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
// Columns with selection using UiDataTableColumnHeader
|
|
83
|
+
const selectableColumns: ColumnDef<Payment>[] = [
|
|
84
|
+
{
|
|
85
|
+
id: 'select',
|
|
86
|
+
header: ({ table }) =>
|
|
87
|
+
h(UiCheckbox, {
|
|
88
|
+
modelValue:
|
|
89
|
+
table.getIsAllPageRowsSelected() ||
|
|
90
|
+
(table.getIsSomePageRowsSelected() && 'indeterminate'),
|
|
91
|
+
'onUpdate:modelValue': (value: boolean) => table.toggleAllPageRowsSelected(!!value),
|
|
92
|
+
ariaLabel: 'Select all',
|
|
93
|
+
name: 'select-all',
|
|
94
|
+
}),
|
|
95
|
+
cell: ({ row }) =>
|
|
96
|
+
h(UiCheckbox, {
|
|
97
|
+
modelValue: row.getIsSelected(),
|
|
98
|
+
'onUpdate:modelValue': (value: boolean) => row.toggleSelected(!!value),
|
|
99
|
+
ariaLabel: 'Select row',
|
|
100
|
+
name: `select-${row.id}`,
|
|
101
|
+
}),
|
|
102
|
+
enableSorting: false,
|
|
103
|
+
enableHiding: false,
|
|
104
|
+
size: 40,
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
accessorKey: 'status',
|
|
108
|
+
header: ({ column }) => h(UiDataTableColumnHeader, { column, title: 'Status' }),
|
|
109
|
+
cell: ({ row }) => h('div', { class: 'capitalize' }, row.getValue('status')),
|
|
110
|
+
size: 120,
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
accessorKey: 'email',
|
|
114
|
+
header: ({ column }) => h(UiDataTableColumnHeader, { column, title: 'Email' }),
|
|
115
|
+
cell: ({ row }) => h('div', { class: 'lowercase' }, row.getValue('email')),
|
|
116
|
+
size: 250,
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
accessorKey: 'amount',
|
|
120
|
+
header: ({ column }) =>
|
|
121
|
+
h(UiDataTableColumnHeader, { column, title: 'Amount', class: 'justify-end' }),
|
|
122
|
+
cell: ({ row }) => {
|
|
123
|
+
const amount = Number.parseFloat(row.getValue('amount'));
|
|
124
|
+
const formatted = new Intl.NumberFormat('de-DE', {
|
|
125
|
+
style: 'currency',
|
|
126
|
+
currency: 'EUR',
|
|
127
|
+
}).format(amount);
|
|
128
|
+
return h('div', { class: 'text-right font-medium' }, formatted);
|
|
129
|
+
},
|
|
130
|
+
size: 120,
|
|
131
|
+
},
|
|
132
|
+
];
|
|
133
|
+
|
|
134
|
+
// Column options for controls
|
|
135
|
+
const columnOptions = {
|
|
136
|
+
Basic: basicColumns,
|
|
137
|
+
Sortable: sortableColumns,
|
|
138
|
+
'With Selection': selectableColumns,
|
|
139
|
+
} as const;
|
|
140
|
+
|
|
141
|
+
const meta = {
|
|
142
|
+
title: 'Compositions/UiDataTable',
|
|
143
|
+
component: UiDataTable,
|
|
144
|
+
tags: ['autodocs'],
|
|
145
|
+
parameters: {
|
|
146
|
+
docs: {
|
|
147
|
+
description: {
|
|
148
|
+
component:
|
|
149
|
+
'A powerful data table component built with TanStack Table and Vue 3. Supports sorting, pagination, filtering, and row selection. Use `UiDataTable` for the core table, `UiDataTablePagination` for pagination controls, and `UiDataTableToolbar` for search and filters.',
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
argTypes: {
|
|
154
|
+
columns: {
|
|
155
|
+
control: 'select',
|
|
156
|
+
options: Object.keys(columnOptions),
|
|
157
|
+
mapping: columnOptions,
|
|
158
|
+
description: 'The column definitions for the table. Select from predefined configurations.',
|
|
159
|
+
},
|
|
160
|
+
data: {
|
|
161
|
+
control: 'select',
|
|
162
|
+
options: Object.keys(datasetOptions),
|
|
163
|
+
mapping: datasetOptions,
|
|
164
|
+
description: 'The data to display in the table. Select from predefined datasets.',
|
|
165
|
+
},
|
|
166
|
+
emptyText: {
|
|
167
|
+
control: 'text',
|
|
168
|
+
description: 'Text to display when there are no results.',
|
|
169
|
+
},
|
|
170
|
+
tableMinHeight: {
|
|
171
|
+
control: 'text',
|
|
172
|
+
description:
|
|
173
|
+
'Minimum height for the table container. Useful for preventing layout shifts during pagination. The last row will have a visible bottom border even when the container is taller than the content.',
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
args: {
|
|
177
|
+
data: 'Large (100 items)',
|
|
178
|
+
columns: 'Sortable',
|
|
179
|
+
},
|
|
180
|
+
} satisfies Meta<typeof UiDataTable>;
|
|
181
|
+
|
|
182
|
+
export default meta;
|
|
183
|
+
type Story = StoryObj<typeof meta>;
|
|
184
|
+
|
|
185
|
+
// Templates for source code display
|
|
186
|
+
const basicTemplateSource = `<script setup lang="ts">
|
|
187
|
+
import { UiDataTable } from '@aleph-alpha/ui-library';
|
|
188
|
+
import type { ColumnDef } from '@tanstack/vue-table';
|
|
189
|
+
|
|
190
|
+
interface Payment {
|
|
191
|
+
id: string;
|
|
192
|
+
amount: number;
|
|
193
|
+
status: string;
|
|
194
|
+
email: string;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const data: Payment[] = [
|
|
198
|
+
{ id: '1', amount: 316, status: 'success', email: 'ken99@yahoo.com' },
|
|
199
|
+
{ id: '2', amount: 242, status: 'success', email: 'abe45@gmail.com' },
|
|
200
|
+
{ id: '3', amount: 837, status: 'processing', email: 'monserrat44@gmail.com' },
|
|
201
|
+
];
|
|
202
|
+
|
|
203
|
+
const columns: ColumnDef<Payment>[] = [
|
|
204
|
+
{ accessorKey: 'status', header: 'Status' },
|
|
205
|
+
{ accessorKey: 'email', header: 'Email' },
|
|
206
|
+
{ accessorKey: 'amount', header: 'Amount' },
|
|
207
|
+
];
|
|
208
|
+
</script>
|
|
209
|
+
|
|
210
|
+
<template>
|
|
211
|
+
<UiDataTable :data="data" :columns="columns" />
|
|
212
|
+
</template>`;
|
|
213
|
+
|
|
214
|
+
const withSortingTemplateSource = `<script setup lang="ts">
|
|
215
|
+
import { h } from 'vue';
|
|
216
|
+
import { UiDataTable, UiDataTableColumnHeader } from '@aleph-alpha/ui-library';
|
|
217
|
+
import type { ColumnDef } from '@tanstack/vue-table';
|
|
218
|
+
|
|
219
|
+
interface Payment {
|
|
220
|
+
id: string;
|
|
221
|
+
amount: number;
|
|
222
|
+
status: string;
|
|
223
|
+
email: string;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const data: Payment[] = [
|
|
227
|
+
{ id: '1', amount: 316, status: 'success', email: 'ken99@yahoo.com' },
|
|
228
|
+
{ id: '2', amount: 242, status: 'success', email: 'abe45@gmail.com' },
|
|
229
|
+
{ id: '3', amount: 837, status: 'processing', email: 'monserrat44@gmail.com' },
|
|
230
|
+
];
|
|
231
|
+
|
|
232
|
+
// Use UiDataTableColumnHeader for sortable columns with dropdown menu
|
|
233
|
+
const columns: ColumnDef<Payment>[] = [
|
|
234
|
+
{
|
|
235
|
+
accessorKey: 'status',
|
|
236
|
+
header: ({ column }) => h(UiDataTableColumnHeader, { column, title: 'Status' }),
|
|
237
|
+
size: 120,
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
accessorKey: 'email',
|
|
241
|
+
header: ({ column }) => h(UiDataTableColumnHeader, { column, title: 'Email' }),
|
|
242
|
+
size: 250,
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
accessorKey: 'amount',
|
|
246
|
+
header: ({ column }) => h(UiDataTableColumnHeader, {
|
|
247
|
+
column,
|
|
248
|
+
title: 'Amount',
|
|
249
|
+
class: 'justify-end'
|
|
250
|
+
}),
|
|
251
|
+
cell: ({ row }) => {
|
|
252
|
+
const amount = Number.parseFloat(row.getValue('amount'));
|
|
253
|
+
return new Intl.NumberFormat('de-DE', {
|
|
254
|
+
style: 'currency',
|
|
255
|
+
currency: 'EUR',
|
|
256
|
+
}).format(amount);
|
|
257
|
+
},
|
|
258
|
+
size: 120,
|
|
259
|
+
},
|
|
260
|
+
];
|
|
261
|
+
</script>
|
|
262
|
+
|
|
263
|
+
<template>
|
|
264
|
+
<UiDataTable :data="data" :columns="columns" />
|
|
265
|
+
</template>`;
|
|
266
|
+
|
|
267
|
+
const withPaginationTemplateSource = `<script setup lang="ts">
|
|
268
|
+
import { h, ref, computed } from 'vue';
|
|
269
|
+
import { UiDataTable, UiDataTableColumnHeader, UiDataTablePagination } from '@aleph-alpha/ui-library';
|
|
270
|
+
import type { ColumnDef } from '@tanstack/vue-table';
|
|
271
|
+
|
|
272
|
+
interface Payment {
|
|
273
|
+
id: string;
|
|
274
|
+
amount: number;
|
|
275
|
+
status: string;
|
|
276
|
+
email: string;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const data: Payment[] = [
|
|
280
|
+
{ id: '1', amount: 316, status: 'success', email: 'ken99@yahoo.com' },
|
|
281
|
+
{ id: '2', amount: 242, status: 'success', email: 'abe45@gmail.com' },
|
|
282
|
+
// ... more data (pagination works best with 10+ items)
|
|
283
|
+
];
|
|
284
|
+
|
|
285
|
+
const columns: ColumnDef<Payment>[] = [
|
|
286
|
+
{
|
|
287
|
+
accessorKey: 'status',
|
|
288
|
+
header: ({ column }) => h(UiDataTableColumnHeader, { column, title: 'Status' }),
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
accessorKey: 'email',
|
|
292
|
+
header: ({ column }) => h(UiDataTableColumnHeader, { column, title: 'Email' }),
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
accessorKey: 'amount',
|
|
296
|
+
header: ({ column }) => h(UiDataTableColumnHeader, { column, title: 'Amount' }),
|
|
297
|
+
},
|
|
298
|
+
];
|
|
299
|
+
|
|
300
|
+
// Access the table instance via ref
|
|
301
|
+
const tableRef = ref<InstanceType<typeof UiDataTable>>();
|
|
302
|
+
const table = computed(() => tableRef.value?.table);
|
|
303
|
+
</script>
|
|
304
|
+
|
|
305
|
+
<template>
|
|
306
|
+
<div class="space-y-4">
|
|
307
|
+
<!-- tableMinHeight prevents layout shifts during pagination -->
|
|
308
|
+
<UiDataTable ref="tableRef" :data="data" :columns="columns" table-min-height="500px" />
|
|
309
|
+
<UiDataTablePagination v-if="table" :table="table" />
|
|
310
|
+
</div>
|
|
311
|
+
</template>`;
|
|
312
|
+
|
|
313
|
+
const withToolbarTemplateSource = `<script setup lang="ts">
|
|
314
|
+
import { h, ref, computed } from 'vue';
|
|
315
|
+
import { UiDataTable, UiDataTableColumnHeader, UiDataTableToolbar } from '@aleph-alpha/ui-library';
|
|
316
|
+
import type { ColumnDef } from '@tanstack/vue-table';
|
|
317
|
+
|
|
318
|
+
interface Payment {
|
|
319
|
+
id: string;
|
|
320
|
+
amount: number;
|
|
321
|
+
status: string;
|
|
322
|
+
email: string;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
const data: Payment[] = [
|
|
326
|
+
{ id: '1', amount: 316, status: 'success', email: 'ken99@yahoo.com' },
|
|
327
|
+
{ id: '2', amount: 242, status: 'success', email: 'abe45@gmail.com' },
|
|
328
|
+
{ id: '3', amount: 837, status: 'processing', email: 'monserrat44@gmail.com' },
|
|
329
|
+
];
|
|
330
|
+
|
|
331
|
+
const columns: ColumnDef<Payment>[] = [
|
|
332
|
+
{
|
|
333
|
+
accessorKey: 'status',
|
|
334
|
+
header: ({ column }) => h(UiDataTableColumnHeader, { column, title: 'Status' }),
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
accessorKey: 'email',
|
|
338
|
+
header: ({ column }) => h(UiDataTableColumnHeader, { column, title: 'Email' }),
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
accessorKey: 'amount',
|
|
342
|
+
header: ({ column }) => h(UiDataTableColumnHeader, { column, title: 'Amount' }),
|
|
343
|
+
},
|
|
344
|
+
];
|
|
345
|
+
|
|
346
|
+
const tableRef = ref<InstanceType<typeof UiDataTable>>();
|
|
347
|
+
const table = computed(() => tableRef.value?.table);
|
|
348
|
+
</script>
|
|
349
|
+
|
|
350
|
+
<template>
|
|
351
|
+
<div class="space-y-4">
|
|
352
|
+
<!-- filter-column filters a specific column -->
|
|
353
|
+
<UiDataTableToolbar
|
|
354
|
+
v-if="table"
|
|
355
|
+
:table="table"
|
|
356
|
+
filter-column="email"
|
|
357
|
+
filter-placeholder="Filter emails..."
|
|
358
|
+
/>
|
|
359
|
+
<UiDataTable ref="tableRef" :data="data" :columns="columns" />
|
|
360
|
+
</div>
|
|
361
|
+
</template>`;
|
|
362
|
+
|
|
363
|
+
const fullExampleTemplateSource = `<script setup lang="ts">
|
|
364
|
+
import { h, ref, computed } from 'vue';
|
|
365
|
+
import {
|
|
366
|
+
UiDataTable,
|
|
367
|
+
UiDataTableColumnHeader,
|
|
368
|
+
UiDataTableToolbar,
|
|
369
|
+
UiDataTablePagination
|
|
370
|
+
} from '@aleph-alpha/ui-library';
|
|
371
|
+
import { UiCheckbox } from '@aleph-alpha/ui-library';
|
|
372
|
+
import type { ColumnDef } from '@tanstack/vue-table';
|
|
373
|
+
|
|
374
|
+
interface Payment {
|
|
375
|
+
id: string;
|
|
376
|
+
amount: number;
|
|
377
|
+
status: string;
|
|
378
|
+
email: string;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
const data: Payment[] = [
|
|
382
|
+
{ id: '1', amount: 316, status: 'success', email: 'ken99@yahoo.com' },
|
|
383
|
+
{ id: '2', amount: 242, status: 'success', email: 'abe45@gmail.com' },
|
|
384
|
+
{ id: '3', amount: 837, status: 'processing', email: 'monserrat44@gmail.com' },
|
|
385
|
+
// ... more data
|
|
386
|
+
];
|
|
387
|
+
|
|
388
|
+
// Columns with selection checkbox and sortable headers
|
|
389
|
+
const columns: ColumnDef<Payment>[] = [
|
|
390
|
+
{
|
|
391
|
+
id: 'select',
|
|
392
|
+
header: ({ table }) => h(UiCheckbox, {
|
|
393
|
+
modelValue: table.getIsAllPageRowsSelected() || (table.getIsSomePageRowsSelected() && 'indeterminate'),
|
|
394
|
+
'onUpdate:modelValue': (value: boolean) => table.toggleAllPageRowsSelected(!!value),
|
|
395
|
+
ariaLabel: 'Select all',
|
|
396
|
+
name: 'select-all',
|
|
397
|
+
}),
|
|
398
|
+
cell: ({ row }) => h(UiCheckbox, {
|
|
399
|
+
modelValue: row.getIsSelected(),
|
|
400
|
+
'onUpdate:modelValue': (value: boolean) => row.toggleSelected(!!value),
|
|
401
|
+
ariaLabel: 'Select row',
|
|
402
|
+
name: \`select-\${row.id}\`,
|
|
403
|
+
}),
|
|
404
|
+
enableSorting: false,
|
|
405
|
+
enableHiding: false,
|
|
406
|
+
size: 40,
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
accessorKey: 'status',
|
|
410
|
+
header: ({ column }) => h(UiDataTableColumnHeader, { column, title: 'Status' }),
|
|
411
|
+
size: 120,
|
|
412
|
+
},
|
|
413
|
+
{
|
|
414
|
+
accessorKey: 'email',
|
|
415
|
+
header: ({ column }) => h(UiDataTableColumnHeader, { column, title: 'Email' }),
|
|
416
|
+
size: 250,
|
|
417
|
+
},
|
|
418
|
+
{
|
|
419
|
+
accessorKey: 'amount',
|
|
420
|
+
header: ({ column }) => h(UiDataTableColumnHeader, { column, title: 'Amount' }),
|
|
421
|
+
size: 120,
|
|
422
|
+
},
|
|
423
|
+
];
|
|
424
|
+
|
|
425
|
+
const tableRef = ref<InstanceType<typeof UiDataTable>>();
|
|
426
|
+
const table = computed(() => tableRef.value?.table);
|
|
427
|
+
</script>
|
|
428
|
+
|
|
429
|
+
<template>
|
|
430
|
+
<div class="space-y-4">
|
|
431
|
+
<UiDataTableToolbar
|
|
432
|
+
v-if="table"
|
|
433
|
+
:table="table"
|
|
434
|
+
global-filter
|
|
435
|
+
filter-placeholder="Search..."
|
|
436
|
+
/>
|
|
437
|
+
<UiDataTable ref="tableRef" :data="data" :columns="columns" />
|
|
438
|
+
<UiDataTablePagination v-if="table" :table="table" />
|
|
439
|
+
</div>
|
|
440
|
+
</template>`;
|
|
441
|
+
|
|
442
|
+
const withGlobalFilterTemplateSource = `<script setup lang="ts">
|
|
443
|
+
import { h, ref, computed } from 'vue';
|
|
444
|
+
import { UiDataTable, UiDataTableColumnHeader, UiDataTableToolbar } from '@aleph-alpha/ui-library';
|
|
445
|
+
import type { ColumnDef } from '@tanstack/vue-table';
|
|
446
|
+
|
|
447
|
+
interface Payment {
|
|
448
|
+
id: string;
|
|
449
|
+
amount: number;
|
|
450
|
+
status: string;
|
|
451
|
+
email: string;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
const data: Payment[] = [
|
|
455
|
+
{ id: '1', amount: 316, status: 'success', email: 'ken99@yahoo.com' },
|
|
456
|
+
{ id: '2', amount: 242, status: 'success', email: 'abe45@gmail.com' },
|
|
457
|
+
{ id: '3', amount: 837, status: 'processing', email: 'monserrat44@gmail.com' },
|
|
458
|
+
];
|
|
459
|
+
|
|
460
|
+
const columns: ColumnDef<Payment>[] = [
|
|
461
|
+
{
|
|
462
|
+
accessorKey: 'status',
|
|
463
|
+
header: ({ column }) => h(UiDataTableColumnHeader, { column, title: 'Status' }),
|
|
464
|
+
size: 120,
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
accessorKey: 'email',
|
|
468
|
+
header: ({ column }) => h(UiDataTableColumnHeader, { column, title: 'Email' }),
|
|
469
|
+
size: 250,
|
|
470
|
+
},
|
|
471
|
+
{
|
|
472
|
+
accessorKey: 'amount',
|
|
473
|
+
header: ({ column }) => h(UiDataTableColumnHeader, { column, title: 'Amount' }),
|
|
474
|
+
size: 120,
|
|
475
|
+
},
|
|
476
|
+
];
|
|
477
|
+
|
|
478
|
+
const tableRef = ref<InstanceType<typeof UiDataTable>>();
|
|
479
|
+
const table = computed(() => tableRef.value?.table);
|
|
480
|
+
</script>
|
|
481
|
+
|
|
482
|
+
<template>
|
|
483
|
+
<div class="space-y-4">
|
|
484
|
+
<!-- global-filter searches across ALL columns -->
|
|
485
|
+
<UiDataTableToolbar
|
|
486
|
+
v-if="table"
|
|
487
|
+
:table="table"
|
|
488
|
+
global-filter
|
|
489
|
+
filter-placeholder="Search all columns..."
|
|
490
|
+
/>
|
|
491
|
+
<UiDataTable ref="tableRef" :data="data" :columns="columns" />
|
|
492
|
+
</div>
|
|
493
|
+
</template>`;
|
|
494
|
+
|
|
495
|
+
const withRowSelectionTemplateSource = `<script setup lang="ts">
|
|
496
|
+
import { h, ref, computed } from 'vue';
|
|
497
|
+
import { UiDataTable, UiDataTableColumnHeader, UiDataTablePagination } from '@aleph-alpha/ui-library';
|
|
498
|
+
import { UiCheckbox } from '@aleph-alpha/ui-library';
|
|
499
|
+
import type { ColumnDef } from '@tanstack/vue-table';
|
|
500
|
+
|
|
501
|
+
interface Payment {
|
|
502
|
+
id: string;
|
|
503
|
+
amount: number;
|
|
504
|
+
status: string;
|
|
505
|
+
email: string;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
const data: Payment[] = [
|
|
509
|
+
{ id: '1', amount: 316, status: 'success', email: 'ken99@yahoo.com' },
|
|
510
|
+
{ id: '2', amount: 242, status: 'success', email: 'abe45@gmail.com' },
|
|
511
|
+
{ id: '3', amount: 837, status: 'processing', email: 'monserrat44@gmail.com' },
|
|
512
|
+
];
|
|
513
|
+
|
|
514
|
+
// Add a selection column using UiCheckbox
|
|
515
|
+
const columns: ColumnDef<Payment>[] = [
|
|
516
|
+
{
|
|
517
|
+
id: 'select',
|
|
518
|
+
header: ({ table }) => h(UiCheckbox, {
|
|
519
|
+
modelValue: table.getIsAllPageRowsSelected() || (table.getIsSomePageRowsSelected() && 'indeterminate'),
|
|
520
|
+
'onUpdate:modelValue': (value: boolean) => table.toggleAllPageRowsSelected(!!value),
|
|
521
|
+
ariaLabel: 'Select all',
|
|
522
|
+
name: 'select-all',
|
|
523
|
+
}),
|
|
524
|
+
cell: ({ row }) => h(UiCheckbox, {
|
|
525
|
+
modelValue: row.getIsSelected(),
|
|
526
|
+
'onUpdate:modelValue': (value: boolean) => row.toggleSelected(!!value),
|
|
527
|
+
ariaLabel: 'Select row',
|
|
528
|
+
name: \`select-\${row.id}\`,
|
|
529
|
+
}),
|
|
530
|
+
enableSorting: false,
|
|
531
|
+
enableHiding: false,
|
|
532
|
+
size: 40,
|
|
533
|
+
},
|
|
534
|
+
{
|
|
535
|
+
accessorKey: 'status',
|
|
536
|
+
header: ({ column }) => h(UiDataTableColumnHeader, { column, title: 'Status' }),
|
|
537
|
+
size: 120,
|
|
538
|
+
},
|
|
539
|
+
{
|
|
540
|
+
accessorKey: 'email',
|
|
541
|
+
header: ({ column }) => h(UiDataTableColumnHeader, { column, title: 'Email' }),
|
|
542
|
+
size: 250,
|
|
543
|
+
},
|
|
544
|
+
{
|
|
545
|
+
accessorKey: 'amount',
|
|
546
|
+
header: ({ column }) => h(UiDataTableColumnHeader, { column, title: 'Amount' }),
|
|
547
|
+
size: 120,
|
|
548
|
+
},
|
|
549
|
+
];
|
|
550
|
+
|
|
551
|
+
const tableRef = ref<InstanceType<typeof UiDataTable>>();
|
|
552
|
+
const table = computed(() => tableRef.value?.table);
|
|
553
|
+
</script>
|
|
554
|
+
|
|
555
|
+
<template>
|
|
556
|
+
<div class="space-y-4">
|
|
557
|
+
<UiDataTable ref="tableRef" :data="data" :columns="columns" />
|
|
558
|
+
<!-- Pagination shows selection count -->
|
|
559
|
+
<UiDataTablePagination v-if="table" :table="table" />
|
|
560
|
+
</div>
|
|
561
|
+
</template>`;
|
|
562
|
+
|
|
563
|
+
const customEmptyStateTemplateSource = `<script setup lang="ts">
|
|
564
|
+
import { UiDataTable } from '@aleph-alpha/ui-library';
|
|
565
|
+
import type { ColumnDef } from '@tanstack/vue-table';
|
|
566
|
+
|
|
567
|
+
interface Payment {
|
|
568
|
+
id: string;
|
|
569
|
+
amount: number;
|
|
570
|
+
status: string;
|
|
571
|
+
email: string;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
const data: Payment[] = []; // Empty data
|
|
575
|
+
|
|
576
|
+
const columns: ColumnDef<Payment>[] = [
|
|
577
|
+
{ accessorKey: 'status', header: 'Status' },
|
|
578
|
+
{ accessorKey: 'email', header: 'Email' },
|
|
579
|
+
{ accessorKey: 'amount', header: 'Amount' },
|
|
580
|
+
];
|
|
581
|
+
</script>
|
|
582
|
+
|
|
583
|
+
<template>
|
|
584
|
+
<!-- Use empty-text prop to customize the empty state message -->
|
|
585
|
+
<UiDataTable
|
|
586
|
+
:data="data"
|
|
587
|
+
:columns="columns"
|
|
588
|
+
empty-text="No payments found."
|
|
589
|
+
/>
|
|
590
|
+
</template>`;
|
|
591
|
+
|
|
592
|
+
const withPageSizeTemplateSource = `<script setup lang="ts">
|
|
593
|
+
import { h, ref, computed } from 'vue';
|
|
594
|
+
import { UiDataTable, UiDataTableColumnHeader, UiDataTablePagination } from '@aleph-alpha/ui-library';
|
|
595
|
+
import type { ColumnDef } from '@tanstack/vue-table';
|
|
596
|
+
|
|
597
|
+
interface Payment {
|
|
598
|
+
id: string;
|
|
599
|
+
amount: number;
|
|
600
|
+
status: string;
|
|
601
|
+
email: string;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
const data: Payment[] = [
|
|
605
|
+
{ id: '1', amount: 316, status: 'success', email: 'ken99@yahoo.com' },
|
|
606
|
+
{ id: '2', amount: 242, status: 'success', email: 'abe45@gmail.com' },
|
|
607
|
+
// ... more data
|
|
608
|
+
];
|
|
609
|
+
|
|
610
|
+
const columns: ColumnDef<Payment>[] = [
|
|
611
|
+
{
|
|
612
|
+
accessorKey: 'status',
|
|
613
|
+
header: ({ column }) => h(UiDataTableColumnHeader, { column, title: 'Status' }),
|
|
614
|
+
size: 120,
|
|
615
|
+
},
|
|
616
|
+
{
|
|
617
|
+
accessorKey: 'email',
|
|
618
|
+
header: ({ column }) => h(UiDataTableColumnHeader, { column, title: 'Email' }),
|
|
619
|
+
size: 250,
|
|
620
|
+
},
|
|
621
|
+
{
|
|
622
|
+
accessorKey: 'amount',
|
|
623
|
+
header: ({ column }) => h(UiDataTableColumnHeader, { column, title: 'Amount' }),
|
|
624
|
+
size: 120,
|
|
625
|
+
},
|
|
626
|
+
];
|
|
627
|
+
|
|
628
|
+
const tableRef = ref<InstanceType<typeof UiDataTable>>();
|
|
629
|
+
const table = computed(() => tableRef.value?.table);
|
|
630
|
+
</script>
|
|
631
|
+
|
|
632
|
+
<template>
|
|
633
|
+
<div class="space-y-4">
|
|
634
|
+
<UiDataTable ref="tableRef" :data="data" :columns="columns" />
|
|
635
|
+
<!-- Customize page sizes and hide selection count -->
|
|
636
|
+
<UiDataTablePagination
|
|
637
|
+
v-if="table"
|
|
638
|
+
:table="table"
|
|
639
|
+
:page-size-options="[5, 10, 20, 50]"
|
|
640
|
+
:show-selection="false"
|
|
641
|
+
/>
|
|
642
|
+
</div>
|
|
643
|
+
</template>`;
|
|
644
|
+
|
|
645
|
+
/**
|
|
646
|
+
* Basic table with minimal configuration.
|
|
647
|
+
*
|
|
648
|
+
* The simplest way to use UiDataTable - just pass `data` and `columns`.
|
|
649
|
+
* Column headers are plain text, no sorting or filtering.
|
|
650
|
+
*/
|
|
651
|
+
export const Basic: Story = {
|
|
652
|
+
args: {
|
|
653
|
+
data: payments,
|
|
654
|
+
columns: basicColumns,
|
|
655
|
+
},
|
|
656
|
+
parameters: {
|
|
657
|
+
docs: {
|
|
658
|
+
source: {
|
|
659
|
+
code: basicTemplateSource,
|
|
660
|
+
},
|
|
661
|
+
},
|
|
662
|
+
},
|
|
663
|
+
render: (args) => ({
|
|
664
|
+
components: { UiDataTable },
|
|
665
|
+
setup() {
|
|
666
|
+
return { args };
|
|
667
|
+
},
|
|
668
|
+
template: '<UiDataTable v-bind="args" />',
|
|
669
|
+
}),
|
|
670
|
+
};
|
|
671
|
+
|
|
672
|
+
/**
|
|
673
|
+
* Table with sortable columns using UiDataTableColumnHeader.
|
|
674
|
+
*
|
|
675
|
+
* Use `UiDataTableColumnHeader` in your column definitions to enable:
|
|
676
|
+
* - Click to sort (ascending/descending)
|
|
677
|
+
* - Dropdown menu with sort options and hide column
|
|
678
|
+
*
|
|
679
|
+
* This is the recommended approach for sortable headers.
|
|
680
|
+
*/
|
|
681
|
+
export const WithSorting: Story = {
|
|
682
|
+
args: {
|
|
683
|
+
data: payments,
|
|
684
|
+
columns: sortableColumns,
|
|
685
|
+
},
|
|
686
|
+
parameters: {
|
|
687
|
+
docs: {
|
|
688
|
+
source: {
|
|
689
|
+
code: withSortingTemplateSource,
|
|
690
|
+
},
|
|
691
|
+
},
|
|
692
|
+
},
|
|
693
|
+
render: (args) => ({
|
|
694
|
+
components: { UiDataTable },
|
|
695
|
+
setup() {
|
|
696
|
+
return { args };
|
|
697
|
+
},
|
|
698
|
+
template: '<UiDataTable v-bind="args" />',
|
|
699
|
+
}),
|
|
700
|
+
};
|
|
701
|
+
|
|
702
|
+
/**
|
|
703
|
+
* Table with pagination controls.
|
|
704
|
+
*
|
|
705
|
+
* Use `UiDataTablePagination` when displaying more than 10 rows.
|
|
706
|
+
* Shows navigation buttons (first, prev, next, last), page info, and rows per page selector.
|
|
707
|
+
*
|
|
708
|
+
* The `tableMinHeight` prop prevents layout shifts during pagination by ensuring
|
|
709
|
+
* the table container maintains a minimum height. The last row has a visible
|
|
710
|
+
* bottom border (Material UI-inspired behavior).
|
|
711
|
+
*
|
|
712
|
+
* Access the table instance via ref to pass to pagination component.
|
|
713
|
+
*/
|
|
714
|
+
export const WithPagination: Story = {
|
|
715
|
+
args: {
|
|
716
|
+
data: payments,
|
|
717
|
+
columns: sortableColumns,
|
|
718
|
+
tableMinHeight: '500px',
|
|
719
|
+
},
|
|
720
|
+
parameters: {
|
|
721
|
+
docs: {
|
|
722
|
+
source: {
|
|
723
|
+
code: withPaginationTemplateSource,
|
|
724
|
+
},
|
|
725
|
+
},
|
|
726
|
+
},
|
|
727
|
+
render: (args) => ({
|
|
728
|
+
components: { UiDataTable, UiDataTablePagination },
|
|
729
|
+
setup() {
|
|
730
|
+
const tableRef = ref<InstanceType<typeof UiDataTable>>();
|
|
731
|
+
const table = computed(() => tableRef.value?.table);
|
|
732
|
+
return { args, tableRef, table };
|
|
733
|
+
},
|
|
734
|
+
template: `
|
|
735
|
+
<div class="space-y-4">
|
|
736
|
+
<UiDataTable ref="tableRef" v-bind="args" />
|
|
737
|
+
<UiDataTablePagination v-if="table" :table="table" />
|
|
738
|
+
</div>
|
|
739
|
+
`,
|
|
740
|
+
}),
|
|
741
|
+
};
|
|
742
|
+
|
|
743
|
+
/**
|
|
744
|
+
* Table with column-specific filtering.
|
|
745
|
+
*
|
|
746
|
+
* Use `UiDataTableToolbar` with `filter-column` prop to filter a specific column.
|
|
747
|
+
*/
|
|
748
|
+
export const WithToolbar: Story = {
|
|
749
|
+
args: {
|
|
750
|
+
data: payments,
|
|
751
|
+
columns: sortableColumns,
|
|
752
|
+
},
|
|
753
|
+
parameters: {
|
|
754
|
+
docs: {
|
|
755
|
+
source: {
|
|
756
|
+
code: withToolbarTemplateSource,
|
|
757
|
+
},
|
|
758
|
+
},
|
|
759
|
+
},
|
|
760
|
+
render: (args) => ({
|
|
761
|
+
components: { UiDataTable, UiDataTableToolbar },
|
|
762
|
+
setup() {
|
|
763
|
+
const tableRef = ref<InstanceType<typeof UiDataTable>>();
|
|
764
|
+
const table = computed(() => tableRef.value?.table);
|
|
765
|
+
return { args, tableRef, table };
|
|
766
|
+
},
|
|
767
|
+
template: `
|
|
768
|
+
<div class="space-y-4">
|
|
769
|
+
<UiDataTableToolbar
|
|
770
|
+
v-if="table"
|
|
771
|
+
:table="table"
|
|
772
|
+
filter-column="email"
|
|
773
|
+
filter-placeholder="Filter emails..."
|
|
774
|
+
/>
|
|
775
|
+
<UiDataTable ref="tableRef" v-bind="args" />
|
|
776
|
+
</div>
|
|
777
|
+
`,
|
|
778
|
+
}),
|
|
779
|
+
};
|
|
780
|
+
|
|
781
|
+
/**
|
|
782
|
+
* Table with global search across all columns.
|
|
783
|
+
*
|
|
784
|
+
* Use `global-filter` prop instead of `filter-column` to search across ALL columns.
|
|
785
|
+
* Matches any value in status, email, amount, or ID.
|
|
786
|
+
*
|
|
787
|
+
* Try typing "success", "gmail", or "316" to see it match different columns.
|
|
788
|
+
*/
|
|
789
|
+
export const WithGlobalFilter: Story = {
|
|
790
|
+
args: {
|
|
791
|
+
data: payments,
|
|
792
|
+
columns: sortableColumns,
|
|
793
|
+
},
|
|
794
|
+
parameters: {
|
|
795
|
+
docs: {
|
|
796
|
+
source: {
|
|
797
|
+
code: withGlobalFilterTemplateSource,
|
|
798
|
+
},
|
|
799
|
+
},
|
|
800
|
+
},
|
|
801
|
+
render: (args) => ({
|
|
802
|
+
components: { UiDataTable, UiDataTableToolbar },
|
|
803
|
+
setup() {
|
|
804
|
+
const tableRef = ref<InstanceType<typeof UiDataTable>>();
|
|
805
|
+
const table = computed(() => tableRef.value?.table);
|
|
806
|
+
return { args, tableRef, table };
|
|
807
|
+
},
|
|
808
|
+
template: `
|
|
809
|
+
<div class="space-y-4">
|
|
810
|
+
<UiDataTableToolbar
|
|
811
|
+
v-if="table"
|
|
812
|
+
:table="table"
|
|
813
|
+
global-filter
|
|
814
|
+
filter-placeholder="Search all columns..."
|
|
815
|
+
/>
|
|
816
|
+
<UiDataTable ref="tableRef" v-bind="args" />
|
|
817
|
+
</div>
|
|
818
|
+
`,
|
|
819
|
+
}),
|
|
820
|
+
};
|
|
821
|
+
|
|
822
|
+
/**
|
|
823
|
+
* Table with row selection checkboxes.
|
|
824
|
+
*
|
|
825
|
+
* Add a selection column using `UiCheckbox` to enable row selection.
|
|
826
|
+
* Use `table.getIsAllPageRowsSelected()` for the header checkbox and
|
|
827
|
+
* `row.getIsSelected()` for row checkboxes.
|
|
828
|
+
*
|
|
829
|
+
* The pagination component shows the selection count automatically.
|
|
830
|
+
*/
|
|
831
|
+
export const WithRowSelection: Story = {
|
|
832
|
+
args: {
|
|
833
|
+
data: payments,
|
|
834
|
+
columns: selectableColumns,
|
|
835
|
+
},
|
|
836
|
+
parameters: {
|
|
837
|
+
docs: {
|
|
838
|
+
source: {
|
|
839
|
+
code: withRowSelectionTemplateSource,
|
|
840
|
+
},
|
|
841
|
+
},
|
|
842
|
+
},
|
|
843
|
+
render: (args) => ({
|
|
844
|
+
components: { UiDataTable, UiDataTablePagination },
|
|
845
|
+
setup() {
|
|
846
|
+
const tableRef = ref<InstanceType<typeof UiDataTable>>();
|
|
847
|
+
const table = computed(() => tableRef.value?.table);
|
|
848
|
+
return { args, tableRef, table };
|
|
849
|
+
},
|
|
850
|
+
template: `
|
|
851
|
+
<div class="space-y-4">
|
|
852
|
+
<UiDataTable ref="tableRef" v-bind="args" />
|
|
853
|
+
<UiDataTablePagination v-if="table" :table="table" />
|
|
854
|
+
</div>
|
|
855
|
+
`,
|
|
856
|
+
}),
|
|
857
|
+
};
|
|
858
|
+
|
|
859
|
+
/**
|
|
860
|
+
* Complete example combining all DataTable features.
|
|
861
|
+
*
|
|
862
|
+
* This example demonstrates the full power of UiDataTable with:
|
|
863
|
+
* - **Sortable columns** using `UiDataTableColumnHeader`
|
|
864
|
+
* - **Row selection** with checkboxes (header + row)
|
|
865
|
+
* - **Global search** across all columns
|
|
866
|
+
* - **Pagination** with page size selector
|
|
867
|
+
*
|
|
868
|
+
* Use this as a reference for building feature-rich data tables.
|
|
869
|
+
*/
|
|
870
|
+
export const FullExample: Story = {
|
|
871
|
+
args: {
|
|
872
|
+
data: payments,
|
|
873
|
+
columns: selectableColumns,
|
|
874
|
+
},
|
|
875
|
+
parameters: {
|
|
876
|
+
docs: {
|
|
877
|
+
source: {
|
|
878
|
+
code: fullExampleTemplateSource,
|
|
879
|
+
},
|
|
880
|
+
},
|
|
881
|
+
},
|
|
882
|
+
render: (args) => ({
|
|
883
|
+
components: { UiDataTable, UiDataTableToolbar, UiDataTablePagination },
|
|
884
|
+
setup() {
|
|
885
|
+
const tableRef = ref<InstanceType<typeof UiDataTable>>();
|
|
886
|
+
const table = computed(() => tableRef.value?.table);
|
|
887
|
+
return { args, tableRef, table };
|
|
888
|
+
},
|
|
889
|
+
template: `
|
|
890
|
+
<div class="space-y-4">
|
|
891
|
+
<UiDataTableToolbar
|
|
892
|
+
v-if="table"
|
|
893
|
+
:table="table"
|
|
894
|
+
global-filter
|
|
895
|
+
filter-placeholder="Search..."
|
|
896
|
+
/>
|
|
897
|
+
<UiDataTable ref="tableRef" v-bind="args" />
|
|
898
|
+
<UiDataTablePagination v-if="table" :table="table" />
|
|
899
|
+
</div>
|
|
900
|
+
`,
|
|
901
|
+
}),
|
|
902
|
+
};
|
|
903
|
+
|
|
904
|
+
/**
|
|
905
|
+
* Table with custom empty state message using the `empty-text` prop.
|
|
906
|
+
*
|
|
907
|
+
* Use the `empty-text` prop to customize the message shown when there's no data.
|
|
908
|
+
* Defaults to "No results." if not specified.
|
|
909
|
+
*/
|
|
910
|
+
export const WithCustomEmptyText: Story = {
|
|
911
|
+
args: {
|
|
912
|
+
data: [],
|
|
913
|
+
columns: basicColumns,
|
|
914
|
+
emptyText: 'No payments found.',
|
|
915
|
+
},
|
|
916
|
+
parameters: {
|
|
917
|
+
docs: {
|
|
918
|
+
source: {
|
|
919
|
+
code: customEmptyStateTemplateSource,
|
|
920
|
+
},
|
|
921
|
+
},
|
|
922
|
+
},
|
|
923
|
+
render: (args) => ({
|
|
924
|
+
components: { UiDataTable },
|
|
925
|
+
setup() {
|
|
926
|
+
return { args };
|
|
927
|
+
},
|
|
928
|
+
template: '<UiDataTable v-bind="args" />',
|
|
929
|
+
}),
|
|
930
|
+
};
|
|
931
|
+
|
|
932
|
+
const withCustomEmptySlotTemplateSource = `<script setup lang="ts">
|
|
933
|
+
import { UiDataTable } from '@aleph-alpha/ui-library';
|
|
934
|
+
import { Ban } from 'lucide-vue-next';
|
|
935
|
+
import type { ColumnDef } from '@tanstack/vue-table';
|
|
936
|
+
|
|
937
|
+
interface Payment {
|
|
938
|
+
id: string;
|
|
939
|
+
amount: number;
|
|
940
|
+
status: string;
|
|
941
|
+
email: string;
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
const data: Payment[] = []; // Empty data
|
|
945
|
+
|
|
946
|
+
const columns: ColumnDef<Payment>[] = [
|
|
947
|
+
{ accessorKey: 'status', header: 'Status' },
|
|
948
|
+
{ accessorKey: 'email', header: 'Email' },
|
|
949
|
+
{ accessorKey: 'amount', header: 'Amount' },
|
|
950
|
+
];
|
|
951
|
+
</script>
|
|
952
|
+
|
|
953
|
+
<template>
|
|
954
|
+
<UiDataTable :data="data" :columns="columns">
|
|
955
|
+
<template #empty>
|
|
956
|
+
<div class="flex flex-col items-center gap-2 text-muted-foreground">
|
|
957
|
+
<Ban class="h-8 w-8" />
|
|
958
|
+
<p>No data available for this view.</p>
|
|
959
|
+
</div>
|
|
960
|
+
</template>
|
|
961
|
+
</UiDataTable>
|
|
962
|
+
</template>`;
|
|
963
|
+
|
|
964
|
+
export const WithCustomEmptySlot: Story = {
|
|
965
|
+
args: {
|
|
966
|
+
data: [],
|
|
967
|
+
columns: basicColumns,
|
|
968
|
+
},
|
|
969
|
+
parameters: {
|
|
970
|
+
docs: {
|
|
971
|
+
description: {
|
|
972
|
+
story:
|
|
973
|
+
'Use the `#empty` slot to provide a fully custom empty state, such as an icon or formatted text.',
|
|
974
|
+
},
|
|
975
|
+
source: {
|
|
976
|
+
code: withCustomEmptySlotTemplateSource,
|
|
977
|
+
},
|
|
978
|
+
},
|
|
979
|
+
},
|
|
980
|
+
render: (args) => ({
|
|
981
|
+
components: { UiDataTable, Ban },
|
|
982
|
+
setup() {
|
|
983
|
+
return { args };
|
|
984
|
+
},
|
|
985
|
+
template: `
|
|
986
|
+
<UiDataTable v-bind="args">
|
|
987
|
+
<template #empty>
|
|
988
|
+
<div class="flex flex-col items-center gap-2 text-muted-foreground">
|
|
989
|
+
<Ban class="h-8 w-8" />
|
|
990
|
+
<p>No data available for this view.</p>
|
|
991
|
+
</div>
|
|
992
|
+
</template>
|
|
993
|
+
</UiDataTable>
|
|
994
|
+
`,
|
|
995
|
+
}),
|
|
996
|
+
};
|
|
997
|
+
|
|
998
|
+
// Columns using UiDataTableColumnHeader component
|
|
999
|
+
const columnHeaderColumns: ColumnDef<Payment>[] = [
|
|
1000
|
+
{
|
|
1001
|
+
accessorKey: 'status',
|
|
1002
|
+
header: ({ column }) => h(UiDataTableColumnHeader, { column, title: 'Status' }),
|
|
1003
|
+
cell: ({ row }) => h('div', { class: 'capitalize' }, row.getValue('status')),
|
|
1004
|
+
size: 120,
|
|
1005
|
+
},
|
|
1006
|
+
{
|
|
1007
|
+
accessorKey: 'email',
|
|
1008
|
+
header: ({ column }) => h(UiDataTableColumnHeader, { column, title: 'Email' }),
|
|
1009
|
+
cell: ({ row }) => h('div', { class: 'lowercase' }, row.getValue('email')),
|
|
1010
|
+
size: 250,
|
|
1011
|
+
},
|
|
1012
|
+
{
|
|
1013
|
+
accessorKey: 'amount',
|
|
1014
|
+
header: ({ column }) =>
|
|
1015
|
+
h(UiDataTableColumnHeader, { column, title: 'Amount', class: 'justify-end' }),
|
|
1016
|
+
cell: ({ row }) => {
|
|
1017
|
+
const amount = Number.parseFloat(row.getValue('amount'));
|
|
1018
|
+
const formatted = new Intl.NumberFormat('de-DE', {
|
|
1019
|
+
style: 'currency',
|
|
1020
|
+
currency: 'EUR',
|
|
1021
|
+
}).format(amount);
|
|
1022
|
+
return h('div', { class: 'text-right font-medium' }, formatted);
|
|
1023
|
+
},
|
|
1024
|
+
size: 120,
|
|
1025
|
+
},
|
|
1026
|
+
];
|
|
1027
|
+
|
|
1028
|
+
const withColumnHeaderTemplateSource = `<script setup lang="ts">
|
|
1029
|
+
import { h } from 'vue';
|
|
1030
|
+
import { UiDataTable, UiDataTableColumnHeader } from '@aleph-alpha/ui-library';
|
|
1031
|
+
import type { ColumnDef } from '@tanstack/vue-table';
|
|
1032
|
+
|
|
1033
|
+
interface Payment {
|
|
1034
|
+
id: string;
|
|
1035
|
+
amount: number;
|
|
1036
|
+
status: string;
|
|
1037
|
+
email: string;
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
const data: Payment[] = [
|
|
1041
|
+
{ id: '1', amount: 316, status: 'success', email: 'ken99@yahoo.com' },
|
|
1042
|
+
// ... more data
|
|
1043
|
+
];
|
|
1044
|
+
|
|
1045
|
+
// Using UiDataTableColumnHeader for sortable headers with hide option
|
|
1046
|
+
const columns: ColumnDef<Payment>[] = [
|
|
1047
|
+
{
|
|
1048
|
+
accessorKey: 'status',
|
|
1049
|
+
header: ({ column }) => h(UiDataTableColumnHeader, { column, title: 'Status' }),
|
|
1050
|
+
cell: ({ row }) => h('div', { class: 'capitalize' }, row.getValue('status')),
|
|
1051
|
+
size: 120,
|
|
1052
|
+
},
|
|
1053
|
+
{
|
|
1054
|
+
accessorKey: 'email',
|
|
1055
|
+
header: ({ column }) => h(UiDataTableColumnHeader, { column, title: 'Email' }),
|
|
1056
|
+
cell: ({ row }) => h('div', { class: 'lowercase' }, row.getValue('email')),
|
|
1057
|
+
size: 250,
|
|
1058
|
+
},
|
|
1059
|
+
{
|
|
1060
|
+
accessorKey: 'amount',
|
|
1061
|
+
header: ({ column }) => h(UiDataTableColumnHeader, {
|
|
1062
|
+
column,
|
|
1063
|
+
title: 'Amount',
|
|
1064
|
+
class: 'justify-end'
|
|
1065
|
+
}),
|
|
1066
|
+
cell: ({ row }) => {
|
|
1067
|
+
const amount = Number.parseFloat(row.getValue('amount'));
|
|
1068
|
+
const formatted = new Intl.NumberFormat('de-DE', {
|
|
1069
|
+
style: 'currency',
|
|
1070
|
+
currency: 'EUR',
|
|
1071
|
+
}).format(amount);
|
|
1072
|
+
return h('div', { class: 'text-right font-medium' }, formatted);
|
|
1073
|
+
},
|
|
1074
|
+
size: 120,
|
|
1075
|
+
},
|
|
1076
|
+
];
|
|
1077
|
+
</script>
|
|
1078
|
+
|
|
1079
|
+
<template>
|
|
1080
|
+
<UiDataTable :data="data" :columns="columns" />
|
|
1081
|
+
</template>`;
|
|
1082
|
+
|
|
1083
|
+
/**
|
|
1084
|
+
* Table demonstrating sortable columns with UiDataTableColumnHeader.
|
|
1085
|
+
*
|
|
1086
|
+
* The `UiDataTableColumnHeader` provides a dropdown with sort options.
|
|
1087
|
+
*
|
|
1088
|
+
* For right-aligned headers (like amounts), pass `class="justify-end"`.
|
|
1089
|
+
*/
|
|
1090
|
+
export const WithColumnHeader: Story = {
|
|
1091
|
+
args: {
|
|
1092
|
+
data: payments,
|
|
1093
|
+
columns: columnHeaderColumns,
|
|
1094
|
+
},
|
|
1095
|
+
parameters: {
|
|
1096
|
+
docs: {
|
|
1097
|
+
source: {
|
|
1098
|
+
code: withColumnHeaderTemplateSource,
|
|
1099
|
+
},
|
|
1100
|
+
},
|
|
1101
|
+
},
|
|
1102
|
+
render: (args) => ({
|
|
1103
|
+
components: { UiDataTable, UiDataTableToolbar },
|
|
1104
|
+
setup() {
|
|
1105
|
+
const tableRef = ref<InstanceType<typeof UiDataTable>>();
|
|
1106
|
+
const table = computed(() => tableRef.value?.table);
|
|
1107
|
+
return { args, tableRef, table };
|
|
1108
|
+
},
|
|
1109
|
+
template: `
|
|
1110
|
+
<div class="space-y-4">
|
|
1111
|
+
<UiDataTableToolbar
|
|
1112
|
+
v-if="table"
|
|
1113
|
+
:table="table"
|
|
1114
|
+
global-filter
|
|
1115
|
+
filter-placeholder="Search..."
|
|
1116
|
+
/>
|
|
1117
|
+
<UiDataTable ref="tableRef" v-bind="args" />
|
|
1118
|
+
</div>
|
|
1119
|
+
`,
|
|
1120
|
+
}),
|
|
1121
|
+
};
|
|
1122
|
+
|
|
1123
|
+
/**
|
|
1124
|
+
* Table with customized pagination options.
|
|
1125
|
+
*
|
|
1126
|
+
* Customize `UiDataTablePagination` with:
|
|
1127
|
+
* - `page-size-options`: Array of page size options (default: [10, 20, 30, 50])
|
|
1128
|
+
* - `show-page-size`: Show/hide the rows per page selector (default: true)
|
|
1129
|
+
* - `show-selection`: Show/hide the selection count (default: true)
|
|
1130
|
+
*/
|
|
1131
|
+
export const WithPageSizeSelector: Story = {
|
|
1132
|
+
args: {
|
|
1133
|
+
data: payments,
|
|
1134
|
+
columns: sortableColumns,
|
|
1135
|
+
},
|
|
1136
|
+
parameters: {
|
|
1137
|
+
docs: {
|
|
1138
|
+
source: {
|
|
1139
|
+
code: withPageSizeTemplateSource,
|
|
1140
|
+
},
|
|
1141
|
+
},
|
|
1142
|
+
},
|
|
1143
|
+
render: (args) => ({
|
|
1144
|
+
components: { UiDataTable, UiDataTablePagination },
|
|
1145
|
+
setup() {
|
|
1146
|
+
const tableRef = ref<InstanceType<typeof UiDataTable>>();
|
|
1147
|
+
const table = computed(() => tableRef.value?.table);
|
|
1148
|
+
return { args, tableRef, table };
|
|
1149
|
+
},
|
|
1150
|
+
template: `
|
|
1151
|
+
<div class="space-y-4">
|
|
1152
|
+
<UiDataTable ref="tableRef" v-bind="args" />
|
|
1153
|
+
<UiDataTablePagination
|
|
1154
|
+
v-if="table"
|
|
1155
|
+
:table="table"
|
|
1156
|
+
:page-size-options="[5, 10, 20, 50]"
|
|
1157
|
+
:show-selection="false"
|
|
1158
|
+
/>
|
|
1159
|
+
</div>
|
|
1160
|
+
`,
|
|
1161
|
+
}),
|
|
1162
|
+
};
|
|
1163
|
+
|
|
1164
|
+
/**
|
|
1165
|
+
* Table with 14 items, minimum height, and pagination.
|
|
1166
|
+
*
|
|
1167
|
+
* Demonstrates how `tableMinHeight` keeps stable layout when there's content
|
|
1168
|
+
* below the table (pagination). Page 1 shows 10 rows, page 2 shows 4 rows -
|
|
1169
|
+
* the table maintains consistent height regardless of how many rows are visible.
|
|
1170
|
+
*/
|
|
1171
|
+
export const WithMinHeightSmallDataset: Story = {
|
|
1172
|
+
args: {
|
|
1173
|
+
// Use 14 items: page 1 = 10 rows, page 2 = 4 rows
|
|
1174
|
+
data: paymentsMedium.slice(0, 14),
|
|
1175
|
+
columns: sortableColumns,
|
|
1176
|
+
tableMinHeight: '500px',
|
|
1177
|
+
},
|
|
1178
|
+
parameters: {
|
|
1179
|
+
docs: {
|
|
1180
|
+
description: {
|
|
1181
|
+
story:
|
|
1182
|
+
'Demonstrates `tableMinHeight` with 14 items and pagination. Page 1 shows 10 rows, page 2 shows only 4 rows. The table keeps a consistent height, preventing layout shifts when navigating between pages.',
|
|
1183
|
+
},
|
|
1184
|
+
source: {
|
|
1185
|
+
code: `<script setup lang="ts">
|
|
1186
|
+
import { h, ref, computed } from 'vue';
|
|
1187
|
+
import { UiDataTable, UiDataTableColumnHeader, UiDataTablePagination } from '@aleph-alpha/ui-library';
|
|
1188
|
+
import type { ColumnDef } from '@tanstack/vue-table';
|
|
1189
|
+
|
|
1190
|
+
interface Payment { id: string; amount: number; status: string; email: string; }
|
|
1191
|
+
|
|
1192
|
+
// 14 items: page 1 = 10 rows, page 2 = 4 rows
|
|
1193
|
+
const data: Payment[] = [
|
|
1194
|
+
{ id: '1', amount: 316, status: 'success', email: 'user1@example.com' },
|
|
1195
|
+
{ id: '2', amount: 242, status: 'pending', email: 'user2@example.com' },
|
|
1196
|
+
{ id: '3', amount: 837, status: 'processing', email: 'user3@example.com' },
|
|
1197
|
+
{ id: '4', amount: 154, status: 'failed', email: 'user4@example.com' },
|
|
1198
|
+
{ id: '5', amount: 429, status: 'success', email: 'user5@example.com' },
|
|
1199
|
+
{ id: '6', amount: 512, status: 'pending', email: 'user6@example.com' },
|
|
1200
|
+
{ id: '7', amount: 623, status: 'processing', email: 'user7@example.com' },
|
|
1201
|
+
{ id: '8', amount: 734, status: 'failed', email: 'user8@example.com' },
|
|
1202
|
+
{ id: '9', amount: 845, status: 'success', email: 'user9@example.com' },
|
|
1203
|
+
{ id: '10', amount: 956, status: 'pending', email: 'user10@example.com' },
|
|
1204
|
+
{ id: '11', amount: 167, status: 'processing', email: 'user11@example.com' },
|
|
1205
|
+
{ id: '12', amount: 278, status: 'failed', email: 'user12@example.com' },
|
|
1206
|
+
{ id: '13', amount: 389, status: 'success', email: 'user13@example.com' },
|
|
1207
|
+
{ id: '14', amount: 490, status: 'pending', email: 'user14@example.com' },
|
|
1208
|
+
];
|
|
1209
|
+
|
|
1210
|
+
const columns: ColumnDef<Payment>[] = [
|
|
1211
|
+
{ accessorKey: 'status', header: ({ column }) => h(UiDataTableColumnHeader, { column, title: 'Status' }) },
|
|
1212
|
+
{ accessorKey: 'email', header: ({ column }) => h(UiDataTableColumnHeader, { column, title: 'Email' }) },
|
|
1213
|
+
{ accessorKey: 'amount', header: ({ column }) => h(UiDataTableColumnHeader, { column, title: 'Amount', class: 'justify-end' }) },
|
|
1214
|
+
];
|
|
1215
|
+
|
|
1216
|
+
const tableRef = ref<InstanceType<typeof UiDataTable>>();
|
|
1217
|
+
const table = computed(() => tableRef.value?.table);
|
|
1218
|
+
</script>
|
|
1219
|
+
|
|
1220
|
+
<template>
|
|
1221
|
+
<div class="space-y-4">
|
|
1222
|
+
<UiDataTable ref="tableRef" :data="data" :columns="columns" table-min-height="500px" />
|
|
1223
|
+
<UiDataTablePagination v-if="table" :table="table" :show-selection="false" />
|
|
1224
|
+
</div>
|
|
1225
|
+
</template>`,
|
|
1226
|
+
},
|
|
1227
|
+
},
|
|
1228
|
+
},
|
|
1229
|
+
render: (args) => ({
|
|
1230
|
+
components: { UiDataTable, UiDataTablePagination },
|
|
1231
|
+
setup() {
|
|
1232
|
+
const tableRef = ref<InstanceType<typeof UiDataTable>>();
|
|
1233
|
+
const table = computed(() => tableRef.value?.table);
|
|
1234
|
+
return { args, tableRef, table };
|
|
1235
|
+
},
|
|
1236
|
+
template: `
|
|
1237
|
+
<div class="space-y-4">
|
|
1238
|
+
<UiDataTable ref="tableRef" v-bind="args" />
|
|
1239
|
+
<UiDataTablePagination v-if="table" :table="table" :show-selection="false" />
|
|
1240
|
+
</div>
|
|
1241
|
+
`,
|
|
1242
|
+
}),
|
|
1243
|
+
};
|
|
1244
|
+
|
|
1245
|
+
// Row Actions columns with dropdown menu
|
|
1246
|
+
const rowActionsColumns: ColumnDef<Payment>[] = [
|
|
1247
|
+
{
|
|
1248
|
+
accessorKey: 'status',
|
|
1249
|
+
header: ({ column }) => h(UiDataTableColumnHeader, { column, title: 'Status' }),
|
|
1250
|
+
cell: ({ row }) => h('div', { class: 'capitalize' }, row.getValue('status')),
|
|
1251
|
+
size: 120,
|
|
1252
|
+
},
|
|
1253
|
+
{
|
|
1254
|
+
accessorKey: 'email',
|
|
1255
|
+
header: ({ column }) => h(UiDataTableColumnHeader, { column, title: 'Email' }),
|
|
1256
|
+
cell: ({ row }) => h('div', { class: 'lowercase' }, row.getValue('email')),
|
|
1257
|
+
size: 250,
|
|
1258
|
+
},
|
|
1259
|
+
{
|
|
1260
|
+
accessorKey: 'amount',
|
|
1261
|
+
header: ({ column }) =>
|
|
1262
|
+
h(UiDataTableColumnHeader, { column, title: 'Amount', class: 'justify-end' }),
|
|
1263
|
+
cell: ({ row }) => {
|
|
1264
|
+
const amount = Number.parseFloat(row.getValue('amount'));
|
|
1265
|
+
const formatted = new Intl.NumberFormat('de-DE', {
|
|
1266
|
+
style: 'currency',
|
|
1267
|
+
currency: 'EUR',
|
|
1268
|
+
}).format(amount);
|
|
1269
|
+
return h('div', { class: 'text-right font-medium' }, formatted);
|
|
1270
|
+
},
|
|
1271
|
+
size: 120,
|
|
1272
|
+
},
|
|
1273
|
+
{
|
|
1274
|
+
id: 'actions',
|
|
1275
|
+
enableHiding: false,
|
|
1276
|
+
enableSorting: false,
|
|
1277
|
+
header: () => h('span', { class: 'sr-only' }, 'Actions'),
|
|
1278
|
+
cell: ({ row }) => {
|
|
1279
|
+
const payment = row.original;
|
|
1280
|
+
return h(
|
|
1281
|
+
UiDropdownMenu,
|
|
1282
|
+
{},
|
|
1283
|
+
{
|
|
1284
|
+
default: () => [
|
|
1285
|
+
h(UiDropdownMenuTrigger, { asChild: true }, () =>
|
|
1286
|
+
h(UiButton, { variant: 'ghost', size: 'icon', class: 'h-8 w-8' }, () => [
|
|
1287
|
+
h('span', { class: 'sr-only' }, 'Open menu'),
|
|
1288
|
+
h(MoreHorizontal, { class: 'h-4 w-4' }),
|
|
1289
|
+
]),
|
|
1290
|
+
),
|
|
1291
|
+
h(UiDropdownMenuContent, { align: 'end' }, () => [
|
|
1292
|
+
h(UiDropdownMenuLabel, {}, () => 'Actions'),
|
|
1293
|
+
h(
|
|
1294
|
+
UiDropdownMenuItem,
|
|
1295
|
+
{ onClick: () => navigator.clipboard.writeText(payment.id) },
|
|
1296
|
+
() => 'Copy payment ID',
|
|
1297
|
+
),
|
|
1298
|
+
h(UiDropdownMenuSeparator),
|
|
1299
|
+
h(UiDropdownMenuItem, {}, () => 'View details'),
|
|
1300
|
+
h(UiDropdownMenuItem, {}, () => 'View customer'),
|
|
1301
|
+
]),
|
|
1302
|
+
],
|
|
1303
|
+
},
|
|
1304
|
+
);
|
|
1305
|
+
},
|
|
1306
|
+
size: 50,
|
|
1307
|
+
},
|
|
1308
|
+
];
|
|
1309
|
+
|
|
1310
|
+
const withRowActionsTemplateSource = `<script setup lang="ts">
|
|
1311
|
+
import { h } from 'vue';
|
|
1312
|
+
import { UiDataTable, UiDataTableColumnHeader } from '@aleph-alpha/ui-library';
|
|
1313
|
+
import {
|
|
1314
|
+
UiDropdownMenu,
|
|
1315
|
+
UiDropdownMenuContent,
|
|
1316
|
+
UiDropdownMenuItem,
|
|
1317
|
+
UiDropdownMenuLabel,
|
|
1318
|
+
UiDropdownMenuSeparator,
|
|
1319
|
+
UiDropdownMenuTrigger,
|
|
1320
|
+
} from '@aleph-alpha/ui-library';
|
|
1321
|
+
import { UiButton } from '@aleph-alpha/ui-library';
|
|
1322
|
+
import type { ColumnDef } from '@tanstack/vue-table';
|
|
1323
|
+
|
|
1324
|
+
interface Payment {
|
|
1325
|
+
id: string;
|
|
1326
|
+
amount: number;
|
|
1327
|
+
status: string;
|
|
1328
|
+
email: string;
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
const data: Payment[] = [
|
|
1332
|
+
{ id: '1', amount: 316, status: 'success', email: 'ken99@yahoo.com' },
|
|
1333
|
+
{ id: '2', amount: 242, status: 'success', email: 'abe45@gmail.com' },
|
|
1334
|
+
{ id: '3', amount: 837, status: 'processing', email: 'monserrat44@gmail.com' },
|
|
1335
|
+
];
|
|
1336
|
+
|
|
1337
|
+
// Define a component for row actions (or use inline h() calls)
|
|
1338
|
+
const columns: ColumnDef<Payment>[] = [
|
|
1339
|
+
{
|
|
1340
|
+
accessorKey: 'status',
|
|
1341
|
+
header: ({ column }) => h(UiDataTableColumnHeader, { column, title: 'Status' }),
|
|
1342
|
+
cell: ({ row }) => h('div', { class: 'capitalize' }, row.getValue('status')),
|
|
1343
|
+
},
|
|
1344
|
+
{
|
|
1345
|
+
accessorKey: 'email',
|
|
1346
|
+
header: ({ column }) => h(UiDataTableColumnHeader, { column, title: 'Email' }),
|
|
1347
|
+
cell: ({ row }) => h('div', { class: 'lowercase' }, row.getValue('email')),
|
|
1348
|
+
},
|
|
1349
|
+
{
|
|
1350
|
+
accessorKey: 'amount',
|
|
1351
|
+
header: ({ column }) => h(UiDataTableColumnHeader, {
|
|
1352
|
+
column,
|
|
1353
|
+
title: 'Amount',
|
|
1354
|
+
class: 'justify-end'
|
|
1355
|
+
}),
|
|
1356
|
+
cell: ({ row }) => {
|
|
1357
|
+
const amount = Number.parseFloat(row.getValue('amount'));
|
|
1358
|
+
const formatted = new Intl.NumberFormat('de-DE', {
|
|
1359
|
+
style: 'currency',
|
|
1360
|
+
currency: 'EUR',
|
|
1361
|
+
}).format(amount);
|
|
1362
|
+
return h('div', { class: 'text-right font-medium' }, formatted);
|
|
1363
|
+
},
|
|
1364
|
+
},
|
|
1365
|
+
{
|
|
1366
|
+
id: 'actions',
|
|
1367
|
+
enableHiding: false,
|
|
1368
|
+
cell: ({ row }) => {
|
|
1369
|
+
const payment = row.original;
|
|
1370
|
+
|
|
1371
|
+
// You can return a Vue component or use h() to render dropdown
|
|
1372
|
+
// For complex actions, create a separate component like DataTableRowActions.vue
|
|
1373
|
+
return h(UiDropdownMenu, {}, {
|
|
1374
|
+
default: () => [
|
|
1375
|
+
h(UiDropdownMenuTrigger, { asChild: true }, () =>
|
|
1376
|
+
h(UiButton, { variant: 'ghost', size: 'sm' }, () => '⋮')
|
|
1377
|
+
),
|
|
1378
|
+
h(UiDropdownMenuContent, { align: 'end' }, () => [
|
|
1379
|
+
h(UiDropdownMenuLabel, {}, () => 'Actions'),
|
|
1380
|
+
h(UiDropdownMenuItem, {
|
|
1381
|
+
onClick: () => navigator.clipboard.writeText(payment.id)
|
|
1382
|
+
}, () => 'Copy payment ID'),
|
|
1383
|
+
h(UiDropdownMenuSeparator),
|
|
1384
|
+
h(UiDropdownMenuItem, {}, () => 'View details'),
|
|
1385
|
+
h(UiDropdownMenuItem, {}, () => 'View customer'),
|
|
1386
|
+
]),
|
|
1387
|
+
],
|
|
1388
|
+
});
|
|
1389
|
+
},
|
|
1390
|
+
},
|
|
1391
|
+
];
|
|
1392
|
+
</script>
|
|
1393
|
+
|
|
1394
|
+
<template>
|
|
1395
|
+
<UiDataTable :data="data" :columns="columns" />
|
|
1396
|
+
</template>`;
|
|
1397
|
+
|
|
1398
|
+
/**
|
|
1399
|
+
* Table with row actions dropdown menu.
|
|
1400
|
+
*
|
|
1401
|
+
* Add an actions column with a dropdown menu for each row.
|
|
1402
|
+
* Use `row.original` to access the full row data for actions.
|
|
1403
|
+
*
|
|
1404
|
+
* For complex actions, create a separate component (e.g., `DataTableRowActions.vue`)
|
|
1405
|
+
* and import it in your column definition.
|
|
1406
|
+
*/
|
|
1407
|
+
export const WithRowActions: Story = {
|
|
1408
|
+
args: {
|
|
1409
|
+
data: payments,
|
|
1410
|
+
columns: rowActionsColumns,
|
|
1411
|
+
},
|
|
1412
|
+
parameters: {
|
|
1413
|
+
docs: {
|
|
1414
|
+
source: {
|
|
1415
|
+
code: withRowActionsTemplateSource,
|
|
1416
|
+
},
|
|
1417
|
+
},
|
|
1418
|
+
},
|
|
1419
|
+
render: (args) => ({
|
|
1420
|
+
components: { UiDataTable },
|
|
1421
|
+
setup() {
|
|
1422
|
+
return { args };
|
|
1423
|
+
},
|
|
1424
|
+
template: '<UiDataTable v-bind="args" />',
|
|
1425
|
+
}),
|
|
1426
|
+
};
|
|
1427
|
+
|
|
1428
|
+
// Cell formatting columns
|
|
1429
|
+
const cellFormattingColumns: ColumnDef<Payment>[] = [
|
|
1430
|
+
{
|
|
1431
|
+
accessorKey: 'status',
|
|
1432
|
+
header: 'Status',
|
|
1433
|
+
cell: ({ row }) => {
|
|
1434
|
+
const status = row.getValue('status') as string;
|
|
1435
|
+
const statusStyles: Record<string, string> = {
|
|
1436
|
+
success: 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300',
|
|
1437
|
+
processing: 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300',
|
|
1438
|
+
pending: 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300',
|
|
1439
|
+
failed: 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300',
|
|
1440
|
+
};
|
|
1441
|
+
return h(
|
|
1442
|
+
'span',
|
|
1443
|
+
{
|
|
1444
|
+
class: `inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium capitalize ${statusStyles[status] || ''}`,
|
|
1445
|
+
},
|
|
1446
|
+
status,
|
|
1447
|
+
);
|
|
1448
|
+
},
|
|
1449
|
+
size: 120,
|
|
1450
|
+
},
|
|
1451
|
+
{
|
|
1452
|
+
accessorKey: 'email',
|
|
1453
|
+
header: 'Email',
|
|
1454
|
+
cell: ({ row }) => h('div', { class: 'lowercase font-mono text-sm' }, row.getValue('email')),
|
|
1455
|
+
size: 250,
|
|
1456
|
+
},
|
|
1457
|
+
{
|
|
1458
|
+
accessorKey: 'amount',
|
|
1459
|
+
header: () => h('div', { class: 'text-right' }, 'Amount'),
|
|
1460
|
+
cell: ({ row }) => {
|
|
1461
|
+
const amount = Number.parseFloat(row.getValue('amount'));
|
|
1462
|
+
const formatted = new Intl.NumberFormat('de-DE', {
|
|
1463
|
+
style: 'currency',
|
|
1464
|
+
currency: 'EUR',
|
|
1465
|
+
}).format(amount);
|
|
1466
|
+
return h(
|
|
1467
|
+
'div',
|
|
1468
|
+
{
|
|
1469
|
+
class: `text-right font-medium ${amount > 500 ? 'text-green-600' : 'text-muted-foreground'}`,
|
|
1470
|
+
},
|
|
1471
|
+
formatted,
|
|
1472
|
+
);
|
|
1473
|
+
},
|
|
1474
|
+
size: 120,
|
|
1475
|
+
},
|
|
1476
|
+
];
|
|
1477
|
+
|
|
1478
|
+
const withCellFormattingTemplateSource = `<script setup lang="ts">
|
|
1479
|
+
import { h } from 'vue';
|
|
1480
|
+
import { UiDataTable } from '@aleph-alpha/ui-library';
|
|
1481
|
+
import type { ColumnDef } from '@tanstack/vue-table';
|
|
1482
|
+
|
|
1483
|
+
interface Payment {
|
|
1484
|
+
id: string;
|
|
1485
|
+
amount: number;
|
|
1486
|
+
status: 'pending' | 'processing' | 'success' | 'failed';
|
|
1487
|
+
email: string;
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1490
|
+
const data: Payment[] = [
|
|
1491
|
+
{ id: '1', amount: 316, status: 'success', email: 'ken99@yahoo.com' },
|
|
1492
|
+
{ id: '2', amount: 242, status: 'pending', email: 'abe45@gmail.com' },
|
|
1493
|
+
{ id: '3', amount: 837, status: 'processing', email: 'monserrat44@gmail.com' },
|
|
1494
|
+
{ id: '4', amount: 721, status: 'failed', email: 'carmella@hotmail.com' },
|
|
1495
|
+
];
|
|
1496
|
+
|
|
1497
|
+
const columns: ColumnDef<Payment>[] = [
|
|
1498
|
+
{
|
|
1499
|
+
accessorKey: 'status',
|
|
1500
|
+
header: 'Status',
|
|
1501
|
+
// Custom status badge with semantic colors
|
|
1502
|
+
cell: ({ row }) => {
|
|
1503
|
+
const status = row.getValue('status') as string;
|
|
1504
|
+
const statusStyles: Record<string, string> = {
|
|
1505
|
+
success: 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300',
|
|
1506
|
+
processing: 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300',
|
|
1507
|
+
pending: 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300',
|
|
1508
|
+
failed: 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300',
|
|
1509
|
+
};
|
|
1510
|
+
return h('span', {
|
|
1511
|
+
class: \`inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium capitalize \${statusStyles[status] || ''}\`,
|
|
1512
|
+
}, status);
|
|
1513
|
+
},
|
|
1514
|
+
},
|
|
1515
|
+
{
|
|
1516
|
+
accessorKey: 'email',
|
|
1517
|
+
header: 'Email',
|
|
1518
|
+
// Monospace font for emails
|
|
1519
|
+
cell: ({ row }) => h('div', {
|
|
1520
|
+
class: 'lowercase font-mono text-sm'
|
|
1521
|
+
}, row.getValue('email')),
|
|
1522
|
+
},
|
|
1523
|
+
{
|
|
1524
|
+
accessorKey: 'amount',
|
|
1525
|
+
// Right-aligned header
|
|
1526
|
+
header: () => h('div', { class: 'text-right' }, 'Amount'),
|
|
1527
|
+
// Conditional formatting: green for high amounts
|
|
1528
|
+
cell: ({ row }) => {
|
|
1529
|
+
const amount = Number.parseFloat(row.getValue('amount'));
|
|
1530
|
+
const formatted = new Intl.NumberFormat('de-DE', {
|
|
1531
|
+
style: 'currency',
|
|
1532
|
+
currency: 'EUR',
|
|
1533
|
+
}).format(amount);
|
|
1534
|
+
return h('div', {
|
|
1535
|
+
class: \`text-right font-medium \${amount > 500 ? 'text-green-600' : 'text-muted-foreground'}\`,
|
|
1536
|
+
}, formatted);
|
|
1537
|
+
},
|
|
1538
|
+
},
|
|
1539
|
+
];
|
|
1540
|
+
</script>
|
|
1541
|
+
|
|
1542
|
+
<template>
|
|
1543
|
+
<UiDataTable :data="data" :columns="columns" />
|
|
1544
|
+
</template>`;
|
|
1545
|
+
|
|
1546
|
+
/**
|
|
1547
|
+
* Table with custom cell formatting.
|
|
1548
|
+
*
|
|
1549
|
+
* Use the `cell` property in column definitions to customize how data is displayed:
|
|
1550
|
+
* - **Status badges** with semantic colors (green=success, yellow=processing, etc.)
|
|
1551
|
+
* - **Monospace font** for emails
|
|
1552
|
+
* - **Currency formatting** with conditional colors based on value
|
|
1553
|
+
*
|
|
1554
|
+
* Access cell value with `row.getValue('columnKey')` and return a VNode using `h()`.
|
|
1555
|
+
*/
|
|
1556
|
+
export const WithCellFormatting: Story = {
|
|
1557
|
+
args: {
|
|
1558
|
+
data: payments,
|
|
1559
|
+
columns: cellFormattingColumns,
|
|
1560
|
+
},
|
|
1561
|
+
parameters: {
|
|
1562
|
+
docs: {
|
|
1563
|
+
source: {
|
|
1564
|
+
code: withCellFormattingTemplateSource,
|
|
1565
|
+
},
|
|
1566
|
+
},
|
|
1567
|
+
},
|
|
1568
|
+
render: (args) => ({
|
|
1569
|
+
components: { UiDataTable },
|
|
1570
|
+
setup() {
|
|
1571
|
+
return { args };
|
|
1572
|
+
},
|
|
1573
|
+
template: '<UiDataTable v-bind="args" />',
|
|
1574
|
+
}),
|
|
1575
|
+
};
|