@diabolic/pointy 1.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/LICENSE +21 -0
- package/README.md +810 -0
- package/dist/pointy.d.ts +851 -0
- package/dist/pointy.esm.js +2175 -0
- package/dist/pointy.js +2183 -0
- package/dist/pointy.min.js +2 -0
- package/dist/pointy.min.js.map +1 -0
- package/package.json +67 -0
- package/src/pointy.d.ts +851 -0
- package/src/pointy.js +2174 -0
package/README.md
ADDED
|
@@ -0,0 +1,810 @@
|
|
|
1
|
+
# Pointy ð
|
|
2
|
+
|
|
3
|
+
A lightweight, dependency-free JavaScript library for creating animated tooltips with a pointing cursor. Perfect for product tours, onboarding flows, and feature highlights.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@diabolic/pointy)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
> ðŽ [Live Demo](https://bugrakaan.github.io/pointy/)
|
|
9
|
+
|
|
10
|
+
## âĻ Features
|
|
11
|
+
|
|
12
|
+
- ðŊ **Animated Pointer** - Smooth cursor animation with customizable SVG
|
|
13
|
+
- ð **Multi-step Tours** - Create guided product tours with multiple steps
|
|
14
|
+
- ðŽ **Multi-message Steps** - Each step can have multiple messages that auto-cycle
|
|
15
|
+
- ðŽ **Autoplay Mode** - Automatically advance through steps
|
|
16
|
+
- ðĻ **Customizable Styling** - CSS variables, custom class names, and SVG support
|
|
17
|
+
- ð **Target Tracking** - Follows target elements in real-time (configurable FPS)
|
|
18
|
+
- âïļ **React Compatible** - Supports JSX/React elements as content
|
|
19
|
+
- ð **Event System** - Comprehensive events with group listeners
|
|
20
|
+
- ð **Smooth Animations** - 11 built-in easing presets
|
|
21
|
+
- ðą **Responsive** - Adapts to window resize and scroll
|
|
22
|
+
- ðŠķ **Lightweight** - Zero dependencies, ~15KB
|
|
23
|
+
|
|
24
|
+
## ðĶ Installation
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# npm
|
|
28
|
+
npm install @diabolic/pointy
|
|
29
|
+
|
|
30
|
+
# yarn
|
|
31
|
+
yarn add @diabolic/pointy
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# pnpm
|
|
35
|
+
pnpm add @diabolic/pointy
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### CDN
|
|
39
|
+
|
|
40
|
+
```html
|
|
41
|
+
<!-- UMD (Global variable) -->
|
|
42
|
+
<script src="https://unpkg.com/@diabolic/pointy/dist/pointy.min.js"></script>
|
|
43
|
+
|
|
44
|
+
<!-- Or from jsDelivr -->
|
|
45
|
+
<script src="https://cdn.jsdelivr.net/npm/@diabolic/pointy/dist/pointy.min.js"></script>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Direct Script Include
|
|
49
|
+
|
|
50
|
+
```html
|
|
51
|
+
<script src="pointy.js"></script>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Usage
|
|
55
|
+
|
|
56
|
+
```javascript
|
|
57
|
+
// ES6 import
|
|
58
|
+
import Pointy from '@diabolic/pointy';
|
|
59
|
+
|
|
60
|
+
// CommonJS
|
|
61
|
+
const Pointy = require('@diabolic/pointy');
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## ð Quick Start
|
|
65
|
+
|
|
66
|
+
```javascript
|
|
67
|
+
const pointy = new Pointy({
|
|
68
|
+
steps: [
|
|
69
|
+
{ target: '#welcome-btn', content: 'Click here to get started!' },
|
|
70
|
+
{ target: '#features', content: 'Explore our features' },
|
|
71
|
+
{ target: '#settings', content: ['Customize your experience', 'Change themes', 'Set preferences'] }
|
|
72
|
+
]
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
pointy.show();
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## ð Configuration Options
|
|
80
|
+
|
|
81
|
+
### Basic Options
|
|
82
|
+
|
|
83
|
+
| Option | Type | Default | Description |
|
|
84
|
+
|--------|------|---------|-------------|
|
|
85
|
+
| `steps` | `Array` | `[]` | Array of step objects |
|
|
86
|
+
| `target` | `string\|HTMLElement` | `null` | Initial target element (for single-step use) |
|
|
87
|
+
| `content` | `string\|string[]` | `''` | Initial content (for single-step use) |
|
|
88
|
+
|
|
89
|
+
### Step Object
|
|
90
|
+
|
|
91
|
+
```javascript
|
|
92
|
+
{
|
|
93
|
+
target: '#element', // CSS selector or HTMLElement
|
|
94
|
+
content: 'Message', // String, HTML, array of strings, or React element
|
|
95
|
+
direction: 'up', // Optional: 'up', 'down', or null (auto)
|
|
96
|
+
duration: 3000 // Optional: step-specific autoplay duration (ms)
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Animation Options
|
|
101
|
+
|
|
102
|
+
| Option | Type | Default | Description |
|
|
103
|
+
|--------|------|---------|-------------|
|
|
104
|
+
| `animationDuration` | `number` | `1000` | Move animation duration (ms) |
|
|
105
|
+
| `introFadeDuration` | `number` | `1000` | Initial fade-in duration (ms) |
|
|
106
|
+
| `bubbleFadeDuration` | `number` | `500` | Bubble fade-in duration (ms) |
|
|
107
|
+
| `messageTransitionDuration` | `number` | `500` | Message change animation (ms) |
|
|
108
|
+
| `easing` | `string` | `'default'` | Easing preset name or custom cubic-bezier |
|
|
109
|
+
| `floatingAnimation` | `boolean` | `true` | Enable floating/bobbing animation |
|
|
110
|
+
|
|
111
|
+
### Position Options
|
|
112
|
+
|
|
113
|
+
| Option | Type | Default | Description |
|
|
114
|
+
|--------|------|---------|-------------|
|
|
115
|
+
| `offsetX` | `number` | `20` | Horizontal offset from target |
|
|
116
|
+
| `offsetY` | `number` | `16` | Vertical offset from target |
|
|
117
|
+
| `initialPosition` | `string\|HTMLElement` | `'center'` | Starting position preset or element |
|
|
118
|
+
| `initialPositionOffset` | `number` | `32` | Offset from edges for position presets |
|
|
119
|
+
| `resetPositionOnHide` | `boolean` | `false` | Reset position when hiding |
|
|
120
|
+
|
|
121
|
+
**Initial Position Presets:**
|
|
122
|
+
- `'center'` - Center of viewport
|
|
123
|
+
- `'top-left'`, `'top-center'`, `'top-right'`
|
|
124
|
+
- `'middle-left'`, `'middle-right'`
|
|
125
|
+
- `'bottom-left'`, `'bottom-center'`, `'bottom-right'`
|
|
126
|
+
- `'first-step'` - Start directly at first step's target (no intro animation)
|
|
127
|
+
- CSS selector (e.g., `'#my-element'`)
|
|
128
|
+
- HTMLElement reference
|
|
129
|
+
|
|
130
|
+
### Tracking Options
|
|
131
|
+
|
|
132
|
+
| Option | Type | Default | Description |
|
|
133
|
+
|--------|------|---------|-------------|
|
|
134
|
+
| `tracking` | `boolean` | `true` | Enable real-time target tracking |
|
|
135
|
+
| `trackingFps` | `number` | `60` | Tracking frame rate (0 = unlimited) |
|
|
136
|
+
|
|
137
|
+
### Message Cycling Options
|
|
138
|
+
|
|
139
|
+
| Option | Type | Default | Description |
|
|
140
|
+
|--------|------|---------|-------------|
|
|
141
|
+
| `messageInterval` | `number\|null` | `null` | Auto-cycle messages interval (ms) |
|
|
142
|
+
|
|
143
|
+
### Autoplay Options
|
|
144
|
+
|
|
145
|
+
| Option | Type | Default | Description |
|
|
146
|
+
|--------|------|---------|-------------|
|
|
147
|
+
| `autoplay` | `number\|null` | `null` | Auto-advance interval (ms), null = manual |
|
|
148
|
+
| `autoplayEnabled` | `boolean` | `false` | Whether autoplay is initially enabled |
|
|
149
|
+
| `autoplayWaitForMessages` | `boolean` | `true` | Wait for all messages before advancing |
|
|
150
|
+
|
|
151
|
+
### Completion Options
|
|
152
|
+
|
|
153
|
+
| Option | Type | Default | Description |
|
|
154
|
+
|--------|------|---------|-------------|
|
|
155
|
+
| `resetOnComplete` | `boolean` | `true` | Reset to initial position on complete |
|
|
156
|
+
| `hideOnComplete` | `boolean` | `true` | Auto-hide after tour completes |
|
|
157
|
+
| `hideOnCompleteDelay` | `number\|null` | `null` | Delay before hide (null = animationDuration) |
|
|
158
|
+
|
|
159
|
+
### Styling Options
|
|
160
|
+
|
|
161
|
+
| Option | Type | Default | Description |
|
|
162
|
+
|--------|------|---------|-------------|
|
|
163
|
+
| `classPrefix` | `string` | `'pointy'` | CSS class prefix |
|
|
164
|
+
| `classSuffixes` | `object` | `{}` | Custom class suffixes |
|
|
165
|
+
| `classNames` | `object` | `{}` | Full override of class names |
|
|
166
|
+
| `cssVarPrefix` | `string` | `classPrefix` | CSS variable prefix |
|
|
167
|
+
| `pointerSvg` | `string` | Built-in SVG | Custom SVG for pointer |
|
|
168
|
+
|
|
169
|
+
### Callbacks
|
|
170
|
+
|
|
171
|
+
| Option | Type | Description |
|
|
172
|
+
|--------|------|-------------|
|
|
173
|
+
| `onStepChange` | `function(index, step)` | Called when step changes |
|
|
174
|
+
| `onComplete` | `function()` | Called when tour completes |
|
|
175
|
+
|
|
176
|
+
## ðŊ Methods
|
|
177
|
+
|
|
178
|
+
### Lifecycle
|
|
179
|
+
|
|
180
|
+
```javascript
|
|
181
|
+
pointy.show(); // Show the pointer
|
|
182
|
+
pointy.hide(); // Hide the pointer
|
|
183
|
+
pointy.destroy(); // Remove and cleanup
|
|
184
|
+
pointy.restart(); // Restart from initial position with intro animation
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Navigation
|
|
188
|
+
|
|
189
|
+
```javascript
|
|
190
|
+
pointy.next(); // Go to next step
|
|
191
|
+
pointy.prev(); // Go to previous step
|
|
192
|
+
pointy.goToStep(index); // Go to specific step by index
|
|
193
|
+
pointy.reset(); // Reset to initial position
|
|
194
|
+
pointy.reset(false); // Reset position without changing step
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Custom Target
|
|
198
|
+
|
|
199
|
+
```javascript
|
|
200
|
+
// Point to any element without changing the current step
|
|
201
|
+
pointy.pointTo('#element');
|
|
202
|
+
pointy.pointTo('#element', 'Custom message');
|
|
203
|
+
pointy.pointTo('#element', 'Message', 'down'); // Force direction
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Content Management
|
|
207
|
+
|
|
208
|
+
```javascript
|
|
209
|
+
pointy.setContent('New message');
|
|
210
|
+
pointy.setContent(['Message 1', 'Message 2', 'Message 3']);
|
|
211
|
+
pointy.setContent('<strong>HTML</strong> content');
|
|
212
|
+
|
|
213
|
+
pointy.nextMessage(); // Show next message
|
|
214
|
+
pointy.prevMessage(); // Show previous message
|
|
215
|
+
pointy.goToMessage(index); // Go to specific message
|
|
216
|
+
|
|
217
|
+
pointy.getCurrentMessage(); // Get current message index
|
|
218
|
+
pointy.getTotalMessages(); // Get total messages count
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Message Cycling
|
|
222
|
+
|
|
223
|
+
```javascript
|
|
224
|
+
pointy.startMessageCycle(); // Start auto-cycling
|
|
225
|
+
pointy.startMessageCycle(3000); // Start with custom interval
|
|
226
|
+
pointy.stopMessageCycle(); // Stop cycling
|
|
227
|
+
pointy.pauseMessageCycle(); // Pause cycling
|
|
228
|
+
pointy.resumeMessageCycle(); // Resume cycling
|
|
229
|
+
|
|
230
|
+
pointy.isMessageCycleActive(); // Check if cycling
|
|
231
|
+
pointy.isMessageCyclePaused(); // Check if paused
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### Autoplay Control
|
|
235
|
+
|
|
236
|
+
```javascript
|
|
237
|
+
pointy.startAutoplay(); // Start autoplay
|
|
238
|
+
pointy.stopAutoplay(); // Stop autoplay
|
|
239
|
+
pointy.pauseAutoplay(); // Pause autoplay
|
|
240
|
+
pointy.resumeAutoplay(); // Resume autoplay
|
|
241
|
+
|
|
242
|
+
pointy.isAutoplayActive(); // Check if autoplay is active
|
|
243
|
+
pointy.isAutoplayPaused(); // Check if autoplay is paused
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### State
|
|
247
|
+
|
|
248
|
+
```javascript
|
|
249
|
+
pointy.getCurrentStep(); // Get current step index
|
|
250
|
+
pointy.getTotalSteps(); // Get total steps count
|
|
251
|
+
pointy.isVisible; // Check visibility (property)
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Setters
|
|
255
|
+
|
|
256
|
+
All setters emit corresponding `*Change` events:
|
|
257
|
+
|
|
258
|
+
```javascript
|
|
259
|
+
// Animation
|
|
260
|
+
pointy.setEasing('bounce');
|
|
261
|
+
pointy.setAnimationDuration(800);
|
|
262
|
+
pointy.setIntroFadeDuration(500);
|
|
263
|
+
pointy.setBubbleFadeDuration(300);
|
|
264
|
+
pointy.setMessageTransitionDuration(400);
|
|
265
|
+
|
|
266
|
+
// Position
|
|
267
|
+
pointy.setOffset(30, 20);
|
|
268
|
+
pointy.setInitialPosition('top-left');
|
|
269
|
+
pointy.setInitialPositionOffset(50);
|
|
270
|
+
|
|
271
|
+
// Tracking
|
|
272
|
+
pointy.setTracking(false);
|
|
273
|
+
pointy.setTrackingFps(30);
|
|
274
|
+
|
|
275
|
+
// Messages
|
|
276
|
+
pointy.setMessageInterval(2000);
|
|
277
|
+
|
|
278
|
+
// Autoplay
|
|
279
|
+
pointy.setAutoplayInterval(3000);
|
|
280
|
+
pointy.setAutoplayWaitForMessages(false);
|
|
281
|
+
|
|
282
|
+
// Completion
|
|
283
|
+
pointy.setResetOnComplete(false);
|
|
284
|
+
pointy.setHideOnComplete(true);
|
|
285
|
+
pointy.setHideOnCompleteDelay(500);
|
|
286
|
+
|
|
287
|
+
// Styling
|
|
288
|
+
pointy.setFloatingAnimation(false);
|
|
289
|
+
pointy.setPointerSvg('<svg>...</svg>');
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### Animation
|
|
293
|
+
|
|
294
|
+
```javascript
|
|
295
|
+
pointy.animateToInitialPosition(); // Animate to current initial position
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
## ðĻ Easing Presets
|
|
299
|
+
|
|
300
|
+
```javascript
|
|
301
|
+
// Built-in presets
|
|
302
|
+
pointy.setEasing('default'); // Smooth deceleration (default)
|
|
303
|
+
pointy.setEasing('bounce'); // Bouncy overshoot
|
|
304
|
+
pointy.setEasing('elastic'); // Elastic spring
|
|
305
|
+
pointy.setEasing('smooth'); // Symmetric ease
|
|
306
|
+
pointy.setEasing('snap'); // Quick snap
|
|
307
|
+
|
|
308
|
+
// Material Design
|
|
309
|
+
pointy.setEasing('standard'); // Material standard
|
|
310
|
+
pointy.setEasing('decelerate'); // Material decelerate
|
|
311
|
+
pointy.setEasing('accelerate'); // Material accelerate
|
|
312
|
+
|
|
313
|
+
// Classic curves
|
|
314
|
+
pointy.setEasing('expo-out'); // Exponential out
|
|
315
|
+
pointy.setEasing('circ-out'); // Circular out
|
|
316
|
+
pointy.setEasing('back-out'); // Back out
|
|
317
|
+
|
|
318
|
+
// CSS built-ins work too
|
|
319
|
+
pointy.setEasing('ease');
|
|
320
|
+
pointy.setEasing('ease-in-out');
|
|
321
|
+
pointy.setEasing('linear');
|
|
322
|
+
|
|
323
|
+
// Custom cubic-bezier
|
|
324
|
+
pointy.setEasing('cubic-bezier(0.68, -0.55, 0.27, 1.55)');
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
Get all available presets:
|
|
328
|
+
```javascript
|
|
329
|
+
Pointy.getEasingPresets();
|
|
330
|
+
// ['default', 'standard', 'decelerate', 'accelerate', 'bounce', 'elastic', ...]
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
## ðĄ Events
|
|
334
|
+
|
|
335
|
+
### Event System
|
|
336
|
+
|
|
337
|
+
```javascript
|
|
338
|
+
// Subscribe to events
|
|
339
|
+
pointy.on('show', (data) => {
|
|
340
|
+
console.log('Pointy shown!', data.target);
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
// Unsubscribe
|
|
344
|
+
const handler = (data) => console.log(data);
|
|
345
|
+
pointy.on('stepChange', handler);
|
|
346
|
+
pointy.off('stepChange', handler);
|
|
347
|
+
|
|
348
|
+
// Remove all listeners for an event
|
|
349
|
+
pointy.off('stepChange');
|
|
350
|
+
|
|
351
|
+
// Chaining
|
|
352
|
+
pointy.on('show', fn1).on('hide', fn2).on('complete', fn3);
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
### Event Groups
|
|
356
|
+
|
|
357
|
+
Listen to multiple related events with a single handler:
|
|
358
|
+
|
|
359
|
+
```javascript
|
|
360
|
+
// Listen to all lifecycle events
|
|
361
|
+
pointy.on('lifecycle', (data) => {
|
|
362
|
+
console.log(data.type); // 'beforeShow', 'show', 'hide', etc.
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
// Listen to all navigation events
|
|
366
|
+
pointy.on('navigation', (data) => {
|
|
367
|
+
console.log(data.type); // 'stepChange', 'next', 'prev', 'complete'
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
// Listen to ALL events
|
|
371
|
+
pointy.on('all', (data) => {
|
|
372
|
+
console.log(data.type, data);
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
// or
|
|
376
|
+
pointy.on('*', (data) => { ... });
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
**Available Groups:**
|
|
380
|
+
| Group | Events |
|
|
381
|
+
|-------|--------|
|
|
382
|
+
| `lifecycle` | beforeShow, show, beforeHide, hide, destroy, beforeRestart, restart, beforeReset, reset |
|
|
383
|
+
| `navigation` | beforeStepChange, stepChange, next, prev, complete |
|
|
384
|
+
| `animation` | animationStart, animationEnd, move, moveComplete, introAnimationStart, introAnimationEnd |
|
|
385
|
+
| `content` | contentSet, messagesSet, messageChange |
|
|
386
|
+
| `messageCycle` | messageCycleStart, messageCycleStop, messageCyclePause, messageCycleResume, messageCycleComplete |
|
|
387
|
+
| `pointing` | beforePointTo, pointTo, pointToComplete |
|
|
388
|
+
| `tracking` | track, targetChange, trackingChange, trackingFpsChange |
|
|
389
|
+
| `autoplay` | autoplayStart, autoplayStop, autoplayPause, autoplayResume, autoplayNext, autoplayComplete, autoHide |
|
|
390
|
+
| `config` | All `*Change` events |
|
|
391
|
+
|
|
392
|
+
### Static Helpers
|
|
393
|
+
|
|
394
|
+
```javascript
|
|
395
|
+
Pointy.getEventGroup('show'); // 'lifecycle'
|
|
396
|
+
Pointy.getEventsInGroup('lifecycle'); // ['beforeShow', 'show', ...]
|
|
397
|
+
Pointy.EVENT_GROUPS; // All groups object
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
### All Events Reference
|
|
401
|
+
|
|
402
|
+
#### Lifecycle Events
|
|
403
|
+
| Event | Data | Description |
|
|
404
|
+
|-------|------|-------------|
|
|
405
|
+
| `beforeShow` | `{ target }` | Before pointer becomes visible |
|
|
406
|
+
| `show` | `{ target, isIntro, isFirstStep? }` | After pointer becomes visible |
|
|
407
|
+
| `beforeHide` | `{ target }` | Before pointer hides |
|
|
408
|
+
| `hide` | `{ target }` | After pointer hides |
|
|
409
|
+
| `destroy` | `{}` | Instance destroyed |
|
|
410
|
+
| `beforeRestart` | `{}` | Before restart |
|
|
411
|
+
| `restart` | `{}` | After restart completed |
|
|
412
|
+
| `beforeReset` | `{ currentStep }` | Before reset to initial position |
|
|
413
|
+
| `reset` | `{ stepIndex }` | After reset completed |
|
|
414
|
+
|
|
415
|
+
#### Navigation Events
|
|
416
|
+
| Event | Data | Description |
|
|
417
|
+
|-------|------|-------------|
|
|
418
|
+
| `beforeStepChange` | `{ fromIndex, toIndex, step, fromTarget }` | Before step transition |
|
|
419
|
+
| `stepChange` | `{ fromIndex, toIndex, step, target }` | After step changed |
|
|
420
|
+
| `next` | `{ fromIndex, toIndex }` | Moving to next step |
|
|
421
|
+
| `prev` | `{ fromIndex, toIndex }` | Moving to previous step |
|
|
422
|
+
| `complete` | `{ totalSteps, source }` | Tour completed (source: 'manual' or 'autoplay') |
|
|
423
|
+
|
|
424
|
+
#### Animation Events
|
|
425
|
+
| Event | Data | Description |
|
|
426
|
+
|-------|------|-------------|
|
|
427
|
+
| `animationStart` | `{ fromTarget, toTarget, type, stepIndex? }` | Movement started |
|
|
428
|
+
| `animationEnd` | `{ fromTarget, toTarget, type, stepIndex? }` | Movement completed |
|
|
429
|
+
| `move` | `{ index, step }` | Position update started |
|
|
430
|
+
| `moveComplete` | `{ index, step, target }` | Position update finished |
|
|
431
|
+
| `introAnimationStart` | `{ duration, initialPosition }` | Intro fade started |
|
|
432
|
+
| `introAnimationEnd` | `{ initialPosition }` | Intro fade completed |
|
|
433
|
+
|
|
434
|
+
#### Content Events
|
|
435
|
+
| Event | Data | Description |
|
|
436
|
+
|-------|------|-------------|
|
|
437
|
+
| `contentSet` | `{ messages, total, animated, cyclePaused }` | Content updated via setContent() |
|
|
438
|
+
| `messagesSet` | `{ messages, total, cyclePaused }` | Messages array set for step |
|
|
439
|
+
| `messageChange` | `{ fromIndex, toIndex, message, total, isAuto? }` | Message changed |
|
|
440
|
+
|
|
441
|
+
#### Message Cycle Events
|
|
442
|
+
| Event | Data | Description |
|
|
443
|
+
|-------|------|-------------|
|
|
444
|
+
| `messageCycleStart` | `{ interval, totalMessages }` | Auto-cycling started |
|
|
445
|
+
| `messageCycleStop` | `{ currentIndex }` | Auto-cycling stopped |
|
|
446
|
+
| `messageCyclePause` | `{ currentIndex }` | Cycling paused |
|
|
447
|
+
| `messageCycleResume` | `{ currentIndex }` | Cycling resumed |
|
|
448
|
+
| `messageCycleComplete` | `{ stepIndex, totalMessages }` | All messages shown |
|
|
449
|
+
|
|
450
|
+
#### Pointing Events
|
|
451
|
+
| Event | Data | Description |
|
|
452
|
+
|-------|------|-------------|
|
|
453
|
+
| `beforePointTo` | `{ target, content, direction, fromTarget }` | Before pointTo() |
|
|
454
|
+
| `pointTo` | `{ target, content, direction }` | pointTo() called |
|
|
455
|
+
| `pointToComplete` | `{ target, content }` | pointTo() animation done |
|
|
456
|
+
|
|
457
|
+
#### Tracking Events
|
|
458
|
+
| Event | Data | Description |
|
|
459
|
+
|-------|------|-------------|
|
|
460
|
+
| `track` | `{ target, timestamp }` | Position tracked (fires at trackingFps rate) |
|
|
461
|
+
| `targetChange` | `{ from, to }` | Target element changed |
|
|
462
|
+
| `trackingChange` | `{ from, to }` | Tracking enabled/disabled |
|
|
463
|
+
| `trackingFpsChange` | `{ from, to }` | Tracking FPS changed |
|
|
464
|
+
|
|
465
|
+
#### Autoplay Events
|
|
466
|
+
| Event | Data | Description |
|
|
467
|
+
|-------|------|-------------|
|
|
468
|
+
| `autoplayStart` | `{}` | Autoplay started |
|
|
469
|
+
| `autoplayStop` | `{}` | Autoplay stopped |
|
|
470
|
+
| `autoplayPause` | `{}` | Autoplay paused |
|
|
471
|
+
| `autoplayResume` | `{}` | Autoplay resumed |
|
|
472
|
+
| `autoplayNext` | `{ fromIndex, duration?, afterMessages? }` | Auto-advancing |
|
|
473
|
+
| `autoplayComplete` | `{ totalSteps }` | Autoplay finished |
|
|
474
|
+
| `autoHide` | `{ delay, source }` | Auto-hide triggered |
|
|
475
|
+
|
|
476
|
+
#### Configuration Events
|
|
477
|
+
All setters emit `*Change` events with `{ from, to }` data:
|
|
478
|
+
- `easingChange`, `animationDurationChange`, `introFadeDurationChange`
|
|
479
|
+
- `bubbleFadeDurationChange`, `messageIntervalChange`, `messageTransitionDurationChange`
|
|
480
|
+
- `offsetChange`, `resetOnCompleteChange`, `hideOnCompleteChange`
|
|
481
|
+
- `hideOnCompleteDelayChange`, `floatingAnimationChange`
|
|
482
|
+
- `initialPositionChange`, `initialPositionOffsetChange`
|
|
483
|
+
- `autoplayChange`, `autoplayWaitForMessagesChange`, `pointerSvgChange`
|
|
484
|
+
|
|
485
|
+
## ðĻ CSS Customization
|
|
486
|
+
|
|
487
|
+
### CSS Variables
|
|
488
|
+
|
|
489
|
+
```css
|
|
490
|
+
.pointy-container {
|
|
491
|
+
--pointy-duration: 1000ms; /* Animation duration */
|
|
492
|
+
--pointy-easing: cubic-bezier(0, 0.55, 0.45, 1); /* Easing */
|
|
493
|
+
--pointy-bubble-fade: 500ms; /* Bubble fade duration */
|
|
494
|
+
}
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
### Custom Class Prefix
|
|
498
|
+
|
|
499
|
+
```javascript
|
|
500
|
+
const pointy = new Pointy({
|
|
501
|
+
classPrefix: 'my-tooltip', // Uses: my-tooltip-container, my-tooltip-pointer, etc.
|
|
502
|
+
cssVarPrefix: 'tooltip', // Uses: --tooltip-duration, etc.
|
|
503
|
+
steps: [...]
|
|
504
|
+
});
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
### Generated Classes
|
|
508
|
+
|
|
509
|
+
| Class | Description |
|
|
510
|
+
|-------|-------------|
|
|
511
|
+
| `{prefix}-container` | Main container element |
|
|
512
|
+
| `{prefix}-pointer` | Pointer/cursor element |
|
|
513
|
+
| `{prefix}-bubble` | Tooltip bubble |
|
|
514
|
+
| `{prefix}-bubble-text` | Text inside bubble |
|
|
515
|
+
| `{prefix}-hidden` | Applied when hidden |
|
|
516
|
+
| `{prefix}-visible` | Applied when visible |
|
|
517
|
+
| `{prefix}-moving` | Applied during animation |
|
|
518
|
+
|
|
519
|
+
### Custom Pointer SVG
|
|
520
|
+
|
|
521
|
+
```javascript
|
|
522
|
+
const pointy = new Pointy({
|
|
523
|
+
pointerSvg: `
|
|
524
|
+
<svg width="40" height="40" viewBox="0 0 40 40">
|
|
525
|
+
<circle cx="20" cy="20" r="15" fill="#ff6b6b"/>
|
|
526
|
+
</svg>
|
|
527
|
+
`,
|
|
528
|
+
steps: [...]
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
// Or change at runtime
|
|
532
|
+
pointy.setPointerSvg('<svg>...</svg>');
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
**React/JSX Support:**
|
|
536
|
+
|
|
537
|
+
```jsx
|
|
538
|
+
// Use React elements as pointer SVG
|
|
539
|
+
const CustomPointer = () => (
|
|
540
|
+
<svg width="40" height="40" viewBox="0 0 40 40">
|
|
541
|
+
<circle cx="20" cy="20" r="15" fill="#ff6b6b"/>
|
|
542
|
+
</svg>
|
|
543
|
+
);
|
|
544
|
+
|
|
545
|
+
const pointy = new Pointy({
|
|
546
|
+
pointerSvg: <CustomPointer />,
|
|
547
|
+
steps: [...]
|
|
548
|
+
});
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
## âïļ React Integration
|
|
552
|
+
|
|
553
|
+
Pointy supports React elements as content and pointer SVG:
|
|
554
|
+
|
|
555
|
+
```jsx
|
|
556
|
+
const pointy = new Pointy({
|
|
557
|
+
steps: [
|
|
558
|
+
{
|
|
559
|
+
target: '#element',
|
|
560
|
+
content: <div><strong>Welcome!</strong> Click to continue</div>
|
|
561
|
+
},
|
|
562
|
+
{
|
|
563
|
+
target: '#features',
|
|
564
|
+
content: [
|
|
565
|
+
<span key="1">First message with <em>JSX</em></span>,
|
|
566
|
+
<span key="2">Second message</span>
|
|
567
|
+
]
|
|
568
|
+
}
|
|
569
|
+
]
|
|
570
|
+
});
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
## ð§ Static Methods
|
|
574
|
+
|
|
575
|
+
```javascript
|
|
576
|
+
// Render content (supports string/HTML and React elements)
|
|
577
|
+
Pointy.renderContent(element, content);
|
|
578
|
+
|
|
579
|
+
// Get DOM element from selector or element
|
|
580
|
+
Pointy.getTargetElement('#selector');
|
|
581
|
+
Pointy.getTargetElement(domElement);
|
|
582
|
+
|
|
583
|
+
// Generate class names with custom prefix
|
|
584
|
+
Pointy.generateClassNames('custom-prefix', { bubble: 'tooltip' });
|
|
585
|
+
|
|
586
|
+
// Get available presets
|
|
587
|
+
Pointy.getEasingPresets(); // ['default', 'bounce', ...]
|
|
588
|
+
Pointy.getInitialPositions(); // ['center', 'top-left', ...]
|
|
589
|
+
|
|
590
|
+
// Event group helpers
|
|
591
|
+
Pointy.getEventGroup('show'); // 'lifecycle'
|
|
592
|
+
Pointy.getEventsInGroup('navigation'); // ['stepChange', 'next', ...]
|
|
593
|
+
Pointy.EVENT_GROUPS; // All groups object
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
## ðĄ Examples
|
|
597
|
+
|
|
598
|
+
### Basic Tour
|
|
599
|
+
|
|
600
|
+
```javascript
|
|
601
|
+
const tour = new Pointy({
|
|
602
|
+
steps: [
|
|
603
|
+
{ target: '#logo', content: 'Welcome to our app!' },
|
|
604
|
+
{ target: '#dashboard', content: 'This is your dashboard' },
|
|
605
|
+
{ target: '#settings', content: 'Customize your settings here' }
|
|
606
|
+
],
|
|
607
|
+
onComplete: () => {
|
|
608
|
+
console.log('Tour completed!');
|
|
609
|
+
}
|
|
610
|
+
});
|
|
611
|
+
|
|
612
|
+
tour.show();
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
### Autoplay Tour
|
|
616
|
+
|
|
617
|
+
```javascript
|
|
618
|
+
const autoTour = new Pointy({
|
|
619
|
+
steps: [
|
|
620
|
+
{ target: '#step1', content: 'Step 1' },
|
|
621
|
+
{ target: '#step2', content: 'Step 2', duration: 5000 }, // Longer pause
|
|
622
|
+
{ target: '#step3', content: 'Step 3' }
|
|
623
|
+
],
|
|
624
|
+
autoplay: 3000, // 3 seconds per step
|
|
625
|
+
autoplayEnabled: true, // Start automatically
|
|
626
|
+
hideOnComplete: true, // Hide when done
|
|
627
|
+
hideOnCompleteDelay: 500 // Wait 500ms before hiding
|
|
628
|
+
});
|
|
629
|
+
|
|
630
|
+
autoTour.show();
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
### Multi-Message Steps with Auto-Cycle
|
|
634
|
+
|
|
635
|
+
```javascript
|
|
636
|
+
const multiMsg = new Pointy({
|
|
637
|
+
steps: [
|
|
638
|
+
{
|
|
639
|
+
target: '#feature',
|
|
640
|
+
content: [
|
|
641
|
+
'Did you know...',
|
|
642
|
+
'You can click this button',
|
|
643
|
+
'To access advanced features!'
|
|
644
|
+
]
|
|
645
|
+
}
|
|
646
|
+
],
|
|
647
|
+
messageInterval: 2500, // Change message every 2.5s
|
|
648
|
+
autoplay: null, // Manual navigation
|
|
649
|
+
autoplayWaitForMessages: true
|
|
650
|
+
});
|
|
651
|
+
|
|
652
|
+
multiMsg.show();
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
### Feature Highlight
|
|
656
|
+
|
|
657
|
+
```javascript
|
|
658
|
+
const highlight = new Pointy({
|
|
659
|
+
target: '#new-feature',
|
|
660
|
+
content: 'New! Check out this feature',
|
|
661
|
+
initialPosition: 'bottom-right',
|
|
662
|
+
floatingAnimation: true
|
|
663
|
+
});
|
|
664
|
+
|
|
665
|
+
highlight.show();
|
|
666
|
+
|
|
667
|
+
// Point to different elements
|
|
668
|
+
highlight.pointTo('#another-element', 'Or explore this!');
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
### Event-Driven Tour
|
|
672
|
+
|
|
673
|
+
```javascript
|
|
674
|
+
const eventTour = new Pointy({
|
|
675
|
+
steps: [...],
|
|
676
|
+
messageInterval: 2000
|
|
677
|
+
});
|
|
678
|
+
|
|
679
|
+
eventTour
|
|
680
|
+
.on('show', () => console.log('Tour started'))
|
|
681
|
+
.on('stepChange', ({ toIndex }) => analytics.track('tour_step', toIndex))
|
|
682
|
+
.on('complete', ({ source }) => {
|
|
683
|
+
analytics.track('tour_complete', { source });
|
|
684
|
+
})
|
|
685
|
+
.on('autoHide', () => {
|
|
686
|
+
showFollowUpModal();
|
|
687
|
+
});
|
|
688
|
+
|
|
689
|
+
eventTour.show();
|
|
690
|
+
```
|
|
691
|
+
|
|
692
|
+
### Pause/Resume on Hover
|
|
693
|
+
|
|
694
|
+
```javascript
|
|
695
|
+
const tour = new Pointy({
|
|
696
|
+
steps: [...],
|
|
697
|
+
autoplay: 3000,
|
|
698
|
+
autoplayEnabled: true
|
|
699
|
+
});
|
|
700
|
+
|
|
701
|
+
tour.bubble.addEventListener('mouseenter', () => {
|
|
702
|
+
tour.pauseAutoplay();
|
|
703
|
+
tour.pauseMessageCycle();
|
|
704
|
+
});
|
|
705
|
+
|
|
706
|
+
tour.bubble.addEventListener('mouseleave', () => {
|
|
707
|
+
tour.resumeAutoplay();
|
|
708
|
+
tour.resumeMessageCycle();
|
|
709
|
+
});
|
|
710
|
+
|
|
711
|
+
tour.show();
|
|
712
|
+
```
|
|
713
|
+
|
|
714
|
+
### Custom Styling
|
|
715
|
+
|
|
716
|
+
```javascript
|
|
717
|
+
const styledPointy = new Pointy({
|
|
718
|
+
classPrefix: 'custom',
|
|
719
|
+
steps: [
|
|
720
|
+
{ target: '#el', content: 'Styled tooltip!' }
|
|
721
|
+
],
|
|
722
|
+
pointerSvg: `
|
|
723
|
+
<svg width="24" height="24" viewBox="0 0 24 24">
|
|
724
|
+
<path d="M12 2L2 12l10 10V2z" fill="#6366f1"/>
|
|
725
|
+
</svg>
|
|
726
|
+
`
|
|
727
|
+
});
|
|
728
|
+
|
|
729
|
+
// Add custom CSS
|
|
730
|
+
const style = document.createElement('style');
|
|
731
|
+
style.textContent = `
|
|
732
|
+
.custom-bubble {
|
|
733
|
+
background: linear-gradient(135deg, #6366f1, #8b5cf6);
|
|
734
|
+
border-radius: 20px;
|
|
735
|
+
padding: 12px 20px;
|
|
736
|
+
}
|
|
737
|
+
`;
|
|
738
|
+
document.head.appendChild(style);
|
|
739
|
+
|
|
740
|
+
styledPointy.show();
|
|
741
|
+
```
|
|
742
|
+
|
|
743
|
+
## ð Browser Support
|
|
744
|
+
|
|
745
|
+
- Chrome 60+
|
|
746
|
+
- Firefox 55+
|
|
747
|
+
- Safari 12+
|
|
748
|
+
- Edge 79+
|
|
749
|
+
|
|
750
|
+
## ð TypeScript Support
|
|
751
|
+
|
|
752
|
+
Pointy includes full TypeScript definitions out of the box. No additional `@types` package needed.
|
|
753
|
+
|
|
754
|
+
```typescript
|
|
755
|
+
import Pointy, { PointyOptions, PointyStep, PointyEventData } from '@diabolic/pointy';
|
|
756
|
+
|
|
757
|
+
const options: PointyOptions = {
|
|
758
|
+
steps: [
|
|
759
|
+
{ target: '#btn', content: 'Click here!' }
|
|
760
|
+
],
|
|
761
|
+
autoplay: 3000
|
|
762
|
+
};
|
|
763
|
+
|
|
764
|
+
const pointy = new Pointy(options);
|
|
765
|
+
|
|
766
|
+
// Full type safety for events
|
|
767
|
+
pointy.on('stepChange', (data) => {
|
|
768
|
+
console.log(data.fromIndex, data.toIndex); // Types inferred
|
|
769
|
+
});
|
|
770
|
+
|
|
771
|
+
// Type-safe event groups
|
|
772
|
+
pointy.on('lifecycle', (data) => {
|
|
773
|
+
console.log(data.type); // 'beforeShow' | 'show' | 'hide' | ...
|
|
774
|
+
});
|
|
775
|
+
```
|
|
776
|
+
|
|
777
|
+
### Exported Types
|
|
778
|
+
|
|
779
|
+
```typescript
|
|
780
|
+
import {
|
|
781
|
+
Pointy,
|
|
782
|
+
PointyOptions,
|
|
783
|
+
PointyStep,
|
|
784
|
+
PointyClassNames,
|
|
785
|
+
PointyInitialPosition,
|
|
786
|
+
PointyEasing,
|
|
787
|
+
PointyEvent,
|
|
788
|
+
PointyEventGroup,
|
|
789
|
+
PointyEventData,
|
|
790
|
+
PointyEventCallback,
|
|
791
|
+
// Event-specific data types
|
|
792
|
+
PointyLifecycleEventData,
|
|
793
|
+
PointyNavigationEventData,
|
|
794
|
+
PointyAnimationEventData,
|
|
795
|
+
PointyContentEventData,
|
|
796
|
+
PointyMessageCycleEventData,
|
|
797
|
+
PointyPointingEventData,
|
|
798
|
+
PointyTrackingEventData,
|
|
799
|
+
PointyAutoplayEventData,
|
|
800
|
+
PointyConfigChangeEventData,
|
|
801
|
+
} from '@diabolic/pointy';
|
|
802
|
+
```
|
|
803
|
+
|
|
804
|
+
## ð License
|
|
805
|
+
|
|
806
|
+
MIT License - feel free to use in personal and commercial projects.
|
|
807
|
+
|
|
808
|
+
---
|
|
809
|
+
|
|
810
|
+
Made with âĪïļ for better user experiences.
|