@diabolic/pointy 1.0.1 → 1.0.2

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/src/pointy.js CHANGED
@@ -73,9 +73,9 @@
73
73
  * - introAnimationEnd: Initial fade-in animation completed
74
74
  *
75
75
  * Content:
76
- * - contentSet: Content updated via setContent()
77
- * - messagesSet: New messages array set for step
78
- * - messageChange: Message changed (manual or auto)
76
+ * - messagesSet: Messages array replaced via setMessages()
77
+ * - messageUpdate: Single message updated via setMessage()
78
+ * - messageChange: Message changed (navigation or auto-cycle)
79
79
  *
80
80
  * Message Cycle:
81
81
  * - messageCycleStart: Auto message cycling started
@@ -126,7 +126,7 @@
126
126
  * Core: show(), hide(), destroy()
127
127
  * Navigation: next(), prev(), goToStep(index), reset(), restart()
128
128
  * Custom Target: pointTo(target, content?, direction?)
129
- * Content: setContent(content), nextMessage(), prevMessage(), goToMessage(index)
129
+ * Content: setMessages(content), setMessage(msg), nextMessage(), prevMessage(), goToMessage(index)
130
130
  * Message Cycle: startMessageCycle(interval?), stopMessageCycle(), pauseMessageCycle(), resumeMessageCycle()
131
131
  * Autoplay: startAutoplay(), stopAutoplay(), pauseAutoplay(), resumeAutoplay()
132
132
  * Animation: animateToInitialPosition()
@@ -713,9 +713,17 @@ class Pointy {
713
713
 
714
714
  this._startTracking();
715
715
 
716
- // Show bubble immediately with fade
716
+ // Show bubble immediately with fade (only if content is not empty)
717
+ const hasContent = this.currentMessages.length > 0 &&
718
+ this.currentMessages.some(m => m !== '' && m !== null && m !== undefined);
719
+
717
720
  this.bubble.style.transition = `opacity ${this.bubbleFadeDuration}ms ease`;
718
- this.bubble.style.opacity = '1';
721
+ if (hasContent) {
722
+ this.bubble.style.opacity = '1';
723
+ } else {
724
+ this.bubble.style.opacity = '0';
725
+ this.bubble.style.pointerEvents = 'none';
726
+ }
719
727
 
720
728
  // Re-enable transitions after bubble fade completes
721
729
  setTimeout(() => {
@@ -744,9 +752,18 @@ class Pointy {
744
752
  this._startTracking();
745
753
 
746
754
  // Show bubble with fade after arriving at first target
755
+ // Show bubble with fade after arriving at first target (only if content is not empty)
747
756
  setTimeout(() => {
757
+ const hasContent = this.currentMessages.length > 0 &&
758
+ this.currentMessages.some(m => m !== '' && m !== null && m !== undefined);
759
+
748
760
  this.bubble.style.transition = '';
749
- this.bubble.style.opacity = '1';
761
+ if (hasContent) {
762
+ this.bubble.style.opacity = '1';
763
+ } else {
764
+ this.bubble.style.opacity = '0';
765
+ this.bubble.style.pointerEvents = 'none';
766
+ }
750
767
 
751
768
  // Start message cycle if multi-message
752
769
  if (this.messageInterval && this.currentMessages.length > 1 && !this._messageIntervalId) {
@@ -998,6 +1015,24 @@ class Pointy {
998
1015
  }
999
1016
 
1000
1017
  updateContent(newContent, animate = true) {
1018
+ // Check if content is empty
1019
+ const isEmpty = newContent === '' || newContent === null || newContent === undefined ||
1020
+ (Array.isArray(newContent) && newContent.length === 0) ||
1021
+ (Array.isArray(newContent) && newContent.every(m => m === '' || m === null || m === undefined));
1022
+
1023
+ if (isEmpty) {
1024
+ // Hide bubble when content is empty
1025
+ this.bubble.style.opacity = '0';
1026
+ this.bubble.style.pointerEvents = 'none';
1027
+ return;
1028
+ }
1029
+
1030
+ // Show bubble if it was hidden
1031
+ if (this.bubble.style.opacity === '0' && this.isVisible) {
1032
+ this.bubble.style.opacity = '1';
1033
+ this.bubble.style.pointerEvents = '';
1034
+ }
1035
+
1001
1036
  // Skip if content is the same (only for string content)
1002
1037
  if (typeof newContent === 'string' && this.bubbleText.innerHTML === newContent) {
1003
1038
  return;
@@ -1019,7 +1054,7 @@ class Pointy {
1019
1054
  * @param {boolean} fromStepChange - Whether this is from a step change (internal)
1020
1055
  * @private
1021
1056
  */
1022
- _setMessages(content, fromStepChange = false) {
1057
+ _applyMessages(content, fromStepChange = false) {
1023
1058
  // Check if cycle was running before
1024
1059
  const wasRunning = this._messageIntervalId !== null;
1025
1060
 
@@ -1033,8 +1068,8 @@ class Pointy {
1033
1068
  // Show first message
1034
1069
  this.updateContent(this.currentMessages[0]);
1035
1070
 
1036
- // Only auto-start cycle on step changes, not on manual setContent
1037
- // For manual setContent, user must call resumeMessageCycle()
1071
+ // Only auto-start cycle on step changes, not on manual setMessages
1072
+ // For manual setMessages, user must call resumeMessageCycle()
1038
1073
  if (fromStepChange && this.messageInterval && this.currentMessages.length > 1) {
1039
1074
  this._startMessageCycle();
1040
1075
  } else if (wasRunning && this.currentMessages.length > 1) {
@@ -1244,16 +1279,36 @@ class Pointy {
1244
1279
  }
1245
1280
 
1246
1281
  /**
1247
- * Set content programmatically (replaces current messages)
1282
+ * Set/update the current message (at current index)
1283
+ * @param {string} message - New message content
1284
+ * @param {boolean} animate - Whether to animate the change (default: true)
1285
+ */
1286
+ setMessage(message, animate = true) {
1287
+ const oldMessage = this.currentMessages[this.currentMessageIndex];
1288
+ this.currentMessages[this.currentMessageIndex] = message;
1289
+
1290
+ this.updateContent(message, animate);
1291
+
1292
+ this._emit('messageUpdate', {
1293
+ index: this.currentMessageIndex,
1294
+ message: message,
1295
+ oldMessage: oldMessage,
1296
+ total: this.currentMessages.length,
1297
+ animated: animate
1298
+ });
1299
+ }
1300
+
1301
+ /**
1302
+ * Set messages programmatically (replaces current messages)
1248
1303
  * @param {string|string[]} content - Single message or array of messages
1249
1304
  * @param {boolean} animate - Whether to animate the change (default: true)
1250
1305
  */
1251
- setContent(content, animate = true) {
1306
+ setMessages(content, animate = true) {
1252
1307
  // Check if cycle was running before
1253
1308
  const wasRunning = this._messageIntervalId !== null;
1254
1309
 
1255
1310
  if (animate) {
1256
- this._setMessages(content, false); // false = not from step change
1311
+ this._applyMessages(content, false); // false = not from step change
1257
1312
  } else {
1258
1313
  // Stop any existing auto-cycle
1259
1314
  this._stopMessageCycle();
@@ -1272,7 +1327,7 @@ class Pointy {
1272
1327
  }
1273
1328
  }
1274
1329
 
1275
- this._emit('contentSet', {
1330
+ this._emit('messagesSet', {
1276
1331
  messages: this.currentMessages,
1277
1332
  total: this.currentMessages.length,
1278
1333
  animated: animate,
@@ -1631,6 +1686,10 @@ class Pointy {
1631
1686
  // Set direction: step.direction can be 'up', 'down', or undefined (auto)
1632
1687
  this.manualDirection = step.direction || null;
1633
1688
 
1689
+ // Reset velocity tracking for new target
1690
+ this._targetYHistory = [];
1691
+ this.lastTargetY = null;
1692
+
1634
1693
  // Pause floating animation during movement
1635
1694
  this.container.classList.add(this.classNames.moving);
1636
1695
  if (this.moveTimeout) clearTimeout(this.moveTimeout);
@@ -1658,7 +1717,7 @@ class Pointy {
1658
1717
 
1659
1718
  this._emit('move', { index: index, step: step });
1660
1719
 
1661
- this._setMessages(step.content, true); // true = from step change, auto-start cycle
1720
+ this._applyMessages(step.content, true); // true = from step change, auto-start cycle
1662
1721
  this.targetElement = Pointy.getTargetElement(step.target);
1663
1722
  this.updatePosition();
1664
1723
 
@@ -1951,6 +2010,10 @@ class Pointy {
1951
2010
  // Set manual direction (null means auto)
1952
2011
  this.manualDirection = direction || null;
1953
2012
 
2013
+ // Reset velocity tracking for new target
2014
+ this._targetYHistory = [];
2015
+ this.lastTargetY = null;
2016
+
1954
2017
  // Pause floating animation during movement
1955
2018
  this.container.classList.add(this.classNames.moving);
1956
2019
  if (this.moveTimeout) clearTimeout(this.moveTimeout);
@@ -1967,7 +2030,7 @@ class Pointy {
1967
2030
  this.targetElement = toTarget;
1968
2031
 
1969
2032
  if (content !== undefined) {
1970
- this._setMessages(content, false); // false = not from step change, don't auto-start cycle
2033
+ this._applyMessages(content, false); // false = not from step change, don't auto-start cycle
1971
2034
  } else {
1972
2035
  // No new content - keep cycling if it was running
1973
2036
  // (cycle state is preserved)
@@ -2036,7 +2099,7 @@ class Pointy {
2036
2099
  * Content:
2037
2100
  * - messagesSet: When messages array is set for a step
2038
2101
  * - messageChange: When current message changes (next/prev message) - includes isAuto flag
2039
- * - contentSet: When setContent() is called
2102
+ * - messagesSet: When setMessages() is called
2040
2103
  * - messageCycleStart: When auto message cycling starts
2041
2104
  * - messageCycleStop: When auto message cycling stops
2042
2105
  * - messageCyclePause: When message cycling is paused