kenobi-js 0.1.39 → 0.1.41

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/browser/dist.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Kenobi SDK v0.1.38
2
+ * Kenobi SDK v0.1.40
3
3
  * (c) 2025 Kenobi.ai
4
4
  */
5
5
  "use strict";
@@ -1112,6 +1112,26 @@ var KenobiLib = (() => {
1112
1112
  ]
1113
1113
  }
1114
1114
  ), "LogoIcon");
1115
+ var ArrowPathIcon = /* @__PURE__ */ __name(() => /* @__PURE__ */ u3(
1116
+ "svg",
1117
+ {
1118
+ xmlns: "http://www.w3.org/2000/svg",
1119
+ fill: "none",
1120
+ viewBox: "0 0 24 24",
1121
+ strokeWidth: 1.5,
1122
+ stroke: "currentColor",
1123
+ width: "16",
1124
+ height: "16",
1125
+ children: /* @__PURE__ */ u3(
1126
+ "path",
1127
+ {
1128
+ strokeLinecap: "round",
1129
+ strokeLinejoin: "round",
1130
+ d: "M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0 3.181 3.183a8.25 8.25 0 0 0 13.803-3.7M4.031 9.865a8.25 8.25 0 0 1 13.803-3.7l3.181 3.182m0-4.991v4.99"
1131
+ }
1132
+ )
1133
+ }
1134
+ ), "ArrowPathIcon");
1115
1135
  var STYLES = `
1116
1136
  :host { --kb-font-family: system-ui, -apple-system, sans-serif; --kb-bg-container: rgba(255, 255, 255, 0.05); --kb-border-container: rgba(255, 255, 255, 0.2); --kb-shadow-container: 0 25px 50px -12px rgba(0, 0, 0, 0.25); --kb-backdrop-blur: 16px; --kb-text-title: #ffffff; --kb-text-subtitle: rgba(255, 255, 255, 0.7); --kb-btn-dismiss-bg: rgba(0, 0, 0, 0.7); --kb-btn-dismiss-border: rgba(255, 255, 255, 0.2); --kb-btn-dismiss-text: rgba(255, 255, 255, 0.8); --kb-btn-dismiss-hover-bg: rgba(0, 0, 0, 0.9); --kb-btn-dismiss-hover-text: #ffffff; --kb-btn-trigger-bg: #ffffff; --kb-btn-trigger-text: #000000; --kb-btn-trigger-hover-bg: rgba(255, 255, 255, 0.9); --kb-progress-track: rgba(255, 255, 255, 0.2); --kb-progress-indicator: #ffffff; --kb-popover-bg: rgba(255, 255, 255, 0.05); --kb-popover-border: rgba(255, 255, 255, 0.2); --kb-popover-text: #ffffff; --kb-input-bg: transparent; --kb-input-border: rgba(255, 255, 255, 0.3); --kb-input-text: #ffffff; --kb-input-placeholder: rgba(255, 255, 255, 0.6); --kb-form-label: #ffffff; --kb-success-color: #6ee7b7; --kb-error-text: #ef4444; --kb-focus-blur: 10px; --kb-kbd-bg: rgba(255, 255, 255, 0.1); --kb-kbd-border: rgba(255, 255, 255, 0.2); --kb-kbd-text: rgba(255, 255, 255, 0.6); --kb-watermark-text: rgba(255, 255, 255, 0.4); font-family: var(--kb-font-family); }
1117
1137
  .theme-light { --kb-bg-container: #ffffff; --kb-border-container: #e2e8f0; --kb-shadow-container: 0 20px 25px -5px rgba(0, 0, 0, 0.1); --kb-backdrop-blur: 0px; --kb-text-title: #0f172a; --kb-text-subtitle: #475569; --kb-btn-dismiss-bg: #ffffff; --kb-btn-dismiss-border: #e2e8f0; --kb-btn-dismiss-text: #64748b; --kb-btn-dismiss-hover-bg: #f1f5f9; --kb-btn-dismiss-hover-text: #0f172a; --kb-btn-trigger-bg: #0f172a; --kb-btn-trigger-text: #ffffff; --kb-btn-trigger-hover-bg: #1e293b; --kb-progress-track: #e2e8f0; --kb-progress-indicator: #0f172a; --kb-popover-bg: #ffffff; --kb-popover-border: #e2e8f0; --kb-popover-text: #0f172a; --kb-input-bg: #ffffff; --kb-input-border: #cbd5e1; --kb-input-text: #0f172a; --kb-input-placeholder: #94a3b8; --kb-form-label: #334155; --kb-success-color: #059669; --kb-error-text: #ef4444; --kb-kbd-bg: #f1f5f9; --kb-kbd-border: #e2e8f0; --kb-kbd-text: #64748b; --kb-watermark-text: #94a3b8; }
@@ -1189,6 +1209,13 @@ var KenobiLib = (() => {
1189
1209
  .launcher .kbd-hint { display: none; }
1190
1210
  .launcher .btn-dismiss.launcher-dismiss { opacity: 1; }
1191
1211
  }
1212
+ /* Toggle personalization button */
1213
+ .btn-toggle-personalization { position: relative; width: 1.75rem; height: 1.75rem; padding: 0; border-radius: 9999px; display: flex; align-items: center; justify-content: center; background-color: var(--kb-btn-dismiss-bg); border: 1px solid var(--kb-btn-dismiss-border); color: var(--kb-btn-dismiss-text); cursor: pointer; transition: all 0.2s ease-out; flex-shrink: 0; margin-left: 0.25rem; }
1214
+ .btn-toggle-personalization:hover { background-color: var(--kb-btn-dismiss-hover-bg); color: var(--kb-btn-dismiss-hover-text); transform: scale(1.05); }
1215
+ .btn-toggle-personalization svg { width: 14px; height: 14px; }
1216
+ /* Custom tooltip for toggle button */
1217
+ .btn-toggle-personalization .toggle-tooltip { position: absolute; top: calc(100% + 6px); left: 50%; transform: translateX(-50%); white-space: nowrap; background-color: var(--kb-bg-container); border: 1px solid var(--kb-border-container); color: var(--kb-text-title); font-size: 0.7rem; font-weight: 500; padding: 0.25rem 0.5rem; border-radius: 4px; opacity: 0; visibility: hidden; transition: opacity 0.15s ease-out, visibility 0.15s ease-out; pointer-events: none; z-index: 100; box-shadow: 0 2px 8px rgba(0,0,0,0.15); }
1218
+ .btn-toggle-personalization:hover .toggle-tooltip { opacity: 1; visibility: visible; }
1192
1219
  `;
1193
1220
  var useEnterExitAnimation = /* @__PURE__ */ __name((ref, isVisible, config) => {
1194
1221
  const hasEnteredRef = A2(false);
@@ -1277,8 +1304,8 @@ var KenobiLib = (() => {
1277
1304
  const formRef = A2(null);
1278
1305
  const [mode, setMode] = d2("card");
1279
1306
  const [isDismissed, setIsDismissed] = d2(false);
1307
+ const [hasHadSuccess, setHasHadSuccess] = d2(false);
1280
1308
  const hasEnteredRef = A2(false);
1281
- const hasHadSuccessRef = A2(false);
1282
1309
  const isShowingInitialSuccessRef = A2(false);
1283
1310
  const justReopenedRef = A2(false);
1284
1311
  const previousModeRef = A2("card");
@@ -1318,7 +1345,7 @@ var KenobiLib = (() => {
1318
1345
  y2(() => {
1319
1346
  const wasLauncher = previousModeRef.current === "launcher";
1320
1347
  const isCard = mode === "card";
1321
- if (wasLauncher && isCard && hasHadSuccessRef.current) {
1348
+ if (wasLauncher && isCard && hasHadSuccess) {
1322
1349
  justReopenedRef.current = true;
1323
1350
  setTimeout(() => {
1324
1351
  justReopenedRef.current = false;
@@ -1335,7 +1362,7 @@ var KenobiLib = (() => {
1335
1362
  }, [mode, setTimerProgress, timerEnabled]);
1336
1363
  y2(() => {
1337
1364
  if (config.status === "success") {
1338
- hasHadSuccessRef.current = true;
1365
+ setHasHadSuccess(true);
1339
1366
  if (config.enableLauncher && mode === "card" && isShowingInitialSuccessRef.current) {
1340
1367
  const timer = setTimeout(() => {
1341
1368
  setMode("launcher");
@@ -1361,7 +1388,7 @@ var KenobiLib = (() => {
1361
1388
  }
1362
1389
  y2(() => {
1363
1390
  if (isOpen) {
1364
- if (hasHadSuccessRef.current && formRef.current) {
1391
+ if (hasHadSuccess && formRef.current) {
1365
1392
  formRef.current.reset();
1366
1393
  }
1367
1394
  const shouldSkipFocus = skipFocusRef.current;
@@ -1525,7 +1552,7 @@ var KenobiLib = (() => {
1525
1552
  if (isSuccess && isShowingInitialSuccessRef.current) {
1526
1553
  return txt.btnSuccess || "Personalised";
1527
1554
  }
1528
- if (hasHadSuccessRef.current) {
1555
+ if (hasHadSuccess) {
1529
1556
  return "Show me again";
1530
1557
  }
1531
1558
  return txt.btnResting || "Show me";
@@ -1862,7 +1889,22 @@ var KenobiLib = (() => {
1862
1889
  }
1863
1890
  ),
1864
1891
  /* @__PURE__ */ u3("div", { class: "launcher-logo", children: /* @__PURE__ */ u3(LogoIcon, {}) }),
1865
- config.textOverrides?.launcherLabel || (hasHadSuccessRef.current ? "Personalize again" : "Personalize"),
1892
+ config.textOverrides?.launcherLabel || (hasHadSuccess ? "Personalize again" : "Personalize"),
1893
+ config.enableUndoToggle && hasHadSuccess && /* @__PURE__ */ u3(
1894
+ "button",
1895
+ {
1896
+ class: "btn-toggle-personalization",
1897
+ "aria-label": config.isPersonalized ? "Show original" : "Show personalized",
1898
+ onClick: (e3) => {
1899
+ e3.stopPropagation();
1900
+ config.onTogglePersonalization?.();
1901
+ },
1902
+ children: [
1903
+ /* @__PURE__ */ u3(ArrowPathIcon, {}),
1904
+ /* @__PURE__ */ u3("span", { class: "toggle-tooltip", children: config.isPersonalized ? "Show original" : "Show personalized" })
1905
+ ]
1906
+ }
1907
+ ),
1866
1908
  config.showKeyboardHints && /* @__PURE__ */ u3("div", { class: "kbd-hint visible", children: /* @__PURE__ */ u3("div", { class: "kbd-group", children: shortcutDisplay.map((k3, i3) => /* @__PURE__ */ u3("div", { class: "kbd", children: k3 }, i3)) }) })
1867
1909
  ]
1868
1910
  }
@@ -2439,7 +2481,9 @@ var KenobiLib = (() => {
2439
2481
  __publicField(this, "currentUrl");
2440
2482
  __publicField(this, "navTicking", false);
2441
2483
  __publicField(this, "transitionDefaults");
2442
- __publicField(this, "cueCardPaths");
2484
+ // Undo toggle state
2485
+ __publicField(this, "lastAppliedTransformations", []);
2486
+ __publicField(this, "isPersonalized", false);
2443
2487
  __publicField(this, "startAutoTransform", /* @__PURE__ */ __name(async () => {
2444
2488
  try {
2445
2489
  this.syncChangeStack();
@@ -2572,18 +2616,6 @@ var KenobiLib = (() => {
2572
2616
  __publicField(this, "getDurationInMilliseconds", /* @__PURE__ */ __name((start, end) => +end - +start, "getDurationInMilliseconds"));
2573
2617
  __publicField(this, "formatThousands", /* @__PURE__ */ __name((number) => new Intl.NumberFormat("en-US").format(number), "formatThousands"));
2574
2618
  __publicField(this, "setDebug", /* @__PURE__ */ __name((value) => this.config.debug = value, "setDebug"));
2575
- /**
2576
- * Checks if a path matches a pattern (exact match only).
2577
- */
2578
- __publicField(this, "matchesPathPattern", /* @__PURE__ */ __name((path, pattern) => {
2579
- const normalizedPath = path === "/" ? "/" : path.replace(/\/$/, "");
2580
- const normalizedPattern = pattern === "/" ? "/" : pattern.replace(/\/$/, "");
2581
- return normalizedPath === normalizedPattern;
2582
- }, "matchesPathPattern"));
2583
- /**
2584
- * Checks if the given path matches any of the configured cueCardPaths.
2585
- */
2586
- __publicField(this, "isPathAllowedForCueCard", /* @__PURE__ */ __name((path) => this.cueCardPaths.some((pattern) => this.matchesPathPattern(path, pattern)), "isPathAllowedForCueCard"));
2587
2619
  __publicField(this, "isInputElement", /* @__PURE__ */ __name((el) => {
2588
2620
  if (!(el instanceof HTMLInputElement) && !(el instanceof HTMLTextAreaElement) && !(el instanceof HTMLSelectElement))
2589
2621
  return false;
@@ -2952,6 +2984,9 @@ var KenobiLib = (() => {
2952
2984
  );
2953
2985
  }
2954
2986
  }
2987
+ this.lastAppliedTransformations = transformations;
2988
+ this.isPersonalized = true;
2989
+ this.updateCueCardPersonalizationState();
2955
2990
  }, "applyTransformations"));
2956
2991
  /**
2957
2992
  * Creates or updates an entry in the change stack for a "Replace" action,
@@ -3040,6 +3075,34 @@ var KenobiLib = (() => {
3040
3075
  __publicField(this, "undoAll", /* @__PURE__ */ __name(() => {
3041
3076
  this.changeStack.forEach((_2, ident) => this.undo(ident));
3042
3077
  }, "undoAll"));
3078
+ /**
3079
+ * Toggles between personalized and original content.
3080
+ * Updates CueCard state accordingly.
3081
+ */
3082
+ __publicField(this, "toggleTransformations", /* @__PURE__ */ __name(async () => {
3083
+ if (this.isPersonalized) {
3084
+ this.undoAll();
3085
+ this.isPersonalized = false;
3086
+ this.log("debug", "Toggled to original content");
3087
+ } else {
3088
+ if (this.lastAppliedTransformations.length > 0) {
3089
+ await this.applyTransformations(this.lastAppliedTransformations, {
3090
+ shouldConsolidate: true
3091
+ });
3092
+ }
3093
+ this.isPersonalized = true;
3094
+ this.log("debug", "Toggled to personalized content");
3095
+ }
3096
+ this.updateCueCardPersonalizationState();
3097
+ }, "toggleTransformations"));
3098
+ /**
3099
+ * Updates the CueCard's isPersonalized state to sync the toggle button.
3100
+ */
3101
+ __publicField(this, "updateCueCardPersonalizationState", /* @__PURE__ */ __name(() => {
3102
+ if (this.cueCardInstance) {
3103
+ this.cueCardInstance.update({ isPersonalized: this.isPersonalized });
3104
+ }
3105
+ }, "updateCueCardPersonalizationState"));
3043
3106
  __publicField(this, "setInputValue", /* @__PURE__ */ __name((el, value) => {
3044
3107
  const proto = el instanceof HTMLTextAreaElement ? HTMLTextAreaElement.prototype : el instanceof HTMLInputElement ? HTMLInputElement.prototype : HTMLSelectElement.prototype;
3045
3108
  const descriptor = Object.getOwnPropertyDescriptor(proto, "value");
@@ -3102,13 +3165,6 @@ var KenobiLib = (() => {
3102
3165
  this.log("warn", "CueCard already initialized, skipping...");
3103
3166
  return;
3104
3167
  }
3105
- if (!this.isPathAllowedForCueCard(this.currentPath)) {
3106
- this.log(
3107
- "debug",
3108
- `CueCard not mounted: path "${this.currentPath}" not in allowed paths`
3109
- );
3110
- return;
3111
- }
3112
3168
  const configResponse = await this.fetchCueCardConfig(this.currentPath);
3113
3169
  if (!configResponse || !configResponse.enabled) {
3114
3170
  this.log(
@@ -3140,6 +3196,8 @@ var KenobiLib = (() => {
3140
3196
  enableLauncher: serverConfig?.enableLauncher ?? true,
3141
3197
  customTheme: serverConfig?.customTheme,
3142
3198
  textOverrides: serverConfig?.textOverrides,
3199
+ enableUndoToggle: serverConfig?.enableUndoToggle ?? false,
3200
+ isPersonalized: this.isPersonalized,
3143
3201
  onDismiss: /* @__PURE__ */ __name(() => {
3144
3202
  this.log("debug", "CueCard dismissed by user");
3145
3203
  }, "onDismiss"),
@@ -3149,33 +3207,28 @@ var KenobiLib = (() => {
3149
3207
  }, "onSubmitPersonalization"),
3150
3208
  onOpenChange: /* @__PURE__ */ __name((isOpen) => {
3151
3209
  this.log("debug", "CueCard open state changed:", isOpen);
3152
- }, "onOpenChange")
3210
+ }, "onOpenChange"),
3211
+ onTogglePersonalization: /* @__PURE__ */ __name(() => {
3212
+ this.log("debug", "CueCard toggle personalization");
3213
+ void this.toggleTransformations();
3214
+ }, "onTogglePersonalization")
3153
3215
  });
3154
3216
  this.cueCardInstance.mount();
3155
3217
  this.log("debug", "CueCard mounted successfully");
3156
3218
  }, "initCueCard"));
3157
3219
  /**
3158
3220
  * Syncs CueCard visibility based on the current path.
3159
- * Mounts CueCard if on an allowed path and active template exists, unmounts if not.
3221
+ * Checks with the server if an active template exists for the new path.
3160
3222
  * Called after navigation changes.
3161
3223
  */
3162
- __publicField(this, "syncCueCardVisibility", /* @__PURE__ */ __name(() => {
3224
+ __publicField(this, "syncCueCardVisibility", /* @__PURE__ */ __name(async () => {
3163
3225
  if (!this.config.publicKey) return;
3164
- const isAllowed = this.isPathAllowedForCueCard(this.currentPath);
3165
- if (isAllowed && !this.cueCardInstance) {
3166
- this.log(
3167
- "debug",
3168
- `Navigated to allowed path "${this.currentPath}", checking for active template...`
3169
- );
3170
- void this.initCueCard();
3171
- } else if (!isAllowed && this.cueCardInstance) {
3172
- this.log(
3173
- "debug",
3174
- `Navigated away from allowed paths to "${this.currentPath}", unmounting CueCard`
3175
- );
3226
+ if (this.cueCardInstance) {
3227
+ this.log("debug", `Navigation detected, unmounting CueCard`);
3176
3228
  this.cueCardInstance.unmount();
3177
3229
  this.cueCardInstance = null;
3178
3230
  }
3231
+ void this.initCueCard();
3179
3232
  }, "syncCueCardVisibility"));
3180
3233
  /**
3181
3234
  * Triggers personalization by calling the API with the provided input.
@@ -3255,7 +3308,6 @@ var KenobiLib = (() => {
3255
3308
  this.config.transitionDefaults
3256
3309
  );
3257
3310
  this.orchestrator = new TransitionOrchestrator();
3258
- this.cueCardPaths = this.config.cueCardPaths ?? ["/"];
3259
3311
  this.syncVisitorKey();
3260
3312
  this.currentPath = this.getCurrentPath();
3261
3313
  this.currentUrl = this.getCurrentUrl();