@feedvalue/core 0.1.5 → 0.1.7

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/index.cjs CHANGED
@@ -389,7 +389,7 @@ var DEFAULT_CONFIG = {
389
389
  locale: "en"
390
390
  };
391
391
  var instances = /* @__PURE__ */ new Map();
392
- var FeedValue = class _FeedValue {
392
+ var _FeedValue = class _FeedValue {
393
393
  /**
394
394
  * Create a new FeedValue instance
395
395
  * Use FeedValue.init() for public API
@@ -423,6 +423,8 @@ var FeedValue = class _FeedValue {
423
423
  __publicField(this, "stylesInjected", false);
424
424
  // Auto-close timeout reference (for cleanup on destroy)
425
425
  __publicField(this, "autoCloseTimeout", null);
426
+ // Destroyed flag - guards async continuations (fixes React StrictMode race condition)
427
+ __publicField(this, "isDestroyed", false);
426
428
  this.widgetId = options.widgetId;
427
429
  this.headless = options.headless ?? false;
428
430
  this.config = { ...DEFAULT_CONFIG, ...options.config };
@@ -467,11 +469,19 @@ var FeedValue = class _FeedValue {
467
469
  this.log("Already initialized");
468
470
  return;
469
471
  }
472
+ if (this.isDestroyed) {
473
+ this.log("Instance destroyed before init could complete");
474
+ return;
475
+ }
470
476
  try {
471
477
  this.log("Initializing...");
472
478
  const fingerprint = generateFingerprint();
473
479
  this.apiClient.setFingerprint(fingerprint);
474
480
  const configResponse = await this.apiClient.fetchConfig(this.widgetId);
481
+ if (this.isDestroyed) {
482
+ this.log("Instance destroyed during config fetch, aborting init");
483
+ return;
484
+ }
475
485
  this.widgetConfig = {
476
486
  widgetId: configResponse.widget_id,
477
487
  widgetKey: configResponse.widget_key,
@@ -513,6 +523,7 @@ var FeedValue = class _FeedValue {
513
523
  */
514
524
  destroy() {
515
525
  this.log("Destroying...");
526
+ this.isDestroyed = true;
516
527
  if (this.autoCloseTimeout) {
517
528
  clearTimeout(this.autoCloseTimeout);
518
529
  this.autoCloseTimeout = null;
@@ -884,9 +895,6 @@ var FeedValue = class _FeedValue {
884
895
  .fv-widget-trigger {
885
896
  position: fixed;
886
897
  ${positionStyles}
887
- display: inline-flex;
888
- align-items: center;
889
- gap: 8px;
890
898
  background-color: ${styling.primaryColor};
891
899
  color: ${styling.buttonTextColor};
892
900
  padding: 12px 24px;
@@ -905,13 +913,18 @@ var FeedValue = class _FeedValue {
905
913
  box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
906
914
  }
907
915
  .fv-widget-trigger-icon {
916
+ width: 56px;
917
+ height: 56px;
918
+ padding: 14px;
919
+ border-radius: 50%;
908
920
  display: flex;
909
921
  align-items: center;
910
922
  justify-content: center;
911
923
  }
912
924
  .fv-widget-trigger-icon svg {
913
- width: 20px;
914
- height: 20px;
925
+ width: 24px;
926
+ height: 24px;
927
+ stroke: currentColor;
915
928
  }
916
929
  .fv-widget-overlay {
917
930
  position: fixed;
@@ -1067,50 +1080,49 @@ var FeedValue = class _FeedValue {
1067
1080
  }
1068
1081
  }
1069
1082
  /**
1070
- * Get SVG icon element for trigger button using safe DOM parsing
1083
+ * Parse SVG string to DOM element safely using DOMParser
1071
1084
  */
1072
- createTriggerIcon(iconType) {
1073
- const icons = {
1074
- chat: '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>',
1075
- message: '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"/></svg>',
1076
- feedback: '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 9V5a3 3 0 0 0-3-3l-4 9v11h11.28a2 2 0 0 0 2-1.7l1.38-9a2 2 0 0 0-2-2.3zM7 22H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h3"/></svg>',
1077
- comment: '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/><line x1="9" y1="10" x2="15" y2="10"/></svg>',
1078
- help: '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>',
1079
- lightbulb: '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="9" y1="18" x2="15" y2="18"/><line x1="10" y1="22" x2="14" y2="22"/><path d="M15.09 14c.18-.98.65-1.74 1.41-2.5A4.65 4.65 0 0 0 18 8 6 6 0 0 0 6 8c0 1 .23 2.23 1.5 3.5A4.61 4.61 0 0 1 8.91 14"/></svg>'
1080
- };
1081
- const svgString = icons[iconType];
1082
- if (!svgString) return null;
1085
+ parseSvgString(svgString) {
1083
1086
  const parser = new DOMParser();
1084
1087
  const doc = parser.parseFromString(svgString, "image/svg+xml");
1088
+ const parserError = doc.querySelector("parsererror");
1089
+ if (parserError) {
1090
+ this.log("SVG parse error:", parserError.textContent);
1091
+ return null;
1092
+ }
1085
1093
  const svg = doc.querySelector("svg");
1086
1094
  if (!svg || svg.nodeName !== "svg") return null;
1087
1095
  return svg;
1088
1096
  }
1089
1097
  /**
1090
1098
  * Render trigger button using safe DOM methods
1099
+ * Matches widget-bundle behavior: icon mode = circular button, text mode = rectangular
1100
+ * Falls back to text mode if icon rendering fails (fixes "square with ellipses" bug)
1091
1101
  */
1092
1102
  renderTrigger() {
1093
1103
  if (!this.widgetConfig) return;
1094
1104
  const { triggerIcon, triggerText } = this.widgetConfig.config;
1105
+ const hasIcon = triggerIcon && triggerIcon !== "none";
1095
1106
  this.triggerButton = document.createElement("button");
1096
- this.triggerButton.className = "fv-widget-trigger";
1097
- if (triggerIcon && triggerIcon !== "none") {
1098
- const iconSvg = this.createTriggerIcon(triggerIcon);
1099
- if (iconSvg) {
1100
- const iconSpan = document.createElement("span");
1101
- iconSpan.className = "fv-widget-trigger-icon";
1102
- iconSpan.appendChild(iconSvg);
1103
- this.triggerButton.appendChild(iconSpan);
1104
- if (triggerText) {
1105
- const textSpan = document.createElement("span");
1106
- textSpan.textContent = triggerText;
1107
- this.triggerButton.appendChild(textSpan);
1107
+ let iconRendered = false;
1108
+ if (hasIcon) {
1109
+ const iconSvgString = _FeedValue.TRIGGER_ICONS[triggerIcon];
1110
+ if (iconSvgString) {
1111
+ const svgElement = this.parseSvgString(iconSvgString);
1112
+ if (svgElement) {
1113
+ this.triggerButton.className = "fv-widget-trigger fv-widget-trigger-icon";
1114
+ this.triggerButton.appendChild(svgElement);
1115
+ iconRendered = true;
1116
+ } else {
1117
+ this.log(`SVG parsing failed for icon: ${triggerIcon}, falling back to text`);
1108
1118
  }
1109
1119
  } else {
1110
- this.triggerButton.textContent = triggerText;
1120
+ this.log(`Icon not found: ${triggerIcon}, falling back to text`);
1111
1121
  }
1112
- } else {
1113
- this.triggerButton.textContent = triggerText;
1122
+ }
1123
+ if (!iconRendered) {
1124
+ this.triggerButton.className = "fv-widget-trigger";
1125
+ this.triggerButton.textContent = triggerText || "Feedback";
1114
1126
  }
1115
1127
  this.triggerButton.addEventListener("click", () => this.open());
1116
1128
  document.body.appendChild(this.triggerButton);
@@ -1267,6 +1279,18 @@ var FeedValue = class _FeedValue {
1267
1279
  }
1268
1280
  }
1269
1281
  };
1282
+ /**
1283
+ * SVG icons for trigger button (matching widget-bundle exactly)
1284
+ */
1285
+ __publicField(_FeedValue, "TRIGGER_ICONS", {
1286
+ chat: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M7.9 20A9 9 0 1 0 4 16.1L2 22Z"/></svg>',
1287
+ message: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="18" x="3" y="3" rx="2"/><path d="M8 12h.01"/><path d="M12 12h.01"/><path d="M16 12h.01"/></svg>',
1288
+ feedback: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 9a2 2 0 0 1-2 2H6l-4 4V4c0-1.1.9-2 2-2h8a2 2 0 0 1 2 2v5Z"/><path d="M18 9h2a2 2 0 0 1 2 2v11l-4-4h-6a2 2 0 0 1-2-2v-1"/></svg>',
1289
+ comment: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/><path d="M13 8H7"/><path d="M17 12H7"/></svg>',
1290
+ help: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/><path d="M12 17h.01"/></svg>',
1291
+ lightbulb: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5"/><path d="M9 18h6"/><path d="M10 22h4"/></svg>'
1292
+ });
1293
+ var FeedValue = _FeedValue;
1270
1294
 
1271
1295
  exports.ApiClient = ApiClient;
1272
1296
  exports.DEFAULT_API_BASE_URL = DEFAULT_API_BASE_URL;