@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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @preprio/toolkit
2
2
 
3
- A framework-agnostic TypeScript library that provides preview functionality, visual editing capabilities, and A/B testing for [Prepr CMS](https://prepr.io). Ships thin wrappers for Next.js, Astro, and SvelteKit on top of a vanilla core that runs anywhere.
3
+ A framework-agnostic TypeScript library that provides preview functionality, visual editing capabilities, and A/B testing for [Prepr CMS](https://prepr.io). Ships thin wrappers for Next.js, Nuxt, Astro, and SvelteKit on top of a vanilla core that runs anywhere.
4
4
 
5
5
  ## Quick Start
6
6
 
@@ -83,6 +83,7 @@ Per-framework requirements:
83
83
  | `@preprio/toolkit/nextjs` | `next` >= 13, `react` >= 17, `react-dom` >= 17 |
84
84
  | `@preprio/toolkit/astro` | none (`.astro` components compile in your own pipeline) |
85
85
  | `@preprio/toolkit/sveltekit` | `svelte` (only for the `.svelte` components) |
86
+ | `@preprio/toolkit/nuxt` | `vue` (only for the `.vue` components) |
86
87
 
87
88
  All peer dependencies are optional — installing without React or Next.js is fine as long as you only import the entry points you have dependencies for.
88
89
 
@@ -471,6 +472,57 @@ const preprHeaders = getPreprHeadersFromLocals(event.locals);
471
472
 
472
473
  See the runnable example at `examples/sveltekit` for the full source of truth.
473
474
 
475
+ ## Nuxt
476
+
477
+ `vue` is an optional peer dependency, needed only if you import the `.vue` components. Requires Nitro's Node.js preset (the Nuxt default).
478
+
479
+ **`server/middleware/prepr.ts`**
480
+
481
+ ```typescript
482
+ import { handlePreprRequest } from '@preprio/toolkit/nuxt';
483
+
484
+ export default defineEventHandler(event => {
485
+ handlePreprRequest(event, { preview: import.meta.dev });
486
+ });
487
+ ```
488
+
489
+ **`app/app.vue`** — resolve the toolbar props on the server, gated on the same flag:
490
+
491
+ ```vue
492
+ <script setup lang="ts">
493
+ import { getToolbarProps } from '@preprio/toolkit/nuxt';
494
+ import PreprToolbar from '@preprio/toolkit/nuxt/components/PreprToolbar';
495
+ import PreprTrackingPixel from '@preprio/toolkit/nuxt/components/PreprTrackingPixel';
496
+
497
+ const requestHeaders = useRequestHeaders();
498
+ const { data: toolbarProps } = await useAsyncData('prepr-toolbar', async () => {
499
+ if (!import.meta.dev) return null;
500
+ return getToolbarProps(
501
+ new Headers(requestHeaders as Record<string, string>),
502
+ useRuntimeConfig().public.preprGraphqlUrl
503
+ );
504
+ });
505
+ </script>
506
+
507
+ <template>
508
+ <NuxtPage />
509
+ <PreprTrackingPixel id="YOUR_ACCESS_TOKEN" />
510
+ <PreprToolbar v-if="toolbarProps" v-bind="toolbarProps" />
511
+ </template>
512
+ ```
513
+
514
+ The `.vue` components ship as source (compiled by your own Vite/Vue pipeline) and mount client-side via `onMounted`, so they never run during SSR.
515
+
516
+ The middleware folds the computed Prepr headers back onto the incoming request — read them via `useRequestHeaders()` in composables, or straight off the h3 event in server routes:
517
+
518
+ ```typescript
519
+ import { getPreprHeadersFromEvent } from '@preprio/toolkit/nuxt';
520
+
521
+ const preprHeaders = getPreprHeadersFromEvent(event);
522
+ ```
523
+
524
+ See the runnable example at `examples/nuxt` for the full source of truth.
525
+
474
526
  ## Any other framework
475
527
 
476
528
  The core is runtime-neutral: it works off a WHATWG `Request` and hands back the headers to forward to Prepr plus the cookies to persist. Adapting it to Express, Hono, Fastify, or a plain server is roughly twenty lines.
@@ -522,7 +574,7 @@ Serialize the server-computed props into the page — a `<script type="applicati
522
574
 
523
575
  Each wrapper exposes the same five helpers, differing only in how they reach the request headers.
524
576
 
525
- | Helper | Next.js | Astro / SvelteKit |
577
+ | Helper | Next.js | Astro / SvelteKit / Nuxt |
526
578
  | --- | --- | --- |
527
579
  | `getPreprUUID` | `await getPreprUUID()` | `getPreprUUID(headers)` |
528
580
  | `getActiveSegment` | `await getActiveSegment()` | `getActiveSegment(headers)` |
@@ -530,7 +582,7 @@ Each wrapper exposes the same five helpers, differing only in how they reach the
530
582
  | `getPreprHeaders` | `await getPreprHeaders()` | `getPreprHeaders(headers)` |
531
583
  | `getToolbarProps` | `await getToolbarProps(token)` | `await getToolbarProps(headers, token)` |
532
584
 
533
- The Next.js versions read via `next/headers` and are async. The Astro and SvelteKit versions take a standard `Headers` (`Astro.request.headers` or `event.request.headers`) and are sync, except `getToolbarProps`.
585
+ The Next.js versions read via `next/headers` and are async. The Astro, SvelteKit and Nuxt versions take a standard `Headers` (`Astro.request.headers`, `event.request.headers`, or one built from `useRequestHeaders()`) and are sync, except `getToolbarProps`.
534
586
 
535
587
  #### `getPreprUUID()`
536
588
 
@@ -895,6 +947,7 @@ Runnable examples live in the repository root:
895
947
  | `examples/nextjs` | App Router, middleware, Apollo, custom image loader |
896
948
  | `examples/astro` | Astro middleware and `.astro` components |
897
949
  | `examples/sveltekit` | `hooks.server.ts`, `+layout.server.ts`, `.svelte` components |
950
+ | `examples/nuxt` | `server/middleware`, `useAsyncData`, `.vue` components |
898
951
  | `examples/express` | Vanilla core — a hand-written adapter for an unsupported framework |
899
952
 
900
953
  ## Support
@@ -30,7 +30,7 @@ __export(astro_exports, {
30
30
  module.exports = __toCommonJS(astro_exports);
31
31
 
32
32
  // src/version.ts
33
- var VERSION = "0.1.0-beta.1";
33
+ var VERSION = "0.1.0-beta.3";
34
34
 
35
35
  // src/core/server.ts
36
36
  var PreprError = class extends Error {
@@ -1,5 +1,5 @@
1
1
  // src/version.ts
2
- var VERSION = "0.1.0-beta.1";
2
+ var VERSION = "0.1.0-beta.3";
3
3
 
4
4
  // src/core/server.ts
5
5
  var PreprError = class extends Error {
@@ -1006,7 +1006,7 @@ var CLOSE_ICON_SVG = `<svg width="10" height="10" viewBox="0 0 10 10" fill="none
1006
1006
  </svg>`;
1007
1007
 
1008
1008
  // src/core/ui/toolbar.generated.ts
1009
- 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}}";
1009
+ 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}}";
1010
1010
 
1011
1011
  // ../../node_modules/.pnpm/preact@10.29.7/node_modules/preact/jsx-runtime/dist/jsxRuntime.mjs
1012
1012
  var f2 = 0;
@@ -1095,10 +1095,13 @@ function SegmentListbox({
1095
1095
  state,
1096
1096
  t: t3,
1097
1097
  listboxOpen,
1098
+ segmentFilter,
1098
1099
  handlers
1099
1100
  }) {
1100
1101
  const segments = state.segments;
1101
1102
  const hasSegments = segments.length > 0;
1103
+ const filter = segmentFilter.trim().toLowerCase();
1104
+ const visibleSegments = filter ? segments.filter((s2) => s2.name.toLowerCase().includes(filter)) : segments;
1102
1105
  let label;
1103
1106
  if (!hasSegments) {
1104
1107
  label = t3("adaptiveContent.none");
@@ -1135,15 +1138,30 @@ function SegmentListbox({
1135
1138
  role: "listbox",
1136
1139
  hidden: !listboxOpen,
1137
1140
  onKeyDown: (e2) => handlers.onOptionsKeydown(e2),
1138
- children: segments.map((seg) => /* @__PURE__ */ u2(
1139
- SegmentOption,
1140
- {
1141
- seg,
1142
- selected: seg._id === state.selectedSegment,
1143
- onChoose: handlers.onChooseSegment
1144
- },
1145
- seg._id
1146
- ))
1141
+ children: [
1142
+ /* @__PURE__ */ u2("li", { class: "prepr-option-search", role: "none", children: /* @__PURE__ */ u2(
1143
+ "input",
1144
+ {
1145
+ type: "text",
1146
+ class: "prepr-segment-search",
1147
+ "data-prepr": "segment-search",
1148
+ placeholder: t3("adaptiveContent.searchSegments"),
1149
+ value: segmentFilter,
1150
+ onInput: (e2) => handlers.onSegmentFilterInput(
1151
+ e2.currentTarget.value
1152
+ )
1153
+ }
1154
+ ) }),
1155
+ visibleSegments.map((seg) => /* @__PURE__ */ u2(
1156
+ SegmentOption,
1157
+ {
1158
+ seg,
1159
+ selected: seg._id === state.selectedSegment,
1160
+ onChoose: handlers.onChooseSegment
1161
+ },
1162
+ seg._id
1163
+ ))
1164
+ ]
1147
1165
  }
1148
1166
  )
1149
1167
  ] });
@@ -1268,7 +1286,7 @@ function StatusPill({
1268
1286
  {
1269
1287
  class: "prepr-status-x",
1270
1288
  "data-prepr": "status-x",
1271
- hidden: state.selectedSegment === null,
1289
+ hidden: !state.previewMode || state.selectedSegment === null,
1272
1290
  children: /* @__PURE__ */ u2(RawSvg, { svg: XMARK_ICON_SVG })
1273
1291
  }
1274
1292
  )
@@ -1297,7 +1315,13 @@ function CloseEditPill({
1297
1315
  }
1298
1316
  );
1299
1317
  }
1300
- function Panel({ state, t: t3, listboxOpen, handlers }) {
1318
+ function Panel({
1319
+ state,
1320
+ t: t3,
1321
+ listboxOpen,
1322
+ segmentFilter,
1323
+ handlers
1324
+ }) {
1301
1325
  const hasPersonalization = state.selectedSegment !== null || state.selectedVariant !== null;
1302
1326
  return /* @__PURE__ */ u2(S, { children: [
1303
1327
  /* @__PURE__ */ u2(
@@ -1354,6 +1378,7 @@ function Panel({ state, t: t3, listboxOpen, handlers }) {
1354
1378
  state,
1355
1379
  t: t3,
1356
1380
  listboxOpen,
1381
+ segmentFilter,
1357
1382
  handlers
1358
1383
  }
1359
1384
  )
@@ -1411,6 +1436,7 @@ var PreprToolbarElement = class extends HTMLElementBase {
1411
1436
  this.t = (key) => key;
1412
1437
  this.unsubscribe = null;
1413
1438
  this.listboxOpen = false;
1439
+ this.segmentFilter = "";
1414
1440
  this.handlers = {
1415
1441
  onToggle: () => this.set({ toolbarOpen: !this.state.toolbarOpen }),
1416
1442
  onClose: () => this.set({ toolbarOpen: false }),
@@ -1441,6 +1467,10 @@ var PreprToolbarElement = class extends HTMLElementBase {
1441
1467
  onSegmentButtonKeydown: (e2) => this.onListboxKeydown(e2),
1442
1468
  onOptionsKeydown: (e2) => this.onListboxKeydown(e2),
1443
1469
  onChooseSegment: (id) => this.chooseSegment(id),
1470
+ onSegmentFilterInput: (value) => {
1471
+ this.segmentFilter = value;
1472
+ this.renderPanel(this.state);
1473
+ },
1444
1474
  onPreviewTooltipEnter: (el) => this.showTooltip(el),
1445
1475
  onPreviewTooltipLeave: () => this.hideTooltip()
1446
1476
  };
@@ -1489,6 +1519,7 @@ var PreprToolbarElement = class extends HTMLElementBase {
1489
1519
  state,
1490
1520
  t: this.t,
1491
1521
  listboxOpen: this.listboxOpen,
1522
+ segmentFilter: this.segmentFilter,
1492
1523
  handlers: this.handlers
1493
1524
  }),
1494
1525
  root
@@ -1554,6 +1585,8 @@ var PreprToolbarElement = class extends HTMLElementBase {
1554
1585
  onListboxKeydown(event) {
1555
1586
  const e2 = event;
1556
1587
  const options = this.optionEls();
1588
+ const inSearch = e2.target?.getAttribute?.("data-prepr") === "segment-search";
1589
+ if (inSearch && e2.key === " ") return;
1557
1590
  if (options.length === 0 && e2.key !== "Escape") return;
1558
1591
  switch (e2.key) {
1559
1592
  case "Enter":
@@ -1615,6 +1648,7 @@ var PreprToolbarElement = class extends HTMLElementBase {
1615
1648
  const button = this.segmentButton();
1616
1649
  if (button?.disabled) return;
1617
1650
  this.listboxOpen = open;
1651
+ this.segmentFilter = "";
1618
1652
  this.renderPanel(this.state);
1619
1653
  if (open) {
1620
1654
  const options = this.optionEls();
@@ -1625,11 +1659,17 @@ var PreprToolbarElement = class extends HTMLElementBase {
1625
1659
  options.forEach(
1626
1660
  (el, i2) => el.setAttribute("data-active", String(i2 === activeIndex))
1627
1661
  );
1628
- options[activeIndex]?.focus();
1662
+ this.searchInput()?.focus();
1629
1663
  }
1630
1664
  }
1665
+ searchInput() {
1666
+ return this.shadowRoot?.querySelector(
1667
+ '[data-prepr="segment-search"]'
1668
+ ) ?? null;
1669
+ }
1631
1670
  chooseSegment(id) {
1632
1671
  this.listboxOpen = false;
1672
+ this.segmentFilter = "";
1633
1673
  this.set({ selectedSegment: id });
1634
1674
  this.renderPanel(this.state);
1635
1675
  this.segmentButton()?.focus();
@@ -1692,6 +1732,7 @@ var en_default = {
1692
1732
  segment: "Segment",
1693
1733
  ABVariant: "A/B variant",
1694
1734
  chooseSegment: "Choose segment",
1735
+ searchSegments: "Search segments",
1695
1736
  none: "No segments",
1696
1737
  allOtherUsers: "All other users",
1697
1738
  offDescription: "View the site as a real user (use cookies)",
@@ -1720,6 +1761,7 @@ var nl_default = {
1720
1761
  segment: "Segment",
1721
1762
  ABVariant: "A/B-variant",
1722
1763
  chooseSegment: "Kies segment",
1764
+ searchSegments: "Zoek segmenten",
1723
1765
  none: "Geen segmenten",
1724
1766
  allOtherUsers: "Alle andere gebruikers",
1725
1767
  offDescription: "Bekijk de site als een echte gebruiker (gebruik cookies)",
@@ -1862,7 +1904,16 @@ function createChangeHandler(deps) {
1862
1904
  setCookie(COOKIE_TOOLBAR_OPEN, "false", COOKIE_OPTS);
1863
1905
  sendPreprEvent("preview_mode_toggled", { previewMode: after.previewMode });
1864
1906
  syncAutoClean(after.previewMode);
1865
- deps.reload();
1907
+ const [path, existing] = splitPath(deps.currentPath());
1908
+ const params = new URLSearchParams(existing);
1909
+ if (params.has(PARAM_SEGMENT) || params.has(PARAM_VARIANT)) {
1910
+ params.delete(PARAM_SEGMENT);
1911
+ params.delete(PARAM_VARIANT);
1912
+ const query = params.toString();
1913
+ deps.navigate(query ? `${path}?${query}` : path);
1914
+ } else {
1915
+ deps.reload();
1916
+ }
1866
1917
  }
1867
1918
  if (before.toolbarOpen !== after.toolbarOpen) {
1868
1919
  setCookie(COOKIE_TOOLBAR_OPEN, String(after.toolbarOpen), COOKIE_OPTS);
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.3";
47
47
 
48
48
  // src/core/constants.ts
49
49
  var COOKIE_PREVIEW_MODE = "Prepr-Preview-Mode";
@@ -95,6 +95,7 @@ var en_default = {
95
95
  segment: "Segment",
96
96
  ABVariant: "A/B variant",
97
97
  chooseSegment: "Choose segment",
98
+ searchSegments: "Search segments",
98
99
  none: "No segments",
99
100
  allOtherUsers: "All other users",
100
101
  offDescription: "View the site as a real user (use cookies)",
@@ -123,6 +124,7 @@ var nl_default = {
123
124
  segment: "Segment",
124
125
  ABVariant: "A/B-variant",
125
126
  chooseSegment: "Kies segment",
127
+ searchSegments: "Zoek segmenten",
126
128
  none: "Geen segmenten",
127
129
  allOtherUsers: "Alle andere gebruikers",
128
130
  offDescription: "Bekijk de site als een echte gebruiker (gebruik cookies)",
@@ -991,7 +993,16 @@ function createChangeHandler(deps) {
991
993
  setCookie(COOKIE_TOOLBAR_OPEN, "false", COOKIE_OPTS);
992
994
  sendPreprEvent("preview_mode_toggled", { previewMode: after.previewMode });
993
995
  syncAutoClean(after.previewMode);
994
- deps.reload();
996
+ const [path, existing] = splitPath(deps.currentPath());
997
+ const params = new URLSearchParams(existing);
998
+ if (params.has(PARAM_SEGMENT) || params.has(PARAM_VARIANT)) {
999
+ params.delete(PARAM_SEGMENT);
1000
+ params.delete(PARAM_VARIANT);
1001
+ const query = params.toString();
1002
+ deps.navigate(query ? `${path}?${query}` : path);
1003
+ } else {
1004
+ deps.reload();
1005
+ }
995
1006
  }
996
1007
  if (before.toolbarOpen !== after.toolbarOpen) {
997
1008
  setCookie(COOKIE_TOOLBAR_OPEN, String(after.toolbarOpen), COOKIE_OPTS);
@@ -1286,7 +1297,7 @@ var CLOSE_ICON_SVG = `<svg width="10" height="10" viewBox="0 0 10 10" fill="none
1286
1297
  </svg>`;
1287
1298
 
1288
1299
  // 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}}";
1300
+ 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
1301
 
1291
1302
  // ../../node_modules/.pnpm/preact@10.29.7/node_modules/preact/jsx-runtime/dist/jsxRuntime.mjs
1292
1303
  var f2 = 0;
@@ -1375,10 +1386,13 @@ function SegmentListbox({
1375
1386
  state,
1376
1387
  t: t3,
1377
1388
  listboxOpen,
1389
+ segmentFilter,
1378
1390
  handlers
1379
1391
  }) {
1380
1392
  const segments = state.segments;
1381
1393
  const hasSegments = segments.length > 0;
1394
+ const filter = segmentFilter.trim().toLowerCase();
1395
+ const visibleSegments = filter ? segments.filter((s2) => s2.name.toLowerCase().includes(filter)) : segments;
1382
1396
  let label;
1383
1397
  if (!hasSegments) {
1384
1398
  label = t3("adaptiveContent.none");
@@ -1415,15 +1429,30 @@ function SegmentListbox({
1415
1429
  role: "listbox",
1416
1430
  hidden: !listboxOpen,
1417
1431
  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
- ))
1432
+ children: [
1433
+ /* @__PURE__ */ u2("li", { class: "prepr-option-search", role: "none", children: /* @__PURE__ */ u2(
1434
+ "input",
1435
+ {
1436
+ type: "text",
1437
+ class: "prepr-segment-search",
1438
+ "data-prepr": "segment-search",
1439
+ placeholder: t3("adaptiveContent.searchSegments"),
1440
+ value: segmentFilter,
1441
+ onInput: (e2) => handlers.onSegmentFilterInput(
1442
+ e2.currentTarget.value
1443
+ )
1444
+ }
1445
+ ) }),
1446
+ visibleSegments.map((seg) => /* @__PURE__ */ u2(
1447
+ SegmentOption,
1448
+ {
1449
+ seg,
1450
+ selected: seg._id === state.selectedSegment,
1451
+ onChoose: handlers.onChooseSegment
1452
+ },
1453
+ seg._id
1454
+ ))
1455
+ ]
1427
1456
  }
1428
1457
  )
1429
1458
  ] });
@@ -1548,7 +1577,7 @@ function StatusPill({
1548
1577
  {
1549
1578
  class: "prepr-status-x",
1550
1579
  "data-prepr": "status-x",
1551
- hidden: state.selectedSegment === null,
1580
+ hidden: !state.previewMode || state.selectedSegment === null,
1552
1581
  children: /* @__PURE__ */ u2(RawSvg, { svg: XMARK_ICON_SVG })
1553
1582
  }
1554
1583
  )
@@ -1577,7 +1606,13 @@ function CloseEditPill({
1577
1606
  }
1578
1607
  );
1579
1608
  }
1580
- function Panel({ state, t: t3, listboxOpen, handlers }) {
1609
+ function Panel({
1610
+ state,
1611
+ t: t3,
1612
+ listboxOpen,
1613
+ segmentFilter,
1614
+ handlers
1615
+ }) {
1581
1616
  const hasPersonalization = state.selectedSegment !== null || state.selectedVariant !== null;
1582
1617
  return /* @__PURE__ */ u2(S, { children: [
1583
1618
  /* @__PURE__ */ u2(
@@ -1634,6 +1669,7 @@ function Panel({ state, t: t3, listboxOpen, handlers }) {
1634
1669
  state,
1635
1670
  t: t3,
1636
1671
  listboxOpen,
1672
+ segmentFilter,
1637
1673
  handlers
1638
1674
  }
1639
1675
  )
@@ -1691,6 +1727,7 @@ var PreprToolbarElement = class extends HTMLElementBase {
1691
1727
  this.t = (key) => key;
1692
1728
  this.unsubscribe = null;
1693
1729
  this.listboxOpen = false;
1730
+ this.segmentFilter = "";
1694
1731
  this.handlers = {
1695
1732
  onToggle: () => this.set({ toolbarOpen: !this.state.toolbarOpen }),
1696
1733
  onClose: () => this.set({ toolbarOpen: false }),
@@ -1721,6 +1758,10 @@ var PreprToolbarElement = class extends HTMLElementBase {
1721
1758
  onSegmentButtonKeydown: (e2) => this.onListboxKeydown(e2),
1722
1759
  onOptionsKeydown: (e2) => this.onListboxKeydown(e2),
1723
1760
  onChooseSegment: (id) => this.chooseSegment(id),
1761
+ onSegmentFilterInput: (value) => {
1762
+ this.segmentFilter = value;
1763
+ this.renderPanel(this.state);
1764
+ },
1724
1765
  onPreviewTooltipEnter: (el) => this.showTooltip(el),
1725
1766
  onPreviewTooltipLeave: () => this.hideTooltip()
1726
1767
  };
@@ -1769,6 +1810,7 @@ var PreprToolbarElement = class extends HTMLElementBase {
1769
1810
  state,
1770
1811
  t: this.t,
1771
1812
  listboxOpen: this.listboxOpen,
1813
+ segmentFilter: this.segmentFilter,
1772
1814
  handlers: this.handlers
1773
1815
  }),
1774
1816
  root
@@ -1834,6 +1876,8 @@ var PreprToolbarElement = class extends HTMLElementBase {
1834
1876
  onListboxKeydown(event) {
1835
1877
  const e2 = event;
1836
1878
  const options = this.optionEls();
1879
+ const inSearch = e2.target?.getAttribute?.("data-prepr") === "segment-search";
1880
+ if (inSearch && e2.key === " ") return;
1837
1881
  if (options.length === 0 && e2.key !== "Escape") return;
1838
1882
  switch (e2.key) {
1839
1883
  case "Enter":
@@ -1895,6 +1939,7 @@ var PreprToolbarElement = class extends HTMLElementBase {
1895
1939
  const button = this.segmentButton();
1896
1940
  if (button?.disabled) return;
1897
1941
  this.listboxOpen = open;
1942
+ this.segmentFilter = "";
1898
1943
  this.renderPanel(this.state);
1899
1944
  if (open) {
1900
1945
  const options = this.optionEls();
@@ -1905,11 +1950,17 @@ var PreprToolbarElement = class extends HTMLElementBase {
1905
1950
  options.forEach(
1906
1951
  (el, i2) => el.setAttribute("data-active", String(i2 === activeIndex))
1907
1952
  );
1908
- options[activeIndex]?.focus();
1953
+ this.searchInput()?.focus();
1909
1954
  }
1910
1955
  }
1956
+ searchInput() {
1957
+ return this.shadowRoot?.querySelector(
1958
+ '[data-prepr="segment-search"]'
1959
+ ) ?? null;
1960
+ }
1911
1961
  chooseSegment(id) {
1912
1962
  this.listboxOpen = false;
1963
+ this.segmentFilter = "";
1913
1964
  this.set({ selectedSegment: id });
1914
1965
  this.renderPanel(this.state);
1915
1966
  this.segmentButton()?.focus();
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.3";
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. */
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.3";
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. */
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-5JGPWQVA.js";
20
20
 
21
21
  // src/version.ts
22
- var VERSION = "0.1.0-beta.1";
22
+ var VERSION = "0.1.0-beta.3";
23
23
 
24
24
  // src/core/server.ts
25
25
  var PreprError = class extends Error {