mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-20 06:20:11 +00:00
feat: align BaseTooltip with Figma design, add Storybook, fix as-child nesting
- Update tooltip variants: shadow-interface, leading-none, export FOR_STORIES - Add keybind and showIcon props to BaseTooltip per Figma design spec - Add comprehensive Storybook stories for all tooltip variants - Fix Popover + BaseTooltip as-child nesting conflict in JobHistoryActionsMenu and JobFilterActions by moving BaseTooltip outside the Popover #button slot Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div class="flex items-center gap-1">
|
||||
<Popover :show-arrow="false">
|
||||
<template #button>
|
||||
<BaseTooltip :text="t('g.more')" side="top">
|
||||
<BaseTooltip :text="t('g.more')" side="top">
|
||||
<div class="flex items-center gap-1">
|
||||
<Popover :show-arrow="false">
|
||||
<template #button>
|
||||
<Button
|
||||
variant="textonly"
|
||||
size="icon"
|
||||
@@ -12,81 +12,83 @@
|
||||
class="icon-[lucide--more-horizontal] block size-4 leading-none text-text-secondary"
|
||||
/>
|
||||
</Button>
|
||||
</BaseTooltip>
|
||||
</template>
|
||||
<template #default="{ close }">
|
||||
<div class="flex min-w-56 flex-col items-stretch font-inter">
|
||||
<Button
|
||||
data-testid="docked-job-history-action"
|
||||
class="w-full justify-between text-sm font-light"
|
||||
variant="textonly"
|
||||
size="md"
|
||||
@click="onToggleDockedJobHistory(close)"
|
||||
>
|
||||
<span class="flex items-center gap-2">
|
||||
<i
|
||||
class="icon-[lucide--panel-left-close] size-4 text-text-secondary"
|
||||
/>
|
||||
<span>{{
|
||||
t('sideToolbar.queueProgressOverlay.dockedJobHistory')
|
||||
}}</span>
|
||||
</span>
|
||||
<i
|
||||
v-if="isQueuePanelV2Enabled"
|
||||
class="icon-[lucide--check] size-4"
|
||||
/>
|
||||
</Button>
|
||||
<Button
|
||||
data-testid="show-run-progress-bar-action"
|
||||
class="w-full justify-between text-sm font-light"
|
||||
variant="textonly"
|
||||
size="md"
|
||||
@click="onToggleRunProgressBar"
|
||||
>
|
||||
<span class="flex items-center gap-2">
|
||||
<i class="icon-[lucide--hourglass] size-4 text-text-secondary" />
|
||||
<span>{{
|
||||
t('sideToolbar.queueProgressOverlay.showRunProgressBar')
|
||||
}}</span>
|
||||
</span>
|
||||
<i
|
||||
v-if="isRunProgressBarEnabled"
|
||||
class="icon-[lucide--check] size-4"
|
||||
/>
|
||||
</Button>
|
||||
<!-- TODO: Bug in assets sidebar panel derives assets from history, so despite this not deleting the assets, it still effectively shows to the user as deleted -->
|
||||
<template v-if="showClearHistoryAction">
|
||||
<div class="my-1 border-t border-interface-stroke" />
|
||||
</template>
|
||||
<template #default="{ close }">
|
||||
<div class="flex min-w-56 flex-col items-stretch font-inter">
|
||||
<Button
|
||||
data-testid="clear-history-action"
|
||||
class="h-auto min-h-8 w-full items-start justify-start whitespace-normal"
|
||||
data-testid="docked-job-history-action"
|
||||
class="w-full justify-between text-sm font-light"
|
||||
variant="textonly"
|
||||
size="md"
|
||||
@click="onClearHistoryFromMenu(close)"
|
||||
@click="onToggleDockedJobHistory(close)"
|
||||
>
|
||||
<i
|
||||
class="icon-[lucide--trash-2] size-4 shrink-0 self-center text-destructive-background"
|
||||
/>
|
||||
<span
|
||||
class="flex flex-col items-start text-left leading-tight wrap-break-word"
|
||||
>
|
||||
<span class="text-sm font-light">
|
||||
{{ t('sideToolbar.queueProgressOverlay.clearHistory') }}
|
||||
</span>
|
||||
<span class="text-xs font-light text-text-secondary">
|
||||
{{
|
||||
t(
|
||||
'sideToolbar.queueProgressOverlay.clearHistoryMenuAssetsNote'
|
||||
)
|
||||
}}
|
||||
</span>
|
||||
<span class="flex items-center gap-2">
|
||||
<i
|
||||
class="icon-[lucide--panel-left-close] size-4 text-text-secondary"
|
||||
/>
|
||||
<span>{{
|
||||
t('sideToolbar.queueProgressOverlay.dockedJobHistory')
|
||||
}}</span>
|
||||
</span>
|
||||
<i
|
||||
v-if="isQueuePanelV2Enabled"
|
||||
class="icon-[lucide--check] size-4"
|
||||
/>
|
||||
</Button>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</Popover>
|
||||
</div>
|
||||
<Button
|
||||
data-testid="show-run-progress-bar-action"
|
||||
class="w-full justify-between text-sm font-light"
|
||||
variant="textonly"
|
||||
size="md"
|
||||
@click="onToggleRunProgressBar"
|
||||
>
|
||||
<span class="flex items-center gap-2">
|
||||
<i
|
||||
class="icon-[lucide--hourglass] size-4 text-text-secondary"
|
||||
/>
|
||||
<span>{{
|
||||
t('sideToolbar.queueProgressOverlay.showRunProgressBar')
|
||||
}}</span>
|
||||
</span>
|
||||
<i
|
||||
v-if="isRunProgressBarEnabled"
|
||||
class="icon-[lucide--check] size-4"
|
||||
/>
|
||||
</Button>
|
||||
<!-- TODO: Bug in assets sidebar panel derives assets from history, so despite this not deleting the assets, it still effectively shows to the user as deleted -->
|
||||
<template v-if="showClearHistoryAction">
|
||||
<div class="my-1 border-t border-interface-stroke" />
|
||||
<Button
|
||||
data-testid="clear-history-action"
|
||||
class="h-auto min-h-8 w-full items-start justify-start whitespace-normal"
|
||||
variant="textonly"
|
||||
size="md"
|
||||
@click="onClearHistoryFromMenu(close)"
|
||||
>
|
||||
<i
|
||||
class="icon-[lucide--trash-2] size-4 shrink-0 self-center text-destructive-background"
|
||||
/>
|
||||
<span
|
||||
class="flex flex-col items-start text-left leading-tight wrap-break-word"
|
||||
>
|
||||
<span class="text-sm font-light">
|
||||
{{ t('sideToolbar.queueProgressOverlay.clearHistory') }}
|
||||
</span>
|
||||
<span class="text-xs font-light text-text-secondary">
|
||||
{{
|
||||
t(
|
||||
'sideToolbar.queueProgressOverlay.clearHistoryMenuAssetsNote'
|
||||
)
|
||||
}}
|
||||
</span>
|
||||
</span>
|
||||
</Button>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</Popover>
|
||||
</div>
|
||||
</BaseTooltip>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
@@ -11,101 +11,105 @@
|
||||
class="flex shrink-0 items-center gap-2"
|
||||
:class="{ 'ml-2': !showSearch }"
|
||||
>
|
||||
<Popover :show-arrow="false">
|
||||
<template #button>
|
||||
<BaseTooltip
|
||||
:text="t('sideToolbar.queueProgressOverlay.filterBy')"
|
||||
side="top"
|
||||
>
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="icon"
|
||||
:aria-label="t('sideToolbar.queueProgressOverlay.filterJobs')"
|
||||
>
|
||||
<i class="icon-[lucide--list-filter] size-4" />
|
||||
<span
|
||||
v-if="selectedWorkflowFilter !== 'all'"
|
||||
class="pointer-events-none absolute -top-1 -right-1 inline-block size-2 rounded-full bg-base-foreground"
|
||||
/>
|
||||
</Button>
|
||||
</BaseTooltip>
|
||||
</template>
|
||||
<template #default="{ close }">
|
||||
<div class="flex min-w-48 flex-col items-stretch">
|
||||
<Button
|
||||
class="w-full justify-between"
|
||||
variant="textonly"
|
||||
size="md"
|
||||
@click="onSelectWorkflowFilter('all', close)"
|
||||
>
|
||||
<span>{{
|
||||
t('sideToolbar.queueProgressOverlay.filterAllWorkflows')
|
||||
}}</span>
|
||||
<i
|
||||
v-if="selectedWorkflowFilter === 'all'"
|
||||
class="icon-[lucide--check] size-4"
|
||||
/>
|
||||
</Button>
|
||||
<div class="mx-2 mt-1 h-px" />
|
||||
<Button
|
||||
class="w-full justify-between"
|
||||
variant="textonly"
|
||||
size="md"
|
||||
@click="onSelectWorkflowFilter('current', close)"
|
||||
>
|
||||
<span>{{
|
||||
t('sideToolbar.queueProgressOverlay.filterCurrentWorkflow')
|
||||
}}</span>
|
||||
<i
|
||||
v-if="selectedWorkflowFilter === 'current'"
|
||||
class="icon-[lucide--check] block size-4 leading-none text-text-secondary"
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
</template>
|
||||
</Popover>
|
||||
<Popover :show-arrow="false">
|
||||
<template #button>
|
||||
<BaseTooltip
|
||||
:text="t('sideToolbar.queueProgressOverlay.sortBy')"
|
||||
side="top"
|
||||
>
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="icon"
|
||||
:aria-label="t('sideToolbar.queueProgressOverlay.sortJobs')"
|
||||
>
|
||||
<i class="icon-[lucide--arrow-up-down] size-4" />
|
||||
<span
|
||||
v-if="selectedSortMode !== 'mostRecent'"
|
||||
class="pointer-events-none absolute -top-1 -right-1 inline-block size-2 rounded-full bg-base-foreground"
|
||||
/>
|
||||
</Button>
|
||||
</BaseTooltip>
|
||||
</template>
|
||||
<template #default="{ close }">
|
||||
<div class="flex min-w-48 flex-col items-stretch">
|
||||
<template v-for="(mode, index) in jobSortModes" :key="mode">
|
||||
<BaseTooltip
|
||||
:text="t('sideToolbar.queueProgressOverlay.filterBy')"
|
||||
side="top"
|
||||
>
|
||||
<div>
|
||||
<Popover :show-arrow="false">
|
||||
<template #button>
|
||||
<Button
|
||||
class="w-full justify-between"
|
||||
variant="textonly"
|
||||
size="md"
|
||||
@click="onSelectSortMode(mode, close)"
|
||||
variant="secondary"
|
||||
size="icon"
|
||||
:aria-label="t('sideToolbar.queueProgressOverlay.filterJobs')"
|
||||
>
|
||||
<span>{{ sortLabel(mode) }}</span>
|
||||
<i
|
||||
v-if="selectedSortMode === mode"
|
||||
class="icon-[lucide--check] size-4 text-text-secondary"
|
||||
<i class="icon-[lucide--list-filter] size-4" />
|
||||
<span
|
||||
v-if="selectedWorkflowFilter !== 'all'"
|
||||
class="pointer-events-none absolute -top-1 -right-1 inline-block size-2 rounded-full bg-base-foreground"
|
||||
/>
|
||||
</Button>
|
||||
<div
|
||||
v-if="index < jobSortModes.length - 1"
|
||||
class="mx-2 mt-1 h-px"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</Popover>
|
||||
<template #default="{ close }">
|
||||
<div class="flex min-w-48 flex-col items-stretch">
|
||||
<Button
|
||||
class="w-full justify-between"
|
||||
variant="textonly"
|
||||
size="md"
|
||||
@click="onSelectWorkflowFilter('all', close)"
|
||||
>
|
||||
<span>{{
|
||||
t('sideToolbar.queueProgressOverlay.filterAllWorkflows')
|
||||
}}</span>
|
||||
<i
|
||||
v-if="selectedWorkflowFilter === 'all'"
|
||||
class="icon-[lucide--check] size-4"
|
||||
/>
|
||||
</Button>
|
||||
<div class="mx-2 mt-1 h-px" />
|
||||
<Button
|
||||
class="w-full justify-between"
|
||||
variant="textonly"
|
||||
size="md"
|
||||
@click="onSelectWorkflowFilter('current', close)"
|
||||
>
|
||||
<span>{{
|
||||
t('sideToolbar.queueProgressOverlay.filterCurrentWorkflow')
|
||||
}}</span>
|
||||
<i
|
||||
v-if="selectedWorkflowFilter === 'current'"
|
||||
class="icon-[lucide--check] block size-4 leading-none text-text-secondary"
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
</template>
|
||||
</Popover>
|
||||
</div>
|
||||
</BaseTooltip>
|
||||
<BaseTooltip
|
||||
:text="t('sideToolbar.queueProgressOverlay.sortBy')"
|
||||
side="top"
|
||||
>
|
||||
<div>
|
||||
<Popover :show-arrow="false">
|
||||
<template #button>
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="icon"
|
||||
:aria-label="t('sideToolbar.queueProgressOverlay.sortJobs')"
|
||||
>
|
||||
<i class="icon-[lucide--arrow-up-down] size-4" />
|
||||
<span
|
||||
v-if="selectedSortMode !== 'mostRecent'"
|
||||
class="pointer-events-none absolute -top-1 -right-1 inline-block size-2 rounded-full bg-base-foreground"
|
||||
/>
|
||||
</Button>
|
||||
</template>
|
||||
<template #default="{ close }">
|
||||
<div class="flex min-w-48 flex-col items-stretch">
|
||||
<template v-for="(mode, index) in jobSortModes" :key="mode">
|
||||
<Button
|
||||
class="w-full justify-between"
|
||||
variant="textonly"
|
||||
size="md"
|
||||
@click="onSelectSortMode(mode, close)"
|
||||
>
|
||||
<span>{{ sortLabel(mode) }}</span>
|
||||
<i
|
||||
v-if="selectedSortMode === mode"
|
||||
class="icon-[lucide--check] size-4 text-text-secondary"
|
||||
/>
|
||||
</Button>
|
||||
<div
|
||||
v-if="index < jobSortModes.length - 1"
|
||||
class="mx-2 mt-1 h-px"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</Popover>
|
||||
</div>
|
||||
</BaseTooltip>
|
||||
<BaseTooltip
|
||||
v-if="showAssetsAction"
|
||||
:text="t('sideToolbar.queueProgressOverlay.showAssets')"
|
||||
|
||||
189
src/components/ui/tooltip/BaseTooltip.stories.ts
Normal file
189
src/components/ui/tooltip/BaseTooltip.stories.ts
Normal file
@@ -0,0 +1,189 @@
|
||||
import type { Meta, StoryObj } from '@storybook/vue3-vite'
|
||||
import { TooltipProvider } from 'reka-ui'
|
||||
|
||||
import BaseTooltip from './BaseTooltip.vue'
|
||||
import { FOR_STORIES } from './tooltip.variants'
|
||||
|
||||
const { sizes, sides } = FOR_STORIES
|
||||
|
||||
const meta: Meta<typeof BaseTooltip> = {
|
||||
title: 'Components/Tooltip/BaseTooltip',
|
||||
component: BaseTooltip,
|
||||
tags: ['autodocs'],
|
||||
decorators: [
|
||||
(story) => ({
|
||||
components: { TooltipProvider, story },
|
||||
template:
|
||||
'<TooltipProvider :delay-duration="0"><div class="flex items-center justify-center p-20"><story /></div></TooltipProvider>'
|
||||
})
|
||||
],
|
||||
argTypes: {
|
||||
size: {
|
||||
control: { type: 'select' },
|
||||
options: sizes
|
||||
},
|
||||
side: {
|
||||
control: { type: 'select' },
|
||||
options: sides
|
||||
},
|
||||
text: { control: 'text' },
|
||||
keybind: { control: 'text' },
|
||||
showIcon: { control: 'boolean' },
|
||||
disabled: { control: 'boolean' }
|
||||
},
|
||||
args: {
|
||||
size: 'small',
|
||||
side: 'top',
|
||||
text: 'Tooltip text',
|
||||
disabled: false
|
||||
}
|
||||
}
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Small: Story = {
|
||||
render: (args) => ({
|
||||
components: { BaseTooltip },
|
||||
setup: () => ({ args }),
|
||||
template: `
|
||||
<BaseTooltip v-bind="args">
|
||||
<button class="rounded-lg bg-secondary-background px-4 py-2 text-sm">
|
||||
Hover me
|
||||
</button>
|
||||
</BaseTooltip>`
|
||||
})
|
||||
}
|
||||
|
||||
export const Large: Story = {
|
||||
args: {
|
||||
size: 'large',
|
||||
text: 'This is a longer tooltip that can wrap to multiple lines for detailed descriptions of node functionality.'
|
||||
},
|
||||
render: (args) => ({
|
||||
components: { BaseTooltip },
|
||||
setup: () => ({ args }),
|
||||
template: `
|
||||
<BaseTooltip v-bind="args">
|
||||
<button class="rounded-lg bg-secondary-background px-4 py-2 text-sm">
|
||||
Hover me
|
||||
</button>
|
||||
</BaseTooltip>`
|
||||
})
|
||||
}
|
||||
|
||||
export const WithKeybind: Story = {
|
||||
args: {
|
||||
text: 'Undo',
|
||||
keybind: 'Ctrl+Z'
|
||||
},
|
||||
render: (args) => ({
|
||||
components: { BaseTooltip },
|
||||
setup: () => ({ args }),
|
||||
template: `
|
||||
<BaseTooltip v-bind="args">
|
||||
<button class="rounded-lg bg-secondary-background px-4 py-2 text-sm">
|
||||
Hover me
|
||||
</button>
|
||||
</BaseTooltip>`
|
||||
})
|
||||
}
|
||||
|
||||
export const WithIcon: Story = {
|
||||
args: {
|
||||
text: 'More options',
|
||||
showIcon: true,
|
||||
size: 'small'
|
||||
},
|
||||
render: (args) => ({
|
||||
components: { BaseTooltip },
|
||||
setup: () => ({ args }),
|
||||
template: `
|
||||
<BaseTooltip v-bind="args">
|
||||
<button class="rounded-lg bg-secondary-background px-4 py-2 text-sm">
|
||||
Hover me
|
||||
</button>
|
||||
</BaseTooltip>`
|
||||
})
|
||||
}
|
||||
|
||||
export const WithKeybindAndIcon: Story = {
|
||||
args: {
|
||||
text: 'Save',
|
||||
keybind: 'Ctrl+S',
|
||||
showIcon: true,
|
||||
size: 'small'
|
||||
},
|
||||
render: (args) => ({
|
||||
components: { BaseTooltip },
|
||||
setup: () => ({ args }),
|
||||
template: `
|
||||
<BaseTooltip v-bind="args">
|
||||
<button class="rounded-lg bg-secondary-background px-4 py-2 text-sm">
|
||||
Hover me
|
||||
</button>
|
||||
</BaseTooltip>`
|
||||
})
|
||||
}
|
||||
|
||||
export const Disabled: Story = {
|
||||
args: {
|
||||
text: 'This tooltip is disabled',
|
||||
disabled: true
|
||||
},
|
||||
render: (args) => ({
|
||||
components: { BaseTooltip },
|
||||
setup: () => ({ args }),
|
||||
template: `
|
||||
<BaseTooltip v-bind="args">
|
||||
<button class="rounded-lg bg-secondary-background px-4 py-2 text-sm">
|
||||
Hover me (disabled tooltip)
|
||||
</button>
|
||||
</BaseTooltip>`
|
||||
})
|
||||
}
|
||||
|
||||
export const AllSides: Story = {
|
||||
render: () => ({
|
||||
components: { BaseTooltip },
|
||||
template: `
|
||||
<div class="grid grid-cols-2 gap-12">
|
||||
${sides
|
||||
.map(
|
||||
(side) => `
|
||||
<BaseTooltip text="${side} tooltip" side="${side}" size="small">
|
||||
<button class="w-full rounded-lg bg-secondary-background px-4 py-2 text-sm">
|
||||
${side}
|
||||
</button>
|
||||
</BaseTooltip>`
|
||||
)
|
||||
.join('\n')}
|
||||
</div>`
|
||||
})
|
||||
}
|
||||
|
||||
export const AllVariants: Story = {
|
||||
render: () => ({
|
||||
components: { BaseTooltip },
|
||||
template: `
|
||||
<div class="flex flex-col gap-12">
|
||||
<div class="flex flex-wrap items-center gap-8">
|
||||
<BaseTooltip text="Small tooltip" size="small" side="bottom">
|
||||
<button class="rounded-lg bg-secondary-background px-4 py-2 text-sm">Small</button>
|
||||
</BaseTooltip>
|
||||
<BaseTooltip text="This is a large tooltip with longer text that wraps across multiple lines." size="large" side="bottom">
|
||||
<button class="rounded-lg bg-secondary-background px-4 py-2 text-sm">Large</button>
|
||||
</BaseTooltip>
|
||||
<BaseTooltip text="Undo" keybind="Ctrl+Z" size="small" side="bottom">
|
||||
<button class="rounded-lg bg-secondary-background px-4 py-2 text-sm">With Keybind</button>
|
||||
</BaseTooltip>
|
||||
<BaseTooltip text="More options" :show-icon="true" size="small" side="bottom">
|
||||
<button class="rounded-lg bg-secondary-background px-4 py-2 text-sm">With Icon</button>
|
||||
</BaseTooltip>
|
||||
<BaseTooltip text="Save" keybind="Ctrl+S" :show-icon="true" size="small" side="bottom">
|
||||
<button class="rounded-lg bg-secondary-background px-4 py-2 text-sm">All Features</button>
|
||||
</BaseTooltip>
|
||||
</div>
|
||||
</div>`
|
||||
})
|
||||
}
|
||||
@@ -18,6 +18,8 @@ const {
|
||||
side = 'top',
|
||||
sideOffset = 4,
|
||||
size = 'small',
|
||||
keybind,
|
||||
showIcon = false,
|
||||
delayDuration,
|
||||
disabled = false,
|
||||
class: className
|
||||
@@ -26,6 +28,8 @@ const {
|
||||
side?: 'top' | 'bottom' | 'left' | 'right'
|
||||
sideOffset?: number
|
||||
size?: NonNullable<TooltipVariants['size']>
|
||||
keybind?: string
|
||||
showIcon?: boolean
|
||||
delayDuration?: number
|
||||
disabled?: boolean
|
||||
class?: HTMLAttributes['class']
|
||||
@@ -43,7 +47,23 @@ const {
|
||||
:side-offset="sideOffset"
|
||||
:class="cn(tooltipVariants({ size }), className)"
|
||||
>
|
||||
{{ text }}
|
||||
<span
|
||||
v-if="keybind || (showIcon && size === 'small')"
|
||||
class="inline-flex items-center gap-2"
|
||||
>
|
||||
<span>{{ text }}</span>
|
||||
<i
|
||||
v-if="showIcon && size === 'small'"
|
||||
class="icon-[lucide--chevron-right] size-4 shrink-0"
|
||||
/>
|
||||
<span
|
||||
v-if="keybind"
|
||||
class="shrink-0 rounded-sm bg-interface-menu-keybind-surface-default px-1 text-xs leading-none"
|
||||
>
|
||||
{{ keybind }}
|
||||
</span>
|
||||
</span>
|
||||
<template v-else>{{ text }}</template>
|
||||
<TooltipArrow
|
||||
:width="8"
|
||||
:height="5"
|
||||
|
||||
@@ -2,10 +2,10 @@ import type { VariantProps } from 'cva'
|
||||
import { cva } from 'cva'
|
||||
|
||||
export const tooltipVariants = cva({
|
||||
base: 'z-50 select-none border border-node-component-tooltip-border bg-node-component-tooltip-surface px-4 py-2 text-node-component-tooltip shadow-none',
|
||||
base: 'z-50 select-none border border-node-component-tooltip-border bg-node-component-tooltip-surface px-4 py-2 text-node-component-tooltip shadow-interface',
|
||||
variants: {
|
||||
size: {
|
||||
small: 'rounded-lg text-xs',
|
||||
small: 'rounded-lg text-xs leading-none',
|
||||
large: 'max-w-75 rounded-sm text-sm/tight font-normal'
|
||||
}
|
||||
},
|
||||
@@ -15,3 +15,10 @@ export const tooltipVariants = cva({
|
||||
})
|
||||
|
||||
export type TooltipVariants = VariantProps<typeof tooltipVariants>
|
||||
|
||||
const sizes = ['small', 'large'] as const satisfies Array<
|
||||
TooltipVariants['size']
|
||||
>
|
||||
const sides = ['top', 'bottom', 'left', 'right'] as const
|
||||
|
||||
export const FOR_STORIES = { sizes, sides } as const
|
||||
|
||||
Reference in New Issue
Block a user