kenobi-js 0.1.40 → 0.1.42

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,6 +1,6 @@
1
1
  /*!
2
- * Kenobi SDK v0.1.38
3
- * (c) 2025 Kenobi.ai
2
+ * Kenobi SDK v0.1.41
3
+ * (c) 2026 Kenobi.ai
4
4
  */
5
5
  "use strict";
6
6
  var KenobiLib = (() => {
@@ -1022,17 +1022,14 @@ var KenobiLib = (() => {
1022
1022
  {
1023
1023
  xmlns: "http://www.w3.org/2000/svg",
1024
1024
  viewBox: "0 0 24 24",
1025
- fill: "currentColor",
1025
+ fill: "none",
1026
+ stroke: "currentColor",
1027
+ "stroke-width": "3",
1028
+ "stroke-linecap": "round",
1029
+ "stroke-linejoin": "round",
1026
1030
  width: "16",
1027
1031
  height: "16",
1028
- children: /* @__PURE__ */ u3(
1029
- "path",
1030
- {
1031
- fillRule: "evenodd",
1032
- d: "M16.72 7.72a.75.75 0 0 1 1.06 0l3.75 3.75a.75.75 0 0 1 0 1.06l-3.75 3.75a.75.75 0 1 1-1.06-1.06l2.47-2.47H3a.75.75 0 0 1 0-1.5h16.19l-2.47-2.47a.75.75 0 0 1 0-1.06Z",
1033
- clipRule: "evenodd"
1034
- }
1035
- )
1032
+ children: /* @__PURE__ */ u3("path", { d: "M5 12h14M12 5l7 7-7 7" })
1036
1033
  }
1037
1034
  ), "ArrowRightIcon");
1038
1035
  var CheckIcon = /* @__PURE__ */ __name(() => /* @__PURE__ */ u3(
@@ -1112,13 +1109,33 @@ var KenobiLib = (() => {
1112
1109
  ]
1113
1110
  }
1114
1111
  ), "LogoIcon");
1112
+ var ArrowPathIcon = /* @__PURE__ */ __name(() => /* @__PURE__ */ u3(
1113
+ "svg",
1114
+ {
1115
+ xmlns: "http://www.w3.org/2000/svg",
1116
+ fill: "none",
1117
+ viewBox: "0 0 24 24",
1118
+ strokeWidth: 1.5,
1119
+ stroke: "currentColor",
1120
+ width: "16",
1121
+ height: "16",
1122
+ children: /* @__PURE__ */ u3(
1123
+ "path",
1124
+ {
1125
+ strokeLinecap: "round",
1126
+ strokeLinejoin: "round",
1127
+ 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"
1128
+ }
1129
+ )
1130
+ }
1131
+ ), "ArrowPathIcon");
1115
1132
  var STYLES = `
1116
- :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); }
1133
+ :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.15); --kb-kbd-border: rgba(255, 255, 255, 0.4); --kb-kbd-text: #ffffff; --kb-watermark-text: rgba(255, 255, 255, 0.4); font-family: var(--kb-font-family); }
1117
1134
  .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; }
1118
1135
  .theme-dark { --kb-bg-container: #0f172a; --kb-border-container: #334155; --kb-shadow-container: 0 25px 50px -12px rgba(0, 0, 0, 0.25); --kb-backdrop-blur: 0px; --kb-text-title: #f1f5f9; --kb-text-subtitle: #94a3b8; --kb-btn-dismiss-bg: #1e293b; --kb-btn-dismiss-border: #334155; --kb-btn-dismiss-text: #cbd5e1; --kb-btn-dismiss-hover-bg: #334155; --kb-btn-dismiss-hover-text: #ffffff; --kb-btn-trigger-bg: #ffffff; --kb-btn-trigger-text: #0f172a; --kb-btn-trigger-hover-bg: #f1f5f9; --kb-progress-track: #1e293b; --kb-progress-indicator: #ffffff; --kb-popover-bg: #0f172a; --kb-popover-border: #334155; --kb-popover-text: #f1f5f9; --kb-input-bg: #0f172a; --kb-input-border: #475569; --kb-input-text: #f1f5f9; --kb-input-placeholder: #94a3b8; --kb-form-label: #e2e8f0; --kb-success-color: #6ee7b7; --kb-error-text: #ef4444; --kb-kbd-bg: #1e293b; --kb-kbd-border: #334155; --kb-kbd-text: #94a3b8; --kb-watermark-text: #64748b; }
1119
1136
  *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
1120
1137
  #cue-card-root { position: fixed; z-index: 2147483647; pointer-events: none; width: 100%; height: 0; top: 0; left: 0; isolation: isolate; }
1121
- .container { position: absolute; pointer-events: auto; background-color: var(--kb-bg-container); border: 1px solid var(--kb-border-container); box-shadow: var(--kb-shadow-container); backdrop-filter: blur(var(--kb-backdrop-blur)); -webkit-backdrop-filter: blur(var(--kb-backdrop-blur)); border-radius: 0.25rem; border-bottom-left-radius: 0.25rem; border-bottom-right-radius: 0.25rem; padding: 1rem; width: auto; min-width: 320px; max-width: 90vw; opacity: 0; z-index: 1; font-family: var(--kb-font-family); }
1138
+ .container { position: absolute; pointer-events: auto; background-color: var(--kb-bg-container); border: 1px solid var(--kb-border-container); box-shadow: var(--kb-shadow-container); backdrop-filter: blur(var(--kb-backdrop-blur)); -webkit-backdrop-filter: blur(var(--kb-backdrop-blur)); border-radius: 0.25rem; border-bottom-left-radius: 0.25rem; border-bottom-right-radius: 0.25rem; padding: 1.25rem 1.5rem; width: auto; min-width: 400px; max-width: 90vw; opacity: 0; z-index: 1; font-family: var(--kb-font-family); }
1122
1139
  .backdrop { position: fixed; inset: 0; background: rgba(0,0,0,0); backdrop-filter: blur(0); -webkit-backdrop-filter: blur(0); transition: all 0.5s ease; z-index: 0; pointer-events: none; }
1123
1140
  .backdrop.active { background: rgba(0,0,0,0.1); backdrop-filter: blur(var(--kb-focus-blur)); -webkit-backdrop-filter: blur(var(--kb-focus-blur)); }
1124
1141
  .launcher { position: absolute; pointer-events: auto; background-color: var(--kb-bg-container); border: 1px solid var(--kb-border-container); box-shadow: var(--kb-shadow-container); backdrop-filter: blur(var(--kb-backdrop-blur)); -webkit-backdrop-filter: blur(var(--kb-backdrop-blur)); border-radius: 9999px; padding: 0.5rem 1rem; display: flex; align-items: center; gap: 0.75rem; cursor: pointer; transition: transform 0.2s, opacity 0.3s; opacity: 0; z-index: 1; color: var(--kb-text-title); font-weight: 500; font-size: 0.875rem; font-family: var(--kb-font-family); }
@@ -1141,21 +1158,31 @@ var KenobiLib = (() => {
1141
1158
  .title { color: var(--kb-text-title); font-size: 1rem; font-weight: 600; line-height: 1.5; }
1142
1159
  .subtitle { color: var(--kb-text-title); font-size: 0.875rem; line-height: 1.25; opacity: 0.8; }
1143
1160
  .btn { display: inline-flex; align-items: center; justify-content: center; border-radius: 0.375rem; font-weight: 500; font-size: 0.875rem; line-height: 1.25rem; padding: 0.5rem 1rem; transition: all 0.2s; cursor: pointer; border: none; outline: none; }
1144
- .btn-trigger { background-color: var(--kb-btn-trigger-bg); color: var(--kb-btn-trigger-text); min-width: 8rem; gap: 0.5rem; }
1161
+ .btn-trigger { background-color: var(--kb-btn-trigger-bg); color: var(--kb-btn-trigger-text); min-width: 8rem; gap: 0.5rem; transition: opacity 0.2s ease-out, background-color 0.2s ease-out; }
1162
+ .btn-trigger.hidden { opacity: 0; pointer-events: none; }
1145
1163
  .btn-trigger:not(:disabled):hover { background-color: var(--kb-btn-trigger-hover-bg); }
1146
1164
  .btn-trigger:disabled { opacity: 0.8; cursor: not-allowed; }
1147
1165
  .btn-trigger.success { background-color: transparent; color: var(--kb-success-color); padding-right: 0.75rem; cursor: default; }
1166
+ .status-text { display: inline-flex; align-items: center; gap: 0.5rem; font-size: 0.875rem; color: var(--kb-text-subtitle); opacity: 0.8; }
1148
1167
  .btn-trigger.success:hover { background-color: transparent; }
1149
1168
  .animate-spin { animation: spin 1s linear infinite; }
1150
1169
  @keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
1170
+ @keyframes shine { 0% { background-position: 0% 0%; } 50% { background-position: 100% 100%; } 100% { background-position: 0% 0%; } }
1171
+ @keyframes sheen-flash { 0% { opacity: 0; transform: translateX(-100%) skewX(-15deg); } 50% { opacity: 0.6; } 100% { opacity: 0; transform: translateX(200%) skewX(-15deg); } }
1172
+ .container-sheen { position: absolute; inset: 0; overflow: hidden; pointer-events: none; border-radius: inherit; }
1173
+ .container-sheen::after { content: ''; position: absolute; top: 0; left: 0; width: 50%; height: 100%; background: linear-gradient(90deg, transparent, rgba(255,255,255,0.4), transparent); transform: translateX(-100%) skewX(-15deg); }
1174
+ .container-sheen.active::after { animation: sheen-flash 0.6s ease-out forwards; }
1175
+ .launcher-shine-border { position: absolute; inset: 0; border-radius: inherit; pointer-events: none; background-size: 300% 300%; animation: shine var(--shine-duration, 14s) linear infinite; mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); mask-composite: exclude; -webkit-mask-composite: xor; padding: var(--shine-border-width, 1px); }
1151
1176
  .btn-dismiss { position: absolute; top: -0.5rem; left: -0.5rem; width: 1.5rem; height: 1.5rem; 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.3s ease-out; z-index: 10; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); }
1152
1177
  .btn-dismiss:hover { background-color: var(--kb-btn-dismiss-hover-bg); color: var(--kb-btn-dismiss-hover-text); }
1153
- .progress-clip { position: absolute; inset: 0; border-radius: inherit; overflow: hidden; pointer-events: none; }
1154
- .progress-container { position: absolute; bottom: 0; left: 0; right: 0; height: 0.25rem; background-color: var(--kb-progress-track); overflow: hidden; pointer-events: none; }
1178
+ .progress-clip { position: absolute; inset: 0; border-radius: inherit; border-bottom-left-radius: 0; border-bottom-right-radius: 0; overflow: hidden; pointer-events: none; }
1179
+ .progress-container { position: absolute; bottom: 0; left: 0; right: 0; height: 0.25rem; background-color: var(--kb-progress-track); overflow: hidden; pointer-events: none; border-radius: 0; }
1155
1180
  .progress-bar { height: 100%; background-color: var(--kb-progress-indicator); width: 0%; transition: width 0.3s ease; }
1156
- .popover { position: absolute; top: 100%; left: 0; right: 0; margin-top: 0.375rem; background-color: var(--kb-popover-bg); border: 1px solid var(--kb-popover-border); border-radius: 0.25rem; border-top-left-radius: 0; border-top-right-radius: 0; padding: 1rem; color: var(--kb-popover-text); box-shadow: var(--kb-shadow-container); backdrop-filter: blur(var(--kb-backdrop-blur)); -webkit-backdrop-filter: blur(var(--kb-backdrop-blur)); opacity: 0; transform: translateY(-10px); pointer-events: none; visibility: hidden; transition: all 0.2s ease-out; }
1181
+ .popover { position: absolute; top: 100%; left: 0; right: 0; margin-top: 0.375rem; background-color: var(--kb-popover-bg); border: 1px solid var(--kb-popover-border); border-radius: 0.25rem; border-top-left-radius: 0; border-top-right-radius: 0; padding: 1rem 1.5rem; color: var(--kb-popover-text); box-shadow: var(--kb-shadow-container); backdrop-filter: blur(var(--kb-backdrop-blur)); -webkit-backdrop-filter: blur(var(--kb-backdrop-blur)); opacity: 0; transform: translateY(-10px); pointer-events: none; visibility: hidden; transition: all 0.2s ease-out; }
1157
1182
  .popover.open { opacity: 1; transform: translateY(0); pointer-events: auto; visibility: visible; }
1158
- .form-group { margin-bottom: 1rem; }
1183
+ .container.popover-open { border-bottom-left-radius: 0; border-bottom-right-radius: 0; }
1184
+ .container.popover-open .progress-clip { border-bottom-left-radius: 0; border-bottom-right-radius: 0; }
1185
+ .form-group { margin-bottom: 0; }
1159
1186
  .form-label { display: block; margin-bottom: 0.5rem; font-size: 0.875rem; color: var(--kb-form-label); font-weight: 500; }
1160
1187
  .input-row { display: flex; gap: 0.5rem; }
1161
1188
  .form-input { flex: 1; background-color: var(--kb-input-bg); border: 1px solid var(--kb-input-border); color: var(--kb-input-text); border-radius: 0.375rem; padding: 0.5rem 0.75rem; font-size: 0.875rem; outline: none; transition: border-color 0.2s; min-height: 44px; }
@@ -1174,6 +1201,9 @@ var KenobiLib = (() => {
1174
1201
  .watermark { text-align: center; font-size: 0.625rem; color: var(--kb-watermark-text); opacity: 0.8; font-weight: 500; letter-spacing: 0.025em; }
1175
1202
  .watermark a { color: inherit; text-decoration: none; cursor: pointer; }
1176
1203
  .watermark a:hover { text-decoration: underline; text-decoration-color: var(--kb-watermark-text); }
1204
+ .popover-watermark { position: absolute; top: 100%; left: 0; right: 0; text-align: center; font-size: 0.625rem; color: var(--kb-watermark-text); opacity: 0.6; font-weight: 500; letter-spacing: 0.025em; padding-top: 0.5rem; }
1205
+ .popover-watermark a { color: inherit; text-decoration: none; cursor: pointer; }
1206
+ .popover-watermark a:hover { text-decoration: underline; opacity: 1; }
1177
1207
  /* Launcher hint positioning */
1178
1208
  .launcher .kbd-hint { position: static; transform: none; opacity: 0.6; transition: opacity 0.2s; }
1179
1209
  .launcher:hover .kbd-hint { opacity: 1; }
@@ -1189,17 +1219,30 @@ var KenobiLib = (() => {
1189
1219
  .launcher .kbd-hint { display: none; }
1190
1220
  .launcher .btn-dismiss.launcher-dismiss { opacity: 1; }
1191
1221
  }
1222
+ /* Toggle personalization button */
1223
+ .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; }
1224
+ .btn-toggle-personalization:hover { background-color: var(--kb-btn-dismiss-hover-bg); color: var(--kb-btn-dismiss-hover-text); transform: scale(1.05); }
1225
+ .btn-toggle-personalization svg { width: 14px; height: 14px; }
1226
+ /* Custom tooltip for toggle button */
1227
+ .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); }
1228
+ .btn-toggle-personalization:hover .toggle-tooltip { opacity: 1; visibility: visible; }
1192
1229
  `;
1193
1230
  var useEnterExitAnimation = /* @__PURE__ */ __name((ref, isVisible, config) => {
1194
1231
  const hasEnteredRef = A2(false);
1232
+ const currentAnimRef = A2(null);
1195
1233
  y2(() => {
1196
1234
  const element = ref.current;
1197
1235
  if (!element) return;
1236
+ if (currentAnimRef.current) {
1237
+ currentAnimRef.current.cancel();
1238
+ currentAnimRef.current = null;
1239
+ }
1198
1240
  const isTopDown = config.direction === "top-to-bottom";
1199
1241
  const initialTransform = isTopDown ? `translateY(-60px)` : `translateX(60px)`;
1200
1242
  const exitTransform = isTopDown ? `translateY(-20px)` : `translateX(20px)`;
1201
1243
  const finalTransform = "translate(0, 0)";
1202
1244
  if (isVisible) {
1245
+ element.style.visibility = "visible";
1203
1246
  hasEnteredRef.current = true;
1204
1247
  const anim = element.animate(
1205
1248
  [
@@ -1213,7 +1256,11 @@ var KenobiLib = (() => {
1213
1256
  fill: "forwards"
1214
1257
  }
1215
1258
  );
1216
- anim.onfinish = () => config.onEntranceComplete?.();
1259
+ currentAnimRef.current = anim;
1260
+ anim.onfinish = () => {
1261
+ currentAnimRef.current = null;
1262
+ config.onEntranceComplete?.();
1263
+ };
1217
1264
  } else {
1218
1265
  if (hasEnteredRef.current) {
1219
1266
  const anim = element.animate(
@@ -1228,10 +1275,16 @@ var KenobiLib = (() => {
1228
1275
  fill: "forwards"
1229
1276
  }
1230
1277
  );
1231
- anim.onfinish = () => config.onExitComplete?.();
1278
+ currentAnimRef.current = anim;
1279
+ anim.onfinish = () => {
1280
+ element.style.visibility = "hidden";
1281
+ currentAnimRef.current = null;
1282
+ config.onExitComplete?.();
1283
+ };
1232
1284
  } else {
1233
1285
  element.style.opacity = "0";
1234
1286
  element.style.transform = exitTransform;
1287
+ element.style.visibility = "hidden";
1235
1288
  }
1236
1289
  }
1237
1290
  }, [isVisible, config.direction]);
@@ -1277,8 +1330,9 @@ var KenobiLib = (() => {
1277
1330
  const formRef = A2(null);
1278
1331
  const [mode, setMode] = d2("card");
1279
1332
  const [isDismissed, setIsDismissed] = d2(false);
1333
+ const [hasHadSuccess, setHasHadSuccess] = d2(false);
1334
+ const [isExitingToLauncher, setIsExitingToLauncher] = d2(false);
1280
1335
  const hasEnteredRef = A2(false);
1281
- const hasHadSuccessRef = A2(false);
1282
1336
  const isShowingInitialSuccessRef = A2(false);
1283
1337
  const justReopenedRef = A2(false);
1284
1338
  const previousModeRef = A2("card");
@@ -1288,6 +1342,7 @@ var KenobiLib = (() => {
1288
1342
  const timerRafRef = A2(null);
1289
1343
  const hasTimerCompletedRef = A2(false);
1290
1344
  const [isHovering, setIsHovering] = d2(false);
1345
+ const [sheenActive, setSheenActive] = d2(false);
1291
1346
  const [errors, setErrors] = d2({});
1292
1347
  const [timerProgress, setTimerProgressState] = d2(0);
1293
1348
  const timerProgressRef = A2(0);
@@ -1318,7 +1373,7 @@ var KenobiLib = (() => {
1318
1373
  y2(() => {
1319
1374
  const wasLauncher = previousModeRef.current === "launcher";
1320
1375
  const isCard = mode === "card";
1321
- if (wasLauncher && isCard && hasHadSuccessRef.current) {
1376
+ if (wasLauncher && isCard && hasHadSuccess) {
1322
1377
  justReopenedRef.current = true;
1323
1378
  setTimeout(() => {
1324
1379
  justReopenedRef.current = false;
@@ -1335,7 +1390,7 @@ var KenobiLib = (() => {
1335
1390
  }, [mode, setTimerProgress, timerEnabled]);
1336
1391
  y2(() => {
1337
1392
  if (config.status === "success") {
1338
- hasHadSuccessRef.current = true;
1393
+ setHasHadSuccess(true);
1339
1394
  if (config.enableLauncher && mode === "card" && isShowingInitialSuccessRef.current) {
1340
1395
  const timer = setTimeout(() => {
1341
1396
  setMode("launcher");
@@ -1361,7 +1416,7 @@ var KenobiLib = (() => {
1361
1416
  }
1362
1417
  y2(() => {
1363
1418
  if (isOpen) {
1364
- if (hasHadSuccessRef.current && formRef.current) {
1419
+ if (hasHadSuccess && formRef.current) {
1365
1420
  formRef.current.reset();
1366
1421
  }
1367
1422
  const shouldSkipFocus = skipFocusRef.current;
@@ -1384,6 +1439,9 @@ var KenobiLib = (() => {
1384
1439
  setMode("card");
1385
1440
  }
1386
1441
  }, [isOpen, mode]);
1442
+ const isFirstAppearance = !hasEnteredRef.current;
1443
+ const wasLauncherPreviously = previousModeRef.current === "launcher";
1444
+ const cardEntranceDelay = isFirstAppearance ? config.entranceDelayMs || 0 : wasLauncherPreviously && mode === "card" ? 400 : 0;
1387
1445
  if (!isInline) {
1388
1446
  useEnterExitAnimation(
1389
1447
  containerRef,
@@ -1391,7 +1449,7 @@ var KenobiLib = (() => {
1391
1449
  {
1392
1450
  direction: config.direction || "top-to-bottom",
1393
1451
  position: config.position || "top-center",
1394
- entranceDelayMs: hasEnteredRef.current ? 0 : config.entranceDelayMs || 0,
1452
+ entranceDelayMs: cardEntranceDelay,
1395
1453
  exitDelayMs: 75,
1396
1454
  onEntranceComplete: /* @__PURE__ */ __name(() => {
1397
1455
  config.onEntranceComplete?.();
@@ -1402,13 +1460,14 @@ var KenobiLib = (() => {
1402
1460
  }, "onExitComplete")
1403
1461
  }
1404
1462
  );
1463
+ const launcherEntranceDelay = 400;
1405
1464
  useEnterExitAnimation(
1406
1465
  launcherRef,
1407
1466
  !!config.isVisible && mode === "launcher" && !isDismissed,
1408
1467
  {
1409
1468
  direction: config.direction || "top-to-bottom",
1410
1469
  position: config.position || "top-center",
1411
- entranceDelayMs: 0,
1470
+ entranceDelayMs: launcherEntranceDelay,
1412
1471
  exitDelayMs: 75
1413
1472
  }
1414
1473
  );
@@ -1416,8 +1475,8 @@ var KenobiLib = (() => {
1416
1475
  y2(() => {
1417
1476
  const el = backdropRef.current;
1418
1477
  if (!el) return;
1419
- const isSuccess2 = config.status === "success";
1420
- if (config.enableFocusMode && mode === "card" && config.isVisible && !isSuccess2) {
1478
+ const isShowingSuccessState = config.status === "success" && isShowingInitialSuccessRef.current;
1479
+ if (config.enableFocusMode && mode === "card" && config.isVisible && !isShowingSuccessState) {
1421
1480
  const timer = setTimeout(() => {
1422
1481
  el.classList.add("active");
1423
1482
  }, config.focusDelayMs || 500);
@@ -1436,14 +1495,16 @@ var KenobiLib = (() => {
1436
1495
  if (!config.isVisible) return;
1437
1496
  const handleKey = /* @__PURE__ */ __name((e3) => {
1438
1497
  if (e3.key === "Escape") {
1439
- if (isOpen) {
1440
- setIsOpen(false);
1441
- return;
1442
- }
1443
1498
  if (mode === "card") {
1444
1499
  if (config.enableLauncher) {
1500
+ setIsExitingToLauncher(true);
1445
1501
  setMode("launcher");
1502
+ setTimeout(() => {
1503
+ setIsOpen(false);
1504
+ setIsExitingToLauncher(false);
1505
+ }, 500);
1446
1506
  } else {
1507
+ setIsOpen(false);
1447
1508
  config.onDismiss?.();
1448
1509
  }
1449
1510
  }
@@ -1525,7 +1586,7 @@ var KenobiLib = (() => {
1525
1586
  if (isSuccess && isShowingInitialSuccessRef.current) {
1526
1587
  return txt.btnSuccess || "Personalised";
1527
1588
  }
1528
- if (hasHadSuccessRef.current) {
1589
+ if (hasHadSuccess) {
1529
1590
  return "Show me again";
1530
1591
  }
1531
1592
  return txt.btnResting || "Show me";
@@ -1608,7 +1669,12 @@ var KenobiLib = (() => {
1608
1669
  const togglePopover = /* @__PURE__ */ __name((e3) => {
1609
1670
  e3.stopPropagation();
1610
1671
  if (isPending || isSuccess) return;
1611
- setIsOpen(!isOpen);
1672
+ const opening = !isOpen;
1673
+ setIsOpen(opening);
1674
+ if (opening && config.enableClickSheen) {
1675
+ setSheenActive(true);
1676
+ setTimeout(() => setSheenActive(false), 600);
1677
+ }
1612
1678
  }, "togglePopover");
1613
1679
  y2(() => {
1614
1680
  if (!timerEnabled) return;
@@ -1689,7 +1755,7 @@ var KenobiLib = (() => {
1689
1755
  "div",
1690
1756
  {
1691
1757
  ref: containerRef,
1692
- class: `container theme-${config.theme || "glass"} pos-${config.position || "top-center"}`,
1758
+ class: `container theme-${config.theme || "glass"} pos-${config.position || "top-center"}${isOpen ? " popover-open" : ""}`,
1693
1759
  style: {
1694
1760
  ...getThemeStyles(config.customTheme),
1695
1761
  pointerEvents: isContainerVisible ? "auto" : "none"
@@ -1698,6 +1764,7 @@ var KenobiLib = (() => {
1698
1764
  onMouseEnter: () => setIsHovering(true),
1699
1765
  onMouseLeave: () => setIsHovering(false),
1700
1766
  children: [
1767
+ config.enableClickSheen && /* @__PURE__ */ u3("div", { class: `container-sheen${sheenActive ? " active" : ""}` }),
1701
1768
  /* @__PURE__ */ u3(
1702
1769
  "button",
1703
1770
  {
@@ -1715,32 +1782,29 @@ var KenobiLib = (() => {
1715
1782
  children: /* @__PURE__ */ u3(XMarkIcon, {})
1716
1783
  }
1717
1784
  ),
1718
- /* @__PURE__ */ u3("div", { class: "content-wrapper", children: [
1719
- /* @__PURE__ */ u3("div", { class: "logo", children: /* @__PURE__ */ u3(LogoIcon, {}) }),
1720
- /* @__PURE__ */ u3("div", { class: "text-content", children: /* @__PURE__ */ u3("div", { class: "text-row", children: [
1721
- /* @__PURE__ */ u3("div", { children: [
1722
- /* @__PURE__ */ u3("div", { class: "title", children: titleText }),
1723
- /* @__PURE__ */ u3("div", { class: "subtitle", children: subtitleText })
1724
- ] }),
1725
- /* @__PURE__ */ u3(
1726
- "button",
1727
- {
1728
- class: `btn btn-trigger ${showAsSuccess ? "success" : ""}`,
1729
- disabled: isPending || showAsSuccess,
1730
- onClick: togglePopover,
1731
- children: isPending ? /* @__PURE__ */ u3(k, { children: [
1732
- /* @__PURE__ */ u3(LoaderIcon, {}),
1733
- " ",
1734
- buttonText
1735
- ] }) : showAsSuccess ? /* @__PURE__ */ u3(k, { children: [
1736
- /* @__PURE__ */ u3(CheckIcon, {}),
1737
- " ",
1738
- buttonText
1739
- ] }) : buttonText
1740
- }
1741
- )
1742
- ] }) })
1743
- ] }),
1785
+ /* @__PURE__ */ u3("div", { class: "content-wrapper", children: /* @__PURE__ */ u3("div", { class: "text-content", children: /* @__PURE__ */ u3("div", { class: "text-row", children: [
1786
+ /* @__PURE__ */ u3("div", { children: [
1787
+ /* @__PURE__ */ u3("div", { class: "title", children: titleText }),
1788
+ /* @__PURE__ */ u3("div", { class: "subtitle", children: subtitleText })
1789
+ ] }),
1790
+ isPending ? /* @__PURE__ */ u3("span", { class: "status-text", children: [
1791
+ /* @__PURE__ */ u3(LoaderIcon, {}),
1792
+ " ",
1793
+ buttonText
1794
+ ] }) : /* @__PURE__ */ u3(
1795
+ "button",
1796
+ {
1797
+ class: `btn btn-trigger ${showAsSuccess ? "success" : ""}${isOpen || isExitingToLauncher ? " hidden" : ""}`,
1798
+ disabled: showAsSuccess,
1799
+ onClick: togglePopover,
1800
+ children: showAsSuccess ? /* @__PURE__ */ u3(k, { children: [
1801
+ /* @__PURE__ */ u3(CheckIcon, {}),
1802
+ " ",
1803
+ buttonText
1804
+ ] }) : buttonText
1805
+ }
1806
+ )
1807
+ ] }) }) }),
1744
1808
  /* @__PURE__ */ u3("div", { class: "progress-clip", children: /* @__PURE__ */ u3("div", { class: "progress-container", children: /* @__PURE__ */ u3(
1745
1809
  "div",
1746
1810
  {
@@ -1801,7 +1865,7 @@ var KenobiLib = (() => {
1801
1865
  }
1802
1866
  )
1803
1867
  ] }),
1804
- config.showWatermark && /* @__PURE__ */ u3("div", { class: "watermark", children: [
1868
+ config.showWatermark && /* @__PURE__ */ u3("div", { class: "popover-watermark", children: [
1805
1869
  "Powered by",
1806
1870
  " ",
1807
1871
  /* @__PURE__ */ u3(
@@ -1837,6 +1901,7 @@ var KenobiLib = (() => {
1837
1901
  class: `launcher theme-${config.theme || "glass"} pos-${config.position || "top-center"}`,
1838
1902
  style: {
1839
1903
  ...getThemeStyles(config.customTheme),
1904
+ ...config.launcherStyles,
1840
1905
  pointerEvents: isLauncherVisible ? "auto" : "none"
1841
1906
  },
1842
1907
  onClick: (e3) => {
@@ -1848,6 +1913,17 @@ var KenobiLib = (() => {
1848
1913
  role: "button",
1849
1914
  tabIndex: 0,
1850
1915
  children: [
1916
+ config.launcherShineBorder?.enabled && /* @__PURE__ */ u3(
1917
+ "div",
1918
+ {
1919
+ class: "launcher-shine-border",
1920
+ style: {
1921
+ "--shine-duration": `${config.launcherShineBorder.duration || 14}s`,
1922
+ "--shine-border-width": `${config.launcherShineBorder.borderWidth || 1}px`,
1923
+ backgroundImage: `radial-gradient(transparent, transparent, ${Array.isArray(config.launcherShineBorder.color) ? config.launcherShineBorder.color.join(",") : config.launcherShineBorder.color || "rgba(255,255,255,0.5)"}, transparent, transparent)`
1924
+ }
1925
+ }
1926
+ ),
1851
1927
  /* @__PURE__ */ u3(
1852
1928
  "button",
1853
1929
  {
@@ -1861,8 +1937,23 @@ var KenobiLib = (() => {
1861
1937
  children: /* @__PURE__ */ u3(XMarkIcon, {})
1862
1938
  }
1863
1939
  ),
1864
- /* @__PURE__ */ u3("div", { class: "launcher-logo", children: /* @__PURE__ */ u3(LogoIcon, {}) }),
1865
- config.textOverrides?.launcherLabel || (hasHadSuccessRef.current ? "Personalize again" : "Personalize"),
1940
+ config.showLauncherLogo !== false && /* @__PURE__ */ u3("div", { class: "launcher-logo", children: /* @__PURE__ */ u3(LogoIcon, {}) }),
1941
+ hasHadSuccess ? config.textOverrides?.launcherLabelSuccess || config.textOverrides?.launcherLabel || "Personalize again" : config.textOverrides?.launcherLabel || "Personalize",
1942
+ config.enableUndoToggle && hasHadSuccess && /* @__PURE__ */ u3(
1943
+ "button",
1944
+ {
1945
+ class: "btn-toggle-personalization",
1946
+ "aria-label": config.isPersonalized ? "Show original" : "Show personalized",
1947
+ onClick: (e3) => {
1948
+ e3.stopPropagation();
1949
+ config.onTogglePersonalization?.();
1950
+ },
1951
+ children: [
1952
+ /* @__PURE__ */ u3(ArrowPathIcon, {}),
1953
+ /* @__PURE__ */ u3("span", { class: "toggle-tooltip", children: config.isPersonalized ? "Show original" : "Show personalized" })
1954
+ ]
1955
+ }
1956
+ ),
1866
1957
  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
1958
  ]
1868
1959
  }
@@ -1912,6 +2003,7 @@ var KenobiLib = (() => {
1912
2003
  applyHostStyles() {
1913
2004
  const isInline = this.config.mountMode === "inline";
1914
2005
  this.host.classList.toggle("kb-inline", isInline);
2006
+ const focusBlur = this.config.focusBlurIntensity ?? "10px";
1915
2007
  if (isInline) {
1916
2008
  this.host.style.cssText = `
1917
2009
  position: relative !important;
@@ -1923,6 +2015,7 @@ var KenobiLib = (() => {
1923
2015
  pointer-events: auto !important;
1924
2016
  isolation: auto !important;
1925
2017
  display: block !important;
2018
+ --kb-focus-blur: ${focusBlur};
1926
2019
  `;
1927
2020
  return;
1928
2021
  }
@@ -1935,6 +2028,7 @@ var KenobiLib = (() => {
1935
2028
  height: 0 !important;
1936
2029
  pointer-events: none !important;
1937
2030
  isolation: isolate !important;
2031
+ --kb-focus-blur: ${focusBlur};
1938
2032
  `;
1939
2033
  }
1940
2034
  mount(target) {
@@ -2439,6 +2533,9 @@ var KenobiLib = (() => {
2439
2533
  __publicField(this, "currentUrl");
2440
2534
  __publicField(this, "navTicking", false);
2441
2535
  __publicField(this, "transitionDefaults");
2536
+ // Undo toggle state
2537
+ __publicField(this, "lastAppliedTransformations", []);
2538
+ __publicField(this, "isPersonalized", false);
2442
2539
  __publicField(this, "startAutoTransform", /* @__PURE__ */ __name(async () => {
2443
2540
  try {
2444
2541
  this.syncChangeStack();
@@ -2939,6 +3036,9 @@ var KenobiLib = (() => {
2939
3036
  );
2940
3037
  }
2941
3038
  }
3039
+ this.lastAppliedTransformations = transformations;
3040
+ this.isPersonalized = true;
3041
+ this.updateCueCardPersonalizationState();
2942
3042
  }, "applyTransformations"));
2943
3043
  /**
2944
3044
  * Creates or updates an entry in the change stack for a "Replace" action,
@@ -3027,6 +3127,34 @@ var KenobiLib = (() => {
3027
3127
  __publicField(this, "undoAll", /* @__PURE__ */ __name(() => {
3028
3128
  this.changeStack.forEach((_2, ident) => this.undo(ident));
3029
3129
  }, "undoAll"));
3130
+ /**
3131
+ * Toggles between personalized and original content.
3132
+ * Updates CueCard state accordingly.
3133
+ */
3134
+ __publicField(this, "toggleTransformations", /* @__PURE__ */ __name(async () => {
3135
+ if (this.isPersonalized) {
3136
+ this.undoAll();
3137
+ this.isPersonalized = false;
3138
+ this.log("debug", "Toggled to original content");
3139
+ } else {
3140
+ if (this.lastAppliedTransformations.length > 0) {
3141
+ await this.applyTransformations(this.lastAppliedTransformations, {
3142
+ shouldConsolidate: true
3143
+ });
3144
+ }
3145
+ this.isPersonalized = true;
3146
+ this.log("debug", "Toggled to personalized content");
3147
+ }
3148
+ this.updateCueCardPersonalizationState();
3149
+ }, "toggleTransformations"));
3150
+ /**
3151
+ * Updates the CueCard's isPersonalized state to sync the toggle button.
3152
+ */
3153
+ __publicField(this, "updateCueCardPersonalizationState", /* @__PURE__ */ __name(() => {
3154
+ if (this.cueCardInstance) {
3155
+ this.cueCardInstance.update({ isPersonalized: this.isPersonalized });
3156
+ }
3157
+ }, "updateCueCardPersonalizationState"));
3030
3158
  __publicField(this, "setInputValue", /* @__PURE__ */ __name((el, value) => {
3031
3159
  const proto = el instanceof HTMLTextAreaElement ? HTMLTextAreaElement.prototype : el instanceof HTMLInputElement ? HTMLInputElement.prototype : HTMLSelectElement.prototype;
3032
3160
  const descriptor = Object.getOwnPropertyDescriptor(proto, "value");
@@ -3120,8 +3248,13 @@ var KenobiLib = (() => {
3120
3248
  enableLauncher: serverConfig?.enableLauncher ?? true,
3121
3249
  customTheme: serverConfig?.customTheme,
3122
3250
  textOverrides: serverConfig?.textOverrides,
3251
+ enableUndoToggle: serverConfig?.enableUndoToggle ?? false,
3252
+ isPersonalized: this.isPersonalized,
3123
3253
  onDismiss: /* @__PURE__ */ __name(() => {
3124
3254
  this.log("debug", "CueCard dismissed by user");
3255
+ this.dispatchKenobiEvent("cuecard:dismiss", {
3256
+ pagePath: this.currentPath
3257
+ });
3125
3258
  }, "onDismiss"),
3126
3259
  onSubmitPersonalization: /* @__PURE__ */ __name((values) => {
3127
3260
  this.log("debug", "CueCard submitted:", values);
@@ -3129,7 +3262,19 @@ var KenobiLib = (() => {
3129
3262
  }, "onSubmitPersonalization"),
3130
3263
  onOpenChange: /* @__PURE__ */ __name((isOpen) => {
3131
3264
  this.log("debug", "CueCard open state changed:", isOpen);
3132
- }, "onOpenChange")
3265
+ this.dispatchKenobiEvent("cuecard:openchange", {
3266
+ isOpen,
3267
+ pagePath: this.currentPath
3268
+ });
3269
+ }, "onOpenChange"),
3270
+ onTogglePersonalization: /* @__PURE__ */ __name(() => {
3271
+ this.log("debug", "CueCard toggle personalization");
3272
+ void this.toggleTransformations();
3273
+ this.dispatchKenobiEvent("cuecard:toggle", {
3274
+ isPersonalized: this.isPersonalized,
3275
+ pagePath: this.currentPath
3276
+ });
3277
+ }, "onTogglePersonalization")
3133
3278
  });
3134
3279
  this.cueCardInstance.mount();
3135
3280
  this.log("debug", "CueCard mounted successfully");
@@ -3148,10 +3293,27 @@ var KenobiLib = (() => {
3148
3293
  }
3149
3294
  void this.initCueCard();
3150
3295
  }, "syncCueCardVisibility"));
3296
+ /**
3297
+ * Dispatches a custom event on window for external listeners.
3298
+ * Events are prefixed with "kenobi:" for namespacing.
3299
+ */
3300
+ __publicField(this, "dispatchKenobiEvent", /* @__PURE__ */ __name((eventName, detail) => {
3301
+ const event = new CustomEvent(`kenobi:${eventName}`, {
3302
+ detail,
3303
+ bubbles: true
3304
+ });
3305
+ window.dispatchEvent(event);
3306
+ this.log("debug", `Dispatched event: kenobi:${eventName}`, detail);
3307
+ }, "dispatchKenobiEvent"));
3151
3308
  /**
3152
3309
  * Triggers personalization by calling the API with the provided input.
3153
3310
  * Updates CueCard status during the flow and applies transformations.
3154
3311
  *
3312
+ * Dispatches events:
3313
+ * - `kenobi:personalization:start` - when personalization begins
3314
+ * - `kenobi:personalization:complete` - when personalization succeeds
3315
+ * - `kenobi:personalization:error` - when personalization fails
3316
+ *
3155
3317
  * @param input - User-provided fields (e.g., { companyDomain: "acme.com" })
3156
3318
  */
3157
3319
  __publicField(this, "personalize", /* @__PURE__ */ __name(async (input) => {
@@ -3161,6 +3323,10 @@ var KenobiLib = (() => {
3161
3323
  }
3162
3324
  const startTime = /* @__PURE__ */ new Date();
3163
3325
  this.log("debug", "Starting personalization with input:", input);
3326
+ this.dispatchKenobiEvent("personalization:start", {
3327
+ input,
3328
+ pagePath: this.currentPath
3329
+ });
3164
3330
  if (this.cueCardInstance) {
3165
3331
  this.cueCardInstance.update({ status: "starting", progressPct: 10 });
3166
3332
  }
@@ -3202,11 +3368,23 @@ var KenobiLib = (() => {
3202
3368
  "debug",
3203
3369
  `Personalization complete, took ${this.formatThousands(duration)} ms`
3204
3370
  );
3371
+ this.dispatchKenobiEvent("personalization:complete", {
3372
+ input,
3373
+ pagePath: this.currentPath,
3374
+ durationMs: duration,
3375
+ transformationsCount: result.transformations?.length ?? 0,
3376
+ metadata: result.metadata
3377
+ });
3205
3378
  } catch (error) {
3206
3379
  this.log("error", "Personalization failed:", error);
3207
3380
  if (this.cueCardInstance) {
3208
3381
  this.cueCardInstance.update({ status: "error", progressPct: 0 });
3209
3382
  }
3383
+ this.dispatchKenobiEvent("personalization:error", {
3384
+ input,
3385
+ pagePath: this.currentPath,
3386
+ error: error instanceof Error ? error.message : String(error)
3387
+ });
3210
3388
  }
3211
3389
  }, "personalize"));
3212
3390
  /**
@@ -3243,7 +3421,7 @@ var KenobiLib = (() => {
3243
3421
  this.log("debug", "Auto-transform is requested... Starting...");
3244
3422
  void this.startAutoTransform();
3245
3423
  }
3246
- if (this.config.publicKey) {
3424
+ if (this.config.publicKey && !this.config.skipCueCardAutoMount) {
3247
3425
  this.log("debug", "Public key provided, checking for active template...");
3248
3426
  void this.initCueCard();
3249
3427
  }