@diabolic/pointy 1.1.0 → 1.2.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 CHANGED
@@ -13,7 +13,8 @@ A lightweight, dependency-free JavaScript library for creating animated tooltips
13
13
  - 📝 **Multi-step Tours** - Create guided product tours with multiple steps
14
14
  - 💬 **Multi-message Steps** - Each step can have multiple messages that auto-cycle
15
15
  - 🎬 **Autoplay Mode** - Automatically advance through steps
16
- - 🎨 **Customizable Styling** - CSS variables, custom class names, and SVG support
16
+ - 🎨 **Customizable Styling** - CSS variables, custom class names, SVG support, and color theming
17
+ - 🎨 **Color Theming** - Customize pointer, bubble background, and text colors
17
18
  - 📍 **Target Tracking** - Follows target elements in real-time
18
19
  - ⚛️ **React Compatible** - Supports JSX/React elements as content
19
20
  - 🔗 **Event System** - Comprehensive events with group listeners
@@ -64,11 +65,67 @@ pointy.show();
64
65
  {
65
66
  target: '#element', // CSS selector or HTMLElement
66
67
  content: 'Message', // String, HTML, array, or React element
67
- direction: 'up', // 'up', 'down', or null (auto)
68
+ direction: 'up-left', // Direction preset or null (auto)
68
69
  duration: 3000 // Step-specific autoplay duration (ms)
69
70
  }
70
71
  ```
71
72
 
73
+ ### Content Types
74
+
75
+ Pointy supports multiple content formats:
76
+
77
+ ```javascript
78
+ // Plain text
79
+ { target: '#el', content: 'Simple message' }
80
+
81
+ // HTML string with custom layout
82
+ { target: '#el', content: `
83
+ <div style="display: flex; gap: 10px; align-items: flex-start; max-width: 260px; margin: 4px 0;">
84
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
85
+ <circle cx="12" cy="12" r="10"/>
86
+ <path d="M12 16v-4M12 8h.01"/>
87
+ </svg>
88
+ <span style="line-height: 1.4;">Custom tooltip with icon and flexible multi-line text layout!</span>
89
+ </div>
90
+ ` }
91
+
92
+ // Multiple messages (auto-cycles)
93
+ { target: '#el', content: ['First message', 'Second message', 'Third message'] }
94
+
95
+ // React/JSX element (if using React)
96
+ { target: '#el', content: <MyCustomComponent /> }
97
+ ```
98
+
99
+ ### Direction Presets
100
+
101
+ Control the pointer and bubble direction manually:
102
+
103
+ | Direction | Description |
104
+ |-----------|-------------|
105
+ | `null` | Auto (default) - automatically adjusts based on viewport |
106
+ | `'up'` | Pointer points up, bubble below target |
107
+ | `'down'` | Pointer points down, bubble above target |
108
+ | `'left'` | Bubble on left side of target |
109
+ | `'right'` | Bubble on right side of target |
110
+ | `'up-left'` | Pointer up, bubble on left |
111
+ | `'up-right'` | Pointer up, bubble on right |
112
+ | `'down-left'` | Pointer down, bubble on left |
113
+ | `'down-right'` | Pointer down, bubble on right |
114
+
115
+ ```javascript
116
+ // In steps
117
+ { target: '#el', content: 'Hello', direction: 'down-right' }
118
+
119
+ // Runtime
120
+ pointy.setDirection('up-left'); // Both axes
121
+ pointy.setHorizontalDirection('right'); // Only horizontal
122
+ pointy.setVerticalDirection('down'); // Only vertical
123
+ pointy.setDirection(null); // Reset to auto
124
+
125
+ // pointTo with direction
126
+ pointy.pointTo('#element', 'Message', 'down-left');
127
+ ```
128
+
72
129
  ### Animation
73
130
 
74
131
  | Option | Type | Default | Description |
@@ -100,6 +157,15 @@ pointy.show();
100
157
  | `autoplayWaitForMessages` | `boolean` | `true` | Wait for all messages |
101
158
  | `messageInterval` | `number\|null` | `null` | Message auto-cycle interval (ms) |
102
159
 
160
+ ### Styling
161
+
162
+ | Option | Type | Default | Description |
163
+ |--------|------|---------|-------------|
164
+ | `pointerColor` | `string` | `null` | Pointer/cursor color (CSS color) |
165
+ | `bubbleBackgroundColor` | `string` | `null` | Bubble background color (CSS color) |
166
+ | `bubbleTextColor` | `string` | `null` | Bubble text color (CSS color) |
167
+ | `bubbleMaxWidth` | `string` | `'min(400px, 90vw)'` | Maximum bubble width (CSS value) |
168
+
103
169
  ### Completion
104
170
 
105
171
  | Option | Type | Default | Description |
@@ -192,6 +258,12 @@ pointy.setOffset(30, 20);
192
258
  pointy.setInitialPosition('top-left');
193
259
  pointy.setInitialPositionOffset(50);
194
260
  pointy.setZIndex(10000);
261
+ pointy.setStayInViewport(true, { x: 50, y: 80 }); // Auto-flip with custom thresholds
262
+
263
+ // Direction
264
+ pointy.setDirection('up-left'); // Set both directions
265
+ pointy.setHorizontalDirection('right'); // Only horizontal (left/right/null)
266
+ pointy.setVerticalDirection('down'); // Only vertical (up/down/null)
195
267
 
196
268
  // Tracking
197
269
  pointy.setTracking(true);
@@ -211,6 +283,10 @@ pointy.setHideOnCompleteDelay(500);
211
283
 
212
284
  // Styling
213
285
  pointy.setPointerSvg('<svg>...</svg>');
286
+ pointy.setPointerColor('#ff6600'); // Pointer color
287
+ pointy.setBubbleBackgroundColor('#1a1a2e'); // Bubble background
288
+ pointy.setBubbleTextColor('#ffffff'); // Bubble text
289
+ pointy.setBubbleMaxWidth('300px'); // Max bubble width
214
290
  ```
215
291
 
216
292
  ## Easing Presets
@@ -297,6 +373,15 @@ pointy.on('all', (data) => {
297
373
  | `moveComplete` | `{ index, step, target }` |
298
374
  | `introAnimationStart` | `{ duration, initialPosition }` |
299
375
  | `introAnimationEnd` | `{ initialPosition }` |
376
+ | `flipHorizontal` | `{ from: 'left'\|'right', to: 'left'\|'right' }` |
377
+ | `flipVertical` | `{ from: 'up'\|'down', to: 'up'\|'down' }` |
378
+
379
+ #### Direction
380
+ | Event | Data |
381
+ |-------|------|
382
+ | `directionChange` | `{ from: { horizontal, vertical }, to: { horizontal, vertical } }` |
383
+ | `horizontalDirectionChange` | `{ from, to }` |
384
+ | `verticalDirectionChange` | `{ from, to }` |
300
385
 
301
386
  #### Content
302
387
  | Event | Data |
@@ -339,9 +424,27 @@ pointy.on('all', (data) => {
339
424
  | `autoplayNext` | `{ fromIndex, duration?, afterMessages? }` |
340
425
  | `autoplayComplete` | `{ totalSteps }` |
341
426
  | `autoHide` | `{ delay, source }` |
427
+ | `autoplayChange` | `{ from, to }` |
428
+ | `autoplayWaitForMessagesChange` | `{ from, to }` |
429
+
430
+ #### Viewport
431
+ | Event | Data |
432
+ |-------|------|
433
+ | `stayInViewportChange` | `{ from: { enabled, x, y }, to: { enabled, x, y } }` |
342
434
 
343
435
  #### Config
344
- All setter methods emit `*Change` events with `{ from, to }` data.
436
+ All setter methods emit `*Change` events with `{ from, to }` data:
437
+
438
+ | Event | Description |
439
+ |-------|-------------|
440
+ | `pointerColorChange` | Pointer color changed |
441
+ | `bubbleBackgroundColorChange` | Bubble background color changed |
442
+ | `bubbleTextColorChange` | Bubble text color changed |
443
+ | `bubbleMaxWidthChange` | Bubble max width changed |
444
+ | `easingChange` | Easing preset changed |
445
+ | `animationDurationChange` | Animation duration changed |
446
+ | `floatingAnimationChange` | Floating animation toggled |
447
+ | ... | (and more for all setters) |
345
448
 
346
449
  ## CSS Customization
347
450
 
@@ -349,9 +452,16 @@ All setter methods emit `*Change` events with `{ from, to }` data.
349
452
 
350
453
  ```css
351
454
  .pointy-container {
455
+ /* Animation */
352
456
  --pointy-duration: 1000ms;
353
457
  --pointy-easing: cubic-bezier(0, 0.55, 0.45, 1);
354
458
  --pointy-bubble-fade: 500ms;
459
+
460
+ /* Colors */
461
+ --pointy-pointer-color: #0a1551;
462
+ --pointy-bubble-bg: #0a1551;
463
+ --pointy-bubble-color: white;
464
+ --pointy-bubble-max-width: min(400px, 90vw);
355
465
  }
356
466
  ```
357
467
 
@@ -436,6 +546,26 @@ const tour = new Pointy({
436
546
  tour.show();
437
547
  ```
438
548
 
549
+ ### Custom Theming
550
+
551
+ ```javascript
552
+ const tour = new Pointy({
553
+ steps: [
554
+ { target: '#feature', content: 'Check out this feature!' }
555
+ ],
556
+ pointerColor: '#ff6600',
557
+ bubbleBackgroundColor: '#1a1a2e',
558
+ bubbleTextColor: '#ffffff',
559
+ bubbleMaxWidth: '300px'
560
+ });
561
+
562
+ tour.show();
563
+
564
+ // Or change colors at runtime
565
+ tour.setPointerColor('#00ff88');
566
+ tour.setBubbleBackgroundColor('#2d2d44');
567
+ ```
568
+
439
569
  ### Autoplay Tour
440
570
 
441
571
  ```javascript
package/dist/pointy.d.ts CHANGED
@@ -7,6 +7,31 @@ declare module '@diabolic/pointy' {
7
7
  export = Pointy;
8
8
  }
9
9
 
10
+ /**
11
+ * Direction presets for pointer positioning
12
+ */
13
+ type PointyDirection = 'up' | 'down' | 'left' | 'right' | 'up-left' | 'up-right' | 'down-left' | 'down-right' | null;
14
+
15
+ /**
16
+ * Horizontal direction
17
+ */
18
+ type PointyHorizontalDirection = 'left' | 'right' | null;
19
+
20
+ /**
21
+ * Vertical direction
22
+ */
23
+ type PointyVerticalDirection = 'up' | 'down' | null;
24
+
25
+ /**
26
+ * Viewport threshold configuration
27
+ */
28
+ interface PointyViewportThresholds {
29
+ /** Horizontal margin from viewport edge to trigger flip (default: 40) */
30
+ x?: number;
31
+ /** Vertical margin from viewport edge to trigger flip (default: 60) */
32
+ y?: number;
33
+ }
34
+
10
35
  /**
11
36
  * Step configuration for tour steps
12
37
  */
@@ -15,8 +40,8 @@ interface PointyStep {
15
40
  target: string | HTMLElement;
16
41
  /** Content to display - can be string, HTML, array of messages, or React element */
17
42
  content: string | string[] | React.ReactNode | React.ReactNode[];
18
- /** Pointer direction: 'up', 'down', or null for auto */
19
- direction?: 'up' | 'down' | null;
43
+ /** Pointer direction: 'up', 'down', 'left', 'right', 'up-left', 'up-right', 'down-left', 'down-right', or null for auto */
44
+ direction?: PointyDirection;
20
45
  /** Step-specific autoplay duration in ms (overrides global autoplay) */
21
46
  duration?: number;
22
47
  }
@@ -110,6 +135,10 @@ interface PointyOptions {
110
135
  /** Enable floating/bobbing animation (default: true) */
111
136
  floatingAnimation?: boolean;
112
137
 
138
+ // Viewport
139
+ /** Auto-flip bubble to stay within viewport (default: true). Can be boolean or threshold config */
140
+ stayInViewport?: boolean | PointyViewportThresholds;
141
+
113
142
  // Position
114
143
  /** Horizontal offset from target in px (default: 20) */
115
144
  offsetX?: number;
@@ -159,6 +188,14 @@ interface PointyOptions {
159
188
  cssVarPrefix?: string;
160
189
  /** Custom SVG markup for pointer or React element */
161
190
  pointerSvg?: string | React.ReactNode;
191
+ /** Custom bubble background color (CSS color value) */
192
+ bubbleBackgroundColor?: string;
193
+ /** Custom bubble text color (CSS color value) */
194
+ bubbleTextColor?: string;
195
+ /** Maximum width for bubble (CSS width value, default: 'min(400px, 90vw)') */
196
+ bubbleMaxWidth?: string;
197
+ /** Custom pointer/cursor color (CSS color value) */
198
+ pointerColor?: string;
162
199
 
163
200
  // Callbacks
164
201
  /** Called when step changes */
@@ -247,10 +284,34 @@ interface PointyMessageCycleEventData extends PointyEventData {
247
284
  interface PointyPointingEventData extends PointyEventData {
248
285
  target?: HTMLElement;
249
286
  content?: string | string[];
250
- direction?: 'up' | 'down' | null;
287
+ direction?: PointyDirection;
251
288
  fromTarget?: HTMLElement;
252
289
  }
253
290
 
291
+ /**
292
+ * Flip event data (when bubble flips due to viewport bounds)
293
+ */
294
+ interface PointyFlipEventData extends PointyEventData {
295
+ from: 'left' | 'right' | 'up' | 'down';
296
+ to: 'left' | 'right' | 'up' | 'down';
297
+ }
298
+
299
+ /**
300
+ * Direction change event data
301
+ */
302
+ interface PointyDirectionChangeEventData extends PointyEventData {
303
+ from: { horizontal: PointyHorizontalDirection; vertical: PointyVerticalDirection };
304
+ to: { horizontal: PointyHorizontalDirection; vertical: PointyVerticalDirection };
305
+ }
306
+
307
+ /**
308
+ * Viewport change event data
309
+ */
310
+ interface PointyViewportChangeEventData extends PointyEventData {
311
+ from: { enabled: boolean; x: number; y: number };
312
+ to: { enabled: boolean; x: number; y: number };
313
+ }
314
+
254
315
  /**
255
316
  * Tracking event data
256
317
  */
@@ -291,15 +352,17 @@ type PointyEventCallback<T = PointyEventData> = (data: T) => void;
291
352
  */
292
353
  type PointyLifecycleEvent = 'beforeShow' | 'show' | 'beforeHide' | 'hide' | 'destroy' | 'beforeRestart' | 'restart' | 'beforeReset' | 'reset';
293
354
  type PointyNavigationEvent = 'beforeStepChange' | 'stepChange' | 'next' | 'prev' | 'complete';
294
- type PointyAnimationEvent = 'animationStart' | 'animationEnd' | 'move' | 'moveComplete' | 'introAnimationStart' | 'introAnimationEnd';
355
+ type PointyAnimationEvent = 'animationStart' | 'animationEnd' | 'move' | 'moveComplete' | 'introAnimationStart' | 'introAnimationEnd' | 'flipHorizontal' | 'flipVertical';
356
+ type PointyDirectionEvent = 'directionChange' | 'horizontalDirectionChange' | 'verticalDirectionChange';
357
+ type PointyViewportEvent = 'stayInViewportChange';
295
358
  type PointyContentEvent = 'contentSet' | 'messagesSet' | 'messageChange';
296
359
  type PointyMessageCycleEvent = 'messageCycleStart' | 'messageCycleStop' | 'messageCyclePause' | 'messageCycleResume' | 'messageCycleComplete';
297
360
  type PointyPointingEvent = 'beforePointTo' | 'pointTo' | 'pointToComplete';
298
361
  type PointyTrackingEvent = 'track' | 'targetChange' | 'trackingChange' | 'trackingFpsChange';
299
362
  type PointyAutoplayEvent = 'autoplayStart' | 'autoplayStop' | 'autoplayPause' | 'autoplayResume' | 'autoplayNext' | 'autoplayComplete' | 'autoHide' | 'autoplayChange' | 'autoplayWaitForMessagesChange';
300
- type PointyConfigEvent = 'easingChange' | 'animationDurationChange' | 'introFadeDurationChange' | 'bubbleFadeDurationChange' | 'messageIntervalChange' | 'messageTransitionDurationChange' | 'offsetChange' | 'resetOnCompleteChange' | 'hideOnCompleteChange' | 'hideOnCompleteDelayChange' | 'floatingAnimationChange' | 'initialPositionChange' | 'initialPositionOffsetChange' | 'pointerSvgChange';
363
+ type PointyConfigEvent = 'easingChange' | 'animationDurationChange' | 'introFadeDurationChange' | 'bubbleFadeDurationChange' | 'bubbleBackgroundColorChange' | 'bubbleTextColorChange' | 'bubbleMaxWidthChange' | 'pointerColorChange' | 'messageIntervalChange' | 'messageTransitionDurationChange' | 'offsetChange' | 'resetOnCompleteChange' | 'hideOnCompleteChange' | 'hideOnCompleteDelayChange' | 'floatingAnimationChange' | 'initialPositionChange' | 'initialPositionOffsetChange' | 'pointerSvgChange' | 'zIndexChange';
301
364
 
302
- type PointyEvent = PointyLifecycleEvent | PointyNavigationEvent | PointyAnimationEvent | PointyContentEvent | PointyMessageCycleEvent | PointyPointingEvent | PointyTrackingEvent | PointyAutoplayEvent | PointyConfigEvent;
365
+ type PointyEvent = PointyLifecycleEvent | PointyNavigationEvent | PointyAnimationEvent | PointyDirectionEvent | PointyViewportEvent | PointyContentEvent | PointyMessageCycleEvent | PointyPointingEvent | PointyTrackingEvent | PointyAutoplayEvent | PointyConfigEvent;
303
366
 
304
367
  /**
305
368
  * Event group names
@@ -313,6 +376,8 @@ interface PointyEventGroups {
313
376
  lifecycle: PointyLifecycleEvent[];
314
377
  navigation: PointyNavigationEvent[];
315
378
  animation: PointyAnimationEvent[];
379
+ direction: PointyDirectionEvent[];
380
+ viewport: PointyViewportEvent[];
316
381
  content: PointyContentEvent[];
317
382
  messageCycle: PointyMessageCycleEvent[];
318
383
  pointing: PointyPointingEvent[];
@@ -474,6 +539,22 @@ declare class Pointy {
474
539
  messageInterval: number | null;
475
540
  /** Current pointer SVG or React element */
476
541
  pointerSvg: string | React.ReactNode;
542
+ /** Custom bubble background color */
543
+ bubbleBackgroundColor: string | null;
544
+ /** Custom bubble text color */
545
+ bubbleTextColor: string | null;
546
+ /** Maximum width for bubble (default: min(400px, 90vw)) */
547
+ bubbleMaxWidth: string | null;
548
+ /** Custom pointer/cursor color */
549
+ pointerColor: string | null;
550
+
551
+ // Viewport properties
552
+ /** Whether to auto-flip bubble to stay in viewport */
553
+ stayInViewport: boolean;
554
+ /** Horizontal viewport threshold */
555
+ viewportThresholdX: number;
556
+ /** Vertical viewport threshold */
557
+ viewportThresholdY: number;
477
558
 
478
559
  // State properties (readonly)
479
560
  /** Whether pointer is currently visible */
@@ -486,8 +567,12 @@ declare class Pointy {
486
567
  readonly currentMessages: (string | React.ReactNode)[];
487
568
  /** Whether pointer is pointing up */
488
569
  readonly isPointingUp: boolean;
489
- /** Manual direction override */
490
- readonly manualDirection: 'up' | 'down' | null;
570
+ /** Whether pointer is on left side of target */
571
+ readonly isPointingLeft: boolean;
572
+ /** Manual horizontal direction override */
573
+ readonly manualHorizontalDirection: PointyHorizontalDirection;
574
+ /** Manual vertical direction override */
575
+ readonly manualVerticalDirection: PointyVerticalDirection;
491
576
 
492
577
  // Callbacks
493
578
  /** Step change callback */
@@ -532,9 +617,9 @@ declare class Pointy {
532
617
  * Point to any element without changing current step
533
618
  * @param target - Target element or CSS selector
534
619
  * @param content - Optional content to display
535
- * @param direction - Optional direction: 'up', 'down', or null for auto
620
+ * @param direction - Optional direction: 'up', 'down', 'left', 'right', 'up-left', 'up-right', 'down-left', 'down-right', or null for auto
536
621
  */
537
- pointTo(target: string | HTMLElement, content?: string | string[], direction?: 'up' | 'down' | null): void;
622
+ pointTo(target: string | HTMLElement, content?: string | string[], direction?: PointyDirection): void;
538
623
 
539
624
  // Content methods
540
625
  /**
@@ -650,6 +735,26 @@ declare class Pointy {
650
735
  * @param duration - Duration in milliseconds
651
736
  */
652
737
  setBubbleFadeDuration(duration: number): void;
738
+ /**
739
+ * Set the bubble background color
740
+ * @param color - CSS color value (hex, rgb, etc.) or null to reset
741
+ */
742
+ setBubbleBackgroundColor(color: string | null): void;
743
+ /**
744
+ * Set the bubble text color
745
+ * @param color - CSS color value (hex, rgb, etc.) or null to reset
746
+ */
747
+ setBubbleTextColor(color: string | null): void;
748
+ /**
749
+ * Set the bubble max width
750
+ * @param width - CSS width value (e.g., '90vw', '300px') or null to reset
751
+ */
752
+ setBubbleMaxWidth(width: string | null): void;
753
+ /**
754
+ * Set the pointer/cursor color
755
+ * @param color - CSS color value (hex, rgb, etc.) or null to reset
756
+ */
757
+ setPointerColor(color: string | null): void;
653
758
  /**
654
759
  * Set the message transition duration
655
760
  * @param duration - Duration in milliseconds
@@ -727,6 +832,32 @@ declare class Pointy {
727
832
  * @param svg - SVG markup string or React element
728
833
  */
729
834
  setPointerSvg(svg: string | React.ReactNode): void;
835
+ /**
836
+ * Set the z-index of the container
837
+ * @param zIndex - CSS z-index value
838
+ */
839
+ setZIndex(zIndex: number): void;
840
+ /**
841
+ * Set stayInViewport enabled/disabled with optional thresholds
842
+ * @param enabled - Whether stayInViewport is enabled
843
+ * @param thresholds - Optional threshold values { x?: number, y?: number }
844
+ */
845
+ setStayInViewport(enabled: boolean, thresholds?: PointyViewportThresholds): void;
846
+ /**
847
+ * Set the pointer direction manually (both horizontal and vertical)
848
+ * @param direction - Direction: 'up', 'down', 'left', 'right', 'up-left', 'up-right', 'down-left', 'down-right', or null for auto
849
+ */
850
+ setDirection(direction: PointyDirection): void;
851
+ /**
852
+ * Set only the horizontal direction
853
+ * @param direction - 'left', 'right', or null for auto
854
+ */
855
+ setHorizontalDirection(direction: PointyHorizontalDirection): void;
856
+ /**
857
+ * Set only the vertical direction
858
+ * @param direction - 'up', 'down', or null for auto
859
+ */
860
+ setVerticalDirection(direction: PointyVerticalDirection): void;
730
861
 
731
862
  // Getter methods
732
863
  /** Get current pointer SVG or React element */
@@ -825,6 +956,10 @@ export {
825
956
  PointyClassSuffixes,
826
957
  PointyInitialPosition,
827
958
  PointyEasing,
959
+ PointyDirection,
960
+ PointyHorizontalDirection,
961
+ PointyVerticalDirection,
962
+ PointyViewportThresholds,
828
963
  PointyEvent,
829
964
  PointyEventGroup,
830
965
  PointyEventGroups,
@@ -836,6 +971,11 @@ export {
836
971
  PointyNavigationEventData,
837
972
  PointyAnimationEvent,
838
973
  PointyAnimationEventData,
974
+ PointyDirectionEvent,
975
+ PointyDirectionChangeEventData,
976
+ PointyViewportEvent,
977
+ PointyViewportChangeEventData,
978
+ PointyFlipEventData,
839
979
  PointyContentEvent,
840
980
  PointyContentEventData,
841
981
  PointyMessageCycleEvent,