Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ export default defineConfig({
{ text: 'Toggle', link: '/docs/components/toggle' },
{ text: 'Toggle Group', link: '/docs/components/toggle-group' },
{ text: 'Toolbar', link: '/docs/components/toolbar' },
{ text: 'Tooltip', link: '/docs/components/tooltip' },
],
},
{
Expand Down
61 changes: 61 additions & 0 deletions docs/components/demo/Tooltip/css/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<script setup lang="ts">
import {
TooltipArrow,
TooltipPopup,
TooltipPortal,
TooltipPositioner,
TooltipProvider,
TooltipRoot,
TooltipTrigger,
} from 'base-ui-vue'
</script>

<template>
<TooltipProvider>
<div class="Panel" aria-label="Formatting controls">
<TooltipRoot>
<TooltipTrigger class="Button" aria-label="Bold">
<span aria-hidden="true" class="Symbol">B</span>
</TooltipTrigger>
<TooltipPortal>
<TooltipPositioner :side-offset="11">
<TooltipPopup class="Popup">
<TooltipArrow class="Arrow" />
Bold
</TooltipPopup>
</TooltipPositioner>
</TooltipPortal>
</TooltipRoot>

<TooltipRoot>
<TooltipTrigger class="Button" aria-label="Italic">
<span aria-hidden="true" class="Symbol Italic">I</span>
</TooltipTrigger>
<TooltipPortal>
<TooltipPositioner :side-offset="11">
<TooltipPopup class="Popup">
<TooltipArrow class="Arrow" />
Italic
</TooltipPopup>
</TooltipPositioner>
</TooltipPortal>
</TooltipRoot>

<TooltipRoot>
<TooltipTrigger class="Button" aria-label="Underline">
<span aria-hidden="true" class="Symbol Underline">U</span>
</TooltipTrigger>
<TooltipPortal>
<TooltipPositioner :side-offset="11">
<TooltipPopup class="Popup">
<TooltipArrow class="Arrow" />
Underline
</TooltipPopup>
</TooltipPositioner>
</TooltipPortal>
</TooltipRoot>
</div>
</TooltipProvider>
</template>

<style src="./styles.css"></style>
121 changes: 121 additions & 0 deletions docs/components/demo/Tooltip/css/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
.Panel {
display: flex;
border: 1px solid var(--color-gray-900);
background-color: var(--color-gray-50);
}

.Button {
box-sizing: border-box;
display: flex;
width: 2rem;
height: 2rem;
align-items: center;
justify-content: center;
margin: 0;
border: 0;
background-color: transparent;
color: var(--color-gray-900);
-webkit-user-select: none;
user-select: none;
}

.Button[data-popup-open] {
background-color: var(--color-gray-100);
}

@media (hover: hover) {
.Button:hover:not([data-trigger-disabled]) {
background-color: var(--color-gray-100);
}
}

.Button:active:not([data-trigger-disabled]) {
background-color: var(--color-gray-200);
}

.Button:focus-visible {
outline: 2px solid var(--color-blue);
outline-offset: -1px;
}

.Symbol {
font-size: 0.875rem;
font-weight: 700;
line-height: 1;
}

.Italic {
font-style: italic;
}

.Underline {
text-decoration: underline;
text-underline-offset: 0.125rem;
}

.Popup {
box-sizing: border-box;
position: relative;
display: flex;
flex-direction: column;
padding: 0.25rem 0.5rem;
border: 1px solid var(--color-gray-900);
background-color: var(--color-gray-50);
color: var(--color-gray-900);
box-shadow: 0.25rem 0.25rem 0 rgb(0 0 0 / 12%);
font-size: 0.875rem;
line-height: 1.25rem;
transform-origin: var(--transform-origin);
transition:
scale 100ms ease-out,
opacity 100ms ease-out;
}

.Popup[data-starting-style],
.Popup[data-ending-style] {
opacity: 0;
scale: 0.98;
}

.Popup[data-instant] {
transition: none;
}

.Arrow {
display: block;
width: 12px;
height: 6px;
overflow: clip;
}

.Arrow[data-side='top'] {
bottom: -6px;
rotate: 180deg;
}

.Arrow[data-side='bottom'] {
top: -6px;
}

.Arrow[data-side='left'] {
right: -9px;
rotate: 90deg;
}

.Arrow[data-side='right'] {
left: -9px;
rotate: -90deg;
}

.Arrow::before {
content: '';
position: absolute;
bottom: 0;
left: 50%;
box-sizing: border-box;
width: calc(6px * sqrt(2));
height: calc(6px * sqrt(2));
border: 1px solid var(--color-gray-900);
background-color: var(--color-gray-50);
transform: translate(-50%, 50%) rotate(45deg);
}
63 changes: 63 additions & 0 deletions docs/components/demo/Tooltip/tailwind/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<script setup lang="ts">
import {
TooltipArrow,
TooltipPopup,
TooltipPortal,
TooltipPositioner,
TooltipProvider,
TooltipRoot,
TooltipTrigger,
} from 'base-ui-vue'

const triggerClass = 'flex size-8 items-center justify-center border-0 bg-transparent text-sm font-bold leading-none text-gray-900 select-none data-popup-open:bg-gray-100 hover:bg-gray-100 active:bg-gray-200 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-blue dark:text-gray-900'
const popupClass = 'relative flex flex-col border border-gray-900 bg-gray-50 px-2 py-1 text-sm leading-5 text-gray-900 origin-(--transform-origin) shadow-[0.25rem_0.25rem_0] shadow-black/12 transition-[scale,opacity] duration-100 ease-out data-ending-style:scale-[0.98] data-ending-style:opacity-0 data-instant:transition-none data-starting-style:scale-[0.98] data-starting-style:opacity-0'
const arrowClass = 'block h-1.5 w-3 overflow-clip data-[side=bottom]:top-[-6px] data-[side=left]:right-[-9px] data-[side=left]:rotate-90 data-[side=right]:left-[-9px] data-[side=right]:-rotate-90 data-[side=top]:bottom-[-6px] data-[side=top]:rotate-180 before:absolute before:bottom-0 before:left-1/2 before:h-[calc(6px*sqrt(2))] before:w-[calc(6px*sqrt(2))] before:border before:border-gray-900 before:bg-gray-50 before:content-[\'\'] before:[transform:translate(-50%,50%)_rotate(45deg)]'
</script>

<template>
<TooltipProvider>
<div class="flex border border-gray-900 bg-gray-50" aria-label="Formatting controls">
<TooltipRoot>
<TooltipTrigger :class="triggerClass" aria-label="Bold">
<span aria-hidden="true">B</span>
</TooltipTrigger>
<TooltipPortal>
<TooltipPositioner :side-offset="11">
<TooltipPopup :class="popupClass">
<TooltipArrow :class="arrowClass" />
Bold
</TooltipPopup>
</TooltipPositioner>
</TooltipPortal>
</TooltipRoot>

<TooltipRoot>
<TooltipTrigger :class="triggerClass" aria-label="Italic">
<span aria-hidden="true" class="italic">I</span>
</TooltipTrigger>
<TooltipPortal>
<TooltipPositioner :side-offset="11">
<TooltipPopup :class="popupClass">
<TooltipArrow :class="arrowClass" />
Italic
</TooltipPopup>
</TooltipPositioner>
</TooltipPortal>
</TooltipRoot>

<TooltipRoot>
<TooltipTrigger :class="triggerClass" aria-label="Underline">
<span aria-hidden="true" class="underline underline-offset-2">U</span>
</TooltipTrigger>
<TooltipPortal>
<TooltipPositioner :side-offset="11">
<TooltipPopup :class="popupClass">
<TooltipArrow :class="arrowClass" />
Underline
</TooltipPopup>
</TooltipPositioner>
</TooltipPortal>
</TooltipRoot>
</div>
</TooltipProvider>
</template>
78 changes: 78 additions & 0 deletions docs/components/demo/TooltipControlled/css/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<script setup lang="ts">
import type { TooltipRootChangeEventDetails } from 'base-ui-vue'
import {
createTooltipHandle,
TooltipArrow,
TooltipPopup,
TooltipPortal,
TooltipPositioner,
TooltipProvider,
TooltipRoot,
TooltipTrigger,
} from 'base-ui-vue'
import { shallowRef } from 'vue'

const tooltip = createTooltipHandle()
const open = shallowRef(false)
const triggerId = shallowRef<string | null>(null)

function handleOpenChange(nextOpen: boolean, details: TooltipRootChangeEventDetails) {
open.value = nextOpen
triggerId.value = details.trigger?.id ?? null
}

function openTimerTrigger() {
triggerId.value = 'trigger-2'
open.value = true
}
</script>

<template>
<TooltipProvider>
<div class="Container">
<div class="ButtonGroup">
<TooltipTrigger id="trigger-1" :handle="tooltip" class="IconButton" aria-label="Trigger 1">
<svg class="Icon" width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" d="M1.5 11V7.5c0-2.5 2.5-6 6.5-6s6.5 3.5 6.5 6V11" />
<path d="M12 7.5c1.3807 0 2.5 1.11929 2.5 2.5v2c0 1.3807-1.1193 2.5-2.5 2.5h-1.5v-7zm-8 0h1.5v7H4c-1.38071 0-2.5-1.1193-2.5-2.5v-2c0-1.38071 1.11929-2.5 2.5-2.5Z" />
</svg>
</TooltipTrigger>
<TooltipTrigger id="trigger-2" :handle="tooltip" class="IconButton" aria-label="Trigger 2">
<svg class="Icon" width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" aria-hidden="true">
<circle cx="8" cy="8.5" r="6" />
<path stroke-linecap="square" stroke-linejoin="round" d="M8 9.5v-5m0-2v-2m-2 0h4M12 4l1.5-1.5" />
</svg>
</TooltipTrigger>
<TooltipTrigger id="trigger-3" :handle="tooltip" class="IconButton" aria-label="Trigger 3">
<svg class="Icon" width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-linejoin="round" aria-hidden="true">
<path stroke-linecap="square" d="M2.5 4h11" />
<path stroke-linecap="round" d="M6.5 4V3c0-.82843.67157-1.5 1.5-1.5S9.5 2.17157 9.5 3v1" />
<path stroke-linecap="square" d="m3.5 4 .87069 9.1422c.07332.7699.7199 1.3578 1.49324 1.3578h4.27217c.7733 0 1.4199-.5879 1.4932-1.3578L12.5 4" />
</svg>
</TooltipTrigger>
</div>

<button type="button" class="ActionButton" @click="openTimerTrigger">
Open programmatically
</button>
</div>

<TooltipRoot
:handle="tooltip"
:open="open"
:trigger-id="triggerId"
@open-change="handleOpenChange"
>
<TooltipPortal>
<TooltipPositioner :side-offset="11" class="Positioner">
<TooltipPopup class="Popup">
<TooltipArrow class="Arrow" />
Controlled tooltip
</TooltipPopup>
</TooltipPositioner>
</TooltipPortal>
</TooltipRoot>
</TooltipProvider>
</template>

<style src="./styles.css"></style>
56 changes: 56 additions & 0 deletions docs/components/demo/TooltipControlled/css/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
@import "../../TooltipDetached/css/styles.css";

.Container {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 0.5rem;
}

.ButtonGroup {
display: flex;
}

.IconButton:not(:first-child) {
border-left: 0;
}

.Positioner {
width: var(--positioner-width);
height: var(--positioner-height);
max-width: var(--available-width);
}

.ActionButton {
box-sizing: border-box;
display: flex;
height: 2rem;
align-items: center;
justify-content: center;
margin: 0;
padding: 0 0.75rem;
border: 1px solid var(--color-gray-900);
background-color: var(--color-gray-50);
color: var(--color-gray-900);
font-family: inherit;
font-size: 0.875rem;
line-height: 1;
white-space: nowrap;
-webkit-user-select: none;
user-select: none;
}

@media (hover: hover) {
.ActionButton:hover {
background-color: var(--color-gray-100);
}
}

.ActionButton:active {
background-color: var(--color-gray-200);
}

.ActionButton:focus-visible {
outline: 2px solid var(--color-blue);
outline-offset: -1px;
}
Loading
Loading