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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -43,7 +43,7 @@ __export(src_exports, {
43
43
  module.exports = __toCommonJS(src_exports);
44
44
 
45
45
  // src/version.ts
46
- var VERSION = "0.1.0-beta.1";
46
+ var VERSION = "0.1.0-beta.4";
47
47
 
48
48
  // src/core/constants.ts
49
49
  var COOKIE_PREVIEW_MODE = "Prepr-Preview-Mode";
@@ -67,16 +67,34 @@ function getCookie(name) {
67
67
  }
68
68
  function setCookie(name, value, options = {}) {
69
69
  if (typeof document === "undefined") return;
70
- const { maxAge, path = "/" } = options;
70
+ const { maxAge, path = "/", sameSite, secure } = options;
71
71
  let cookie = `${name}=${encodeURIComponent(value)};path=${path}`;
72
72
  if (typeof maxAge === "number") {
73
73
  cookie += `;max-age=${maxAge}`;
74
74
  }
75
+ if (sameSite) {
76
+ cookie += `;samesite=${sameSite}`;
77
+ }
78
+ if (secure) {
79
+ cookie += ";secure";
80
+ }
75
81
  document.cookie = cookie;
76
82
  }
77
- function removeCookie(name, path = "/") {
83
+ function removeCookie(name, path = "/", options = {}) {
78
84
  if (typeof document === "undefined") return;
79
- document.cookie = `${name}=;path=${path};expires=Thu, 01 Jan 1970 00:00:00 GMT`;
85
+ const { sameSite, secure } = options;
86
+ let cookie = `${name}=;path=${path};expires=Thu, 01 Jan 1970 00:00:00 GMT`;
87
+ if (sameSite) {
88
+ cookie += `;samesite=${sameSite}`;
89
+ }
90
+ if (secure) {
91
+ cookie += ";secure";
92
+ }
93
+ document.cookie = cookie;
94
+ }
95
+ function crossSiteCookieOptions() {
96
+ if (typeof window === "undefined" || !window.isSecureContext) return {};
97
+ return { sameSite: "None", secure: true };
80
98
  }
81
99
 
82
100
  // src/core/locales/en.json
@@ -95,6 +113,7 @@ var en_default = {
95
113
  segment: "Segment",
96
114
  ABVariant: "A/B variant",
97
115
  chooseSegment: "Choose segment",
116
+ searchSegments: "Search segments",
98
117
  none: "No segments",
99
118
  allOtherUsers: "All other users",
100
119
  offDescription: "View the site as a real user (use cookies)",
@@ -123,6 +142,7 @@ var nl_default = {
123
142
  segment: "Segment",
124
143
  ABVariant: "A/B-variant",
125
144
  chooseSegment: "Kies segment",
145
+ searchSegments: "Zoek segmenten",
126
146
  none: "Geen segmenten",
127
147
  allOtherUsers: "Alle andere gebruikers",
128
148
  offDescription: "Bekijk de site als een echte gebruiker (gebruik cookies)",
@@ -931,7 +951,13 @@ function createToolbarStore(initial = {}) {
931
951
  }
932
952
 
933
953
  // src/core/toolbar-change-handler.ts
934
- var COOKIE_OPTS = { maxAge: ONE_YEAR_SECONDS, path: "/" };
954
+ function cookieOpts() {
955
+ return {
956
+ maxAge: ONE_YEAR_SECONDS,
957
+ path: "/",
958
+ ...crossSiteCookieOptions()
959
+ };
960
+ }
935
961
  function createChangeHandler(deps) {
936
962
  const { store, stega, syncAutoClean } = deps;
937
963
  function updateParam(name, value) {
@@ -948,9 +974,9 @@ function createChangeHandler(deps) {
948
974
  return function handleChange(before, after) {
949
975
  if (before.selectedSegment !== after.selectedSegment) {
950
976
  if (after.selectedSegment === null) {
951
- removeCookie(COOKIE_SEGMENT);
977
+ removeCookie(COOKIE_SEGMENT, "/", crossSiteCookieOptions());
952
978
  } else {
953
- setCookie(COOKIE_SEGMENT, after.selectedSegment, COOKIE_OPTS);
979
+ setCookie(COOKIE_SEGMENT, after.selectedSegment, cookieOpts());
954
980
  }
955
981
  updateParam(PARAM_SEGMENT, after.selectedSegment);
956
982
  sendPreprEvent("segment_changed", {
@@ -959,9 +985,9 @@ function createChangeHandler(deps) {
959
985
  }
960
986
  if (before.selectedVariant !== after.selectedVariant) {
961
987
  if (after.selectedVariant === null) {
962
- removeCookie(COOKIE_VARIANT);
988
+ removeCookie(COOKIE_VARIANT, "/", crossSiteCookieOptions());
963
989
  } else {
964
- setCookie(COOKIE_VARIANT, after.selectedVariant, COOKIE_OPTS);
990
+ setCookie(COOKIE_VARIANT, after.selectedVariant, cookieOpts());
965
991
  }
966
992
  updateParam(PARAM_VARIANT, after.selectedVariant);
967
993
  sendPreprEvent("variant_changed", {
@@ -987,14 +1013,23 @@ function createChangeHandler(deps) {
987
1013
  if (Object.keys(coupled).length > 0) {
988
1014
  store.set(coupled);
989
1015
  }
990
- setCookie(COOKIE_PREVIEW_MODE, String(after.previewMode), COOKIE_OPTS);
991
- setCookie(COOKIE_TOOLBAR_OPEN, "false", COOKIE_OPTS);
1016
+ setCookie(COOKIE_PREVIEW_MODE, String(after.previewMode), cookieOpts());
1017
+ setCookie(COOKIE_TOOLBAR_OPEN, "false", cookieOpts());
992
1018
  sendPreprEvent("preview_mode_toggled", { previewMode: after.previewMode });
993
1019
  syncAutoClean(after.previewMode);
994
- deps.reload();
1020
+ const [path, existing] = splitPath(deps.currentPath());
1021
+ const params = new URLSearchParams(existing);
1022
+ if (params.has(PARAM_SEGMENT) || params.has(PARAM_VARIANT)) {
1023
+ params.delete(PARAM_SEGMENT);
1024
+ params.delete(PARAM_VARIANT);
1025
+ const query = params.toString();
1026
+ deps.navigate(query ? `${path}?${query}` : path);
1027
+ } else {
1028
+ deps.reload();
1029
+ }
995
1030
  }
996
1031
  if (before.toolbarOpen !== after.toolbarOpen) {
997
- setCookie(COOKIE_TOOLBAR_OPEN, String(after.toolbarOpen), COOKIE_OPTS);
1032
+ setCookie(COOKIE_TOOLBAR_OPEN, String(after.toolbarOpen), cookieOpts());
998
1033
  }
999
1034
  };
1000
1035
  }
@@ -1286,7 +1321,7 @@ var CLOSE_ICON_SVG = `<svg width="10" height="10" viewBox="0 0 10 10" fill="none
1286
1321
  </svg>`;
1287
1322
 
1288
1323
  // src/core/ui/toolbar.generated.ts
1289
- 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}}";
1324
+ 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}}";
1290
1325
 
1291
1326
  // ../../node_modules/.pnpm/preact@10.29.7/node_modules/preact/jsx-runtime/dist/jsxRuntime.mjs
1292
1327
  var f2 = 0;
@@ -1375,10 +1410,13 @@ function SegmentListbox({
1375
1410
  state,
1376
1411
  t: t3,
1377
1412
  listboxOpen,
1413
+ segmentFilter,
1378
1414
  handlers
1379
1415
  }) {
1380
1416
  const segments = state.segments;
1381
1417
  const hasSegments = segments.length > 0;
1418
+ const filter = segmentFilter.trim().toLowerCase();
1419
+ const visibleSegments = filter ? segments.filter((s2) => s2.name.toLowerCase().includes(filter)) : segments;
1382
1420
  let label;
1383
1421
  if (!hasSegments) {
1384
1422
  label = t3("adaptiveContent.none");
@@ -1415,15 +1453,30 @@ function SegmentListbox({
1415
1453
  role: "listbox",
1416
1454
  hidden: !listboxOpen,
1417
1455
  onKeyDown: (e2) => handlers.onOptionsKeydown(e2),
1418
- children: segments.map((seg) => /* @__PURE__ */ u2(
1419
- SegmentOption,
1420
- {
1421
- seg,
1422
- selected: seg._id === state.selectedSegment,
1423
- onChoose: handlers.onChooseSegment
1424
- },
1425
- seg._id
1426
- ))
1456
+ children: [
1457
+ /* @__PURE__ */ u2("li", { class: "prepr-option-search", role: "none", children: /* @__PURE__ */ u2(
1458
+ "input",
1459
+ {
1460
+ type: "text",
1461
+ class: "prepr-segment-search",
1462
+ "data-prepr": "segment-search",
1463
+ placeholder: t3("adaptiveContent.searchSegments"),
1464
+ value: segmentFilter,
1465
+ onInput: (e2) => handlers.onSegmentFilterInput(
1466
+ e2.currentTarget.value
1467
+ )
1468
+ }
1469
+ ) }),
1470
+ visibleSegments.map((seg) => /* @__PURE__ */ u2(
1471
+ SegmentOption,
1472
+ {
1473
+ seg,
1474
+ selected: seg._id === state.selectedSegment,
1475
+ onChoose: handlers.onChooseSegment
1476
+ },
1477
+ seg._id
1478
+ ))
1479
+ ]
1427
1480
  }
1428
1481
  )
1429
1482
  ] });
@@ -1548,7 +1601,7 @@ function StatusPill({
1548
1601
  {
1549
1602
  class: "prepr-status-x",
1550
1603
  "data-prepr": "status-x",
1551
- hidden: state.selectedSegment === null,
1604
+ hidden: !state.previewMode || state.selectedSegment === null,
1552
1605
  children: /* @__PURE__ */ u2(RawSvg, { svg: XMARK_ICON_SVG })
1553
1606
  }
1554
1607
  )
@@ -1577,7 +1630,13 @@ function CloseEditPill({
1577
1630
  }
1578
1631
  );
1579
1632
  }
1580
- function Panel({ state, t: t3, listboxOpen, handlers }) {
1633
+ function Panel({
1634
+ state,
1635
+ t: t3,
1636
+ listboxOpen,
1637
+ segmentFilter,
1638
+ handlers
1639
+ }) {
1581
1640
  const hasPersonalization = state.selectedSegment !== null || state.selectedVariant !== null;
1582
1641
  return /* @__PURE__ */ u2(S, { children: [
1583
1642
  /* @__PURE__ */ u2(
@@ -1634,6 +1693,7 @@ function Panel({ state, t: t3, listboxOpen, handlers }) {
1634
1693
  state,
1635
1694
  t: t3,
1636
1695
  listboxOpen,
1696
+ segmentFilter,
1637
1697
  handlers
1638
1698
  }
1639
1699
  )
@@ -1691,6 +1751,7 @@ var PreprToolbarElement = class extends HTMLElementBase {
1691
1751
  this.t = (key) => key;
1692
1752
  this.unsubscribe = null;
1693
1753
  this.listboxOpen = false;
1754
+ this.segmentFilter = "";
1694
1755
  this.handlers = {
1695
1756
  onToggle: () => this.set({ toolbarOpen: !this.state.toolbarOpen }),
1696
1757
  onClose: () => this.set({ toolbarOpen: false }),
@@ -1721,6 +1782,10 @@ var PreprToolbarElement = class extends HTMLElementBase {
1721
1782
  onSegmentButtonKeydown: (e2) => this.onListboxKeydown(e2),
1722
1783
  onOptionsKeydown: (e2) => this.onListboxKeydown(e2),
1723
1784
  onChooseSegment: (id) => this.chooseSegment(id),
1785
+ onSegmentFilterInput: (value) => {
1786
+ this.segmentFilter = value;
1787
+ this.renderPanel(this.state);
1788
+ },
1724
1789
  onPreviewTooltipEnter: (el) => this.showTooltip(el),
1725
1790
  onPreviewTooltipLeave: () => this.hideTooltip()
1726
1791
  };
@@ -1769,6 +1834,7 @@ var PreprToolbarElement = class extends HTMLElementBase {
1769
1834
  state,
1770
1835
  t: this.t,
1771
1836
  listboxOpen: this.listboxOpen,
1837
+ segmentFilter: this.segmentFilter,
1772
1838
  handlers: this.handlers
1773
1839
  }),
1774
1840
  root
@@ -1834,6 +1900,8 @@ var PreprToolbarElement = class extends HTMLElementBase {
1834
1900
  onListboxKeydown(event) {
1835
1901
  const e2 = event;
1836
1902
  const options = this.optionEls();
1903
+ const inSearch = e2.target?.getAttribute?.("data-prepr") === "segment-search";
1904
+ if (inSearch && e2.key === " ") return;
1837
1905
  if (options.length === 0 && e2.key !== "Escape") return;
1838
1906
  switch (e2.key) {
1839
1907
  case "Enter":
@@ -1895,6 +1963,7 @@ var PreprToolbarElement = class extends HTMLElementBase {
1895
1963
  const button = this.segmentButton();
1896
1964
  if (button?.disabled) return;
1897
1965
  this.listboxOpen = open;
1966
+ this.segmentFilter = "";
1898
1967
  this.renderPanel(this.state);
1899
1968
  if (open) {
1900
1969
  const options = this.optionEls();
@@ -1905,11 +1974,17 @@ var PreprToolbarElement = class extends HTMLElementBase {
1905
1974
  options.forEach(
1906
1975
  (el, i2) => el.setAttribute("data-active", String(i2 === activeIndex))
1907
1976
  );
1908
- options[activeIndex]?.focus();
1977
+ this.searchInput()?.focus();
1909
1978
  }
1910
1979
  }
1980
+ searchInput() {
1981
+ return this.shadowRoot?.querySelector(
1982
+ '[data-prepr="segment-search"]'
1983
+ ) ?? null;
1984
+ }
1911
1985
  chooseSegment(id) {
1912
1986
  this.listboxOpen = false;
1987
+ this.segmentFilter = "";
1913
1988
  this.set({ selectedSegment: id });
1914
1989
  this.renderPanel(this.state);
1915
1990
  this.segmentButton()?.focus();
@@ -2220,7 +2295,11 @@ function processPreprRequest(request, opts) {
2220
2295
  const requestHeaders = new Headers(request.headers);
2221
2296
  const responseCookies = [];
2222
2297
  const requestCookies = parseCookies(request);
2223
- const searchParams = new URL(request.url).searchParams;
2298
+ const url = new URL(request.url);
2299
+ const searchParams = url.searchParams;
2300
+ const forwardedProto = request.headers.get("x-forwarded-proto")?.split(",")[0]?.trim();
2301
+ const isSecure = forwardedProto ? forwardedProto === "https" : url.protocol === "https:";
2302
+ const crossSite = isSecure ? { sameSite: "None", secure: true } : {};
2224
2303
  for (const key of UTM_PARAMS) {
2225
2304
  const value = searchParams.get(key);
2226
2305
  if (value !== null) {
@@ -2269,6 +2348,15 @@ function processPreprRequest(request, opts) {
2269
2348
  }
2270
2349
  requestHeaders.set("Prepr-Preview-Bar", "true");
2271
2350
  const isLivePreview = searchParams.get(PARAM_HIDE_BAR) === "true";
2351
+ if (!isLivePreview && !requestCookies.has(COOKIE_PREVIEW_MODE)) {
2352
+ responseCookies.push({
2353
+ name: COOKIE_PREVIEW_MODE,
2354
+ value: "true",
2355
+ maxAge: ONE_YEAR_SECONDS,
2356
+ path: "/",
2357
+ ...crossSite
2358
+ });
2359
+ }
2272
2360
  if (!isLivePreview) {
2273
2361
  const segmentCookie = requestCookies.get(COOKIE_SEGMENT);
2274
2362
  if (segmentCookie) {
@@ -2287,7 +2375,8 @@ function processPreprRequest(request, opts) {
2287
2375
  name: COOKIE_VARIANT,
2288
2376
  value: previewAb,
2289
2377
  maxAge: ONE_YEAR_SECONDS,
2290
- path: "/"
2378
+ path: "/",
2379
+ ...crossSite
2291
2380
  });
2292
2381
  }
2293
2382
  }
@@ -2299,7 +2388,8 @@ function processPreprRequest(request, opts) {
2299
2388
  name: COOKIE_SEGMENT,
2300
2389
  value: previewSegment,
2301
2390
  maxAge: ONE_YEAR_SECONDS,
2302
- path: "/"
2391
+ path: "/",
2392
+ ...crossSite
2303
2393
  });
2304
2394
  }
2305
2395
  }
package/dist/index.d.cts CHANGED
@@ -5,7 +5,7 @@ export { f as PreprEnvironment, g as PreprEventType, h as PreprHeaderName, i as
5
5
  * Package version; must match package.json. Lives in its own leaf module so
6
6
  * core can import it without cycling through the barrel.
7
7
  */
8
- declare const VERSION = "0.1.0-beta.1";
8
+ declare const VERSION = "0.1.0-beta.4";
9
9
 
10
10
  interface ToolbarState {
11
11
  locale: Locale;
@@ -80,6 +80,7 @@ declare class PreprToolbarElement extends HTMLElementBase {
80
80
  private t;
81
81
  private unsubscribe;
82
82
  private listboxOpen;
83
+ private segmentFilter;
83
84
  private readonly handlers;
84
85
  /** Idempotent: calling connect twice re-wires to the (possibly new) store. */
85
86
  connect(store: ToolbarStore, t: Translate): void;
@@ -105,6 +106,7 @@ declare class PreprToolbarElement extends HTMLElementBase {
105
106
  private activeOptionIndex;
106
107
  private moveActiveOption;
107
108
  private toggleListbox;
109
+ private searchInput;
108
110
  private chooseSegment;
109
111
  }
110
112
  /** Idempotent, including across bundles that each try to define the element. */
@@ -158,6 +160,15 @@ interface CookieSpec {
158
160
  value: string;
159
161
  maxAge: number;
160
162
  path: string;
163
+ /**
164
+ * Set to `'None'` for cookies that must survive the Prepr editor's
165
+ * cross-site preview iframe — browsers drop the browser-default `Lax`
166
+ * cookies there. Always paired with `secure`, which browsers require for
167
+ * `SameSite=None`.
168
+ */
169
+ sameSite?: 'Strict' | 'Lax' | 'None';
170
+ /** Adds `Secure`. Required by browsers alongside `SameSite=None`. */
171
+ secure?: boolean;
161
172
  }
162
173
  interface PreprMiddlewareResult {
163
174
  requestHeaders: Headers;
package/dist/index.d.ts CHANGED
@@ -5,7 +5,7 @@ export { f as PreprEnvironment, g as PreprEventType, h as PreprHeaderName, i as
5
5
  * Package version; must match package.json. Lives in its own leaf module so
6
6
  * core can import it without cycling through the barrel.
7
7
  */
8
- declare const VERSION = "0.1.0-beta.1";
8
+ declare const VERSION = "0.1.0-beta.4";
9
9
 
10
10
  interface ToolbarState {
11
11
  locale: Locale;
@@ -80,6 +80,7 @@ declare class PreprToolbarElement extends HTMLElementBase {
80
80
  private t;
81
81
  private unsubscribe;
82
82
  private listboxOpen;
83
+ private segmentFilter;
83
84
  private readonly handlers;
84
85
  /** Idempotent: calling connect twice re-wires to the (possibly new) store. */
85
86
  connect(store: ToolbarStore, t: Translate): void;
@@ -105,6 +106,7 @@ declare class PreprToolbarElement extends HTMLElementBase {
105
106
  private activeOptionIndex;
106
107
  private moveActiveOption;
107
108
  private toggleListbox;
109
+ private searchInput;
108
110
  private chooseSegment;
109
111
  }
110
112
  /** Idempotent, including across bundles that each try to define the element. */
@@ -158,6 +160,15 @@ interface CookieSpec {
158
160
  value: string;
159
161
  maxAge: number;
160
162
  path: string;
163
+ /**
164
+ * Set to `'None'` for cookies that must survive the Prepr editor's
165
+ * cross-site preview iframe — browsers drop the browser-default `Lax`
166
+ * cookies there. Always paired with `secure`, which browsers require for
167
+ * `SameSite=None`.
168
+ */
169
+ sameSite?: 'Strict' | 'Lax' | 'None';
170
+ /** Adds `Secure`. Required by browsers alongside `SameSite=None`. */
171
+ secure?: boolean;
161
172
  }
162
173
  interface PreprMiddlewareResult {
163
174
  requestHeaders: Headers;
package/dist/index.js CHANGED
@@ -16,10 +16,10 @@ import {
16
16
  setTrackingParam,
17
17
  stegaClean,
18
18
  trackEvent
19
- } from "./chunk-H7HVQSSF.js";
19
+ } from "./chunk-3FOY6KL4.js";
20
20
 
21
21
  // src/version.ts
22
- var VERSION = "0.1.0-beta.1";
22
+ var VERSION = "0.1.0-beta.4";
23
23
 
24
24
  // src/core/server.ts
25
25
  var PreprError = class extends Error {
@@ -198,7 +198,11 @@ function processPreprRequest(request, opts) {
198
198
  const requestHeaders = new Headers(request.headers);
199
199
  const responseCookies = [];
200
200
  const requestCookies = parseCookies(request);
201
- const searchParams = new URL(request.url).searchParams;
201
+ const url = new URL(request.url);
202
+ const searchParams = url.searchParams;
203
+ const forwardedProto = request.headers.get("x-forwarded-proto")?.split(",")[0]?.trim();
204
+ const isSecure = forwardedProto ? forwardedProto === "https" : url.protocol === "https:";
205
+ const crossSite = isSecure ? { sameSite: "None", secure: true } : {};
202
206
  for (const key of UTM_PARAMS) {
203
207
  const value = searchParams.get(key);
204
208
  if (value !== null) {
@@ -247,6 +251,15 @@ function processPreprRequest(request, opts) {
247
251
  }
248
252
  requestHeaders.set("Prepr-Preview-Bar", "true");
249
253
  const isLivePreview = searchParams.get(PARAM_HIDE_BAR) === "true";
254
+ if (!isLivePreview && !requestCookies.has(COOKIE_PREVIEW_MODE)) {
255
+ responseCookies.push({
256
+ name: COOKIE_PREVIEW_MODE,
257
+ value: "true",
258
+ maxAge: ONE_YEAR_SECONDS,
259
+ path: "/",
260
+ ...crossSite
261
+ });
262
+ }
250
263
  if (!isLivePreview) {
251
264
  const segmentCookie = requestCookies.get(COOKIE_SEGMENT);
252
265
  if (segmentCookie) {
@@ -265,7 +278,8 @@ function processPreprRequest(request, opts) {
265
278
  name: COOKIE_VARIANT,
266
279
  value: previewAb,
267
280
  maxAge: ONE_YEAR_SECONDS,
268
- path: "/"
281
+ path: "/",
282
+ ...crossSite
269
283
  });
270
284
  }
271
285
  }
@@ -277,7 +291,8 @@ function processPreprRequest(request, opts) {
277
291
  name: COOKIE_SEGMENT,
278
292
  value: previewSegment,
279
293
  maxAge: ONE_YEAR_SECONDS,
280
- path: "/"
294
+ path: "/",
295
+ ...crossSite
281
296
  });
282
297
  }
283
298
  }