wally-ui 1.11.1 → 1.12.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/dist/cli.js +7 -0
- package/dist/cli.js.map +1 -1
- package/package.json +4 -2
- package/playground/showcase/public/sitemap.xml +32 -0
- package/playground/showcase/src/app/app.routes.server.ts +8 -0
- package/playground/showcase/src/app/components/ai/ai-chat/ai-chat.css +0 -0
- package/playground/showcase/src/app/components/ai/ai-chat/ai-chat.html +5 -0
- package/playground/showcase/src/app/components/ai/ai-chat/ai-chat.spec.ts +23 -0
- package/playground/showcase/src/app/components/ai/ai-chat/ai-chat.ts +17 -0
- package/playground/showcase/src/app/components/ai/ai-composer/ai-composer.css +0 -0
- package/playground/showcase/src/app/components/ai/ai-composer/ai-composer.html +69 -0
- package/playground/showcase/src/app/components/ai/ai-composer/ai-composer.spec.ts +23 -0
- package/playground/showcase/src/app/components/ai/ai-composer/ai-composer.ts +19 -0
- package/playground/showcase/src/app/components/ai/ai-prompt-input/ai-prompt-input.css +0 -0
- package/playground/showcase/src/app/components/ai/ai-prompt-input/ai-prompt-input.html +10 -0
- package/playground/showcase/src/app/components/ai/ai-prompt-input/ai-prompt-input.spec.ts +23 -0
- package/playground/showcase/src/app/components/ai/ai-prompt-input/ai-prompt-input.ts +25 -0
- package/playground/showcase/src/app/components/button/button.html +5 -1
- package/playground/showcase/src/app/components/button/button.ts +1 -0
- package/playground/showcase/src/app/components/carousel/carousel.html +1 -33
- package/playground/showcase/src/app/components/carousel/carousel.ts +199 -251
- package/playground/showcase/src/app/components/tooltip/tooltip.css +0 -0
- package/playground/showcase/src/app/components/tooltip/tooltip.html +9 -0
- package/playground/showcase/src/app/components/tooltip/tooltip.ts +189 -0
- package/playground/showcase/src/app/pages/documentation/chat-sdk/chat-sdk.html +99 -0
- package/playground/showcase/src/app/pages/documentation/chat-sdk/chat-sdk.ts +20 -0
- package/playground/showcase/src/app/pages/documentation/components/components.html +23 -0
- package/playground/showcase/src/app/pages/documentation/components/components.routes.ts +4 -0
- package/playground/showcase/src/app/pages/documentation/components/tooltip-docs/tooltip-docs.css +1 -0
- package/playground/showcase/src/app/pages/documentation/components/tooltip-docs/tooltip-docs.examples.ts +150 -0
- package/playground/showcase/src/app/pages/documentation/components/tooltip-docs/tooltip-docs.html +471 -0
- package/playground/showcase/src/app/pages/documentation/components/tooltip-docs/tooltip-docs.ts +69 -0
- package/playground/showcase/src/app/pages/documentation/documentation.routes.ts +4 -0
- package/playground/showcase/src/app/pages/home/home.html +26 -0
- package/playground/showcase/src/app/pages/home/home.ts +3 -2
- package/playground/showcase/src/index.html +7 -4
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { Component, computed, effect, ElementRef, input, InputSignal, OnDestroy, signal, ViewChild, WritableSignal } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
|
|
4
|
+
type TooltipPosition = 'top' | 'bottom' | 'left' | 'right' | 'auto';
|
|
5
|
+
|
|
6
|
+
@Component({
|
|
7
|
+
selector: 'wally-tooltip',
|
|
8
|
+
imports: [CommonModule],
|
|
9
|
+
templateUrl: './tooltip.html',
|
|
10
|
+
styleUrl: './tooltip.css'
|
|
11
|
+
})
|
|
12
|
+
export class Tooltip implements OnDestroy {
|
|
13
|
+
@ViewChild('tooltipElement', { read: ElementRef }) tooltipElement?: ElementRef<HTMLDivElement>;
|
|
14
|
+
|
|
15
|
+
text: InputSignal<string> = input.required<string>();
|
|
16
|
+
position: InputSignal<TooltipPosition> = input<TooltipPosition>('auto');
|
|
17
|
+
delay: InputSignal<number> = input<number>(200);
|
|
18
|
+
disabled: InputSignal<boolean> = input<boolean>(false);
|
|
19
|
+
offset: InputSignal<number> = input<number>(2);
|
|
20
|
+
|
|
21
|
+
visible: WritableSignal<boolean> = signal<boolean>(false);
|
|
22
|
+
actualPosition = signal<Exclude<TooltipPosition, 'auto'>>('top');
|
|
23
|
+
tooltipId = `tooltip-${Math.random().toString(36).substr(2, 9)}`;
|
|
24
|
+
|
|
25
|
+
private showTimeout?: number;
|
|
26
|
+
private hideTimeout?: number;
|
|
27
|
+
|
|
28
|
+
tooltipClasses = computed(() => {
|
|
29
|
+
const base = 'absolute z-50 py-1.5 px-3 text-sm text-white bg-[#121212] shadow-lg whitespace-nowrap pointer-events-none rounded-xl';
|
|
30
|
+
const darkMode = 'dark:bg-white dark:text-[#121212]';
|
|
31
|
+
|
|
32
|
+
const positions = {
|
|
33
|
+
top: `bottom-full left-1/2 -translate-x-1/2 mb-${this.offset()}`,
|
|
34
|
+
bottom: `top-full left-1/2 -translate-x-1/2 mt-${this.offset()}`,
|
|
35
|
+
left: `right-full top-1/2 -translate-y-1/2 mr-${this.offset()}`,
|
|
36
|
+
right: `left-full top-1/2 -translate-y-1/2 ml-${this.offset()}`
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// Animação super suave - apenas fade rápido
|
|
40
|
+
const animation = this.visible()
|
|
41
|
+
? 'transition-opacity duration-150 opacity-100'
|
|
42
|
+
: 'transition-opacity duration-100 opacity-0';
|
|
43
|
+
|
|
44
|
+
return `${base} ${darkMode} ${positions[this.actualPosition()]} ${animation}`;
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
constructor(
|
|
48
|
+
private elementRef: ElementRef
|
|
49
|
+
) {
|
|
50
|
+
effect(() => {
|
|
51
|
+
if (this.visible() && this.position() === 'auto') {
|
|
52
|
+
setTimeout(() => this.calculateBestPosition(), 10);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
ngOnDestroy() {
|
|
58
|
+
if (this.showTimeout) {
|
|
59
|
+
window.clearTimeout(this.showTimeout);
|
|
60
|
+
}
|
|
61
|
+
if (this.hideTimeout) {
|
|
62
|
+
window.clearTimeout(this.hideTimeout);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
show(): void {
|
|
67
|
+
if (this.disabled()) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (this.hideTimeout) {
|
|
72
|
+
window.clearTimeout(this.hideTimeout);
|
|
73
|
+
this.hideTimeout = undefined;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
this.showTimeout = window.setTimeout(() => {
|
|
77
|
+
this.visible.set(true);
|
|
78
|
+
|
|
79
|
+
if (this.position() !== 'auto') {
|
|
80
|
+
this.actualPosition.set(this.position() as Exclude<TooltipPosition, 'auto'>);
|
|
81
|
+
}
|
|
82
|
+
}, this.delay());
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
hide(): void {
|
|
86
|
+
if (this.showTimeout) {
|
|
87
|
+
window.clearTimeout(this.showTimeout);
|
|
88
|
+
this.showTimeout = undefined;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
this.hideTimeout = window.setTimeout(() => {
|
|
92
|
+
this.visible.set(false);
|
|
93
|
+
}, 100);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
private calculateBestPosition() {
|
|
97
|
+
const hostElement =
|
|
98
|
+
this.elementRef.nativeElement.querySelector('.tooltip-wrapper');
|
|
99
|
+
if (!hostElement) return;
|
|
100
|
+
|
|
101
|
+
const rect = hostElement.getBoundingClientRect();
|
|
102
|
+
const tooltipEl = this.tooltipElement?.nativeElement;
|
|
103
|
+
if (!tooltipEl) return;
|
|
104
|
+
|
|
105
|
+
const tooltipRect = tooltipEl.getBoundingClientRect();
|
|
106
|
+
const offset = this.offset();
|
|
107
|
+
|
|
108
|
+
const viewportWidth = window.innerWidth;
|
|
109
|
+
const viewportHeight = window.innerHeight;
|
|
110
|
+
|
|
111
|
+
const spaceAbove = rect.top;
|
|
112
|
+
const spaceBelow = viewportHeight - rect.bottom;
|
|
113
|
+
const spaceLeft = rect.left;
|
|
114
|
+
const spaceRight = viewportWidth - rect.right;
|
|
115
|
+
|
|
116
|
+
const tooltipWidth = tooltipRect.width || 150;
|
|
117
|
+
const tooltipHeight = tooltipRect.height || 40;
|
|
118
|
+
|
|
119
|
+
const positions: {
|
|
120
|
+
position: Exclude<TooltipPosition, 'auto'>; space: number; isValid: boolean}[] = [
|
|
121
|
+
{
|
|
122
|
+
position: 'top',
|
|
123
|
+
space: spaceAbove,
|
|
124
|
+
isValid: spaceAbove >= tooltipHeight + offset
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
position: 'bottom',
|
|
128
|
+
space: spaceBelow,
|
|
129
|
+
isValid: spaceBelow >= tooltipHeight + offset
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
position: 'left',
|
|
133
|
+
space: spaceLeft,
|
|
134
|
+
isValid: spaceLeft >= tooltipWidth + offset
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
position: 'right',
|
|
138
|
+
space: spaceRight,
|
|
139
|
+
isValid: spaceRight >= tooltipWidth + offset
|
|
140
|
+
}
|
|
141
|
+
];
|
|
142
|
+
|
|
143
|
+
const priorityOrder: Exclude<TooltipPosition, 'auto'>[] = ['top', 'bottom', 'right', 'left'];
|
|
144
|
+
|
|
145
|
+
let bestPosition: Exclude<TooltipPosition, 'auto'> = 'top';
|
|
146
|
+
|
|
147
|
+
for (const preferred of priorityOrder) {
|
|
148
|
+
const pos = positions.find(p => p.position === preferred);
|
|
149
|
+
if (pos?.isValid) {
|
|
150
|
+
bestPosition = preferred;
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (!positions.find(p => p.position ===
|
|
156
|
+
bestPosition)?.isValid) {
|
|
157
|
+
const maxSpace = positions.reduce((max, pos) => pos.space >
|
|
158
|
+
max.space ? pos : max, positions[0]);
|
|
159
|
+
bestPosition = maxSpace.position;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
this.actualPosition.set(bestPosition);
|
|
163
|
+
|
|
164
|
+
setTimeout(() => {
|
|
165
|
+
const updatedTooltipRect = tooltipEl.getBoundingClientRect();
|
|
166
|
+
const padding = 8;
|
|
167
|
+
|
|
168
|
+
if (bestPosition === 'top' || bestPosition === 'bottom') {
|
|
169
|
+
if (updatedTooltipRect.left < padding) {
|
|
170
|
+
const shift = padding - updatedTooltipRect.left;
|
|
171
|
+
tooltipEl.style.transform = `translateX(${shift}px)`;
|
|
172
|
+
} else if (updatedTooltipRect.right > viewportWidth - padding) {
|
|
173
|
+
const shift = (viewportWidth - padding) - updatedTooltipRect.right;
|
|
174
|
+
tooltipEl.style.transform = `translateX(${shift}px)`;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (bestPosition === 'left' || bestPosition === 'right') {
|
|
179
|
+
if (updatedTooltipRect.top < padding) {
|
|
180
|
+
const shift = padding - updatedTooltipRect.top;
|
|
181
|
+
tooltipEl.style.transform = `translateY(${shift}px)`;
|
|
182
|
+
} else if (updatedTooltipRect.bottom > viewportHeight - padding) {
|
|
183
|
+
const shift = (viewportHeight - padding) - updatedTooltipRect.bottom;
|
|
184
|
+
tooltipEl.style.transform = `translateY(${shift}px)`;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}, 0);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
<main class="min-h-dvh bg-white dark:bg-[#0a0a0a] font-mono" role="main">
|
|
2
|
+
<div class="max-w-4xl mx-auto px-4 py-8 sm:px-6 md:px-8">
|
|
3
|
+
|
|
4
|
+
<!-- Breadcrumb Navigation -->
|
|
5
|
+
<nav class="mb-8" aria-label="Breadcrumb navigation">
|
|
6
|
+
<wally-breadcrumb [items]="breadcrumbItems"></wally-breadcrumb>
|
|
7
|
+
</nav>
|
|
8
|
+
|
|
9
|
+
<!-- Header -->
|
|
10
|
+
<header class="mb-12" role="banner">
|
|
11
|
+
<div class="flex items-center gap-3 mb-4">
|
|
12
|
+
<h1 id="page-title" class="text-3xl sm:text-4xl font-bold text-[#0a0a0a] dark:text-white uppercase">
|
|
13
|
+
<span aria-hidden="true">>_ </span>Chat SDK
|
|
14
|
+
</h1>
|
|
15
|
+
<span class="text-[10px] font-bold bg-blue-500 text-white px-2 py-1 uppercase tracking-wider" aria-label="Status: Coming Soon">
|
|
16
|
+
COMING SOON
|
|
17
|
+
</span>
|
|
18
|
+
</div>
|
|
19
|
+
<p class="text-sm sm:text-base text-neutral-700 dark:text-neutral-300 border-l-2 border-neutral-300 dark:border-neutral-700 pl-4 leading-relaxed">
|
|
20
|
+
Complete chat development SDK with AI interface, message matrix navigation, streaming data service, and full visual customization using Wally UI components.
|
|
21
|
+
</p>
|
|
22
|
+
</header>
|
|
23
|
+
|
|
24
|
+
<!-- Live Demo -->
|
|
25
|
+
<section id="live-demo" class="mb-12" aria-labelledby="demo-heading">
|
|
26
|
+
<h2 id="demo-heading" class="text-[10px] sm:text-xs text-neutral-500 dark:text-neutral-500 uppercase tracking-wider mb-4">
|
|
27
|
+
[ Live Demo ]
|
|
28
|
+
</h2>
|
|
29
|
+
<div class="bg-white dark:bg-[#0a0a0a] border-2 border-neutral-300 dark:border-neutral-700 p-6">
|
|
30
|
+
<wally-ai-chat></wally-ai-chat>
|
|
31
|
+
</div>
|
|
32
|
+
</section>
|
|
33
|
+
|
|
34
|
+
<!-- Features Overview -->
|
|
35
|
+
<section id="features" class="mb-12" aria-labelledby="features-heading">
|
|
36
|
+
<h2 id="features-heading" class="text-[10px] sm:text-xs text-neutral-500 dark:text-neutral-500 uppercase tracking-wider mb-4">
|
|
37
|
+
[ Features Overview ]
|
|
38
|
+
</h2>
|
|
39
|
+
|
|
40
|
+
<div class="space-y-4">
|
|
41
|
+
<article class="bg-neutral-100 dark:bg-[#121212] border border-neutral-300 dark:border-neutral-700 p-4">
|
|
42
|
+
<h3 class="text-sm sm:text-base font-bold text-[#0a0a0a] dark:text-white mb-2 uppercase">
|
|
43
|
+
<span aria-hidden="true">> </span>Message Matrix Navigation
|
|
44
|
+
</h3>
|
|
45
|
+
<p class="text-xs sm:text-sm text-neutral-600 dark:text-neutral-400 leading-relaxed">
|
|
46
|
+
Advanced conversation branching with matrix-style navigation. Track multiple AI responses (ai: 1/2, 1/3) and user messages (me: 1/1) with intuitive side-to-side navigation between conversation branches.
|
|
47
|
+
</p>
|
|
48
|
+
</article>
|
|
49
|
+
|
|
50
|
+
<article class="bg-neutral-100 dark:bg-[#121212] border border-neutral-300 dark:border-neutral-700 p-4">
|
|
51
|
+
<h3 class="text-sm sm:text-base font-bold text-[#0a0a0a] dark:text-white mb-2 uppercase">
|
|
52
|
+
<span aria-hidden="true">> </span>Streaming Data Service
|
|
53
|
+
</h3>
|
|
54
|
+
<p class="text-xs sm:text-sm text-neutral-600 dark:text-neutral-400 leading-relaxed">
|
|
55
|
+
Enterprise-grade streaming service for real-time AI responses. Handles SSE (Server-Sent Events), WebSocket connections, and progressive message rendering with automatic retry logic.
|
|
56
|
+
</p>
|
|
57
|
+
</article>
|
|
58
|
+
|
|
59
|
+
<article class="bg-neutral-100 dark:bg-[#121212] border border-neutral-300 dark:border-neutral-700 p-4">
|
|
60
|
+
<h3 class="text-sm sm:text-base font-bold text-[#0a0a0a] dark:text-white mb-2 uppercase">
|
|
61
|
+
<span aria-hidden="true">> </span>Wally UI Components
|
|
62
|
+
</h3>
|
|
63
|
+
<p class="text-xs sm:text-sm text-neutral-600 dark:text-neutral-400 leading-relaxed">
|
|
64
|
+
Built entirely with Wally UI components: AI Composer for message input, AI Prompt Input with auto-resize, custom scrollbars, and complete dark mode support. Fully accessible and SSR-ready.
|
|
65
|
+
</p>
|
|
66
|
+
</article>
|
|
67
|
+
|
|
68
|
+
<article class="bg-neutral-100 dark:bg-[#121212] border border-neutral-300 dark:border-neutral-700 p-4">
|
|
69
|
+
<h3 class="text-sm sm:text-base font-bold text-[#0a0a0a] dark:text-white mb-2 uppercase">
|
|
70
|
+
<span aria-hidden="true">> </span>Visual Customization
|
|
71
|
+
</h3>
|
|
72
|
+
<p class="text-xs sm:text-sm text-neutral-600 dark:text-neutral-400 leading-relaxed">
|
|
73
|
+
Complete visual control over chat interface: message bubbles, avatars, timestamps, typing indicators, and markdown rendering. All styles customizable via Tailwind CSS classes.
|
|
74
|
+
</p>
|
|
75
|
+
</article>
|
|
76
|
+
</div>
|
|
77
|
+
</section>
|
|
78
|
+
|
|
79
|
+
<!-- Coming Soon Notice -->
|
|
80
|
+
<section id="status" class="mb-12" aria-labelledby="status-heading">
|
|
81
|
+
<h2 id="status-heading" class="text-[10px] sm:text-xs text-neutral-500 dark:text-neutral-500 uppercase tracking-wider mb-3">
|
|
82
|
+
[ Development Status ]
|
|
83
|
+
</h2>
|
|
84
|
+
<div class="bg-neutral-100 dark:bg-[#121212] border-2 border-neutral-300 dark:border-neutral-700 p-4">
|
|
85
|
+
<p class="text-xs sm:text-sm text-neutral-700 dark:text-neutral-300 leading-relaxed mb-3">
|
|
86
|
+
The Chat SDK is currently in active development. The demo above shows the current progress with the AI Composer component. Full release will include:
|
|
87
|
+
</p>
|
|
88
|
+
<ul class="text-xs sm:text-sm text-neutral-600 dark:text-neutral-400 space-y-2 ml-4">
|
|
89
|
+
<li><span aria-hidden="true">▸ </span>Complete message matrix implementation</li>
|
|
90
|
+
<li><span aria-hidden="true">▸ </span>Streaming data service with retry logic</li>
|
|
91
|
+
<li><span aria-hidden="true">▸ </span>Full chat history and conversation management</li>
|
|
92
|
+
<li><span aria-hidden="true">▸ </span>Markdown rendering with code syntax highlighting</li>
|
|
93
|
+
<li><span aria-hidden="true">▸ </span>Installation via CLI: <span class="bg-neutral-200 dark:bg-neutral-800 px-2 py-1 rounded">npx wally-ui add chat-sdk</span></li>
|
|
94
|
+
</ul>
|
|
95
|
+
</div>
|
|
96
|
+
</section>
|
|
97
|
+
|
|
98
|
+
</div>
|
|
99
|
+
</main>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
import { Breadcrumb, BreadcrumbItem } from '../../../components/breadcrumb/breadcrumb';
|
|
4
|
+
import { AiChat } from '../../../components/ai/ai-chat/ai-chat';
|
|
5
|
+
|
|
6
|
+
@Component({
|
|
7
|
+
selector: 'app-chat-sdk',
|
|
8
|
+
imports: [
|
|
9
|
+
Breadcrumb,
|
|
10
|
+
AiChat
|
|
11
|
+
],
|
|
12
|
+
templateUrl: './chat-sdk.html'
|
|
13
|
+
})
|
|
14
|
+
export class ChatSdk {
|
|
15
|
+
breadcrumbItems: BreadcrumbItem[] = [
|
|
16
|
+
{ label: 'Home', url: '/' },
|
|
17
|
+
{ label: 'Documentation', url: '/documentation' },
|
|
18
|
+
{ label: 'Chat SDK' }
|
|
19
|
+
];
|
|
20
|
+
}
|
|
@@ -128,6 +128,29 @@
|
|
|
128
128
|
</a>
|
|
129
129
|
</article>
|
|
130
130
|
|
|
131
|
+
<!-- Tooltip Component -->
|
|
132
|
+
<article class="group border-b-2 border-neutral-300 dark:border-neutral-700 last:border-b-0" role="article" aria-labelledby="tooltip-heading">
|
|
133
|
+
<a href="/documentation/components/tooltip"
|
|
134
|
+
class="block px-4 py-4 sm:py-5 bg-white dark:bg-[#0a0a0a] hover:bg-[#0a0a0a] dark:hover:bg-white transition-all duration-150 cursor-pointer"
|
|
135
|
+
aria-label="Navigate to Tooltip component documentation with smart auto-positioning, overflow detection, and accessibility features">
|
|
136
|
+
<div class="flex flex-col sm:flex-row sm:items-start sm:justify-between gap-3">
|
|
137
|
+
<div class="flex-1">
|
|
138
|
+
<div class="flex items-center gap-3 mb-2">
|
|
139
|
+
<h3 id="tooltip-heading" class="text-base sm:text-lg font-bold text-[#0a0a0a] dark:text-white group-hover:text-white dark:group-hover:text-[#0a0a0a] uppercase tracking-wide transition-colors duration-150">
|
|
140
|
+
<span aria-hidden="true">>_ </span>Tooltip
|
|
141
|
+
</h3>
|
|
142
|
+
<span class="text-[10px] font-bold bg-blue-500 text-white px-2 py-1 uppercase tracking-wider" aria-label="Status: New Component">
|
|
143
|
+
NEW
|
|
144
|
+
</span>
|
|
145
|
+
</div>
|
|
146
|
+
<p class="text-xs sm:text-sm text-neutral-600 dark:text-neutral-400 group-hover:text-neutral-300 dark:group-hover:text-neutral-600 transition-colors duration-150">
|
|
147
|
+
Smart tooltip with auto-positioning, overflow detection, smooth animations, and arrow indicator. Wraps any element with full ARIA support and keyboard navigation. Rich content support coming in v2.0.
|
|
148
|
+
</p>
|
|
149
|
+
</div>
|
|
150
|
+
</div>
|
|
151
|
+
</a>
|
|
152
|
+
</article>
|
|
153
|
+
|
|
131
154
|
</div>
|
|
132
155
|
</section>
|
|
133
156
|
|
|
@@ -20,5 +20,9 @@ export const componentsRoutes: Routes = [
|
|
|
20
20
|
{
|
|
21
21
|
path: 'carousel',
|
|
22
22
|
loadComponent: () => import('./carousel-docs/carousel-docs').then(m => m.CarouselDocs)
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
path: 'tooltip',
|
|
26
|
+
loadComponent: () => import('./tooltip-docs/tooltip-docs').then(m => m.TooltipDocs)
|
|
23
27
|
}
|
|
24
28
|
];
|
package/playground/showcase/src/app/pages/documentation/components/tooltip-docs/tooltip-docs.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/* Tooltip documentation styles - Retro terminal theme */
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
export const TooltipCodeExamples = {
|
|
2
|
+
installation: `npx wally-ui add tooltip`,
|
|
3
|
+
|
|
4
|
+
import: `// app.component.ts or your module file
|
|
5
|
+
import { Tooltip } from './components/tooltip/tooltip';`,
|
|
6
|
+
|
|
7
|
+
componentImport: `@Component({
|
|
8
|
+
selector: 'app-root',
|
|
9
|
+
imports: [Tooltip],
|
|
10
|
+
// ...
|
|
11
|
+
})`,
|
|
12
|
+
|
|
13
|
+
basicUsage: `<wally-tooltip text="This is a tooltip">
|
|
14
|
+
<button>Hover me</button>
|
|
15
|
+
</wally-tooltip>`,
|
|
16
|
+
|
|
17
|
+
positions: `<!-- Auto positioning (default) -->
|
|
18
|
+
<wally-tooltip text="Auto positioned" position="auto">
|
|
19
|
+
<button>Auto</button>
|
|
20
|
+
</wally-tooltip>
|
|
21
|
+
|
|
22
|
+
<!-- Fixed positions -->
|
|
23
|
+
<wally-tooltip text="Always on top" position="top">
|
|
24
|
+
<button>Top</button>
|
|
25
|
+
</wally-tooltip>
|
|
26
|
+
|
|
27
|
+
<wally-tooltip text="Always on bottom" position="bottom">
|
|
28
|
+
<button>Bottom</button>
|
|
29
|
+
</wally-tooltip>
|
|
30
|
+
|
|
31
|
+
<wally-tooltip text="Always on left" position="left">
|
|
32
|
+
<button>Left</button>
|
|
33
|
+
</wally-tooltip>
|
|
34
|
+
|
|
35
|
+
<wally-tooltip text="Always on right" position="right">
|
|
36
|
+
<button>Right</button>
|
|
37
|
+
</wally-tooltip>`,
|
|
38
|
+
|
|
39
|
+
withButton: `<wally-tooltip text="Save your changes">
|
|
40
|
+
<wally-button variant="primary">Save</wally-button>
|
|
41
|
+
</wally-tooltip>`,
|
|
42
|
+
|
|
43
|
+
withIcon: `<wally-tooltip text="Send message">
|
|
44
|
+
<wally-button [variant]="'ghost'" [rounded]="true" ariaLabel="Send">
|
|
45
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-5">
|
|
46
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M6 12 3.269 3.125A59.769 59.769 0 0 1 21.485 12 59.768 59.768 0 0 1 3.27 20.875L5.999 12Zm0 0h7.5" />
|
|
47
|
+
</svg>
|
|
48
|
+
</wally-button>
|
|
49
|
+
</wally-tooltip>`,
|
|
50
|
+
|
|
51
|
+
customDelay: `<!-- Fast tooltip (100ms) -->
|
|
52
|
+
<wally-tooltip text="Quick tooltip" [delay]="100">
|
|
53
|
+
<button>Fast</button>
|
|
54
|
+
</wally-tooltip>
|
|
55
|
+
|
|
56
|
+
<!-- Slow tooltip (500ms) -->
|
|
57
|
+
<wally-tooltip text="Delayed tooltip" [delay]="500">
|
|
58
|
+
<button>Slow</button>
|
|
59
|
+
</wally-tooltip>`,
|
|
60
|
+
|
|
61
|
+
disabled: `<wally-tooltip text="This won't show" [disabled]="true">
|
|
62
|
+
<button>Disabled Tooltip</button>
|
|
63
|
+
</wally-tooltip>`,
|
|
64
|
+
|
|
65
|
+
customOffset: `<!-- More spacing from element -->
|
|
66
|
+
<wally-tooltip text="More space" [offset]="4">
|
|
67
|
+
<button>Large offset</button>
|
|
68
|
+
</wally-tooltip>
|
|
69
|
+
|
|
70
|
+
<!-- Less spacing from element -->
|
|
71
|
+
<wally-tooltip text="Close" [offset]="1">
|
|
72
|
+
<button>Small offset</button>
|
|
73
|
+
</wally-tooltip>`,
|
|
74
|
+
|
|
75
|
+
dashboard: `<!-- Toolbar with tooltips -->
|
|
76
|
+
<div class="flex gap-2">
|
|
77
|
+
<wally-tooltip text="Export data to CSV">
|
|
78
|
+
<wally-button variant="outline" ariaLabel="Export">
|
|
79
|
+
<svg class="size-5"><!-- Export icon --></svg>
|
|
80
|
+
</wally-button>
|
|
81
|
+
</wally-tooltip>
|
|
82
|
+
|
|
83
|
+
<wally-tooltip text="Refresh dashboard">
|
|
84
|
+
<wally-button variant="outline" ariaLabel="Refresh">
|
|
85
|
+
<svg class="size-5"><!-- Refresh icon --></svg>
|
|
86
|
+
</wally-button>
|
|
87
|
+
</wally-tooltip>
|
|
88
|
+
|
|
89
|
+
<wally-tooltip text="Settings">
|
|
90
|
+
<wally-button variant="outline" ariaLabel="Settings">
|
|
91
|
+
<svg class="size-5"><!-- Settings icon --></svg>
|
|
92
|
+
</wally-button>
|
|
93
|
+
</wally-tooltip>
|
|
94
|
+
</div>`,
|
|
95
|
+
|
|
96
|
+
formField: `<!-- Form field with help tooltip -->
|
|
97
|
+
<div class="flex items-start gap-2">
|
|
98
|
+
<wally-input label="Email" type="email" placeholder="your@email.com" class="flex-1" />
|
|
99
|
+
<wally-tooltip text="We'll never share your email">
|
|
100
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="size-4 text-neutral-500 cursor-help mt-[30px]">
|
|
101
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" />
|
|
102
|
+
</svg>
|
|
103
|
+
</wally-tooltip>
|
|
104
|
+
</div>`,
|
|
105
|
+
|
|
106
|
+
navigation: `<!-- Navigation with tooltips -->
|
|
107
|
+
<nav class="flex flex-col gap-2">
|
|
108
|
+
<wally-tooltip text="Dashboard" position="right">
|
|
109
|
+
<a href="/dashboard" class="p-2">
|
|
110
|
+
<svg class="size-6"><!-- Dashboard icon --></svg>
|
|
111
|
+
</a>
|
|
112
|
+
</wally-tooltip>
|
|
113
|
+
|
|
114
|
+
<wally-tooltip text="Analytics" position="right">
|
|
115
|
+
<a href="/analytics" class="p-2">
|
|
116
|
+
<svg class="size-6"><!-- Analytics icon --></svg>
|
|
117
|
+
</a>
|
|
118
|
+
</wally-tooltip>
|
|
119
|
+
|
|
120
|
+
<wally-tooltip text="Settings" position="right">
|
|
121
|
+
<a href="/settings" class="p-2">
|
|
122
|
+
<svg class="size-6"><!-- Settings icon --></svg>
|
|
123
|
+
</a>
|
|
124
|
+
</wally-tooltip>
|
|
125
|
+
</nav>`,
|
|
126
|
+
|
|
127
|
+
avatar: `<!-- User avatar with name tooltip -->
|
|
128
|
+
<wally-tooltip text="John Doe (john@example.com)">
|
|
129
|
+
<img src="avatar.jpg" alt="User avatar" class="size-10 rounded-full cursor-pointer" />
|
|
130
|
+
</wally-tooltip>`,
|
|
131
|
+
|
|
132
|
+
statusBadge: `<!-- Status badge with details tooltip -->
|
|
133
|
+
<wally-tooltip text="Last updated: 2 minutes ago">
|
|
134
|
+
<span class="px-2 py-1 bg-green-500 text-white text-xs rounded-full cursor-help">
|
|
135
|
+
Active
|
|
136
|
+
</span>
|
|
137
|
+
</wally-tooltip>`,
|
|
138
|
+
|
|
139
|
+
richContent: `<!-- Future API (v2.0.0) -->
|
|
140
|
+
<wally-tooltip>
|
|
141
|
+
<div class="p-4">
|
|
142
|
+
<img src="preview.jpg" />
|
|
143
|
+
<h4>Custom Content</h4>
|
|
144
|
+
<p>Any HTML here</p>
|
|
145
|
+
</div>
|
|
146
|
+
|
|
147
|
+
<!-- Trigger element -->
|
|
148
|
+
<button>Show Rich Tooltip</button>
|
|
149
|
+
</wally-tooltip>`,
|
|
150
|
+
};
|