@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.js CHANGED
@@ -387,7 +387,7 @@ var DEFAULT_CONFIG = {
387
387
  locale: "en"
388
388
  };
389
389
  var instances = /* @__PURE__ */ new Map();
390
- var FeedValue = class _FeedValue {
390
+ var _FeedValue = class _FeedValue {
391
391
  /**
392
392
  * Create a new FeedValue instance
393
393
  * Use FeedValue.init() for public API
@@ -421,6 +421,8 @@ var FeedValue = class _FeedValue {
421
421
  __publicField(this, "stylesInjected", false);
422
422
  // Auto-close timeout reference (for cleanup on destroy)
423
423
  __publicField(this, "autoCloseTimeout", null);
424
+ // Destroyed flag - guards async continuations (fixes React StrictMode race condition)
425
+ __publicField(this, "isDestroyed", false);
424
426
  this.widgetId = options.widgetId;
425
427
  this.headless = options.headless ?? false;
426
428
  this.config = { ...DEFAULT_CONFIG, ...options.config };
@@ -465,11 +467,19 @@ var FeedValue = class _FeedValue {
465
467
  this.log("Already initialized");
466
468
  return;
467
469
  }
470
+ if (this.isDestroyed) {
471
+ this.log("Instance destroyed before init could complete");
472
+ return;
473
+ }
468
474
  try {
469
475
  this.log("Initializing...");
470
476
  const fingerprint = generateFingerprint();
471
477
  this.apiClient.setFingerprint(fingerprint);
472
478
  const configResponse = await this.apiClient.fetchConfig(this.widgetId);
479
+ if (this.isDestroyed) {
480
+ this.log("Instance destroyed during config fetch, aborting init");
481
+ return;
482
+ }
473
483
  this.widgetConfig = {
474
484
  widgetId: configResponse.widget_id,
475
485
  widgetKey: configResponse.widget_key,
@@ -511,6 +521,7 @@ var FeedValue = class _FeedValue {
511
521
  */
512
522
  destroy() {
513
523
  this.log("Destroying...");
524
+ this.isDestroyed = true;
514
525
  if (this.autoCloseTimeout) {
515
526
  clearTimeout(this.autoCloseTimeout);
516
527
  this.autoCloseTimeout = null;
@@ -882,9 +893,6 @@ var FeedValue = class _FeedValue {
882
893
  .fv-widget-trigger {
883
894
  position: fixed;
884
895
  ${positionStyles}
885
- display: inline-flex;
886
- align-items: center;
887
- gap: 8px;
888
896
  background-color: ${styling.primaryColor};
889
897
  color: ${styling.buttonTextColor};
890
898
  padding: 12px 24px;
@@ -903,13 +911,18 @@ var FeedValue = class _FeedValue {
903
911
  box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
904
912
  }
905
913
  .fv-widget-trigger-icon {
914
+ width: 56px;
915
+ height: 56px;
916
+ padding: 14px;
917
+ border-radius: 50%;
906
918
  display: flex;
907
919
  align-items: center;
908
920
  justify-content: center;
909
921
  }
910
922
  .fv-widget-trigger-icon svg {
911
- width: 20px;
912
- height: 20px;
923
+ width: 24px;
924
+ height: 24px;
925
+ stroke: currentColor;
913
926
  }
914
927
  .fv-widget-overlay {
915
928
  position: fixed;
@@ -1065,50 +1078,49 @@ var FeedValue = class _FeedValue {
1065
1078
  }
1066
1079
  }
1067
1080
  /**
1068
- * Get SVG icon element for trigger button using safe DOM parsing
1081
+ * Parse SVG string to DOM element safely using DOMParser
1069
1082
  */
1070
- createTriggerIcon(iconType) {
1071
- const icons = {
1072
- 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>',
1073
- 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>',
1074
- 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>',
1075
- 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>',
1076
- 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>',
1077
- 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>'
1078
- };
1079
- const svgString = icons[iconType];
1080
- if (!svgString) return null;
1083
+ parseSvgString(svgString) {
1081
1084
  const parser = new DOMParser();
1082
1085
  const doc = parser.parseFromString(svgString, "image/svg+xml");
1086
+ const parserError = doc.querySelector("parsererror");
1087
+ if (parserError) {
1088
+ this.log("SVG parse error:", parserError.textContent);
1089
+ return null;
1090
+ }
1083
1091
  const svg = doc.querySelector("svg");
1084
1092
  if (!svg || svg.nodeName !== "svg") return null;
1085
1093
  return svg;
1086
1094
  }
1087
1095
  /**
1088
1096
  * Render trigger button using safe DOM methods
1097
+ * Matches widget-bundle behavior: icon mode = circular button, text mode = rectangular
1098
+ * Falls back to text mode if icon rendering fails (fixes "square with ellipses" bug)
1089
1099
  */
1090
1100
  renderTrigger() {
1091
1101
  if (!this.widgetConfig) return;
1092
1102
  const { triggerIcon, triggerText } = this.widgetConfig.config;
1103
+ const hasIcon = triggerIcon && triggerIcon !== "none";
1093
1104
  this.triggerButton = document.createElement("button");
1094
- this.triggerButton.className = "fv-widget-trigger";
1095
- if (triggerIcon && triggerIcon !== "none") {
1096
- const iconSvg = this.createTriggerIcon(triggerIcon);
1097
- if (iconSvg) {
1098
- const iconSpan = document.createElement("span");
1099
- iconSpan.className = "fv-widget-trigger-icon";
1100
- iconSpan.appendChild(iconSvg);
1101
- this.triggerButton.appendChild(iconSpan);
1102
- if (triggerText) {
1103
- const textSpan = document.createElement("span");
1104
- textSpan.textContent = triggerText;
1105
- this.triggerButton.appendChild(textSpan);
1105
+ let iconRendered = false;
1106
+ if (hasIcon) {
1107
+ const iconSvgString = _FeedValue.TRIGGER_ICONS[triggerIcon];
1108
+ if (iconSvgString) {
1109
+ const svgElement = this.parseSvgString(iconSvgString);
1110
+ if (svgElement) {
1111
+ this.triggerButton.className = "fv-widget-trigger fv-widget-trigger-icon";
1112
+ this.triggerButton.appendChild(svgElement);
1113
+ iconRendered = true;
1114
+ } else {
1115
+ this.log(`SVG parsing failed for icon: ${triggerIcon}, falling back to text`);
1106
1116
  }
1107
1117
  } else {
1108
- this.triggerButton.textContent = triggerText;
1118
+ this.log(`Icon not found: ${triggerIcon}, falling back to text`);
1109
1119
  }
1110
- } else {
1111
- this.triggerButton.textContent = triggerText;
1120
+ }
1121
+ if (!iconRendered) {
1122
+ this.triggerButton.className = "fv-widget-trigger";
1123
+ this.triggerButton.textContent = triggerText || "Feedback";
1112
1124
  }
1113
1125
  this.triggerButton.addEventListener("click", () => this.open());
1114
1126
  document.body.appendChild(this.triggerButton);
@@ -1265,6 +1277,18 @@ var FeedValue = class _FeedValue {
1265
1277
  }
1266
1278
  }
1267
1279
  };
1280
+ /**
1281
+ * SVG icons for trigger button (matching widget-bundle exactly)
1282
+ */
1283
+ __publicField(_FeedValue, "TRIGGER_ICONS", {
1284
+ 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>',
1285
+ 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>',
1286
+ 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>',
1287
+ 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>',
1288
+ 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>',
1289
+ 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>'
1290
+ });
1291
+ var FeedValue = _FeedValue;
1268
1292
 
1269
1293
  export { ApiClient, DEFAULT_API_BASE_URL, FeedValue, TypedEventEmitter, clearFingerprint, generateFingerprint };
1270
1294
  //# sourceMappingURL=index.js.map