Skip to content

Commit b0940b9

Browse files
authored
Merge pull request #3 from borsTiHD/add-preset-stylings
Predefined Styling Presets for Popular UI Frameworks
2 parents ae7b5a1 + 1f0fee1 commit b0940b9

File tree

16 files changed

+684
-66
lines changed

16 files changed

+684
-66
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
- Theme presets: Tooltips can now be globally styled with the "default", "primevue", or "vuetify" presets. Switching themes at runtime is supported.
12+
1013
## [1.2.2] - 2025-10-27
1114

1215
### Fixed

README.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ const app = createApp(App)
5656

5757
// Configure global defaults for all tooltips
5858
app.use(VueCustomTooltip, {
59+
theme: 'default', // or 'vuetify' or 'primevue'
5960
globalConfig: {
6061
position: 'top', // Default position for all tooltips
6162
trigger: 'hover', // Default trigger behavior
@@ -381,6 +382,59 @@ The `v-tooltip` directive is also fully typed when you install the plugin. TypeS
381382
</template>
382383
```
383384

385+
## Theme Presets
386+
387+
Vue Custom Tooltip supports built-in theme presets for easy integration with popular UI frameworks, as well as a default theme:
388+
389+
- **default**: Uses the component's original built-in styles (no extra CSS loaded)
390+
- **primevue**: Styles inspired by PrimeVue's design system
391+
- **vuetify**: Styles inspired by Vuetify's Material Design implementation
392+
393+
You can select a theme globally when registering the plugin:
394+
395+
```typescript
396+
import { VueCustomTooltip } from '@borstihd/vue-custom-tooltip'
397+
import { createApp } from 'vue'
398+
import App from './App.vue'
399+
import '@borstihd/vue-custom-tooltip/dist/style.css'
400+
401+
const app = createApp(App)
402+
403+
// Use a theme preset
404+
app.use(VueCustomTooltip, {
405+
theme: 'primevue' // or 'vuetify' or 'default'
406+
})
407+
408+
// The default theme is used if you omit the theme option:
409+
app.use(VueCustomTooltip) // same as theme: 'default'
410+
411+
app.mount('#app')
412+
```
413+
414+
You can also switch themes at runtime:
415+
416+
```typescript
417+
import { setTooltipGlobalTheme } from '@borstihd/vue-custom-tooltip'
418+
419+
setTooltipGlobalTheme('vuetify') // Switch to Vuetify theme
420+
setTooltipGlobalTheme('default') // Revert to default styles
421+
```
422+
423+
### Customizing Theme Styles
424+
425+
Each theme uses CSS custom properties (variables) for easy customization. You can override these in your global CSS:
426+
427+
```css
428+
:root {
429+
/* Example for PrimeVue theme */
430+
--vct-primevue-background: #1a1a1a;
431+
--vct-primevue-text-color: #fff;
432+
--vct-primevue-border-radius: 8px;
433+
}
434+
```
435+
436+
See the [src/styles/themes/README.md](src/styles/themes/README.md) for a full list of theme variables and instructions for creating your own custom themes.
437+
384438
## Styling
385439

386440
The tooltip uses CSS custom properties for theming. You can customize the appearance by overriding these variables:

THEME_GUIDE.md

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
# Theme Configuration Guide
2+
3+
## Overview
4+
5+
Vue Custom Tooltip supports predefined UI framework themes! You can easily apply PrimeVue or Vuetify styling to all your tooltips with a simple configuration option.
6+
7+
## Available Themes
8+
9+
- **`default`**: The built-in theme using the component's original styles (no additional CSS loaded)
10+
- **`primevue`**: Styles inspired by PrimeVue's design system
11+
- **`vuetify`**: Styles inspired by Vuetify's Material Design implementation
12+
13+
## Basic Usage
14+
15+
### Option 1: Global Theme Configuration
16+
17+
Apply a theme to all tooltips in your application:
18+
19+
```typescript
20+
import { createApp } from 'vue'
21+
import { VueCustomTooltip } from 'vue-custom-tooltip'
22+
import App from './App.vue'
23+
24+
const app = createApp(App)
25+
26+
app.use(VueCustomTooltip, {
27+
theme: 'primevue' // or 'vuetify' or 'default'
28+
})
29+
30+
app.mount('#app')
31+
```
32+
33+
### Option 2: Theme with Global Config
34+
35+
Combine theme styling with global configuration:
36+
37+
```typescript
38+
app.use(VueCustomTooltip, {
39+
theme: 'primevue',
40+
globalConfig: {
41+
position: 'top',
42+
trigger: 'hover',
43+
showDelay: 200,
44+
hideDelay: 150,
45+
dark: 'auto', // Supports auto-detection, true, or false
46+
showArrow: true,
47+
offset: 12,
48+
maxWidth: '300px',
49+
},
50+
})
51+
```
52+
53+
### Option 3: No Theme (Default Styling)
54+
55+
If you don't specify a theme, the default tooltip styling will be used:
56+
57+
```typescript
58+
// These are equivalent
59+
app.use(VueCustomTooltip)
60+
app.use(VueCustomTooltip, { theme: 'default' })
61+
```
62+
63+
## Programmatic Theme Control
64+
65+
You can also change the theme programmatically:
66+
67+
```typescript
68+
import { getTooltipGlobalTheme, setTooltipGlobalTheme } from 'vue-custom-tooltip'
69+
70+
// Change theme at runtime
71+
setTooltipGlobalTheme('vuetify')
72+
73+
// Get current theme
74+
const currentTheme = getTooltipGlobalTheme()
75+
76+
// Revert to default (uses component's built-in styles)
77+
setTooltipGlobalTheme('default')
78+
// or
79+
setTooltipGlobalTheme(undefined)
80+
```
81+
82+
## Theme Features
83+
84+
### Dark Mode Support
85+
86+
All themes automatically support dark mode through:
87+
1. **Auto detection** (`dark: 'auto'`): Responds to Tailwind's `.dark` class or `prefers-color-scheme`
88+
2. **Forced dark mode** (`dark: true`): Always use dark theme
89+
3. **Forced light mode** (`dark: false`): Always use light theme
90+
91+
```typescript
92+
// Auto-detect dark mode
93+
app.use(VueCustomTooltip, {
94+
theme: 'primevue',
95+
globalConfig: {
96+
dark: 'auto', // Default
97+
},
98+
})
99+
100+
// Force dark mode
101+
app.use(VueCustomTooltip, {
102+
theme: 'vuetify',
103+
globalConfig: {
104+
dark: true,
105+
},
106+
})
107+
```
108+
109+
### CSS Custom Properties
110+
111+
Each theme uses CSS custom properties that you can override in your own styles:
112+
113+
```css
114+
/* Override PrimeVue theme colors */
115+
:root {
116+
--vct-primevue-background: #1a1a1a;
117+
--vct-primevue-text-color: #ffffff;
118+
--vct-primevue-border-radius: 8px;
119+
}
120+
121+
/* Override Vuetify theme colors */
122+
:root {
123+
--vct-vuetify-background: rgba(50, 50, 50, 0.95);
124+
--vct-vuetify-text-color: #e0e0e0;
125+
--vct-vuetify-font-family: 'Custom Font', sans-serif;
126+
}
127+
```
128+
129+
## Notes
130+
131+
- Themes are injected as `<style>` elements in the document `<head>`
132+
- Only one theme can be active at a time
133+
- Changing themes at runtime will automatically remove the previous theme styles
134+
- Themes work with both the component API (`<Tooltip>`) and directive API (`v-tooltip`)
135+
- All theme styles respect the tooltip's position, trigger, and other configuration options
136+
137+
## Creating Custom Themes
138+
139+
See [styles/themes/README.md](../src/styles/themes/README.md) for information on creating your own custom themes.

src/App.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<script setup lang="ts">
22
import { ref } from 'vue'
33
import Button from '@/components/Button.vue'
4+
import PresetSwitcher from '@/components/PresetSwitcher.vue'
45
import ThemeToggle from '@/components/ThemeToggle.vue'
56
import TooltipDirectiveBenchmark from '@/components/tooltip/TooltipDirectiveBenchmark.vue'
67
import TooltipDirectiveExample from '@/components/tooltip/TooltipDirectiveExample.vue'
@@ -40,6 +41,7 @@ const githubRepo = packageJson.repository.url.replace('.git', '')
4041
TypeScript
4142
</span>
4243

44+
<PresetSwitcher />
4345
<ThemeToggle />
4446
</div>
4547
</div>

src/components/PresetSwitcher.vue

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<script setup lang="ts">
2+
import type { TooltipTheme } from '@/types/tooltip'
3+
import { ref } from 'vue'
4+
import { getTooltipGlobalTheme, setTooltipGlobalTheme } from '../index'
5+
6+
// Theme switching logic
7+
const themeOptions = [
8+
{ label: 'Default', value: 'default' },
9+
{ label: 'PrimeVue', value: 'primevue' },
10+
{ label: 'Vuetify', value: 'vuetify' },
11+
]
12+
const currentTheme = ref<TooltipTheme>(getTooltipGlobalTheme() || 'default')
13+
async function handleThemeChange(e: Event) {
14+
const value = (e.target as HTMLSelectElement).value as TooltipTheme
15+
setTooltipGlobalTheme(value)
16+
}
17+
</script>
18+
19+
<template>
20+
<div class="relative inline-block">
21+
<label for="theme-switcher" class="sr-only">Tooltip Theme</label>
22+
<select
23+
id="theme-switcher"
24+
v-model="currentTheme"
25+
class="appearance-none flex gap-2 px-2 h-10 items-center rounded-md border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-200 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 pr-8"
26+
@change="handleThemeChange"
27+
>
28+
<option v-for="opt in themeOptions" :key="opt.value" :value="opt.value">
29+
{{ opt.label }}
30+
</option>
31+
</select>
32+
<span class="pointer-events-none absolute right-2 top-1/2 -translate-y-1/2 text-gray-400 dark:text-gray-500">
33+
<svg width="18" height="18" fill="none" viewBox="0 0 20 20">
34+
<path d="M6 8l4 4 4-4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
35+
</svg>
36+
</span>
37+
</div>
38+
</template>

src/components/ThemeToggle.vue

Lines changed: 2 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ watchEffect((onCleanup) => {
6969
<template>
7070
<button
7171
type="button"
72-
class="theme-toggle"
72+
class="flex gap-2 px-4 h-10 items-center rounded-md border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-200 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
7373
:aria-label="`Switch to ${currentTheme === 'light' ? 'dark' : currentTheme === 'dark' ? 'system' : 'light'} mode`"
7474
:title="`Current: ${currentTheme} mode`"
7575
@click="toggleTheme"
@@ -132,47 +132,6 @@ watchEffect((onCleanup) => {
132132
<line x1="12" y1="17" x2="12" y2="21" />
133133
</svg>
134134

135-
<span class="theme-label">{{ currentTheme }}</span>
135+
<span class="capitalize">{{ currentTheme }}</span>
136136
</button>
137137
</template>
138-
139-
<style scoped>
140-
.theme-toggle {
141-
display: flex;
142-
align-items: center;
143-
gap: 0.5rem;
144-
padding: 0.5rem 1rem;
145-
border: 1px solid #e5e7eb;
146-
border-radius: 0.375rem;
147-
background-color: #ffffff;
148-
color: #374151;
149-
cursor: pointer;
150-
transition: all 0.2s ease;
151-
font-size: 0.875rem;
152-
font-weight: 500;
153-
}
154-
155-
.theme-toggle:hover {
156-
background-color: #f9fafb;
157-
border-color: #d1d5db;
158-
}
159-
160-
.theme-toggle:active {
161-
transform: scale(0.98);
162-
}
163-
164-
.dark .theme-toggle {
165-
background-color: #1f2937;
166-
color: #f9fafb;
167-
border-color: #374151;
168-
}
169-
170-
.dark .theme-toggle:hover {
171-
background-color: #374151;
172-
border-color: #4b5563;
173-
}
174-
175-
.theme-label {
176-
text-transform: capitalize;
177-
}
178-
</style>

src/components/tooltip/Tooltip.vue

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ import {
5050
useTooltipProps,
5151
useTooltipVisibility,
5252
} from '../../composables'
53+
import { getTooltipGlobalThemeRef } from '../../config/index'
5354
5455
/**
5556
* Generic Tooltip Component
@@ -159,6 +160,9 @@ const {
159160
// Computed properties
160161
const hasContentSlot = computed(() => !!slots.content)
161162
163+
// Get global theme
164+
const globalTheme = getTooltipGlobalThemeRef()
165+
162166
const tooltipClasses = computed(() => [
163167
'custom-tooltip',
164168
`tooltip-${actualPosition.value}`,
@@ -169,6 +173,8 @@ const tooltipClasses = computed(() => [
169173
'tooltip-light': effectiveDark.value === false,
170174
'tooltip-auto': effectiveDark.value === 'auto',
171175
},
176+
// Only apply theme class if it's not 'default' (default uses component's built-in styles)
177+
globalTheme.value && globalTheme.value !== 'default' ? `tooltip-theme-${globalTheme.value}` : '',
172178
effectiveTooltipClass.value,
173179
])
174180

0 commit comments

Comments
 (0)