@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,135 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, inject, ref, unref, useSlots } from 'vue'
|
|
3
|
+
import { PopoverContent, PopoverPortal, PopoverRoot, PopoverTrigger } from 'reka-ui'
|
|
4
|
+
import { useTranslate } from '../../utils/i18n'
|
|
5
|
+
import { UI_TABLE_SIZE_KEY, type UiTableSize } from './context'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Host for trailing row actions. Place it as the last cell of a row, under a
|
|
9
|
+
* UiTableActionsHeaderCell. The overlay variants reveal the actions over the
|
|
10
|
+
* preceding cells on row hover or keyboard focus; the menu variant renders a
|
|
11
|
+
* persistent trigger instead. Without content it renders an empty cell, for
|
|
12
|
+
* rows that have no actions.
|
|
13
|
+
*/
|
|
14
|
+
export interface UiTableActionsCellProps {
|
|
15
|
+
/**
|
|
16
|
+
* `default` masks the cells behind the actions with a row-state backdrop,
|
|
17
|
+
* for bare buttons per the Figma spec. `floating` drops the backdrop for
|
|
18
|
+
* self-contained content that brings its own surface, like a UiActionBar.
|
|
19
|
+
* `menu` tucks the actions behind an always-visible trigger button that
|
|
20
|
+
* opens them in a popover on click — no hover needed, so it also works
|
|
21
|
+
* on touch devices.
|
|
22
|
+
* @default 'default'
|
|
23
|
+
*/
|
|
24
|
+
variant?: 'default' | 'floating' | 'menu'
|
|
25
|
+
/**
|
|
26
|
+
* Accessible label of the menu trigger. Defaults to the built-in
|
|
27
|
+
* "More actions" label.
|
|
28
|
+
*/
|
|
29
|
+
menuLabel?: string
|
|
30
|
+
/**
|
|
31
|
+
* Keeps the overlay actions shown without row hover or focus, e.g. while
|
|
32
|
+
* a menu they opened is open.
|
|
33
|
+
* @default false
|
|
34
|
+
*/
|
|
35
|
+
revealed?: boolean
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const props = withDefaults(defineProps<UiTableActionsCellProps>(), {
|
|
39
|
+
variant: 'default',
|
|
40
|
+
menuLabel: undefined,
|
|
41
|
+
revealed: false,
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
const slots = useSlots()
|
|
45
|
+
|
|
46
|
+
const translate = useTranslate()
|
|
47
|
+
|
|
48
|
+
const size = inject(UI_TABLE_SIZE_KEY, ref<UiTableSize>('md'))
|
|
49
|
+
|
|
50
|
+
const heightClass = computed(() => (unref(size) === 'lg' ? 'h-16' : 'h-12'))
|
|
51
|
+
|
|
52
|
+
const overlayVisibilityClass = computed(() => (
|
|
53
|
+
props.revealed
|
|
54
|
+
? 'pointer-events-auto opacity-100'
|
|
55
|
+
: 'pointer-events-none opacity-0 group-hover:pointer-events-auto group-hover:opacity-100 group-focus-within:pointer-events-auto group-focus-within:opacity-100'
|
|
56
|
+
))
|
|
57
|
+
|
|
58
|
+
const overlayVariantClass = computed(() => (
|
|
59
|
+
props.variant === 'floating'
|
|
60
|
+
? 'pr-3'
|
|
61
|
+
: 'ui-table__actions--backdrop gap-2 rounded-r-table-row py-1 pl-2 pr-3'
|
|
62
|
+
))
|
|
63
|
+
|
|
64
|
+
const emptyCellClasses = computed(() => [heightClass.value, props.variant === 'menu' ? 'ui-table__empty-menu-cell' : 'ui-table__zero-width-cell'])
|
|
65
|
+
|
|
66
|
+
const menuOpen = ref(false)
|
|
67
|
+
const menuContent = ref<HTMLElement | null>(null)
|
|
68
|
+
|
|
69
|
+
const menuTriggerLabel = computed(() => props.menuLabel ?? translate('general_table_more-actions'))
|
|
70
|
+
|
|
71
|
+
// Land the opening focus on the container, not the first action: focusing
|
|
72
|
+
// an action would immediately pop its tooltip.
|
|
73
|
+
function onMenuOpenAutoFocus (event: Event) {
|
|
74
|
+
event.preventDefault()
|
|
75
|
+
menuContent.value?.focus()
|
|
76
|
+
}
|
|
77
|
+
</script>
|
|
78
|
+
|
|
79
|
+
<template>
|
|
80
|
+
<td
|
|
81
|
+
v-if="!slots.default"
|
|
82
|
+
class="p-0"
|
|
83
|
+
:class="emptyCellClasses"
|
|
84
|
+
/>
|
|
85
|
+
<td
|
|
86
|
+
v-else-if="variant === 'menu'"
|
|
87
|
+
class="ui-table__menu-cell relative px-3 text-right"
|
|
88
|
+
:class="heightClass"
|
|
89
|
+
@click.stop
|
|
90
|
+
@keydown.stop
|
|
91
|
+
>
|
|
92
|
+
<PopoverRoot v-model:open="menuOpen">
|
|
93
|
+
<PopoverTrigger
|
|
94
|
+
:aria-label="menuTriggerLabel"
|
|
95
|
+
class="inline-flex size-button-sm cursor-pointer items-center justify-center rounded-button-sm align-middle text-actions-neutral-idle transition-colors hover:bg-actions-neutral-hover-overlay"
|
|
96
|
+
>
|
|
97
|
+
<span class="i-ph-dots-three size-4 shrink-0" />
|
|
98
|
+
</PopoverTrigger>
|
|
99
|
+
<PopoverPortal>
|
|
100
|
+
<PopoverContent
|
|
101
|
+
side="bottom"
|
|
102
|
+
align="end"
|
|
103
|
+
:side-offset="4"
|
|
104
|
+
class="z-overlay"
|
|
105
|
+
@open-auto-focus="onMenuOpenAutoFocus"
|
|
106
|
+
>
|
|
107
|
+
<!-- Row action menus are one-shot: picking an action closes them. -->
|
|
108
|
+
<div
|
|
109
|
+
ref="menuContent"
|
|
110
|
+
tabindex="-1"
|
|
111
|
+
class="focus-indicator-none outline-none"
|
|
112
|
+
@click="menuOpen = false"
|
|
113
|
+
>
|
|
114
|
+
<slot />
|
|
115
|
+
</div>
|
|
116
|
+
</PopoverContent>
|
|
117
|
+
</PopoverPortal>
|
|
118
|
+
</PopoverRoot>
|
|
119
|
+
</td>
|
|
120
|
+
<td
|
|
121
|
+
v-else
|
|
122
|
+
class="ui-table__actions-cell ui-table__zero-width-cell sticky right-0 w-0 p-0"
|
|
123
|
+
:class="heightClass"
|
|
124
|
+
>
|
|
125
|
+
<div
|
|
126
|
+
class="ui-table__actions absolute inset-y-0 right-0 flex items-center transition-opacity"
|
|
127
|
+
:class="[overlayVisibilityClass, overlayVariantClass]"
|
|
128
|
+
data-testid="ui-table-actions"
|
|
129
|
+
@click.stop
|
|
130
|
+
@keydown.stop
|
|
131
|
+
>
|
|
132
|
+
<slot />
|
|
133
|
+
</div>
|
|
134
|
+
</td>
|
|
135
|
+
</template>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { useTranslate } from '../../utils/i18n'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Header of the trailing actions column, paired with UiTableActionsCell. The
|
|
6
|
+
* column takes no width of its own: overlay actions sit over the row end and
|
|
7
|
+
* menu triggers size it. It names the column for assistive tech.
|
|
8
|
+
*/
|
|
9
|
+
const translate = useTranslate()
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<template>
|
|
13
|
+
<th
|
|
14
|
+
scope="col"
|
|
15
|
+
class="w-0 p-0"
|
|
16
|
+
>
|
|
17
|
+
<span class="sr-only">{{ translate('general_table_more-actions') }}</span>
|
|
18
|
+
</th>
|
|
19
|
+
</template>
|
|
@@ -1,5 +1,20 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
export interface UiTableBodyProps {
|
|
3
|
+
/**
|
|
4
|
+
* Starts the zebra on the first row, so a body that follows another body
|
|
5
|
+
* with an odd number of rows keeps the stripes alternating.
|
|
6
|
+
* @default false
|
|
7
|
+
*/
|
|
8
|
+
zebraOffset?: boolean
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
withDefaults(defineProps<UiTableBodyProps>(), {
|
|
12
|
+
zebraOffset: false,
|
|
13
|
+
})
|
|
14
|
+
</script>
|
|
15
|
+
|
|
1
16
|
<template>
|
|
2
|
-
<tbody>
|
|
17
|
+
<tbody :data-zebra-offset="zebraOffset ? '' : undefined">
|
|
3
18
|
<slot />
|
|
4
19
|
</tbody>
|
|
5
20
|
</template>
|
|
@@ -1,26 +1,43 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { inject,
|
|
2
|
+
import { computed, inject, ref, unref } from 'vue'
|
|
3
|
+
import { UI_TABLE_SIZE_KEY, type UiTableSize } from './context'
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
export interface UiTableCellProps {
|
|
6
|
+
/**
|
|
7
|
+
* Renders an en dash (–), the convention for missing values.
|
|
8
|
+
* @default false
|
|
9
|
+
*/
|
|
10
|
+
empty?: boolean
|
|
11
|
+
/**
|
|
12
|
+
* Content alignment. Textual data stays left-aligned; reserve `right` for numeric data.
|
|
13
|
+
* @default 'left'
|
|
14
|
+
*/
|
|
15
|
+
align?: 'left' | 'right'
|
|
16
|
+
}
|
|
7
17
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
18
|
+
withDefaults(defineProps<UiTableCellProps>(), {
|
|
19
|
+
empty: false,
|
|
20
|
+
align: 'left',
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
const size = inject(UI_TABLE_SIZE_KEY, ref<UiTableSize>('md'))
|
|
24
|
+
|
|
25
|
+
const sizeClasses = computed(() => (
|
|
26
|
+
unref(size) === 'lg'
|
|
27
|
+
? 'h-16 text-content-text-md-medium'
|
|
28
|
+
: 'h-12 text-content-legends-medium-md'
|
|
29
|
+
))
|
|
17
30
|
</script>
|
|
18
31
|
|
|
19
32
|
<template>
|
|
20
33
|
<td
|
|
21
|
-
:class="
|
|
22
|
-
class="px-3
|
|
34
|
+
:class="[sizeClasses, align === 'right' ? 'text-right' : 'text-left']"
|
|
35
|
+
class="overflow-hidden px-3 text-ellipsis text-text-neutral-base transition-colors"
|
|
23
36
|
>
|
|
24
|
-
<
|
|
37
|
+
<span
|
|
38
|
+
v-if="empty"
|
|
39
|
+
class="text-text-neutral-secondary"
|
|
40
|
+
>–</span>
|
|
41
|
+
<slot v-else />
|
|
25
42
|
</td>
|
|
26
43
|
</template>
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { inject,
|
|
2
|
+
import { computed, inject, ref, unref } from 'vue'
|
|
3
|
+
import { UI_TABLE_SIZE_KEY, type UiTableSize } from './context'
|
|
3
4
|
|
|
4
|
-
const
|
|
5
|
+
const size = inject(UI_TABLE_SIZE_KEY, ref<UiTableSize>('md'))
|
|
5
6
|
|
|
6
7
|
const headerClasses = computed(() => ({
|
|
7
|
-
'h-10': unref(
|
|
8
|
-
'h-12': unref(
|
|
9
|
-
'sticky top-0 z-20': true,
|
|
8
|
+
'h-10': unref(size) === 'md',
|
|
9
|
+
'h-12': unref(size) === 'lg',
|
|
10
|
+
'sticky top-0 z-20 bg-surface-neutral-bg-main': true,
|
|
10
11
|
}))
|
|
11
12
|
</script>
|
|
12
13
|
|
|
@@ -1,19 +1,71 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { inject,
|
|
2
|
+
import { computed, inject, ref, unref } from 'vue'
|
|
3
|
+
import { UI_TABLE_SIZE_KEY, type UiTableSize } from './context'
|
|
3
4
|
|
|
4
|
-
|
|
5
|
+
export type UiTableSortDirection = 'asc' | 'desc' | 'none'
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
export interface UiTableHeaderCellProps {
|
|
8
|
+
/**
|
|
9
|
+
* Renders the sort affordance and makes the header interactive.
|
|
10
|
+
* Sorting itself stays in the consumer: listen to `sort` and update `sort-direction`.
|
|
11
|
+
* @default false
|
|
12
|
+
*/
|
|
13
|
+
sortable?: boolean
|
|
14
|
+
/**
|
|
15
|
+
* Current sort direction, controlled by the consumer.
|
|
16
|
+
* @default 'none'
|
|
17
|
+
*/
|
|
18
|
+
sortDirection?: UiTableSortDirection
|
|
19
|
+
/**
|
|
20
|
+
* Content alignment. Textual data stays left-aligned; reserve `right` for numeric data.
|
|
21
|
+
* @default 'left'
|
|
22
|
+
*/
|
|
23
|
+
align?: 'left' | 'right'
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const props = withDefaults(defineProps<UiTableHeaderCellProps>(), {
|
|
27
|
+
sortable: false,
|
|
28
|
+
sortDirection: 'none',
|
|
29
|
+
align: 'left',
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
const emit = defineEmits<{
|
|
33
|
+
sort: []
|
|
34
|
+
}>()
|
|
35
|
+
|
|
36
|
+
const size = inject(UI_TABLE_SIZE_KEY, ref<UiTableSize>('md'))
|
|
37
|
+
|
|
38
|
+
const heightClass = computed(() => (unref(size) === 'lg' ? 'h-12' : 'h-10'))
|
|
39
|
+
|
|
40
|
+
const ariaSort = computed(() => {
|
|
41
|
+
if (!props.sortable) return undefined
|
|
42
|
+
return ({ asc: 'ascending', desc: 'descending', none: 'none' } as const)[props.sortDirection]
|
|
43
|
+
})
|
|
10
44
|
</script>
|
|
11
45
|
|
|
12
46
|
<template>
|
|
13
47
|
<th
|
|
14
|
-
|
|
15
|
-
|
|
48
|
+
scope="col"
|
|
49
|
+
:aria-sort="ariaSort"
|
|
50
|
+
:class="[heightClass, align === 'right' ? 'text-right' : 'text-left', sortable ? 'p-0' : 'px-3 pt-1 pb-2.5']"
|
|
51
|
+
class="align-bottom text-content-legends-bold-md text-text-neutral-tertiary"
|
|
16
52
|
>
|
|
17
|
-
<
|
|
53
|
+
<button
|
|
54
|
+
v-if="sortable"
|
|
55
|
+
type="button"
|
|
56
|
+
class="group/sort flex size-full items-end justify-start gap-2 rounded-row px-3 pt-1 pb-2.5 transition-colors hover:text-text-neutral-base focus-visible:text-text-neutral-base"
|
|
57
|
+
:class="align === 'right' ? 'flex-row-reverse text-right' : 'text-left'"
|
|
58
|
+
@click="emit('sort')"
|
|
59
|
+
>
|
|
60
|
+
<slot />
|
|
61
|
+
<span
|
|
62
|
+
class="size-3 shrink-0 transition-opacity"
|
|
63
|
+
:class="[
|
|
64
|
+
sortDirection === 'asc' ? 'i-ph-caret-up' : 'i-ph-caret-down',
|
|
65
|
+
sortDirection === 'none' ? 'opacity-0 group-hover/sort:opacity-100 group-focus-visible/sort:opacity-100' : 'opacity-100',
|
|
66
|
+
]"
|
|
67
|
+
/>
|
|
68
|
+
</button>
|
|
69
|
+
<slot v-else />
|
|
18
70
|
</th>
|
|
19
71
|
</template>
|
|
@@ -1,26 +1,62 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import { computed } from 'vue'
|
|
3
3
|
|
|
4
4
|
export interface UiTableRowProps {
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Marks the row as selected.
|
|
7
|
+
* @default false
|
|
8
|
+
*/
|
|
9
|
+
selected?: boolean
|
|
10
|
+
/**
|
|
11
|
+
* Makes the row interactive: hover feedback, pointer cursor and keyboard focus.
|
|
12
|
+
* @default false
|
|
13
|
+
*/
|
|
14
|
+
clickable?: boolean
|
|
15
|
+
/**
|
|
16
|
+
* The row hosts a link stretched over it: positions the row for the link
|
|
17
|
+
* and gives it the hover and focus tone.
|
|
18
|
+
* @default false
|
|
19
|
+
*/
|
|
20
|
+
linked?: boolean
|
|
21
|
+
/**
|
|
22
|
+
* Takes part in the table zebra. Turn it off for a row that is not a data
|
|
23
|
+
* row, such as an overlay over the rows: it is neither striped nor counted.
|
|
24
|
+
* @default true
|
|
25
|
+
*/
|
|
26
|
+
zebra?: boolean
|
|
6
27
|
}
|
|
7
28
|
|
|
8
|
-
const props = defineProps<UiTableRowProps>()
|
|
29
|
+
const props = withDefaults(defineProps<UiTableRowProps>(), {
|
|
30
|
+
selected: false,
|
|
31
|
+
clickable: false,
|
|
32
|
+
linked: false,
|
|
33
|
+
zebra: true,
|
|
34
|
+
})
|
|
9
35
|
|
|
10
|
-
const
|
|
36
|
+
const rowClasses = computed(() => ({ 'cursor-pointer': props.clickable, relative: props.linked }))
|
|
11
37
|
|
|
12
|
-
|
|
38
|
+
const emit = defineEmits<{
|
|
39
|
+
click: [event: MouseEvent | KeyboardEvent]
|
|
40
|
+
}>()
|
|
13
41
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
'
|
|
17
|
-
}
|
|
42
|
+
function onActivate (event: MouseEvent | KeyboardEvent) {
|
|
43
|
+
if (!props.clickable) return
|
|
44
|
+
emit('click', event)
|
|
45
|
+
}
|
|
18
46
|
</script>
|
|
19
47
|
|
|
20
48
|
<template>
|
|
21
49
|
<tr
|
|
22
|
-
:class="rowClasses"
|
|
23
50
|
class="group"
|
|
51
|
+
:class="rowClasses"
|
|
52
|
+
:data-clickable="clickable ? '' : undefined"
|
|
53
|
+
:data-linked="linked ? '' : undefined"
|
|
54
|
+
:data-selected="selected ? '' : undefined"
|
|
55
|
+
:data-zebra-skip="zebra ? undefined : ''"
|
|
56
|
+
:tabindex="clickable ? 0 : undefined"
|
|
57
|
+
@click="onActivate"
|
|
58
|
+
@keydown.enter.self="onActivate"
|
|
59
|
+
@keydown.space.self.prevent="onActivate"
|
|
24
60
|
>
|
|
25
61
|
<slot />
|
|
26
62
|
</tr>
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
export { default as UiTable } from './UiTable.vue'
|
|
2
2
|
export { default as UiTableHeader } from './UiTableHeader.vue'
|
|
3
3
|
export { default as UiTableHeaderCell } from './UiTableHeaderCell.vue'
|
|
4
|
+
export { default as UiTableActionsHeaderCell } from './UiTableActionsHeaderCell.vue'
|
|
4
5
|
export { default as UiTableBody } from './UiTableBody.vue'
|
|
5
6
|
export { default as UiTableRow } from './UiTableRow.vue'
|
|
6
7
|
export { default as UiTableCell } from './UiTableCell.vue'
|
|
8
|
+
export { default as UiTableActionsCell } from './UiTableActionsCell.vue'
|
|
9
|
+
export type { UiTableSize } from './context'
|
|
10
|
+
export type { UiTableSortDirection } from './UiTableHeaderCell.vue'
|
|
@@ -23,22 +23,23 @@ export interface UiTabsProps {
|
|
|
23
23
|
modelValue: string
|
|
24
24
|
/** Size of the tabs */
|
|
25
25
|
size?: 'sm' | 'md'
|
|
26
|
+
/** Horizontal alignment of the tabs inside the component */
|
|
27
|
+
align?: 'start' | 'center'
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
const props = withDefaults(defineProps<UiTabsProps>(), {
|
|
29
31
|
size: 'md',
|
|
32
|
+
align: 'start',
|
|
30
33
|
})
|
|
31
34
|
|
|
32
35
|
const emit = defineEmits<{
|
|
33
36
|
'update:modelValue': [value: string]
|
|
34
37
|
}>()
|
|
35
38
|
|
|
36
|
-
|
|
39
|
+
defineSlots<{
|
|
37
40
|
badge?(props: { tab: Tab }): unknown
|
|
38
41
|
}>()
|
|
39
42
|
|
|
40
|
-
const hasBadgeSlot = computed(() => !!slots.badge)
|
|
41
|
-
|
|
42
43
|
const sizeClasses = computed(() => {
|
|
43
44
|
return {
|
|
44
45
|
container: 'gap-4',
|
|
@@ -124,17 +125,12 @@ function handleKeydown (event: KeyboardEvent, currentValue: string) {
|
|
|
124
125
|
}
|
|
125
126
|
|
|
126
127
|
function updateIndicatorPosition () {
|
|
127
|
-
if (!tabsContainer.value) return
|
|
128
|
-
|
|
129
128
|
const activeButton = tabRefs.value.get(props.modelValue)
|
|
130
129
|
if (!activeButton) return
|
|
131
130
|
|
|
132
|
-
const containerRect = tabsContainer.value.getBoundingClientRect()
|
|
133
|
-
const buttonRect = activeButton.getBoundingClientRect()
|
|
134
|
-
|
|
135
131
|
indicatorStyle.value = {
|
|
136
|
-
transform: `translateX(${
|
|
137
|
-
width: `${
|
|
132
|
+
transform: `translateX(${activeButton.offsetLeft}px)`,
|
|
133
|
+
width: `${activeButton.offsetWidth}px`,
|
|
138
134
|
}
|
|
139
135
|
}
|
|
140
136
|
|
|
@@ -152,7 +148,7 @@ onMounted(async () => {
|
|
|
152
148
|
updateIndicatorPosition()
|
|
153
149
|
})
|
|
154
150
|
|
|
155
|
-
useResizeObserver(tabsContainer, debouncedUpdatePosition)
|
|
151
|
+
useResizeObserver(() => [tabsContainer.value, ...tabRefs.value.values()], debouncedUpdatePosition)
|
|
156
152
|
|
|
157
153
|
onBeforeUnmount(() => {
|
|
158
154
|
tabRefs.value.clear()
|
|
@@ -160,62 +156,61 @@ onBeforeUnmount(() => {
|
|
|
160
156
|
</script>
|
|
161
157
|
|
|
162
158
|
<template>
|
|
163
|
-
<div class="ui-tabs border-b border-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
v-for="tab in tabs"
|
|
172
|
-
:key="tab.value"
|
|
173
|
-
:ref="(el) => setTabRef(el, tab.value)"
|
|
174
|
-
type="button"
|
|
175
|
-
role="tab"
|
|
176
|
-
:aria-selected="isActive(tab.value)"
|
|
177
|
-
:aria-disabled="tab.disabled"
|
|
178
|
-
:data-testid="tab.testId"
|
|
179
|
-
:tabindex="isActive(tab.value) ? 0 : -1"
|
|
180
|
-
class="relative outline-none flex items-center gap-2 cursor-pointer font-semibold transition-colors duration-150"
|
|
181
|
-
:class="[
|
|
182
|
-
sizeClasses.tab,
|
|
183
|
-
sizeClasses.text,
|
|
184
|
-
{
|
|
185
|
-
'text-actions-primary-idle': isActive(tab.value),
|
|
186
|
-
'text-actions-neutral-idle-alpha-strong hover:text-actions-neutral-idle': !isActive(tab.value) && !tab.disabled,
|
|
187
|
-
'text-actions-neutral-idle-alpha-strong cursor-not-allowed opacity-50': tab.disabled,
|
|
188
|
-
},
|
|
189
|
-
]"
|
|
190
|
-
:disabled="tab.disabled"
|
|
191
|
-
@click="selectTab(tab.value)"
|
|
192
|
-
@keydown="handleKeydown($event, tab.value)"
|
|
159
|
+
<div class="ui-tabs border-b border-divider">
|
|
160
|
+
<!-- The 1px bottom overlap lays the indicator over the border -->
|
|
161
|
+
<div class="relative -mb-px overflow-x-auto [scrollbar-width:none]">
|
|
162
|
+
<div
|
|
163
|
+
ref="tabsContainer"
|
|
164
|
+
role="tablist"
|
|
165
|
+
class="flex items-center"
|
|
166
|
+
:class="[sizeClasses.container, { 'justify-center-safe': align === 'center' }]"
|
|
193
167
|
>
|
|
194
|
-
<
|
|
195
|
-
v-
|
|
196
|
-
:
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
168
|
+
<button
|
|
169
|
+
v-for="tab in tabs"
|
|
170
|
+
:key="tab.value"
|
|
171
|
+
:ref="(el) => setTabRef(el, tab.value)"
|
|
172
|
+
type="button"
|
|
173
|
+
role="tab"
|
|
174
|
+
:aria-selected="isActive(tab.value)"
|
|
175
|
+
:aria-disabled="tab.disabled"
|
|
176
|
+
:data-testid="tab.testId"
|
|
177
|
+
:tabindex="isActive(tab.value) ? 0 : -1"
|
|
178
|
+
class="relative outline-none flex shrink-0 items-center gap-2 whitespace-nowrap cursor-pointer font-semibold transition-colors duration-150"
|
|
179
|
+
:class="[
|
|
180
|
+
sizeClasses.tab,
|
|
181
|
+
sizeClasses.text,
|
|
182
|
+
{
|
|
183
|
+
'text-actions-primary-idle': isActive(tab.value),
|
|
184
|
+
'text-actions-neutral-idle-alpha-strong hover:text-actions-neutral-idle': !isActive(tab.value) && !tab.disabled,
|
|
185
|
+
'text-actions-neutral-idle-alpha-strong cursor-not-allowed opacity-50': tab.disabled,
|
|
186
|
+
},
|
|
187
|
+
]"
|
|
188
|
+
:disabled="tab.disabled"
|
|
189
|
+
@click="selectTab(tab.value)"
|
|
190
|
+
@keydown="handleKeydown($event, tab.value)"
|
|
203
191
|
>
|
|
192
|
+
<span
|
|
193
|
+
v-if="tab.icon"
|
|
194
|
+
:class="tab.icon"
|
|
195
|
+
class="size-5"
|
|
196
|
+
/>
|
|
197
|
+
<span>{{ tab.label }}</span>
|
|
204
198
|
<slot
|
|
205
199
|
name="badge"
|
|
206
200
|
:tab="tab"
|
|
207
201
|
/>
|
|
208
|
-
</
|
|
209
|
-
</
|
|
202
|
+
</button>
|
|
203
|
+
</div>
|
|
204
|
+
|
|
205
|
+
<!-- Sliding indicator -->
|
|
206
|
+
<div
|
|
207
|
+
data-testid="ui-tabs-indicator"
|
|
208
|
+
class="absolute bottom-0 left-0 h-0.5 bg-actions-primary-idle transition-[transform,width] duration-[250ms] ease-out will-change-[transform,width]"
|
|
209
|
+
:style="{
|
|
210
|
+
transform: indicatorStyle.transform,
|
|
211
|
+
width: indicatorStyle.width,
|
|
212
|
+
}"
|
|
213
|
+
/>
|
|
210
214
|
</div>
|
|
211
|
-
|
|
212
|
-
<!-- Sliding indicator -->
|
|
213
|
-
<div
|
|
214
|
-
class="absolute -bottom-px left-0 h-0.5 bg-actions-primary-idle transition-[transform,width] duration-[250ms] ease-out will-change-[transform,width]"
|
|
215
|
-
:style="{
|
|
216
|
-
transform: indicatorStyle.transform,
|
|
217
|
-
width: indicatorStyle.width,
|
|
218
|
-
}"
|
|
219
|
-
/>
|
|
220
215
|
</div>
|
|
221
216
|
</template>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export type UiTagSize = 'xxs' | 'xs' | 'sm' | 'md'
|
|
2
|
+
|
|
3
|
+
export type UiTagColor = 'primary' | 'neutral' | 'danger' | 'warning' | 'success' | 'neutral-invert'
|
|
4
|
+
|
|
5
|
+
export type UiTagVariant = 'light' | 'strong'
|
|
6
|
+
|
|
7
|
+
export interface UiTagProps {
|
|
8
|
+
/**
|
|
9
|
+
* Size of the tag
|
|
10
|
+
*/
|
|
11
|
+
size?: UiTagSize
|
|
12
|
+
/**
|
|
13
|
+
* Color variant of the tag
|
|
14
|
+
*/
|
|
15
|
+
color?: UiTagColor
|
|
16
|
+
/**
|
|
17
|
+
* Variant of the tag
|
|
18
|
+
*/
|
|
19
|
+
variant?: UiTagVariant
|
|
20
|
+
/**
|
|
21
|
+
* Label text for the tag
|
|
22
|
+
*/
|
|
23
|
+
label?: string
|
|
24
|
+
/**
|
|
25
|
+
* Whether to show hover effects
|
|
26
|
+
*/
|
|
27
|
+
withHoverEffect?: boolean
|
|
28
|
+
}
|