@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/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
+ [![npm version](https://img.shields.io/npm/v/@diabolic/pointy.svg)](https://www.npmjs.com/package/@diabolic/pointy)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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.