@preprio/toolkit 0.1.0-beta.1 → 0.1.0-beta.3

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.
@@ -76,6 +76,7 @@ var en_default = {
76
76
  segment: "Segment",
77
77
  ABVariant: "A/B variant",
78
78
  chooseSegment: "Choose segment",
79
+ searchSegments: "Search segments",
79
80
  none: "No segments",
80
81
  allOtherUsers: "All other users",
81
82
  offDescription: "View the site as a real user (use cookies)",
@@ -104,6 +105,7 @@ var nl_default = {
104
105
  segment: "Segment",
105
106
  ABVariant: "A/B-variant",
106
107
  chooseSegment: "Kies segment",
108
+ searchSegments: "Zoek segmenten",
107
109
  none: "Geen segmenten",
108
110
  allOtherUsers: "Alle andere gebruikers",
109
111
  offDescription: "Bekijk de site als een echte gebruiker (gebruik cookies)",
@@ -968,7 +970,16 @@ function createChangeHandler(deps) {
968
970
  setCookie(COOKIE_TOOLBAR_OPEN, "false", COOKIE_OPTS);
969
971
  sendPreprEvent("preview_mode_toggled", { previewMode: after.previewMode });
970
972
  syncAutoClean(after.previewMode);
971
- deps.reload();
973
+ const [path, existing] = splitPath(deps.currentPath());
974
+ const params = new URLSearchParams(existing);
975
+ if (params.has(PARAM_SEGMENT) || params.has(PARAM_VARIANT)) {
976
+ params.delete(PARAM_SEGMENT);
977
+ params.delete(PARAM_VARIANT);
978
+ const query = params.toString();
979
+ deps.navigate(query ? `${path}?${query}` : path);
980
+ } else {
981
+ deps.reload();
982
+ }
972
983
  }
973
984
  if (before.toolbarOpen !== after.toolbarOpen) {
974
985
  setCookie(COOKIE_TOOLBAR_OPEN, String(after.toolbarOpen), COOKIE_OPTS);
@@ -1263,7 +1274,7 @@ var CLOSE_ICON_SVG = `<svg width="10" height="10" viewBox="0 0 10 10" fill="none
1263
1274
  </svg>`;
1264
1275
 
1265
1276
  // src/core/ui/toolbar.generated.ts
1266
- var TOOLBAR_CSS = ":host{--prepr-primary:#4338ca;--prepr-bg:#eef2ff;--prepr-text:#1f2937;--prepr-radius:8px;--prepr-shadow:0px 0px 40px 0px #1f29373d;--prepr-z-index:10000;--prepr-primary-50:#eef2ff;--prepr-primary-100:#e0e7ff;--prepr-primary-800:#3730a3;--prepr-indigo-600:#4f46e5;--prepr-indigo-50:#eef2ff;--prepr-indigo-700:#4338ca;--prepr-secondary-400:#fb923c;--prepr-secondary-500:#f97316;--prepr-gray-100:#f3f4f6;--prepr-gray-200:#e5e7eb;--prepr-gray-300:#d1d5db;--prepr-gray-400:#9ca3af;--prepr-gray-500:#6b7280;--prepr-gray-700:#374151;--prepr-gray-800:#1f2937;--prepr-gray-900:#111827;--prepr-shadow-sm:0px 0px 12px 0px #c3c3c3cc;color:var(--prepr-text);box-sizing:border-box;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif;font-size:14px;line-height:1.5}:host *,:host :before,:host :after,*,:before,:after{box-sizing:border-box}button{font-family:inherit;font-size:inherit;margin:0}.prepr-regular-text{font-size:.875rem;font-weight:500;line-height:1.5}.prepr-backdrop{z-index:calc(var(--prepr-z-index) - 1);opacity:0;pointer-events:none;background:#0000001a;transition:opacity .2s ease-in-out;position:fixed;top:0;bottom:0;left:0;right:0}.prepr-backdrop[data-open=true]{opacity:1;pointer-events:auto;animation:.2s ease-in-out prepr-fade-in}.prepr-container{z-index:var(--prepr-z-index);justify-content:flex-end;align-items:center;display:flex;position:fixed;top:calc(50% - 64px);right:0}.prepr-toggle-holder{padding:.5rem}.prepr-toggle{cursor:pointer;background:var(--prepr-primary);color:#fff;border:none;border-radius:9999px;justify-content:center;align-items:center;width:2.25rem;height:2.25rem;display:flex}.prepr-toggle svg{color:#fff}.prepr-panel{z-index:var(--prepr-z-index);opacity:0;pointer-events:none;justify-content:flex-end;padding:.75rem;transition:opacity .2s ease-in-out;display:flex;position:fixed;top:50%;right:0;transform:translateY(-50%)}.prepr-panel[data-open=true]{opacity:1;pointer-events:auto;animation:.2s ease-in-out prepr-fade-in}.prepr-content{box-shadow:var(--prepr-shadow);border-radius:var(--prepr-radius);background:var(--prepr-bg);flex-direction:column;gap:2.5rem;width:100%;padding:1.5rem;display:flex}@media (min-width:640px){.prepr-panel{margin-right:4rem;padding:0}.prepr-content{width:502px;padding:2.5rem}}.prepr-header{justify-content:space-between;align-items:center;gap:.5rem;display:flex}.prepr-header-left{align-items:flex-start;gap:.75rem;display:flex}.prepr-badge{background:var(--prepr-primary-100);height:1.5rem;color:var(--prepr-primary);border-radius:4px;align-items:center;padding:.25rem .75rem;font-size:.875rem;display:flex}.prepr-header-close{cursor:pointer;background:var(--prepr-primary-100);width:2rem;height:2rem;color:var(--prepr-gray-700);border:none;border-radius:6px;justify-content:center;align-items:center;display:flex}.prepr-section{flex-direction:column;gap:.5rem;display:flex}.prepr-section-label{color:var(--prepr-gray-400);font-size:.875rem}.prepr-row{flex-wrap:wrap;justify-content:space-between;align-items:center;gap:.5rem 1.5rem;display:flex}.prepr-row-title{color:var(--prepr-gray-800);margin:0;font-size:1rem;font-weight:600}.prepr-radiogroup{border-radius:var(--prepr-radius);border:1px solid var(--prepr-gray-300);background:#fff;align-items:center;gap:.25rem;height:2.5rem;padding:.25rem;display:flex}.prepr-radiogroup[data-disabled=true]{cursor:not-allowed;opacity:.5}.prepr-radiogroup[data-disabled=true] .prepr-radio{pointer-events:none}.prepr-radio{cursor:pointer;white-space:nowrap;text-align:center;height:2rem;color:var(--prepr-gray-900);background:0 0;border:none;border-radius:6px;justify-content:center;align-items:center;padding:.5rem 1.125rem;font-size:.875rem;font-weight:500;transition:all .2s ease-in-out;display:flex}.prepr-radio[data-checked=true]{background:var(--prepr-indigo-600);color:#fff;box-shadow:var(--prepr-shadow-sm)}.prepr-radio[data-checked=true][data-off=true]{background:var(--prepr-gray-800);color:#fff}.prepr-radio-variant{width:82px}.prepr-listbox{position:relative}.prepr-segment-button{border-radius:var(--prepr-radius);border:1px solid var(--prepr-gray-300);width:240px;height:2.5rem;color:var(--prepr-gray-500);cursor:pointer;background:#fff;flex-shrink:0;align-items:center;gap:.5rem;padding:0 .5rem;font-size:.875rem;font-weight:500;display:flex;overflow:hidden}@media (min-width:768px){.prepr-segment-button{padding:0 1rem}}.prepr-segment-button:disabled{cursor:not-allowed;background:var(--prepr-gray-200);color:var(--prepr-gray-400)}.prepr-segment-button[aria-expanded=true]{border-bottom-color:#fff;border-bottom-right-radius:0;border-bottom-left-radius:0}.prepr-segment-label{white-space:nowrap;text-overflow:ellipsis;text-align:left;width:100%;margin-right:auto;overflow:hidden}.prepr-segment-caret{color:var(--prepr-gray-800);display:flex}.prepr-options{z-index:calc(var(--prepr-z-index) + 1);border-left:1px solid var(--prepr-gray-300);border-right:1px solid var(--prepr-gray-300);border-bottom:1px solid var(--prepr-gray-300);-ms-overflow-style:none;scrollbar-width:none;background:#fff;border-radius:0 0 6px 6px;width:240px;max-height:300px;margin:0;padding:0;list-style:none;position:absolute;top:100%;left:0;overflow-y:auto;box-shadow:0 20px 25px -5px #0000001a,0 8px 10px -6px #0000001a}.prepr-options::-webkit-scrollbar{display:none}.prepr-options[hidden]{display:none}.prepr-option{cursor:pointer;width:100%;color:var(--prepr-gray-900);background:#fff;align-items:center;padding:.5rem 1rem;font-size:.875rem;font-weight:500;display:flex}.prepr-option:hover{background:var(--prepr-gray-100)}.prepr-option[aria-selected=true]{background:var(--prepr-indigo-50);color:var(--prepr-indigo-700)}.prepr-option-label{white-space:nowrap;text-overflow:ellipsis;text-align:left;width:100%;margin-right:auto;overflow:hidden}.prepr-reset{background:var(--prepr-secondary-400);color:#fff;cursor:pointer;border:none;border-radius:6px;justify-content:center;align-items:center;gap:.5rem;width:100%;height:2.5rem;padding:.5rem .75rem;font-size:.875rem;font-weight:500;display:flex}.prepr-reset:hover:not(:disabled){background:var(--prepr-secondary-500)}.prepr-reset:disabled{background:var(--prepr-gray-400);color:var(--prepr-gray-500);cursor:not-allowed}@media (min-width:768px){.prepr-reset{width:108px}}.prepr-indicators{z-index:var(--prepr-z-index);gap:.75rem;display:flex;position:fixed;bottom:1.5rem;right:1.5rem}.prepr-status-pill{background:var(--prepr-primary);color:#fff;cursor:pointer;border:none;border-radius:9999px;align-items:center;gap:.5rem;padding:.5rem 1rem;font-size:.75rem;font-weight:500;transition:background-color .15s;display:flex;box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a}.prepr-status-pill:hover{background:var(--prepr-primary-800)}.prepr-status-pill[hidden]{display:none}.prepr-status-viewing{color:#fff9;font-size:10px}.prepr-status-segment{text-overflow:ellipsis;white-space:nowrap;max-width:120px;display:inline-block;overflow:hidden}.prepr-status-variant{text-overflow:ellipsis;white-space:nowrap;background:#fff3;border-radius:4px;max-width:80px;padding:0 .5rem;display:inline-block;overflow:hidden}.prepr-status-x{color:#fff;width:.75rem;height:.75rem}.prepr-close-edit-pill{background:var(--prepr-primary-50);color:var(--prepr-gray-800);cursor:pointer;border:none;border-radius:9999px;align-items:center;gap:.5rem;padding:.5rem 1rem;font-size:.75rem;font-weight:500;transition:background-color .15s;display:flex;box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a}.prepr-close-edit-pill:hover{background:var(--prepr-primary-100)}.prepr-close-edit-pill[hidden]{display:none}.prepr-close-edit-x{width:1rem;height:1rem;color:var(--prepr-gray-500);transition:color .15s}.prepr-close-edit-pill:hover .prepr-close-edit-x{color:var(--prepr-gray-700)}.prepr-tip{z-index:calc(var(--prepr-z-index) + 2);overflow-wrap:break-word;background:var(--prepr-gray-900);color:#fff;pointer-events:none;border-radius:6px;width:auto;max-width:min(420px,100vw - 16px);padding:.5rem .75rem;font-size:.75rem;font-weight:500;position:fixed;box-shadow:0 20px 25px -5px #0000001a,0 8px 10px -6px #0000001a}.prepr-tip-arrow{border-left:6px solid #0000;border-right:6px solid #0000;border-top:6px solid var(--prepr-gray-900);width:0;height:0;position:absolute;top:100%;transform:translate(-50%)}[hidden]{display:none!important}@keyframes prepr-fade-in{0%{opacity:0}to{opacity:1}}";
1277
+ var TOOLBAR_CSS = ":host{--prepr-primary:#4338ca;--prepr-bg:#eef2ff;--prepr-text:#1f2937;--prepr-radius:8px;--prepr-shadow:0px 0px 40px 0px #1f29373d;--prepr-z-index:10000;--prepr-primary-50:#eef2ff;--prepr-primary-100:#e0e7ff;--prepr-primary-800:#3730a3;--prepr-indigo-600:#4f46e5;--prepr-indigo-50:#eef2ff;--prepr-indigo-700:#4338ca;--prepr-secondary-400:#fb923c;--prepr-secondary-500:#f97316;--prepr-gray-100:#f3f4f6;--prepr-gray-200:#e5e7eb;--prepr-gray-300:#d1d5db;--prepr-gray-400:#9ca3af;--prepr-gray-500:#6b7280;--prepr-gray-700:#374151;--prepr-gray-800:#1f2937;--prepr-gray-900:#111827;--prepr-shadow-sm:0px 0px 12px 0px #c3c3c3cc;color:var(--prepr-text);box-sizing:border-box;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif;font-size:14px;line-height:1.5}:host *,:host :before,:host :after,*,:before,:after{box-sizing:border-box}button{font-family:inherit;font-size:inherit;margin:0}.prepr-regular-text{font-size:.875rem;font-weight:500;line-height:1.5}.prepr-backdrop{z-index:calc(var(--prepr-z-index) - 1);opacity:0;pointer-events:none;background:#0000001a;transition:opacity .2s ease-in-out;position:fixed;top:0;bottom:0;left:0;right:0}.prepr-backdrop[data-open=true]{opacity:1;pointer-events:auto;animation:.2s ease-in-out prepr-fade-in}.prepr-container{z-index:var(--prepr-z-index);justify-content:flex-end;align-items:center;display:flex;position:fixed;top:calc(50% - 64px);right:0}.prepr-toggle-holder{padding:.5rem}.prepr-toggle{cursor:pointer;background:var(--prepr-primary);color:#fff;border:none;border-radius:9999px;justify-content:center;align-items:center;width:2.25rem;height:2.25rem;display:flex}.prepr-toggle svg{color:#fff}.prepr-panel{z-index:var(--prepr-z-index);opacity:0;pointer-events:none;justify-content:flex-end;padding:.75rem;transition:opacity .2s ease-in-out;display:flex;position:fixed;top:50%;right:0;transform:translateY(-50%)}.prepr-panel[data-open=true]{opacity:1;pointer-events:auto;animation:.2s ease-in-out prepr-fade-in}.prepr-content{box-shadow:var(--prepr-shadow);border-radius:var(--prepr-radius);background:var(--prepr-bg);flex-direction:column;gap:2.5rem;width:100%;padding:1.5rem;display:flex}@media (min-width:640px){.prepr-panel{margin-right:4rem;padding:0}.prepr-content{width:502px;padding:2.5rem}}.prepr-header{justify-content:space-between;align-items:center;gap:.5rem;display:flex}.prepr-header-left{align-items:flex-start;gap:.75rem;display:flex}.prepr-badge{background:var(--prepr-primary-100);height:1.5rem;color:var(--prepr-primary);border-radius:4px;align-items:center;padding:.25rem .75rem;font-size:.875rem;display:flex}.prepr-header-close{cursor:pointer;background:var(--prepr-primary-100);width:2rem;height:2rem;color:var(--prepr-gray-700);border:none;border-radius:6px;justify-content:center;align-items:center;display:flex}.prepr-section{flex-direction:column;gap:.5rem;display:flex}.prepr-section-label{color:var(--prepr-gray-400);font-size:.875rem}.prepr-row{flex-wrap:wrap;justify-content:space-between;align-items:center;gap:.5rem 1.5rem;display:flex}.prepr-row-title{color:var(--prepr-gray-800);margin:0;font-size:1rem;font-weight:600}.prepr-radiogroup{border-radius:var(--prepr-radius);border:1px solid var(--prepr-gray-300);background:#fff;align-items:center;gap:.25rem;height:2.5rem;padding:.25rem;display:flex}.prepr-radiogroup[data-disabled=true]{cursor:not-allowed;opacity:.5}.prepr-radiogroup[data-disabled=true] .prepr-radio{pointer-events:none}.prepr-radio{cursor:pointer;white-space:nowrap;text-align:center;height:2rem;color:var(--prepr-gray-900);background:0 0;border:none;border-radius:6px;justify-content:center;align-items:center;padding:.5rem 1.125rem;font-size:.875rem;font-weight:500;transition:all .2s ease-in-out;display:flex}.prepr-radio[data-checked=true]{background:var(--prepr-indigo-600);color:#fff;box-shadow:var(--prepr-shadow-sm)}.prepr-radio[data-checked=true][data-off=true]{background:var(--prepr-gray-800);color:#fff}.prepr-radio-variant{width:82px}.prepr-listbox{position:relative}.prepr-segment-button{border-radius:var(--prepr-radius);border:1px solid var(--prepr-gray-300);width:240px;height:2.5rem;color:var(--prepr-gray-500);cursor:pointer;background:#fff;flex-shrink:0;align-items:center;gap:.5rem;padding:0 .5rem;font-size:.875rem;font-weight:500;display:flex;overflow:hidden}@media (min-width:768px){.prepr-segment-button{padding:0 1rem}}.prepr-segment-button:disabled{cursor:not-allowed;background:var(--prepr-gray-200);color:var(--prepr-gray-400)}.prepr-segment-button[aria-expanded=true]{border-bottom-color:#fff;border-bottom-right-radius:0;border-bottom-left-radius:0}.prepr-segment-label{white-space:nowrap;text-overflow:ellipsis;text-align:left;width:100%;margin-right:auto;overflow:hidden}.prepr-segment-caret{color:var(--prepr-gray-800);display:flex}.prepr-options{z-index:calc(var(--prepr-z-index) + 1);border-left:1px solid var(--prepr-gray-300);border-right:1px solid var(--prepr-gray-300);border-bottom:1px solid var(--prepr-gray-300);-ms-overflow-style:none;scrollbar-width:none;background:#fff;border-radius:0 0 6px 6px;width:240px;max-height:300px;margin:0;padding:0;list-style:none;position:absolute;top:100%;left:0;overflow-y:auto;box-shadow:0 20px 25px -5px #0000001a,0 8px 10px -6px #0000001a}.prepr-options::-webkit-scrollbar{display:none}.prepr-options[hidden]{display:none}.prepr-option-search{background:#fff;padding:.5rem;position:-webkit-sticky;position:sticky;top:0}.prepr-segment-search{border:1px solid var(--prepr-gray-300);border-radius:var(--prepr-radius);width:100%;height:2rem;font:inherit;color:var(--prepr-gray-900);box-sizing:border-box;background:#fff;padding:0 .5rem;font-size:.875rem}.prepr-segment-search::placeholder{color:var(--prepr-gray-400)}.prepr-segment-search:focus{border-color:var(--prepr-gray-400);outline:none}.prepr-option{cursor:pointer;width:100%;color:var(--prepr-gray-900);background:#fff;align-items:center;padding:.5rem 1rem;font-size:.875rem;font-weight:500;display:flex}.prepr-option:hover{background:var(--prepr-gray-100)}.prepr-option[aria-selected=true]{background:var(--prepr-indigo-50);color:var(--prepr-indigo-700)}.prepr-option-label{white-space:nowrap;text-overflow:ellipsis;text-align:left;width:100%;margin-right:auto;overflow:hidden}.prepr-reset{background:var(--prepr-secondary-400);color:#fff;cursor:pointer;border:none;border-radius:6px;justify-content:center;align-items:center;gap:.5rem;width:100%;height:2.5rem;padding:.5rem .75rem;font-size:.875rem;font-weight:500;display:flex}.prepr-reset:hover:not(:disabled){background:var(--prepr-secondary-500)}.prepr-reset:disabled{background:var(--prepr-gray-400);color:var(--prepr-gray-500);cursor:not-allowed}@media (min-width:768px){.prepr-reset{width:108px}}.prepr-indicators{z-index:var(--prepr-z-index);gap:.75rem;display:flex;position:fixed;bottom:1.5rem;right:1.5rem}.prepr-status-pill{background:var(--prepr-primary);color:#fff;cursor:pointer;border:none;border-radius:9999px;align-items:center;gap:.5rem;padding:.5rem 1rem;font-size:.75rem;font-weight:500;transition:background-color .15s;display:flex;box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a}.prepr-status-pill:hover{background:var(--prepr-primary-800)}.prepr-status-pill[hidden]{display:none}.prepr-status-viewing{color:#fff9;font-size:10px}.prepr-status-segment{text-overflow:ellipsis;white-space:nowrap;max-width:120px;display:inline-block;overflow:hidden}.prepr-status-variant{text-overflow:ellipsis;white-space:nowrap;background:#fff3;border-radius:4px;max-width:80px;padding:0 .5rem;display:inline-block;overflow:hidden}.prepr-status-x{color:#fff;width:.75rem;height:.75rem}.prepr-close-edit-pill{background:var(--prepr-primary-50);color:var(--prepr-gray-800);cursor:pointer;border:none;border-radius:9999px;align-items:center;gap:.5rem;padding:.5rem 1rem;font-size:.75rem;font-weight:500;transition:background-color .15s;display:flex;box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a}.prepr-close-edit-pill:hover{background:var(--prepr-primary-100)}.prepr-close-edit-pill[hidden]{display:none}.prepr-close-edit-x{width:1rem;height:1rem;color:var(--prepr-gray-500);transition:color .15s}.prepr-close-edit-pill:hover .prepr-close-edit-x{color:var(--prepr-gray-700)}.prepr-tip{z-index:calc(var(--prepr-z-index) + 2);overflow-wrap:break-word;background:var(--prepr-gray-900);color:#fff;pointer-events:none;border-radius:6px;width:auto;max-width:min(420px,100vw - 16px);padding:.5rem .75rem;font-size:.75rem;font-weight:500;position:fixed;box-shadow:0 20px 25px -5px #0000001a,0 8px 10px -6px #0000001a}.prepr-tip-arrow{border-left:6px solid #0000;border-right:6px solid #0000;border-top:6px solid var(--prepr-gray-900);width:0;height:0;position:absolute;top:100%;transform:translate(-50%)}[hidden]{display:none!important}@keyframes prepr-fade-in{0%{opacity:0}to{opacity:1}}";
1267
1278
 
1268
1279
  // ../../node_modules/.pnpm/preact@10.29.7/node_modules/preact/jsx-runtime/dist/jsxRuntime.mjs
1269
1280
  var f2 = 0;
@@ -1352,10 +1363,13 @@ function SegmentListbox({
1352
1363
  state,
1353
1364
  t: t3,
1354
1365
  listboxOpen,
1366
+ segmentFilter,
1355
1367
  handlers
1356
1368
  }) {
1357
1369
  const segments = state.segments;
1358
1370
  const hasSegments = segments.length > 0;
1371
+ const filter = segmentFilter.trim().toLowerCase();
1372
+ const visibleSegments = filter ? segments.filter((s2) => s2.name.toLowerCase().includes(filter)) : segments;
1359
1373
  let label;
1360
1374
  if (!hasSegments) {
1361
1375
  label = t3("adaptiveContent.none");
@@ -1392,15 +1406,30 @@ function SegmentListbox({
1392
1406
  role: "listbox",
1393
1407
  hidden: !listboxOpen,
1394
1408
  onKeyDown: (e2) => handlers.onOptionsKeydown(e2),
1395
- children: segments.map((seg) => /* @__PURE__ */ u2(
1396
- SegmentOption,
1397
- {
1398
- seg,
1399
- selected: seg._id === state.selectedSegment,
1400
- onChoose: handlers.onChooseSegment
1401
- },
1402
- seg._id
1403
- ))
1409
+ children: [
1410
+ /* @__PURE__ */ u2("li", { class: "prepr-option-search", role: "none", children: /* @__PURE__ */ u2(
1411
+ "input",
1412
+ {
1413
+ type: "text",
1414
+ class: "prepr-segment-search",
1415
+ "data-prepr": "segment-search",
1416
+ placeholder: t3("adaptiveContent.searchSegments"),
1417
+ value: segmentFilter,
1418
+ onInput: (e2) => handlers.onSegmentFilterInput(
1419
+ e2.currentTarget.value
1420
+ )
1421
+ }
1422
+ ) }),
1423
+ visibleSegments.map((seg) => /* @__PURE__ */ u2(
1424
+ SegmentOption,
1425
+ {
1426
+ seg,
1427
+ selected: seg._id === state.selectedSegment,
1428
+ onChoose: handlers.onChooseSegment
1429
+ },
1430
+ seg._id
1431
+ ))
1432
+ ]
1404
1433
  }
1405
1434
  )
1406
1435
  ] });
@@ -1525,7 +1554,7 @@ function StatusPill({
1525
1554
  {
1526
1555
  class: "prepr-status-x",
1527
1556
  "data-prepr": "status-x",
1528
- hidden: state.selectedSegment === null,
1557
+ hidden: !state.previewMode || state.selectedSegment === null,
1529
1558
  children: /* @__PURE__ */ u2(RawSvg, { svg: XMARK_ICON_SVG })
1530
1559
  }
1531
1560
  )
@@ -1554,7 +1583,13 @@ function CloseEditPill({
1554
1583
  }
1555
1584
  );
1556
1585
  }
1557
- function Panel({ state, t: t3, listboxOpen, handlers }) {
1586
+ function Panel({
1587
+ state,
1588
+ t: t3,
1589
+ listboxOpen,
1590
+ segmentFilter,
1591
+ handlers
1592
+ }) {
1558
1593
  const hasPersonalization = state.selectedSegment !== null || state.selectedVariant !== null;
1559
1594
  return /* @__PURE__ */ u2(S, { children: [
1560
1595
  /* @__PURE__ */ u2(
@@ -1611,6 +1646,7 @@ function Panel({ state, t: t3, listboxOpen, handlers }) {
1611
1646
  state,
1612
1647
  t: t3,
1613
1648
  listboxOpen,
1649
+ segmentFilter,
1614
1650
  handlers
1615
1651
  }
1616
1652
  )
@@ -1668,6 +1704,7 @@ var PreprToolbarElement = class extends HTMLElementBase {
1668
1704
  this.t = (key) => key;
1669
1705
  this.unsubscribe = null;
1670
1706
  this.listboxOpen = false;
1707
+ this.segmentFilter = "";
1671
1708
  this.handlers = {
1672
1709
  onToggle: () => this.set({ toolbarOpen: !this.state.toolbarOpen }),
1673
1710
  onClose: () => this.set({ toolbarOpen: false }),
@@ -1698,6 +1735,10 @@ var PreprToolbarElement = class extends HTMLElementBase {
1698
1735
  onSegmentButtonKeydown: (e2) => this.onListboxKeydown(e2),
1699
1736
  onOptionsKeydown: (e2) => this.onListboxKeydown(e2),
1700
1737
  onChooseSegment: (id) => this.chooseSegment(id),
1738
+ onSegmentFilterInput: (value) => {
1739
+ this.segmentFilter = value;
1740
+ this.renderPanel(this.state);
1741
+ },
1701
1742
  onPreviewTooltipEnter: (el) => this.showTooltip(el),
1702
1743
  onPreviewTooltipLeave: () => this.hideTooltip()
1703
1744
  };
@@ -1746,6 +1787,7 @@ var PreprToolbarElement = class extends HTMLElementBase {
1746
1787
  state,
1747
1788
  t: this.t,
1748
1789
  listboxOpen: this.listboxOpen,
1790
+ segmentFilter: this.segmentFilter,
1749
1791
  handlers: this.handlers
1750
1792
  }),
1751
1793
  root
@@ -1811,6 +1853,8 @@ var PreprToolbarElement = class extends HTMLElementBase {
1811
1853
  onListboxKeydown(event) {
1812
1854
  const e2 = event;
1813
1855
  const options = this.optionEls();
1856
+ const inSearch = e2.target?.getAttribute?.("data-prepr") === "segment-search";
1857
+ if (inSearch && e2.key === " ") return;
1814
1858
  if (options.length === 0 && e2.key !== "Escape") return;
1815
1859
  switch (e2.key) {
1816
1860
  case "Enter":
@@ -1872,6 +1916,7 @@ var PreprToolbarElement = class extends HTMLElementBase {
1872
1916
  const button = this.segmentButton();
1873
1917
  if (button?.disabled) return;
1874
1918
  this.listboxOpen = open;
1919
+ this.segmentFilter = "";
1875
1920
  this.renderPanel(this.state);
1876
1921
  if (open) {
1877
1922
  const options = this.optionEls();
@@ -1882,11 +1927,17 @@ var PreprToolbarElement = class extends HTMLElementBase {
1882
1927
  options.forEach(
1883
1928
  (el, i2) => el.setAttribute("data-active", String(i2 === activeIndex))
1884
1929
  );
1885
- options[activeIndex]?.focus();
1930
+ this.searchInput()?.focus();
1886
1931
  }
1887
1932
  }
1933
+ searchInput() {
1934
+ return this.shadowRoot?.querySelector(
1935
+ '[data-prepr="segment-search"]'
1936
+ ) ?? null;
1937
+ }
1888
1938
  chooseSegment(id) {
1889
1939
  this.listboxOpen = false;
1940
+ this.segmentFilter = "";
1890
1941
  this.set({ selectedSegment: id });
1891
1942
  this.renderPanel(this.state);
1892
1943
  this.segmentButton()?.focus();
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  createPreprToolbar,
4
4
  loadTrackingPixel
5
- } from "../chunk-H7HVQSSF.js";
5
+ } from "../chunk-5JGPWQVA.js";
6
6
 
7
7
  // src/nextjs/components.ts
8
8
  import { usePathname, useRouter } from "next/navigation";
@@ -38,7 +38,7 @@ module.exports = __toCommonJS(nextjs_exports);
38
38
  var import_server = require("next/server");
39
39
 
40
40
  // src/version.ts
41
- var VERSION = "0.1.0-beta.1";
41
+ var VERSION = "0.1.0-beta.3";
42
42
 
43
43
  // src/core/constants.ts
44
44
  var COOKIE_PREVIEW_MODE = "Prepr-Preview-Mode";
@@ -2,7 +2,7 @@
2
2
  import { NextResponse } from "next/server";
3
3
 
4
4
  // src/version.ts
5
- var VERSION = "0.1.0-beta.1";
5
+ var VERSION = "0.1.0-beta.3";
6
6
 
7
7
  // src/core/constants.ts
8
8
  var COOKIE_PREVIEW_MODE = "Prepr-Preview-Mode";
@@ -0,0 +1,375 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/nuxt/index.ts
21
+ var nuxt_exports = {};
22
+ __export(nuxt_exports, {
23
+ PREPR_CONTEXT_KEY: () => PREPR_CONTEXT_KEY,
24
+ PreprError: () => PreprError,
25
+ extractAccessToken: () => extractAccessToken,
26
+ getActiveSegment: () => getActiveSegment,
27
+ getActiveVariant: () => getActiveVariant,
28
+ getPreprHeaders: () => getPreprHeaders,
29
+ getPreprHeadersFromEvent: () => getPreprHeadersFromEvent,
30
+ getPreprUUID: () => getPreprUUID,
31
+ getToolbarProps: () => getToolbarProps,
32
+ handlePreprRequest: () => handlePreprRequest,
33
+ validatePreprToken: () => validatePreprToken
34
+ });
35
+ module.exports = __toCommonJS(nuxt_exports);
36
+
37
+ // src/version.ts
38
+ var VERSION = "0.1.0-beta.3";
39
+
40
+ // src/core/constants.ts
41
+ var COOKIE_PREVIEW_MODE = "Prepr-Preview-Mode";
42
+ var COOKIE_SEGMENT = "Prepr-Segments";
43
+ var COOKIE_VARIANT = "Prepr-ABtesting";
44
+ var COOKIE_UID = "__prepr_uid";
45
+ var COOKIE_HUBSPOT = "hubspotutk";
46
+ var PARAM_SEGMENT = "prepr_preview_segment";
47
+ var PARAM_VARIANT = "prepr_preview_ab";
48
+ var PARAM_HIDE_BAR = "prepr_hide_bar";
49
+ var ONE_YEAR_SECONDS = 60 * 60 * 24 * 365;
50
+
51
+ // src/core/middleware.ts
52
+ var UTM_PARAMS = [
53
+ "utm_source",
54
+ "utm_medium",
55
+ "utm_term",
56
+ "utm_content",
57
+ "utm_campaign"
58
+ ];
59
+ function parseCookies(request) {
60
+ const cookies = /* @__PURE__ */ new Map();
61
+ const header = request.headers.get("cookie");
62
+ if (!header) return cookies;
63
+ for (const part of header.split(";")) {
64
+ const eq = part.indexOf("=");
65
+ if (eq === -1) continue;
66
+ const name = part.slice(0, eq).trim();
67
+ const value = part.slice(eq + 1).trim();
68
+ if (!name) continue;
69
+ cookies.set(name, decodeURIComponent(value));
70
+ }
71
+ return cookies;
72
+ }
73
+ function processPreprRequest(request, opts) {
74
+ const requestHeaders = new Headers(request.headers);
75
+ const responseCookies = [];
76
+ const requestCookies = parseCookies(request);
77
+ const searchParams = new URL(request.url).searchParams;
78
+ for (const key of UTM_PARAMS) {
79
+ const value = searchParams.get(key);
80
+ if (value !== null) {
81
+ requestHeaders.set(`Prepr-Context-${key}`, value);
82
+ }
83
+ }
84
+ const referer = request.headers.get("referer");
85
+ if (referer) {
86
+ requestHeaders.set("Prepr-Context-initial_referral", referer);
87
+ }
88
+ const userAgent = request.headers.get("user-agent");
89
+ if (userAgent) {
90
+ requestHeaders.set("Prepr-User-Agent", userAgent);
91
+ }
92
+ requestHeaders.set("Prepr-Package", `@preprio/toolkit@${opts?.version ?? VERSION}`);
93
+ const ip = request.headers.get("Cf-Connecting-Ip") ?? request.headers.get("x-real-ip");
94
+ if (ip) {
95
+ requestHeaders.set("Prepr-Visitor-IP", ip);
96
+ }
97
+ const hutkCookie = requestCookies.get(COOKIE_HUBSPOT);
98
+ if (hutkCookie) {
99
+ requestHeaders.set("Prepr-Hubspot-Id", hutkCookie);
100
+ }
101
+ let uid = requestCookies.get(COOKIE_UID);
102
+ if (!uid) {
103
+ uid = crypto.randomUUID();
104
+ responseCookies.push({
105
+ name: COOKIE_UID,
106
+ value: uid,
107
+ maxAge: ONE_YEAR_SECONDS,
108
+ path: "/"
109
+ });
110
+ requestHeaders.set("Prepr-Customer-Id-Created", "true");
111
+ }
112
+ requestHeaders.set("Prepr-Customer-Id", uid);
113
+ if (!opts?.preview) {
114
+ return { requestHeaders, responseCookies };
115
+ }
116
+ const hasPreviewParams = searchParams.has(PARAM_SEGMENT) || searchParams.has(PARAM_VARIANT);
117
+ if (!hasPreviewParams) {
118
+ const previewModeCookie = requestCookies.get(COOKIE_PREVIEW_MODE);
119
+ const previewModeEnabled = previewModeCookie !== "false";
120
+ if (!previewModeEnabled) {
121
+ return { requestHeaders, responseCookies };
122
+ }
123
+ }
124
+ requestHeaders.set("Prepr-Preview-Bar", "true");
125
+ const isLivePreview = searchParams.get(PARAM_HIDE_BAR) === "true";
126
+ if (!isLivePreview) {
127
+ const segmentCookie = requestCookies.get(COOKIE_SEGMENT);
128
+ if (segmentCookie) {
129
+ requestHeaders.set("Prepr-Segments", segmentCookie);
130
+ }
131
+ const abCookie = requestCookies.get(COOKIE_VARIANT);
132
+ if (abCookie) {
133
+ requestHeaders.set("Prepr-ABtesting", abCookie);
134
+ }
135
+ }
136
+ const previewAb = searchParams.get(PARAM_VARIANT);
137
+ if (previewAb !== null) {
138
+ requestHeaders.set("Prepr-ABtesting", previewAb);
139
+ if (!isLivePreview) {
140
+ responseCookies.push({
141
+ name: COOKIE_VARIANT,
142
+ value: previewAb,
143
+ maxAge: ONE_YEAR_SECONDS,
144
+ path: "/"
145
+ });
146
+ }
147
+ }
148
+ const previewSegment = searchParams.get(PARAM_SEGMENT);
149
+ if (previewSegment !== null) {
150
+ requestHeaders.set("Prepr-Segments", previewSegment);
151
+ if (!isLivePreview) {
152
+ responseCookies.push({
153
+ name: COOKIE_SEGMENT,
154
+ value: previewSegment,
155
+ maxAge: ONE_YEAR_SECONDS,
156
+ path: "/"
157
+ });
158
+ }
159
+ }
160
+ return { requestHeaders, responseCookies };
161
+ }
162
+
163
+ // src/nuxt/middleware.ts
164
+ var PREPR_CONTEXT_KEY = "prepr";
165
+ function handlePreprRequest(event, options) {
166
+ const req = event.node.req;
167
+ const host = typeof req.headers.host === "string" ? req.headers.host : "localhost";
168
+ const request = new Request(`http://${host}${req.url ?? "/"}`);
169
+ for (const [key, value] of Object.entries(req.headers)) {
170
+ if (typeof value === "string") {
171
+ request.headers.set(key, value);
172
+ } else if (Array.isArray(value)) {
173
+ request.headers.set(key, value.join(", "));
174
+ }
175
+ }
176
+ const { requestHeaders, responseCookies } = processPreprRequest(request, options);
177
+ requestHeaders.forEach((value, key) => {
178
+ req.headers[key.toLowerCase()] = value;
179
+ });
180
+ event.context[PREPR_CONTEXT_KEY] = requestHeaders;
181
+ for (const cookie of responseCookies) {
182
+ const parts = [
183
+ `${cookie.name}=${encodeURIComponent(cookie.value)}`,
184
+ `Max-Age=${cookie.maxAge}`,
185
+ `Path=${cookie.path}`
186
+ ];
187
+ event.node.res.appendHeader("Set-Cookie", parts.join("; "));
188
+ }
189
+ }
190
+ function getPreprHeadersFromEvent(event) {
191
+ const headers = event.context[PREPR_CONTEXT_KEY];
192
+ return headers instanceof Headers ? headers : new Headers();
193
+ }
194
+
195
+ // src/core/server.ts
196
+ var PreprError = class extends Error {
197
+ constructor(message, code, context, originalError) {
198
+ super(message);
199
+ this.code = code;
200
+ this.context = context;
201
+ this.originalError = originalError;
202
+ this.name = "PreprError";
203
+ }
204
+ };
205
+ function getPreprUUIDFromHeaders(headers) {
206
+ return headers.get("prepr-customer-id");
207
+ }
208
+ function getActiveSegmentFromHeaders(headers) {
209
+ return headers.get("Prepr-Segments");
210
+ }
211
+ function getActiveVariantFromHeaders(headers) {
212
+ return headers.get("Prepr-ABtesting");
213
+ }
214
+ var PREPR_HEADER_KEYS = [
215
+ "prepr-customer-id",
216
+ "Prepr-Segments",
217
+ "Prepr-ABtesting",
218
+ "Prepr-Preview-Bar",
219
+ "Prepr-Context-utm_source",
220
+ "Prepr-Context-utm_medium",
221
+ "Prepr-Context-utm_term",
222
+ "Prepr-Context-utm_content",
223
+ "Prepr-Context-utm_campaign",
224
+ "Prepr-Context-initial_referral",
225
+ "Prepr-Visitor-IP",
226
+ "Prepr-Hubspot-Id",
227
+ "Prepr-Customer-Id-Created",
228
+ "Prepr-User-Agent"
229
+ ];
230
+ function getPreprHeadersFromHeaders(headers) {
231
+ const preprHeaders = {};
232
+ const copy = (key) => {
233
+ const value = headers.get(key);
234
+ if (value !== null) {
235
+ preprHeaders[key] = value;
236
+ }
237
+ };
238
+ for (const key of PREPR_HEADER_KEYS) {
239
+ copy(key);
240
+ }
241
+ return preprHeaders;
242
+ }
243
+ function validatePreprToken(token) {
244
+ if (!token) {
245
+ throw new PreprError("Token is required", "MISSING_TOKEN", "validatePreprToken");
246
+ }
247
+ if (!token.startsWith("https://")) {
248
+ throw new PreprError(
249
+ "Token must be a valid HTTPS URL",
250
+ "INVALID_TOKEN",
251
+ "validatePreprToken"
252
+ );
253
+ }
254
+ }
255
+ function extractAccessToken(graphqlUrl) {
256
+ let url;
257
+ try {
258
+ url = new URL(graphqlUrl);
259
+ } catch (error) {
260
+ throw new PreprError(
261
+ "Token must be a valid URL",
262
+ "INVALID_TOKEN",
263
+ "extractAccessToken",
264
+ error instanceof Error ? error : new Error(String(error))
265
+ );
266
+ }
267
+ if (url.hostname !== "graphql.prepr.io") {
268
+ throw new PreprError(
269
+ "Token must be a graphql.prepr.io URL",
270
+ "INVALID_TOKEN",
271
+ "extractAccessToken"
272
+ );
273
+ }
274
+ const pathParts = url.pathname.split("/");
275
+ const token = pathParts[pathParts.length - 1];
276
+ if (!token) {
277
+ throw new PreprError(
278
+ "Token URL is missing an access token segment",
279
+ "INVALID_TOKEN",
280
+ "extractAccessToken"
281
+ );
282
+ }
283
+ return token;
284
+ }
285
+ async function getPreprEnvironmentSegments(token) {
286
+ validatePreprToken(token);
287
+ try {
288
+ const response = await fetch(token, {
289
+ headers: {
290
+ "User-Agent": `Prepr-Preview-Bar/${VERSION}`,
291
+ "Content-Type": "application/json"
292
+ },
293
+ method: "POST",
294
+ body: JSON.stringify({
295
+ query: `{
296
+ _Segments {
297
+ _id
298
+ name
299
+ }
300
+ }`
301
+ })
302
+ });
303
+ if (!response.ok) {
304
+ throw new PreprError(
305
+ `HTTP ${response.status}: ${response.statusText}`,
306
+ "HTTP_ERROR",
307
+ "getPreprEnvironmentSegments"
308
+ );
309
+ }
310
+ const json = await response.json();
311
+ if (!json || !json.data || !json.data._Segments) {
312
+ throw new PreprError(
313
+ "Invalid response format from Prepr API",
314
+ "INVALID_RESPONSE",
315
+ "getPreprEnvironmentSegments"
316
+ );
317
+ }
318
+ return json.data._Segments;
319
+ } catch (error) {
320
+ if (error instanceof PreprError) {
321
+ throw error;
322
+ }
323
+ throw new PreprError(
324
+ "Failed to fetch segments from Prepr API",
325
+ "FETCH_ERROR",
326
+ "getPreprEnvironmentSegments",
327
+ error instanceof Error ? error : new Error(String(error))
328
+ );
329
+ }
330
+ }
331
+ async function getToolbarPropsFromHeaders(headers, token) {
332
+ let segments = [];
333
+ try {
334
+ segments = await getPreprEnvironmentSegments(token);
335
+ } catch {
336
+ segments = [];
337
+ }
338
+ return {
339
+ activeSegment: getActiveSegmentFromHeaders(headers),
340
+ activeVariant: getActiveVariantFromHeaders(headers),
341
+ segments,
342
+ data: segments
343
+ };
344
+ }
345
+
346
+ // src/nuxt/server.ts
347
+ function getPreprUUID(headers) {
348
+ return getPreprUUIDFromHeaders(headers);
349
+ }
350
+ function getActiveSegment(headers) {
351
+ return getActiveSegmentFromHeaders(headers);
352
+ }
353
+ function getActiveVariant(headers) {
354
+ return getActiveVariantFromHeaders(headers);
355
+ }
356
+ function getPreprHeaders(headers) {
357
+ return getPreprHeadersFromHeaders(headers);
358
+ }
359
+ async function getToolbarProps(headers, token) {
360
+ return getToolbarPropsFromHeaders(headers, token);
361
+ }
362
+ // Annotate the CommonJS export names for ESM import in node:
363
+ 0 && (module.exports = {
364
+ PREPR_CONTEXT_KEY,
365
+ PreprError,
366
+ extractAccessToken,
367
+ getActiveSegment,
368
+ getActiveVariant,
369
+ getPreprHeaders,
370
+ getPreprHeadersFromEvent,
371
+ getPreprUUID,
372
+ getToolbarProps,
373
+ handlePreprRequest,
374
+ validatePreprToken
375
+ });