@livestorm/ui-vue 3.0.0 → 4.0.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 +3 -3
- package/components-vite.js +2 -2
- package/dist/UiButton-uyW8EHRJ.mjs +602 -0
- package/dist/UiTimelineItem-EiOEi1yF.mjs +7293 -0
- package/dist/UiTooltip-DZcPD6_N.mjs +158 -0
- package/dist/a11y-CaZxRWzo.mjs +6 -0
- package/dist/breakpoints.mjs +4 -9
- package/dist/bus.mjs +5 -5
- package/dist/components.mjs +236 -231
- package/dist/i18n-B8QOMuFD.mjs +46 -0
- package/dist/index.mjs +4 -91
- package/dist/integrations.mjs +3 -14
- package/dist/layouts.mjs +228 -236
- package/dist/responsive.mjs +31 -36
- package/dist/slot.mjs +11 -17
- package/dist/toastDSV2-D3xDZPe5.mjs +105 -0
- package/dist/types/index.d.ts +19 -1
- package/dist/types/src/components/Toast/ToastMessage.vue.d.ts +17 -7
- package/dist/types/src/components/Toast/toastDSV2.d.ts +89 -64
- package/dist/types/src/components/UiActionBar/types.d.ts +2 -0
- package/dist/types/src/components/UiAvatar/UiAvatar.vue.d.ts +4 -2
- package/dist/types/src/components/UiAvatarList/UiAvatarList.vue.d.ts +3 -2
- package/dist/types/src/components/UiBanner/UiBanner.vue.d.ts +13 -1
- package/dist/types/src/components/UiButton/UiButton.vue.d.ts +95 -35
- package/dist/types/src/components/UiButtonGroup/UiButtonGroup.vue.d.ts +8 -2
- package/dist/types/src/components/UiButtonGroup/types.d.ts +4 -0
- package/dist/types/src/components/UiChoice/UiChoice.vue.d.ts +71 -0
- package/dist/types/src/components/UiChoice/index.d.ts +2 -0
- package/dist/types/src/components/UiChoice/types.d.ts +7 -0
- package/dist/types/src/components/UiColorField/UiColorField.vue.d.ts +1 -1
- package/dist/types/src/components/UiColorPicker/UiColorPicker.vue.d.ts +2 -2
- package/dist/types/src/components/UiCombobox/UiCombobox.types.d.ts +47 -0
- package/dist/types/src/components/UiCombobox/UiCombobox.vue.d.ts +40 -0
- package/dist/types/src/components/UiCombobox/index.d.ts +2 -0
- package/dist/types/src/components/UiDataTable/UiDataTable.types.d.ts +46 -0
- package/dist/types/src/components/UiDataTable/UiDataTable.vue.d.ts +136 -0
- package/dist/types/src/components/UiDataTable/index.d.ts +5 -0
- package/dist/types/src/components/UiDrawer/UiDrawer.vue.d.ts +28 -0
- package/dist/types/src/components/UiDrawer/UiDrawerContent.vue.d.ts +18 -0
- package/dist/types/src/components/UiDrawer/UiDrawerTrigger.vue.d.ts +14 -0
- package/dist/types/src/components/UiDropdown/DropdownItemCheckbox.vue.d.ts +3 -0
- package/dist/types/src/components/UiDropdown/UiDropdownContent.vue.d.ts +10 -0
- package/dist/types/src/components/UiDropdown/UiDropdownGroup.vue.d.ts +17 -0
- package/dist/types/src/components/UiDropdown/UiDropdownItem.vue.d.ts +8 -5
- package/dist/types/src/components/UiDropdown/UiDropdownTrigger.vue.d.ts +21 -5
- package/dist/types/src/components/UiDropdown/index.d.ts +1 -0
- package/dist/types/src/components/UiEmojiPickerList/UiEmojiPickerList.vue.d.ts +22 -0
- package/dist/types/src/components/UiEmptyState/UiEmptyState.vue.d.ts +8 -3
- package/dist/types/src/components/UiFieldWrapper/UiFieldWrapper.vue.d.ts +2 -2
- package/dist/types/src/components/UiInputCheckbox/CheckboxGlyph.vue.d.ts +17 -0
- package/dist/types/src/components/UiInputCheckbox/UiInputCheckbox.vue.d.ts +35 -4
- package/dist/types/src/components/UiInputRadio/RadioGlyph.vue.d.ts +19 -0
- package/dist/types/src/components/UiInputRadio/UiInputRadio.vue.d.ts +21 -8
- package/dist/types/src/components/UiInputRadio/UiInputRadioGroup.vue.d.ts +6 -1
- package/dist/types/src/components/UiInputRadio/types.d.ts +1 -1
- package/dist/types/src/components/UiInputSelect/UiInputSelect.vue.d.ts +5 -5
- package/dist/types/src/components/UiInputTextarea/UiInputTextarea.vue.d.ts +5 -5
- package/dist/types/src/components/UiListItem/UiListItem.vue.d.ts +18 -4
- package/dist/types/src/components/UiLoader/UiSpinnerIcon.vue.d.ts +3 -0
- package/dist/types/src/components/UiMenu/UiMenuContent.vue.d.ts +15 -2
- package/dist/types/src/components/UiMenu/UiMenuItem.vue.d.ts +9 -3
- package/dist/types/src/components/UiNestedOptions/UiNestedOptions.vue.d.ts +13 -0
- package/dist/types/src/components/UiPage/UiPage.vue.d.ts +79 -15
- package/dist/types/src/components/UiPagination/UiPagination.vue.d.ts +36 -0
- package/dist/types/src/components/UiPagination/index.d.ts +2 -0
- package/dist/types/src/components/UiPagination/types.d.ts +4 -0
- package/dist/types/src/components/UiPane/UiPane.vue.d.ts +22 -0
- package/dist/types/src/components/UiPane/UiPaneContent.vue.d.ts +75 -0
- package/dist/types/src/components/UiPane/UiPaneTrigger.vue.d.ts +14 -0
- package/dist/types/src/components/UiPane/index.d.ts +5 -0
- package/dist/types/src/components/UiRating/UiRating.vue.d.ts +62 -0
- package/dist/types/src/components/UiRating/types.d.ts +1 -0
- package/dist/types/src/components/UiRoomButton/UiRoomButton.vue.d.ts +5 -3
- package/dist/types/src/components/UiRoomCountdown/UiRoomCountdown.vue.d.ts +32 -0
- package/dist/types/src/components/UiShell/UiShell.vue.d.ts +3 -0
- package/dist/types/src/components/UiSideMenu/UiSideMenu.vue.d.ts +22 -1
- package/dist/types/src/components/UiSideMenu/UiSideMenuItemContent.vue.d.ts +2 -2
- package/dist/types/src/components/UiSwitch/UiSwitch.vue.d.ts +10 -5
- package/dist/types/src/components/UiTable/UiTable.vue.d.ts +13 -4
- package/dist/types/src/components/UiTable/UiTableActionsCell.vue.d.ts +49 -0
- package/dist/types/src/components/UiTable/UiTableActionsHeaderCell.vue.d.ts +3 -0
- package/dist/types/src/components/UiTable/UiTableBody.vue.d.ts +11 -1
- package/dist/types/src/components/UiTable/UiTableCell.vue.d.ts +16 -1
- package/dist/types/src/components/UiTable/UiTableHeaderCell.vue.d.ts +31 -2
- package/dist/types/src/components/UiTable/UiTableRow.vue.d.ts +32 -2
- package/dist/types/src/components/UiTable/context.d.ts +3 -0
- package/dist/types/src/components/UiTable/index.d.ts +4 -0
- package/dist/types/src/components/UiTabs/UiTabs.vue.d.ts +3 -0
- package/dist/types/src/components/UiTag/UiTag.types.d.ts +25 -0
- package/dist/types/src/components/UiTag/UiTag.vue.d.ts +5 -26
- package/dist/types/src/components/UiTag/index.d.ts +2 -1
- package/dist/types/src/components/UiTextField/UiTextField.vue.d.ts +10 -5
- package/dist/types/src/components/UiTooltip/UiTooltipProvider.vue.d.ts +1 -0
- package/dist/types/src/components/UiTooltip/UiTooltipTrigger.vue.d.ts +2 -2
- package/dist/types/src/composables/storedThemingApplies.d.ts +17 -0
- package/dist/types/src/composables/useButtonStyles.d.ts +1 -0
- package/dist/types/src/composables/useChoiceboxSurface.d.ts +11 -0
- package/dist/types/src/composables/useContentMode.d.ts +7 -9
- package/dist/types/src/composables/useControlModes.d.ts +7 -0
- package/dist/types/src/composables/useControlShape.d.ts +24 -0
- package/dist/types/src/composables/useFieldFocusEvents.d.ts +12 -0
- package/dist/types/src/composables/useIconSize.d.ts +2 -0
- package/dist/types/src/composables/usePullGesture.d.ts +42 -0
- package/dist/types/src/composables/useThemeAndModes.d.ts +4 -0
- package/dist/types/src/theming/colorScale.d.ts +165 -0
- package/dist/types/src/theming/legacyColorScale.d.ts +27 -0
- package/dist/types/src/theming/presetColors.d.ts +11 -0
- package/dist/types/src/theming/primitiveTokens.d.ts +2 -0
- package/dist/types/src/utils/effectiveOpacity.d.ts +2 -0
- package/dist/types/src/utils/numbers.d.ts +1 -2
- package/dist/types/src/utils/tokenColor.d.ts +2 -0
- package/dist/ui-vue.css +2 -1
- package/dist/utils.mjs +165 -194
- package/index.d.ts +18 -0
- package/index.js +36 -0
- package/package.json +26 -21
- package/src/components/Toast/LayoutToasts.vue +19 -11
- package/src/components/Toast/ToastMessage.vue +125 -68
- package/src/components/Toast/toastDSV2.ts +238 -67
- package/src/components/UiActionBar/UiActionBar.vue +4 -3
- package/src/components/UiActionBar/UiActionBarItem.vue +9 -6
- package/src/components/UiActionBar/types.ts +13 -0
- package/src/components/UiAvatar/UiAvatar.vue +8 -2
- package/src/components/UiAvatarList/UiAvatarList.vue +51 -20
- package/src/components/UiBadge/UiBadge.vue +1 -1
- package/src/components/UiBanner/UiBanner.vue +71 -21
- package/src/components/UiBreadcrumb/UiBreadcrumb.vue +1 -1
- package/src/components/UiButton/UiButton.vue +92 -25
- package/src/components/UiButtonGroup/UiButtonGroup.vue +21 -17
- package/src/components/UiButtonGroup/UiButtonGroupItem.vue +33 -15
- package/src/components/UiButtonGroup/types.ts +19 -0
- package/src/components/UiCard/UiCard.vue +20 -23
- package/src/components/UiChoice/UiChoice.vue +187 -0
- package/src/components/UiChoice/index.ts +2 -0
- package/src/components/UiChoice/types.ts +11 -0
- package/src/components/UiColorField/UiColorField.vue +2 -2
- package/src/components/UiColorPicker/UiColorPicker.vue +11 -8
- package/src/components/UiCombobox/UiCombobox.types.ts +52 -0
- package/src/components/UiCombobox/UiCombobox.vue +296 -0
- package/src/components/UiCombobox/index.ts +2 -0
- package/src/components/UiDataTable/UiDataTable.types.ts +47 -0
- package/src/components/UiDataTable/UiDataTable.vue +422 -0
- package/src/components/UiDataTable/index.ts +12 -0
- package/src/components/UiDialog/UiDialogContent.vue +22 -7
- package/src/components/UiDrawer/UiDrawer.vue +16 -0
- package/src/components/UiDrawer/UiDrawerContent.vue +42 -0
- package/src/components/UiDrawer/UiDrawerTrigger.vue +17 -0
- package/src/components/UiDropdown/DropdownItemCheckbox.vue +10 -0
- package/src/components/UiDropdown/UiDropdownContent.vue +32 -21
- package/src/components/UiDropdown/UiDropdownGroup.vue +23 -0
- package/src/components/UiDropdown/UiDropdownItem.vue +38 -18
- package/src/components/UiDropdown/UiDropdownSeparator.vue +1 -1
- package/src/components/UiDropdown/UiDropdownTrigger.vue +138 -43
- package/src/components/UiDropdown/index.ts +1 -0
- package/src/components/UiEmojiPickerList/UiEmojiPickerList.vue +122 -0
- package/src/components/UiEmptyState/UiEmptyState.vue +16 -4
- package/src/components/UiFieldWrapper/UiFieldWrapper.vue +9 -3
- package/src/components/UiHorizontalSeparator/UiHorizontalSeparator.vue +2 -2
- package/src/components/UiInputCheckbox/CheckboxGlyph.vue +78 -0
- package/src/components/UiInputCheckbox/UiInputCheckbox.vue +213 -177
- package/src/components/UiInputEmoji/UiInputEmoji.vue +18 -95
- package/src/components/UiInputRadio/RadioGlyph.vue +45 -0
- package/src/components/UiInputRadio/UiInputRadio.vue +177 -169
- package/src/components/UiInputRadio/UiInputRadioGroup.vue +15 -5
- package/src/components/UiInputRadio/types.ts +1 -2
- package/src/components/UiInputSelect/UiInputSelect.vue +9 -7
- package/src/components/UiInputTextarea/UiInputTextarea.vue +20 -35
- package/src/components/UiLabel/UiLabel.vue +1 -1
- package/src/components/UiListItem/UiListItem.vue +55 -9
- package/src/components/UiLoader/UiLoader.vue +4 -20
- package/src/components/UiLoader/UiSpinnerIcon.vue +21 -0
- package/src/components/UiMenu/UiMenuContent.vue +24 -3
- package/src/components/UiMenu/UiMenuGroup.vue +1 -1
- package/src/components/UiMenu/UiMenuItem.vue +14 -3
- package/src/components/UiMenu/UiMenuSubContent.vue +1 -1
- package/src/components/UiMenu/UiMenuSubTrigger.vue +1 -1
- package/src/components/UiNestedOptions/UiNestedOptions.vue +6 -0
- package/src/components/UiPage/UiPage.vue +190 -32
- package/src/components/UiPagination/UiPagination.vue +99 -0
- package/src/components/UiPagination/index.ts +2 -0
- package/src/components/UiPagination/types.ts +28 -0
- package/src/components/UiPane/UiPane.vue +20 -0
- package/src/components/UiPane/UiPaneContent.vue +232 -0
- package/src/components/UiPane/UiPaneTrigger.vue +14 -0
- package/src/components/UiPane/index.ts +12 -0
- package/src/components/UiPopover/UiPopoverContent.vue +21 -1
- package/src/components/UiProgress/UiProgress.vue +2 -2
- package/src/components/UiRating/UiRating.vue +258 -0
- package/src/components/UiRating/types.ts +1 -0
- package/src/components/UiRoomButton/UiRoomButton.vue +10 -41
- package/src/components/UiRoomCountdown/UiRoomCountdown.vue +376 -0
- package/src/components/UiShell/UiShell.vue +9 -3
- package/src/components/UiSideMenu/UiSideMenu.vue +155 -18
- package/src/components/UiSideMenu/UiSideMenuItemContent.vue +20 -16
- package/src/components/UiStepper/UiStepper.vue +3 -16
- package/src/components/UiStepper/UiStepperDescription.vue +1 -13
- package/src/components/UiStepper/UiStepperIndicator.vue +11 -48
- package/src/components/UiStepper/UiStepperItem.vue +1 -8
- package/src/components/UiStepper/UiStepperSeparator.vue +5 -16
- package/src/components/UiStepper/UiStepperTitle.vue +1 -10
- package/src/components/UiSwitch/UiSwitch.vue +44 -28
- package/src/components/UiTable/UiTable.vue +98 -8
- package/src/components/UiTable/UiTableActionsCell.vue +135 -0
- package/src/components/UiTable/UiTableActionsHeaderCell.vue +19 -0
- package/src/components/UiTable/UiTableBody.vue +16 -1
- package/src/components/UiTable/UiTableCell.vue +33 -16
- package/src/components/UiTable/UiTableHeader.vue +6 -5
- package/src/components/UiTable/UiTableHeaderCell.vue +61 -9
- package/src/components/UiTable/UiTableRow.vue +46 -10
- package/src/components/UiTable/context.ts +5 -0
- package/src/components/UiTable/index.ts +4 -0
- package/src/components/UiTabs/UiTabs.vue +56 -61
- package/src/components/UiTag/UiTag.types.ts +28 -0
- package/src/components/UiTag/UiTag.vue +24 -42
- package/src/components/UiTag/index.ts +2 -0
- package/src/components/UiTextField/UiTextField.vue +21 -36
- package/src/components/UiTooltip/UiTooltipContent.vue +1 -1
- package/src/components/UiTooltip/UiTooltipProvider.vue +3 -0
- package/src/components/UiTooltip/UiTooltipTrigger.vue +16 -1
- package/src/composables/storedThemingApplies.ts +19 -0
- package/src/composables/useButtonStyles.ts +9 -13
- package/src/composables/useChoiceboxSurface.ts +36 -0
- package/src/composables/useContentMode.ts +29 -16
- package/src/composables/useControlModes.ts +11 -0
- package/src/composables/useControlShape.ts +34 -0
- package/src/composables/useFieldFocusEvents.ts +30 -0
- package/src/composables/useIconSize.ts +15 -0
- package/src/composables/usePullGesture.ts +142 -0
- package/src/composables/useThemeAndModes.ts +28 -1
- package/src/css/body.css +16 -1
- package/src/css/fonts.css +39 -5
- package/src/global.d.ts +36 -0
- package/src/theming/colorScale.ts +173 -0
- package/src/theming/legacyColorScale.ts +58 -0
- package/src/theming/presetColors.ts +33 -0
- package/src/theming/primitiveTokens.ts +71 -0
- package/src/utils/effectiveOpacity.ts +8 -0
- package/src/utils/i18n.ts +6 -0
- package/src/utils/numbers.ts +1 -1
- package/src/utils/responsive.d.ts +14 -0
- package/src/utils/tokenColor.ts +9 -0
- package/dist/UiTimelineItem.vue_vue_type_style_index_0_lang-LpdvGf5X.mjs +0 -6093
- package/dist/a11y-BhF_nl7L.mjs +0 -159
- package/dist/i18n-Cktw9hIu.mjs +0 -49
- package/dist/toastDSV2-wMh-UMzW.mjs +0 -74
- package/dist/types/src/components/UiAvatar/index.d.ts +0 -1
- package/dist/types/src/components/UiAvatarList/index.d.ts +0 -1
- package/dist/types/src/components/UiBadge/index.d.ts +0 -1
- package/dist/types/src/components/UiBanner/index.d.ts +0 -2
- package/dist/types/src/components/UiButtonGroup/index.d.ts +0 -3
- package/dist/types/src/components/UiCarousel/index.d.ts +0 -2
- package/dist/types/src/components/UiColorField/index.d.ts +0 -2
- package/dist/types/src/components/UiDialog/MarketplaceHeaderExample.vue.d.ts +0 -28
- package/dist/types/src/components/UiDialog/index.d.ts +0 -7
- package/dist/types/src/components/UiFieldWrapper/index.d.ts +0 -1
- package/dist/types/src/components/UiInputCheckbox/index.d.ts +0 -2
- package/dist/types/src/components/UiInputEmoji/index.d.ts +0 -1
- package/dist/types/src/components/UiInputRadio/index.d.ts +0 -3
- package/dist/types/src/components/UiInputSelect/index.d.ts +0 -2
- package/dist/types/src/components/UiInputTextarea/index.d.ts +0 -2
- package/dist/types/src/components/UiMenu/index.d.ts +0 -10
- package/dist/types/src/components/UiProgress/index.d.ts +0 -2
- package/dist/types/src/components/UiSwitch/index.d.ts +0 -2
- package/dist/types/src/components/UiTabs/index.d.ts +0 -2
- package/dist/types/src/components/UiTimeline/index.d.ts +0 -2
- package/dist/types/src/components/UiTooltip/index.d.ts +0 -4
- package/dist/types/src/mixins/DynamicAction.d.ts +0 -30
- package/dist/useThemeAndModes-BzYwSOEv.mjs +0 -108
- package/src/components/UiAvatar/index.js +0 -1
- package/src/components/UiAvatarList/index.js +0 -1
- package/src/components/UiBadge/index.ts +0 -2
- package/src/components/UiBanner/index.ts +0 -2
- package/src/components/UiButtonGroup/index.ts +0 -3
- package/src/components/UiCarousel/index.ts +0 -2
- package/src/components/UiColorField/index.ts +0 -2
- package/src/components/UiDialog/MarketplaceHeaderExample.vue +0 -217
- package/src/components/UiDialog/index.ts +0 -18
- package/src/components/UiFieldWrapper/index.ts +0 -1
- package/src/components/UiInputCheckbox/index.ts +0 -2
- package/src/components/UiInputEmoji/index.ts +0 -1
- package/src/components/UiInputRadio/index.ts +0 -3
- package/src/components/UiInputSelect/index.ts +0 -2
- package/src/components/UiInputTextarea/index.ts +0 -2
- package/src/components/UiMenu/index.ts +0 -10
- package/src/components/UiProgress/index.ts +0 -2
- package/src/components/UiSwitch/index.ts +0 -2
- package/src/components/UiTabs/index.ts +0 -5
- package/src/components/UiTag/index.js +0 -1
- package/src/components/UiTimeline/index.ts +0 -2
- package/src/components/UiTooltip/index.js +0 -4
- package/src/mixins/DynamicAction.js +0 -61
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
<script setup lang="ts" generic="TData extends Record<string, unknown>">
|
|
2
|
+
import type { ColumnDef, RowSelectionState, SortingState, Updater } from '@tanstack/vue-table'
|
|
3
|
+
import { rowSelectionFeature, rowSortingFeature, tableFeatures, useTable } from '@tanstack/vue-table'
|
|
4
|
+
import { useResizeObserver } from '@vueuse/core'
|
|
5
|
+
import { computed, ref, useSlots, useTemplateRef } from 'vue'
|
|
6
|
+
import type { RouteLocationRaw } from 'vue-router'
|
|
7
|
+
import {
|
|
8
|
+
UiTable,
|
|
9
|
+
UiTableHeader,
|
|
10
|
+
UiTableHeaderCell,
|
|
11
|
+
UiTableActionsHeaderCell,
|
|
12
|
+
UiTableBody,
|
|
13
|
+
UiTableRow,
|
|
14
|
+
UiTableCell,
|
|
15
|
+
UiTableActionsCell,
|
|
16
|
+
} from '../UiTable/index'
|
|
17
|
+
import UiInputCheckbox from '../UiInputCheckbox/UiInputCheckbox.vue'
|
|
18
|
+
import type { UiTableSize } from '../UiTable/context'
|
|
19
|
+
import { useTranslate } from '../../utils/i18n'
|
|
20
|
+
import type { UiDataTableColumn, UiDataTableSort } from './UiDataTable.types'
|
|
21
|
+
|
|
22
|
+
export interface UiDataTableProps<TData> {
|
|
23
|
+
/** Column definitions. Each column can be customized via `#cell-<id>` and `#header-<id>` slots. */
|
|
24
|
+
columns: UiDataTableColumn<TData>[]
|
|
25
|
+
/** Rows, already sorted/filtered by the consumer. */
|
|
26
|
+
data: TData[]
|
|
27
|
+
/**
|
|
28
|
+
* Row heights: `md` = 40px header / 48px rows, `lg` = 48px header / 64px rows.
|
|
29
|
+
* @default 'md'
|
|
30
|
+
*/
|
|
31
|
+
size?: UiTableSize
|
|
32
|
+
/**
|
|
33
|
+
* Alternating row backgrounds. Preferred over row dividers.
|
|
34
|
+
* @default true
|
|
35
|
+
*/
|
|
36
|
+
zebra?: boolean
|
|
37
|
+
/**
|
|
38
|
+
* Renders skeleton rows instead of data.
|
|
39
|
+
* @default false
|
|
40
|
+
*/
|
|
41
|
+
loading?: boolean
|
|
42
|
+
/**
|
|
43
|
+
* Number of skeleton rows while loading.
|
|
44
|
+
* @default 5
|
|
45
|
+
*/
|
|
46
|
+
skeletonRows?: number
|
|
47
|
+
/**
|
|
48
|
+
* Current sort, controlled by the consumer (`v-model:sorting`). The table
|
|
49
|
+
* only renders the affordance and emits; sorting the data stays consumer-side.
|
|
50
|
+
* @default null
|
|
51
|
+
*/
|
|
52
|
+
sorting?: UiDataTableSort | null
|
|
53
|
+
/**
|
|
54
|
+
* Makes rows interactive: hover feedback, keyboard focus and `row-click` emits.
|
|
55
|
+
* @default false
|
|
56
|
+
*/
|
|
57
|
+
rowClickable?: boolean
|
|
58
|
+
/**
|
|
59
|
+
* Turns each row into a link to the returned location. The first cell holds
|
|
60
|
+
* a router link stretched over the row, so Cmd/Ctrl click, middle click and
|
|
61
|
+
* keyboard focus behave like any link. The first column's content sits
|
|
62
|
+
* inside the link, so it must hold no interactive content. Content of other
|
|
63
|
+
* cells that must stay interactive above the link (tooltips, buttons) needs
|
|
64
|
+
* `relative z-10`; the selection checkbox and `#actions` already sit above
|
|
65
|
+
* it. Takes precedence over `rowClickable`.
|
|
66
|
+
*/
|
|
67
|
+
rowLink?: (row: TData) => RouteLocationRaw
|
|
68
|
+
/**
|
|
69
|
+
* Adds a leftmost checkbox column with a select-all header. Selection is
|
|
70
|
+
* controlled through `v-model:selectedRowIds`; pass `getRowId` so ids stay
|
|
71
|
+
* stable across data changes.
|
|
72
|
+
* @default false
|
|
73
|
+
*/
|
|
74
|
+
selectable?: boolean
|
|
75
|
+
/**
|
|
76
|
+
* Selected row ids, controlled by the consumer (`v-model:selectedRowIds`).
|
|
77
|
+
* @default []
|
|
78
|
+
*/
|
|
79
|
+
selectedRowIds?: string[]
|
|
80
|
+
/**
|
|
81
|
+
* How the `#actions` slot attaches to the row. `default` reveals it on
|
|
82
|
+
* hover, masking the cells behind bare action buttons; `floating` also
|
|
83
|
+
* reveals on hover but drops that backdrop for self-contained content
|
|
84
|
+
* like a UiActionBar; `menu` tucks it behind an always-visible trigger
|
|
85
|
+
* button that opens a popover on click.
|
|
86
|
+
* @default 'default'
|
|
87
|
+
*/
|
|
88
|
+
actionsVariant?: 'default' | 'floating' | 'menu'
|
|
89
|
+
/**
|
|
90
|
+
* Whether a row has trailing actions. Rows that return false get an empty
|
|
91
|
+
* actions cell, so nothing reveals over them on hover. All rows have
|
|
92
|
+
* actions when omitted.
|
|
93
|
+
*/
|
|
94
|
+
rowHasActions?: (row: TData) => boolean
|
|
95
|
+
/**
|
|
96
|
+
* Id of the row whose hover actions stay shown without hover or focus,
|
|
97
|
+
* e.g. while a menu opened from them is open. Matches `getRowId`.
|
|
98
|
+
* @default null
|
|
99
|
+
*/
|
|
100
|
+
revealedActionsRowId?: string | null
|
|
101
|
+
/** Stable row identity; falls back to the row index. */
|
|
102
|
+
getRowId?: (row: TData, index: number) => string
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const props = withDefaults(defineProps<UiDataTableProps<TData>>(), {
|
|
106
|
+
size: 'md',
|
|
107
|
+
zebra: true,
|
|
108
|
+
loading: false,
|
|
109
|
+
skeletonRows: 5,
|
|
110
|
+
sorting: null,
|
|
111
|
+
rowClickable: false,
|
|
112
|
+
rowLink: undefined,
|
|
113
|
+
selectable: false,
|
|
114
|
+
selectedRowIds: () => [],
|
|
115
|
+
actionsVariant: 'default',
|
|
116
|
+
rowHasActions: undefined,
|
|
117
|
+
revealedActionsRowId: null,
|
|
118
|
+
getRowId: undefined,
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
const emit = defineEmits<{
|
|
122
|
+
'update:sorting': [sort: UiDataTableSort | null]
|
|
123
|
+
'update:selectedRowIds': [ids: string[]]
|
|
124
|
+
'rowClick': [row: TData]
|
|
125
|
+
}>()
|
|
126
|
+
|
|
127
|
+
const translate = useTranslate()
|
|
128
|
+
|
|
129
|
+
defineSlots<
|
|
130
|
+
{
|
|
131
|
+
/** Trailing row actions, revealed on row hover/focus. */
|
|
132
|
+
actions?: (props: { row: TData }) => unknown
|
|
133
|
+
/**
|
|
134
|
+
* Rows after the data rows, in a second body of the same table, e.g. a
|
|
135
|
+
* teaser for rows the plan hides. They share the column grid and the
|
|
136
|
+
* zebra of the data rows. Render a `UiTableCell` per column, after an
|
|
137
|
+
* empty one when `selectable`, and end each row with an empty
|
|
138
|
+
* `UiTableActionsCell` when `hasActions`. The body is positioned, so an
|
|
139
|
+
* overlay over these rows can sit in a `UiTableRow` with `zebra` off.
|
|
140
|
+
*/
|
|
141
|
+
'body-end'?: (props: {
|
|
142
|
+
columns: UiDataTableColumn<TData>[]
|
|
143
|
+
selectable: boolean
|
|
144
|
+
hasActions: boolean
|
|
145
|
+
actionsVariant: 'default' | 'floating' | 'menu'
|
|
146
|
+
}) => unknown
|
|
147
|
+
}
|
|
148
|
+
& Partial<Record<`cell-${string}`, (props: { row: TData, value: unknown }) => unknown>>
|
|
149
|
+
& Partial<Record<`header-${string}`, (props: { column: UiDataTableColumn<TData> }) => unknown>>
|
|
150
|
+
>()
|
|
151
|
+
|
|
152
|
+
const slots = useSlots()
|
|
153
|
+
const hasActions = computed(() => !!slots.actions)
|
|
154
|
+
|
|
155
|
+
const features = tableFeatures({ rowSortingFeature, rowSelectionFeature })
|
|
156
|
+
|
|
157
|
+
const tanstackColumns = computed(() => props.columns.map(column => ({
|
|
158
|
+
id: column.id,
|
|
159
|
+
header: column.header,
|
|
160
|
+
...(column.accessorKey ? { accessorKey: column.accessorKey } : {}),
|
|
161
|
+
enableSorting: column.sortable ?? false,
|
|
162
|
+
}) as ColumnDef<typeof features, TData>))
|
|
163
|
+
|
|
164
|
+
const sortingState = computed<SortingState>(() => (
|
|
165
|
+
props.sorting
|
|
166
|
+
? [{ id: props.sorting.id, desc: props.sorting.direction === 'desc' }]
|
|
167
|
+
: []
|
|
168
|
+
))
|
|
169
|
+
|
|
170
|
+
function toSort (state: SortingState): UiDataTableSort | null {
|
|
171
|
+
const [first] = state
|
|
172
|
+
if (!first) return null
|
|
173
|
+
return { id: first.id, direction: first.desc ? 'desc' : 'asc' }
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const rowSelectionState = computed<RowSelectionState>(() => (
|
|
177
|
+
Object.fromEntries(props.selectedRowIds.map(id => [id, true as const]))
|
|
178
|
+
))
|
|
179
|
+
|
|
180
|
+
const table = useTable<typeof features, TData>({
|
|
181
|
+
features,
|
|
182
|
+
columns: tanstackColumns,
|
|
183
|
+
data: computed(() => props.data),
|
|
184
|
+
...(props.getRowId ? { getRowId: props.getRowId } : {}),
|
|
185
|
+
manualSorting: true,
|
|
186
|
+
enableMultiSort: false,
|
|
187
|
+
enableSortingRemoval: false,
|
|
188
|
+
enableRowSelection: computed(() => props.selectable),
|
|
189
|
+
state: computed(() => ({ sorting: sortingState.value, rowSelection: rowSelectionState.value })),
|
|
190
|
+
onSortingChange: (updater: Updater<SortingState>) => {
|
|
191
|
+
const next = typeof updater === 'function' ? updater(sortingState.value) : updater
|
|
192
|
+
emit('update:sorting', toSort(next))
|
|
193
|
+
},
|
|
194
|
+
onRowSelectionChange: (updater: Updater<RowSelectionState>) => {
|
|
195
|
+
const next = typeof updater === 'function' ? updater(rowSelectionState.value) : updater
|
|
196
|
+
emit('update:selectedRowIds', Object.keys(next))
|
|
197
|
+
},
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
// Escape hatch: the underlying TanStack table instance, e.g.
|
|
201
|
+
// `tableRef.value?.table.setSorting(...)`.
|
|
202
|
+
defineExpose({ table })
|
|
203
|
+
|
|
204
|
+
function sortDirectionFor (columnId: string) {
|
|
205
|
+
if (props.sorting?.id !== columnId) return 'none'
|
|
206
|
+
return props.sorting.direction
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function onHeaderSort (column: UiDataTableColumn<TData>) {
|
|
210
|
+
const direction = sortDirectionFor(column.id) === 'asc' ? 'desc' : 'asc'
|
|
211
|
+
emit('update:sorting', { id: column.id, direction })
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const columnById = computed(() => new Map(props.columns.map(column => [column.id, column])))
|
|
215
|
+
|
|
216
|
+
function headerStyle (columnId: string) {
|
|
217
|
+
const column = columnById.value.get(columnId)
|
|
218
|
+
return { width: column?.width, minWidth: column?.minWidth }
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function cellStyle (columnId: string) {
|
|
222
|
+
return { minWidth: columnById.value.get(columnId)?.minWidth }
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function wrapClass (columnId: string) {
|
|
226
|
+
return columnById.value.get(columnId)?.nowrap ? 'whitespace-nowrap' : undefined
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function isEmptyValue (value: unknown) {
|
|
230
|
+
return value === null || value === undefined || value === ''
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function isEmptyCell (columnId: string, value: unknown) {
|
|
234
|
+
return !slots[`cell-${columnId}`] && isEmptyValue(value)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function isLinkCell (cellIndex: number) {
|
|
238
|
+
return !!props.rowLink && cellIndex === 0
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const renderedRowCount = computed(() => (props.loading ? props.skeletonRows : table.getRowModel().rows.length))
|
|
242
|
+
|
|
243
|
+
// A scroll container captures the sticky header, so the region only scrolls once the columns overflow it
|
|
244
|
+
const region = useTemplateRef<HTMLElement>('region')
|
|
245
|
+
const columnsOverflow = ref(true)
|
|
246
|
+
|
|
247
|
+
const regionTable = computed(() => region.value?.firstElementChild as HTMLElement | null | undefined)
|
|
248
|
+
|
|
249
|
+
useResizeObserver(() => [region.value, regionTable.value], () => {
|
|
250
|
+
const element = region.value
|
|
251
|
+
const table = regionTable.value
|
|
252
|
+
if (!element || !table) return
|
|
253
|
+
const { paddingLeft, paddingRight } = getComputedStyle(element)
|
|
254
|
+
columnsOverflow.value = table.offsetWidth > element.clientWidth - parseFloat(paddingLeft) - parseFloat(paddingRight)
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
const regionClasses = computed(() => columnsOverflow.value && 'overflow-x-auto')
|
|
258
|
+
|
|
259
|
+
// A row link stretches over the row, so the selection cell rises above it to stay clickable
|
|
260
|
+
const selectionCellClasses = computed(() => props.rowLink && 'relative z-10')
|
|
261
|
+
</script>
|
|
262
|
+
|
|
263
|
+
<template>
|
|
264
|
+
<div
|
|
265
|
+
ref="region"
|
|
266
|
+
class="px-(--ui-page-inline,0px)"
|
|
267
|
+
:class="regionClasses"
|
|
268
|
+
data-testid="ui-data-table-region"
|
|
269
|
+
>
|
|
270
|
+
<UiTable
|
|
271
|
+
:size="size"
|
|
272
|
+
:zebra="zebra"
|
|
273
|
+
>
|
|
274
|
+
<UiTableHeader>
|
|
275
|
+
<tr
|
|
276
|
+
v-for="headerGroup in table.getHeaderGroups()"
|
|
277
|
+
:key="headerGroup.id"
|
|
278
|
+
>
|
|
279
|
+
<UiTableHeaderCell
|
|
280
|
+
v-if="selectable"
|
|
281
|
+
class="w-0"
|
|
282
|
+
>
|
|
283
|
+
<UiInputCheckbox
|
|
284
|
+
:checked="table.getIsAllRowsSelected()"
|
|
285
|
+
:indeterminate="table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()"
|
|
286
|
+
:aria-label="translate('general_form_multiselect-select-all')"
|
|
287
|
+
@change="table.toggleAllRowsSelected()"
|
|
288
|
+
/>
|
|
289
|
+
</UiTableHeaderCell>
|
|
290
|
+
<UiTableHeaderCell
|
|
291
|
+
v-for="header in headerGroup.headers"
|
|
292
|
+
:key="header.id"
|
|
293
|
+
:sortable="columnById.get(header.column.id)?.sortable ?? false"
|
|
294
|
+
:sort-direction="sortDirectionFor(header.column.id)"
|
|
295
|
+
:align="columnById.get(header.column.id)?.align ?? 'left'"
|
|
296
|
+
:class="wrapClass(header.column.id)"
|
|
297
|
+
:style="headerStyle(header.column.id)"
|
|
298
|
+
@sort="onHeaderSort(columnById.get(header.column.id)!)"
|
|
299
|
+
>
|
|
300
|
+
<slot
|
|
301
|
+
:name="`header-${header.column.id}`"
|
|
302
|
+
:column="columnById.get(header.column.id)!"
|
|
303
|
+
>
|
|
304
|
+
{{ columnById.get(header.column.id)?.header }}
|
|
305
|
+
</slot>
|
|
306
|
+
</UiTableHeaderCell>
|
|
307
|
+
<UiTableActionsHeaderCell v-if="hasActions" />
|
|
308
|
+
</tr>
|
|
309
|
+
</UiTableHeader>
|
|
310
|
+
<UiTableBody>
|
|
311
|
+
<template v-if="loading">
|
|
312
|
+
<UiTableRow
|
|
313
|
+
v-for="index in skeletonRows"
|
|
314
|
+
:key="`skeleton-${index}`"
|
|
315
|
+
>
|
|
316
|
+
<UiTableCell v-if="selectable" />
|
|
317
|
+
<UiTableCell
|
|
318
|
+
v-for="column in columns"
|
|
319
|
+
:key="column.id"
|
|
320
|
+
:align="column.align ?? 'left'"
|
|
321
|
+
>
|
|
322
|
+
<div
|
|
323
|
+
class="h-4 animate-pulse rounded-sm bg-surface-neutral-alpha-200"
|
|
324
|
+
:class="index % 2 === 0 ? 'w-1/2' : 'w-2/3'"
|
|
325
|
+
/>
|
|
326
|
+
</UiTableCell>
|
|
327
|
+
<UiTableActionsCell v-if="hasActions" />
|
|
328
|
+
</UiTableRow>
|
|
329
|
+
</template>
|
|
330
|
+
<template v-else>
|
|
331
|
+
<UiTableRow
|
|
332
|
+
v-for="row in table.getRowModel().rows"
|
|
333
|
+
:key="row.id"
|
|
334
|
+
:clickable="rowClickable && !rowLink"
|
|
335
|
+
:linked="!!rowLink"
|
|
336
|
+
:selected="selectable && row.getIsSelected()"
|
|
337
|
+
@click="emit('rowClick', row.original)"
|
|
338
|
+
>
|
|
339
|
+
<UiTableCell
|
|
340
|
+
v-if="selectable"
|
|
341
|
+
:class="selectionCellClasses"
|
|
342
|
+
@click.stop
|
|
343
|
+
>
|
|
344
|
+
<UiInputCheckbox
|
|
345
|
+
:checked="row.getIsSelected()"
|
|
346
|
+
:aria-label="translate('general_table_select-row')"
|
|
347
|
+
@change="row.toggleSelected()"
|
|
348
|
+
/>
|
|
349
|
+
</UiTableCell>
|
|
350
|
+
<UiTableCell
|
|
351
|
+
v-for="(cell, cellIndex) in row.getAllCells()"
|
|
352
|
+
:key="cell.id"
|
|
353
|
+
:align="columnById.get(cell.column.id)?.align ?? 'left'"
|
|
354
|
+
:empty="!isLinkCell(cellIndex) && isEmptyCell(cell.column.id, cell.getValue())"
|
|
355
|
+
:class="wrapClass(cell.column.id)"
|
|
356
|
+
:style="cellStyle(cell.column.id)"
|
|
357
|
+
>
|
|
358
|
+
<component
|
|
359
|
+
:is="'router-link'"
|
|
360
|
+
v-if="isLinkCell(cellIndex)"
|
|
361
|
+
:to="rowLink!(row.original)"
|
|
362
|
+
class="block min-w-0 text-inherit no-underline focus-indicator-none after:absolute after:inset-0 after:rounded-table-row focus-visible:after:focus-ring"
|
|
363
|
+
data-testid="ui-data-table-row-link"
|
|
364
|
+
>
|
|
365
|
+
<slot
|
|
366
|
+
:name="`cell-${cell.column.id}`"
|
|
367
|
+
:row="row.original"
|
|
368
|
+
:value="cell.getValue()"
|
|
369
|
+
>
|
|
370
|
+
<span
|
|
371
|
+
v-if="isEmptyValue(cell.getValue())"
|
|
372
|
+
class="text-text-neutral-secondary"
|
|
373
|
+
>–</span>
|
|
374
|
+
<template v-else>
|
|
375
|
+
{{ cell.getValue() }}
|
|
376
|
+
</template>
|
|
377
|
+
</slot>
|
|
378
|
+
</component>
|
|
379
|
+
<slot
|
|
380
|
+
v-else
|
|
381
|
+
:name="`cell-${cell.column.id}`"
|
|
382
|
+
:row="row.original"
|
|
383
|
+
:value="cell.getValue()"
|
|
384
|
+
>
|
|
385
|
+
{{ cell.getValue() }}
|
|
386
|
+
</slot>
|
|
387
|
+
</UiTableCell>
|
|
388
|
+
<template v-if="hasActions">
|
|
389
|
+
<UiTableActionsCell
|
|
390
|
+
v-if="!rowHasActions || rowHasActions(row.original)"
|
|
391
|
+
:variant="actionsVariant"
|
|
392
|
+
:revealed="row.id === revealedActionsRowId"
|
|
393
|
+
>
|
|
394
|
+
<slot
|
|
395
|
+
name="actions"
|
|
396
|
+
:row="row.original"
|
|
397
|
+
/>
|
|
398
|
+
</UiTableActionsCell>
|
|
399
|
+
<UiTableActionsCell
|
|
400
|
+
v-else
|
|
401
|
+
:variant="actionsVariant"
|
|
402
|
+
/>
|
|
403
|
+
</template>
|
|
404
|
+
</UiTableRow>
|
|
405
|
+
</template>
|
|
406
|
+
</UiTableBody>
|
|
407
|
+
<UiTableBody
|
|
408
|
+
v-if="slots['body-end']"
|
|
409
|
+
class="relative"
|
|
410
|
+
:zebra-offset="renderedRowCount % 2 === 1"
|
|
411
|
+
>
|
|
412
|
+
<slot
|
|
413
|
+
name="body-end"
|
|
414
|
+
:columns="columns"
|
|
415
|
+
:selectable="selectable"
|
|
416
|
+
:has-actions="hasActions"
|
|
417
|
+
:actions-variant="actionsVariant"
|
|
418
|
+
/>
|
|
419
|
+
</UiTableBody>
|
|
420
|
+
</UiTable>
|
|
421
|
+
</div>
|
|
422
|
+
</template>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { default as UiDataTable } from './UiDataTable.vue'
|
|
2
|
+
export type { UiDataTableProps } from './UiDataTable.vue'
|
|
3
|
+
export type { UiDataTableColumn, UiDataTableSort } from './UiDataTable.types'
|
|
4
|
+
|
|
5
|
+
// Escape hatch for tables that outgrow UiDataTable: compose the UiTable
|
|
6
|
+
// primitives with TanStack Table directly.
|
|
7
|
+
export {
|
|
8
|
+
FlexRender,
|
|
9
|
+
tableFeatures,
|
|
10
|
+
useTable,
|
|
11
|
+
} from '@tanstack/vue-table'
|
|
12
|
+
export type { ColumnDef, SortingState } from '@tanstack/vue-table'
|
|
@@ -110,12 +110,12 @@ useMutationObserver(contentRef, () => {
|
|
|
110
110
|
<DialogPortal>
|
|
111
111
|
<DialogOverlay
|
|
112
112
|
:class="[
|
|
113
|
-
'fixed inset-0 bg-surface-overlay-alpha z-
|
|
113
|
+
'fixed inset-0 bg-surface-overlay-alpha z-overlay',
|
|
114
114
|
'ui-dialog-overlay',
|
|
115
115
|
overlayClass,
|
|
116
116
|
]"
|
|
117
117
|
/>
|
|
118
|
-
<div class="fixed inset-0 z-
|
|
118
|
+
<div class="fixed inset-0 z-overlay flex items-center justify-center pointer-events-none">
|
|
119
119
|
<DialogContent
|
|
120
120
|
v-bind="{ ...forwarded, ...$attrs }"
|
|
121
121
|
:class="[
|
|
@@ -124,7 +124,7 @@ useMutationObserver(contentRef, () => {
|
|
|
124
124
|
'w-[95vw] max-h-[85vh]',
|
|
125
125
|
widthClass,
|
|
126
126
|
'overflow-hidden flex flex-col',
|
|
127
|
-
'ui-dialog-content
|
|
127
|
+
'ui-dialog-content',
|
|
128
128
|
'focus:outline-hidden focus-indicator-none',
|
|
129
129
|
'm-2',
|
|
130
130
|
!noPadding && 'py-6'
|
|
@@ -205,7 +205,7 @@ useMutationObserver(contentRef, () => {
|
|
|
205
205
|
v-if="$slots.footer"
|
|
206
206
|
:class="[
|
|
207
207
|
!noPadding && 'px-6 pt-6',
|
|
208
|
-
hasScroll && 'border-t border-
|
|
208
|
+
hasScroll && 'border-t border-divider',
|
|
209
209
|
]"
|
|
210
210
|
>
|
|
211
211
|
<slot name="footer" />
|
|
@@ -235,12 +235,27 @@ useMutationObserver(contentRef, () => {
|
|
|
235
235
|
animation: fade-out 150ms ease-in;
|
|
236
236
|
}
|
|
237
237
|
|
|
238
|
-
/* Content animations
|
|
238
|
+
/* Content animations — the panel carries its own keyframes rather than the
|
|
239
|
+
shared reka-animations.css ones: a consumer that does not load that
|
|
240
|
+
stylesheet would otherwise leave reka waiting for an `animationend` that
|
|
241
|
+
never fires, and the panel would never unmount on close. In and out need
|
|
242
|
+
distinct names for the same reason — a same-name animation never restarts,
|
|
243
|
+
so no end event would ever come. */
|
|
244
|
+
@keyframes fade-scale-in {
|
|
245
|
+
from { opacity: 0; transform: scale(0.95); }
|
|
246
|
+
to { opacity: 1; transform: scale(1); }
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
@keyframes fade-scale-out {
|
|
250
|
+
from { opacity: 1; transform: scale(1); }
|
|
251
|
+
to { opacity: 0; transform: scale(0.95); }
|
|
252
|
+
}
|
|
253
|
+
|
|
239
254
|
.ui-dialog-content[data-state='open'] {
|
|
240
|
-
animation: fade-scale 200ms ease-out;
|
|
255
|
+
animation: fade-scale-in 200ms ease-out both;
|
|
241
256
|
}
|
|
242
257
|
|
|
243
258
|
.ui-dialog-content[data-state='closed'] {
|
|
244
|
-
animation: fade-scale 150ms ease-in
|
|
259
|
+
animation: fade-scale-out 150ms ease-in both;
|
|
245
260
|
}
|
|
246
261
|
</style>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { DrawerRootEmits, DrawerRootProps } from 'vaul-vue'
|
|
3
|
+
import { DrawerRoot } from 'vaul-vue'
|
|
4
|
+
import { useForwardPropsEmits } from 'reka-ui'
|
|
5
|
+
|
|
6
|
+
const props = defineProps<DrawerRootProps>()
|
|
7
|
+
const emits = defineEmits<DrawerRootEmits>()
|
|
8
|
+
|
|
9
|
+
const forwarded = useForwardPropsEmits(props, emits)
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<template>
|
|
13
|
+
<DrawerRoot v-bind="{ ...forwarded, ...$attrs }">
|
|
14
|
+
<slot />
|
|
15
|
+
</DrawerRoot>
|
|
16
|
+
</template>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { DrawerContent, DrawerHandle, DrawerOverlay, DrawerPortal, DrawerTitle } from 'vaul-vue'
|
|
3
|
+
import { VisuallyHidden } from 'reka-ui'
|
|
4
|
+
import { useTranslate } from '../../utils/i18n'
|
|
5
|
+
|
|
6
|
+
interface UiDrawerContentProps {
|
|
7
|
+
title?: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const props = withDefaults(defineProps<UiDrawerContentProps>(), {
|
|
11
|
+
title: undefined,
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
const translate = useTranslate()
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<template>
|
|
18
|
+
<DrawerPortal>
|
|
19
|
+
<DrawerOverlay class="fixed inset-0 z-overlay bg-surface-overlay-alpha" />
|
|
20
|
+
|
|
21
|
+
<DrawerContent
|
|
22
|
+
v-bind="$attrs"
|
|
23
|
+
class="fixed inset-x-0 bottom-0 z-overlay flex max-h-[85vh] flex-col rounded-t-2xl border-t border-divider bg-surface-neutral-bg-main shadow-shadows-drop-shadow-2xl focus:outline-hidden focus-indicator-none"
|
|
24
|
+
>
|
|
25
|
+
<VisuallyHidden as-child>
|
|
26
|
+
<DrawerTitle>{{ props.title ?? translate('general_dialog_title') }}</DrawerTitle>
|
|
27
|
+
</VisuallyHidden>
|
|
28
|
+
|
|
29
|
+
<DrawerHandle class="mt-2 bg-borders-neutral-default!" />
|
|
30
|
+
|
|
31
|
+
<div class="ui-drawer-content-body min-h-0 flex-1 overflow-y-auto">
|
|
32
|
+
<slot />
|
|
33
|
+
</div>
|
|
34
|
+
</DrawerContent>
|
|
35
|
+
</DrawerPortal>
|
|
36
|
+
</template>
|
|
37
|
+
|
|
38
|
+
<style scoped>
|
|
39
|
+
.ui-drawer-content-body {
|
|
40
|
+
padding-bottom: env(safe-area-inset-bottom);
|
|
41
|
+
}
|
|
42
|
+
</style>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { DrawerTriggerProps } from 'vaul-vue'
|
|
3
|
+
import { DrawerTrigger } from 'vaul-vue'
|
|
4
|
+
import { useForwardProps } from 'reka-ui'
|
|
5
|
+
|
|
6
|
+
const props = defineProps<DrawerTriggerProps>()
|
|
7
|
+
|
|
8
|
+
const forwarded = useForwardProps(props)
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<template>
|
|
12
|
+
<DrawerTrigger
|
|
13
|
+
v-bind="{ ...forwarded, ...$attrs }"
|
|
14
|
+
>
|
|
15
|
+
<slot />
|
|
16
|
+
</DrawerTrigger>
|
|
17
|
+
</template>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { injectSelectItemContext } from 'reka-ui'
|
|
3
|
+
import CheckboxGlyph from '../UiInputCheckbox/CheckboxGlyph.vue'
|
|
4
|
+
|
|
5
|
+
const item = injectSelectItemContext()
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<template>
|
|
9
|
+
<CheckboxGlyph :checked="item.isSelected.value" />
|
|
10
|
+
</template>
|
|
@@ -3,8 +3,18 @@ import type { SelectContentProps } from 'reka-ui'
|
|
|
3
3
|
import { SelectContent, SelectPortal, SelectScrollDownButton, SelectScrollUpButton, SelectViewport } from 'reka-ui'
|
|
4
4
|
import { useSlots } from 'vue'
|
|
5
5
|
|
|
6
|
+
const WIDTH_CLASSES = {
|
|
7
|
+
auto: '',
|
|
8
|
+
lg: 'w-75',
|
|
9
|
+
} as const
|
|
10
|
+
|
|
6
11
|
interface Props extends SelectContentProps {
|
|
7
12
|
showScrollButtons?: boolean
|
|
13
|
+
/**
|
|
14
|
+
* 'auto' sizes the content to the trigger and its items; 'lg' gives items with descriptions a fixed 300px
|
|
15
|
+
* @default 'auto'
|
|
16
|
+
*/
|
|
17
|
+
width?: keyof typeof WIDTH_CLASSES
|
|
8
18
|
/**
|
|
9
19
|
* The color semantic mode for the dropdown content
|
|
10
20
|
* @default 'light'
|
|
@@ -12,7 +22,8 @@ interface Props extends SelectContentProps {
|
|
|
12
22
|
colorsSemantic?: 'light' | 'dark'
|
|
13
23
|
}
|
|
14
24
|
|
|
15
|
-
withDefaults(defineProps<Props>(), {
|
|
25
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
26
|
+
width: 'auto',
|
|
16
27
|
position: 'popper',
|
|
17
28
|
side: 'bottom',
|
|
18
29
|
sideOffset: 8,
|
|
@@ -26,44 +37,44 @@ const slots = useSlots()
|
|
|
26
37
|
<template>
|
|
27
38
|
<SelectPortal>
|
|
28
39
|
<SelectContent
|
|
40
|
+
data-testid="ui-dropdown-content"
|
|
29
41
|
v-bind="$attrs"
|
|
30
42
|
:position="position"
|
|
31
43
|
:side-offset="sideOffset"
|
|
32
44
|
:align="align"
|
|
33
45
|
:side="side"
|
|
34
46
|
:data-colors-semantic="colorsSemantic"
|
|
35
|
-
class="
|
|
47
|
+
:class="WIDTH_CLASSES[props.width]"
|
|
48
|
+
class="ui-dropdown-content focus-indicator-none z-overlay relative p-1 rounded-container border border-container-border bg-surface-neutral-bg-main min-w-(--reka-select-trigger-width) max-w-(--reka-select-content-available-width) max-h-(--reka-select-content-available-height) shadow-shadows-drop-shadow-lg data-[state=open]:animate-[slideDownAndFade_0.2s_ease] data-[state=closed]:animate-[slideUpAndFade_0.15s_ease]"
|
|
36
49
|
>
|
|
37
50
|
<div
|
|
38
51
|
v-if="slots.header"
|
|
39
|
-
class="
|
|
52
|
+
class="pb-1"
|
|
40
53
|
>
|
|
41
54
|
<slot name="header" />
|
|
42
55
|
</div>
|
|
43
56
|
|
|
44
|
-
<
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
</SelectScrollUpButton>
|
|
57
|
+
<SelectScrollUpButton
|
|
58
|
+
v-if="showScrollButtons"
|
|
59
|
+
class="flex items-center justify-center h-6 cursor-default text-text-neutral-base"
|
|
60
|
+
>
|
|
61
|
+
<div class="i-ph-caret-up size-4" />
|
|
62
|
+
</SelectScrollUpButton>
|
|
51
63
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
64
|
+
<SelectViewport class="flex flex-col gap-1 max-h-[300px] rounded-row">
|
|
65
|
+
<slot />
|
|
66
|
+
</SelectViewport>
|
|
55
67
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
</div>
|
|
68
|
+
<SelectScrollDownButton
|
|
69
|
+
v-if="showScrollButtons"
|
|
70
|
+
class="flex items-center justify-center h-6 cursor-default text-text-neutral-base"
|
|
71
|
+
>
|
|
72
|
+
<div class="i-ph-caret-down size-4" />
|
|
73
|
+
</SelectScrollDownButton>
|
|
63
74
|
|
|
64
75
|
<div
|
|
65
76
|
v-if="slots.footer"
|
|
66
|
-
class="
|
|
77
|
+
class="pt-1"
|
|
67
78
|
>
|
|
68
79
|
<slot name="footer" />
|
|
69
80
|
</div>
|