🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@unleash/toolbar

Package Overview
Dependencies
Maintainers
10
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@unleash/toolbar - npm Package Compare versions

Comparing version
1.1.0
to
1.1.1
+5
dist/__tests__/setup.d.ts
interface GlobalWithLit {
litIssuedWarnings?: Set<string>;
}
declare const g: GlobalWithLit;
//# sourceMappingURL=setup.d.ts.map
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/__tests__/setup.ts"],"names":[],"mappings":"AAGA,UAAU,aAAa;IACrB,iBAAiB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACjC;AAED,QAAA,MAAM,CAAC,EAA4B,aAAa,CAAC"}
import { ToolbarStateManager } from './state';
import { DragPosition } from './types';
/**
* Determine which window edge a dragged toolbar should snap to, and where along
* that edge it sits. Pure function so it can be unit-tested independently.
*
* @param left/top - top-left corner of the dragged element (viewport coords)
* @param width/height - size of the dragged element
* @param vw/vh - viewport dimensions
*/
export declare function computeDragPosition(left: number, top: number, width: number, height: number, vw: number, vh: number): DragPosition;
/** Static config the controller needs to position the toolbar */
export interface DragControllerConfig {
/** Whether the floating icon can be dragged */
draggable: boolean;
/** Preset position used when the toolbar has not been dragged */
position: string;
}
/** Callbacks the controller uses to talk back to the owning UI */
export interface DragControllerCallbacks {
/** Open the toolbar panel (a plain click on the floating icon) */
onOpen: () => void;
/** Ask the owning UI to re-render (after the drag position changes) */
requestRender: () => void;
}
/**
* Owns toolbar placement and the drag-to-move interaction for the floating
* icon. It manipulates the root container's position (preset class or inline
* coordinates) and tracks pointer state during a drag, then snaps to the
* nearest window edge on release.
*
* It depends only on the root element, the state manager, static config, and a
* pair of callbacks — so it stays decoupled from the rest of the UI rendering.
*/
export declare class DragController {
private root;
private state;
private config;
private callbacks;
private isDragging;
private dragMoved;
private suppressClick;
private dragGrabX;
private dragGrabY;
private dragStartX;
private dragStartY;
private snapTimer?;
constructor(root: HTMLElement, state: ToolbarStateManager, config: DragControllerConfig, callbacks: DragControllerCallbacks);
private handleResize;
/**
* Apply the toolbar position to the root container. When the user has dragged
* the toolbar, position via inline coordinates; otherwise fall back to the
* preset position-* class from the `position` option.
*/
apply(): void;
/** Inline coordinates for the collapsed floating icon at a dragged position */
private computeIconCoords;
/**
* Inline coordinates for the expanded panel at a dragged position. The panel
* hugs the same edge as the icon and is centered near the icon's offset, then
* clamped so the 400px-wide panel never overflows the viewport.
*/
private computePanelCoords;
onToggleClick(): void;
onPointerDown(e: PointerEvent): void;
private onPointerMove;
private onPointerUp;
private removeDragListeners;
/** Remove all listeners and cancel any pending snap animation */
destroy(): void;
}
//# sourceMappingURL=drag-controller.d.ts.map
{"version":3,"file":"drag-controller.d.ts","sourceRoot":"","sources":["../src/drag-controller.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAoB5C;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,GACT,YAAY,CAmBd;AAED,iEAAiE;AACjE,MAAM,WAAW,oBAAoB;IACnC,+CAA+C;IAC/C,SAAS,EAAE,OAAO,CAAC;IACnB,iEAAiE;IACjE,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,kEAAkE;AAClE,MAAM,WAAW,uBAAuB;IACtC,kEAAkE;IAClE,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,uEAAuE;IACvE,aAAa,EAAE,MAAM,IAAI,CAAC;CAC3B;AAED;;;;;;;;GAQG;AACH,qBAAa,cAAc;IAWvB,OAAO,CAAC,IAAI;IACZ,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,SAAS;IAbnB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,SAAS,CAAC,CAAgC;gBAGxC,IAAI,EAAE,WAAW,EACjB,KAAK,EAAE,mBAAmB,EAC1B,MAAM,EAAE,oBAAoB,EAC5B,SAAS,EAAE,uBAAuB;IAQ5C,OAAO,CAAC,YAAY,CAElB;IAEF;;;;OAIG;IACH,KAAK,IAAI,IAAI;IA2Bb,+EAA+E;IAC/E,OAAO,CAAC,iBAAiB;IA0BzB;;;;OAIG;IACH,OAAO,CAAC,kBAAkB;IAgC1B,aAAa,IAAI,IAAI;IASrB,aAAa,CAAC,CAAC,EAAE,YAAY,GAAG,IAAI;IAsBpC,OAAO,CAAC,aAAa,CAsBnB;IAEF,OAAO,CAAC,WAAW,CA6BjB;IAEF,OAAO,CAAC,mBAAmB;IAK3B,iEAAiE;IACjE,OAAO,IAAI,IAAI;CAOhB"}
import { UnleashClient } from 'unleash-proxy-client';
import { ToolbarStateManager } from './state';
import { FlagOverride, InitToolbarOptions, ToolbarState, UnleashContext, UnleashToolbarInstance, WrappedUnleashClient } from './types';
/**
* Main toolbar instance implementation
*/
export declare class UnleashToolbar implements UnleashToolbarInstance {
private stateManager;
private ui;
readonly client: WrappedUnleashClient;
constructor(stateManager: ToolbarStateManager, wrappedClient: WrappedUnleashClient, options: InitToolbarOptions);
private initUI;
show(): void;
hide(): void;
destroy(): void;
getState(): ToolbarState;
getFlagNames(): string[];
setFlagOverride(name: string, override: FlagOverride | null): void;
setContextOverride(context: Partial<UnleashContext>): void;
removeContextOverride(fieldName: keyof UnleashContext): void;
resetOverrides(): void;
resetContextOverrides(): void;
}
/**
* Initialize the Unleash Toolbar with a client
* This is the main entry point - handles both toolbar creation and client wrapping
* Returns the wrapped client directly for immediate use
*
* @param client - The Unleash client to wrap
* @param options - Toolbar configuration options
*/
export declare function initUnleashToolbar(client: UnleashClient, options?: InitToolbarOptions): WrappedUnleashClient;
export { ToolbarStateManager } from './state';
export * from './types';
export { wrapUnleashClient } from './wrapper';
//# sourceMappingURL=index.d.ts.map
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAC9C,OAAO,KAAK,EACV,YAAY,EACZ,kBAAkB,EAElB,YAAY,EACZ,cAAc,EACd,sBAAsB,EACtB,oBAAoB,EACrB,MAAM,SAAS,CAAC;AAGjB;;GAEG;AACH,qBAAa,cAAe,YAAW,sBAAsB;IAC3D,OAAO,CAAC,YAAY,CAAsB;IAC1C,OAAO,CAAC,EAAE,CAAoB;IAC9B,SAAgB,MAAM,EAAE,oBAAoB,CAAC;gBAG3C,YAAY,EAAE,mBAAmB,EACjC,aAAa,EAAE,oBAAoB,EACnC,OAAO,EAAE,kBAAkB;YAUf,MAAM;IASpB,IAAI,IAAI,IAAI;IAIZ,IAAI,IAAI,IAAI;IAIZ,OAAO,IAAI,IAAI;IAKf,QAAQ,IAAI,YAAY;IAIxB,YAAY,IAAI,MAAM,EAAE;IAIxB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,GAAG,IAAI,GAAG,IAAI;IAIlE,kBAAkB,CAAC,OAAO,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,IAAI;IAI1D,qBAAqB,CAAC,SAAS,EAAE,MAAM,cAAc,GAAG,IAAI;IAI5D,cAAc,IAAI,IAAI;IAItB,qBAAqB,IAAI,IAAI;CAG9B;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,aAAa,EACrB,OAAO,GAAE,kBAAuB,GAC/B,oBAAoB,CAuBtB;AAUD,OAAO,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAE9C,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC"}
import{i as s,n as r,r as a,t as o}from"./src-BKCgoQZx.js";export{s as ToolbarStateManager,o as UnleashToolbar,r as initUnleashToolbar,a as wrapUnleashClient};
var e="unleash-toolbar-state";function a(e){if(!e)return null;try{return JSON.parse(decodeURIComponent(e))}catch{return null}}function t(t){return a(t.get(e)?.value)}function n(e,a){const n=t(a);if(!n||!e)return e;const r=JSON.parse(JSON.stringify(e));r.features||(r.features=[]);const s=new Set(r.features.map(e=>e.name));r.features=r.features.map(e=>{const a=n.flags[e.name]?.override;return a?"flag"===a.type?{...e,enabled:a.value,strategies:a.value?e.strategies&&e.strategies.length>0?e.strategies:[{name:"default",parameters:{},constraints:[]}]:[]}:"variant"===a.type&&e.variants?{...e,enabled:!0,strategies:e.strategies&&e.strategies.length>0?e.strategies:[{name:"default",parameters:{},constraints:[]}],variants:e.variants.map(e=>({...e,weight:e.name===a.variantKey?1e3:0}))}:e:e});for(const[t,i]of Object.entries(n.flags))if(!s.has(t)&&i.override){const e=i.override;"flag"===e.type?r.features.push({name:t,enabled:e.value,strategies:e.value?[{name:"default",parameters:{},constraints:[]}]:[]}):"variant"===e.type&&r.features.push({name:t,enabled:!0,strategies:[{name:"default",parameters:{},constraints:[]}],variants:[{name:e.variantKey,weight:1e3}]})}return r}function r(e,a){const n=t(a);return n&&e?e.map(e=>{const a=n.flags[e.name]?.override;return a?"flag"===a.type?{...e,enabled:a.value,variant:a.value?e.variant:{name:"disabled",enabled:!1}}:"variant"===a.type?{...e,enabled:!0,variant:{name:a.variantKey,enabled:!0,payload:e.variant?.payload}}:e:e}):e}export{e as UNLEASH_TOOLBAR_COOKIE,n as applyToolbarOverrides,r as applyToolbarOverridesToToggles,t as getToolbarStateFromCookies,a as parseToolbarState};
//# sourceMappingURL=next-server.es.js.map
{"version":3,"file":"next-server.es.js","names":[],"sources":["../src/next/server.ts"],"sourcesContent":["/**\n * Server-side Next.js integration for Unleash Toolbar\n *\n * This module provides utilities for applying toolbar overrides in server components,\n * SSR, SSG, and App Router scenarios. It reads overrides from cookies to ensure\n * server-side flag evaluations respect client-side toolbar changes.\n *\n * @example App Router Server Component\n * ```tsx\n * import { cookies } from 'next/headers';\n * import { getDefinitions, evaluateFlags, flagsClient } from '@unleash/nextjs';\n * import { applyToolbarOverrides } from '@unleash/toolbar/next/server';\n *\n * export default async function ServerPage() {\n * const cookieStore = await cookies();\n * const definitions = await getDefinitions();\n * const modifiedDefinitions = applyToolbarOverrides(definitions, cookieStore);\n *\n * const { toggles } = evaluateFlags(modifiedDefinitions, {\n * sessionId: 'session-123'\n * });\n *\n * const flags = flagsClient(toggles);\n * const isEnabled = flags.isEnabled('my-flag');\n *\n * return <div>{isEnabled ? 'ON' : 'OFF'}</div>;\n * }\n * ```\n */\n\nimport type { IToggle } from '@unleash/nextjs';\nimport type { ClientFeaturesResponse } from 'unleash-client';\nimport type { VariantDefinition } from 'unleash-client/lib/variant';\nimport type { ToolbarState } from '../types';\n\nexport const UNLEASH_TOOLBAR_COOKIE = 'unleash-toolbar-state';\n\n/**\n * Cookie store interface compatible with Next.js cookies()\n */\ninterface CookieStore {\n get(name: string): { value: string } | undefined;\n}\n\n/**\n * Parses toolbar state from cookie value\n */\nexport function parseToolbarState(cookieValue: string | undefined): ToolbarState | null {\n if (!cookieValue) return null;\n\n try {\n return JSON.parse(decodeURIComponent(cookieValue));\n } catch {\n return null;\n }\n}\n\n/**\n * Reads toolbar state from Next.js cookie store\n */\nexport function getToolbarStateFromCookies(cookieStore: CookieStore): ToolbarState | null {\n const cookie = cookieStore.get(UNLEASH_TOOLBAR_COOKIE);\n return parseToolbarState(cookie?.value);\n}\n\n/**\n * Applies toolbar overrides to Unleash feature flag definitions.\n *\n * Use this with getDefinitions() from @unleash/nextjs before evaluating flags\n * to ensure server-side evaluations respect toolbar overrides.\n *\n * @param definitions - Feature flag definitions from getDefinitions()\n * @param cookieStore - Next.js cookie store from cookies()\n * @returns Modified definitions with overrides applied\n *\n * @example\n * ```tsx\n * import { getDefinitions, evaluateFlags } from '@unleash/nextjs';\n * import { cookies } from 'next/headers';\n * import { applyToolbarOverrides } from '@unleash/toolbar/next/server';\n *\n * const cookieStore = await cookies();\n * const definitions = await getDefinitions();\n * const modified = applyToolbarOverrides(definitions, cookieStore);\n * const { toggles } = evaluateFlags(modified, context);\n * ```\n */\nexport function applyToolbarOverrides(\n definitions: ClientFeaturesResponse,\n cookieStore: CookieStore,\n): ClientFeaturesResponse {\n const state = getToolbarStateFromCookies(cookieStore);\n\n if (!state || !definitions) return definitions;\n\n // Clone definitions to avoid mutation\n const modified = JSON.parse(JSON.stringify(definitions)) as ClientFeaturesResponse;\n\n if (!modified.features) {\n modified.features = [];\n }\n\n // Track which features we've seen\n const existingFeatureNames = new Set(modified.features.map((f) => f.name));\n\n // Apply overrides to existing features\n modified.features = modified.features.map((feature) => {\n const override = state.flags[feature.name]?.override;\n\n if (!override) return feature;\n\n if (override.type === 'flag') {\n // Force flag to enabled/disabled\n return {\n ...feature,\n enabled: override.value,\n // Override strategies to force the value\n // When enabling, ensure we have at least a default strategy\n strategies: override.value\n ? feature.strategies && feature.strategies.length > 0\n ? feature.strategies\n : [{ name: 'default', parameters: {}, constraints: [] }]\n : [],\n };\n }\n\n if (override.type === 'variant' && feature.variants) {\n // Force specific variant\n return {\n ...feature,\n enabled: true,\n strategies:\n feature.strategies && feature.strategies.length > 0\n ? feature.strategies\n : [{ name: 'default', parameters: {}, constraints: [] }],\n variants: feature.variants.map((v: VariantDefinition) => ({\n ...v,\n weight: v.name === override.variantKey ? 1000 : 0,\n })),\n };\n }\n\n return feature;\n });\n\n // Add features that don't exist in the API but have overrides\n for (const [flagName, metadata] of Object.entries(state.flags)) {\n if (!existingFeatureNames.has(flagName) && metadata.override) {\n const override = metadata.override;\n\n if (override.type === 'flag') {\n // Add a new feature for the override\n modified.features.push({\n name: flagName,\n enabled: override.value,\n strategies: override.value ? [{ name: 'default', parameters: {}, constraints: [] }] : [],\n });\n } else if (override.type === 'variant') {\n // Add a new feature with a variant\n modified.features.push({\n name: flagName,\n enabled: true,\n strategies: [{ name: 'default', parameters: {}, constraints: [] }],\n variants: [\n {\n name: override.variantKey,\n weight: 1000,\n },\n ],\n });\n }\n }\n }\n\n return modified;\n}\n\n/**\n * Applies toolbar overrides to evaluated toggles.\n *\n * Alternative to applyToolbarOverrides() - use this if you already have\n * evaluated toggles and want to apply overrides post-evaluation.\n *\n * @param toggles - Evaluated toggles array from evaluateFlags()\n * @param cookieStore - Next.js cookie store from cookies()\n * @returns Modified toggles with overrides applied\n *\n * @example\n * ```tsx\n * import { getDefinitions, evaluateFlags, flagsClient } from '@unleash/nextjs';\n * import { cookies } from 'next/headers';\n * import { applyToolbarOverridesToToggles } from '@unleash/toolbar/next/server';\n *\n * const definitions = await getDefinitions();\n * const { toggles } = evaluateFlags(definitions, context);\n * const modified = applyToolbarOverridesToToggles(toggles, await cookies());\n * const flags = flagsClient(modified);\n * ```\n */\nexport function applyToolbarOverridesToToggles(\n toggles: IToggle[],\n cookieStore: CookieStore,\n): IToggle[] {\n const state = getToolbarStateFromCookies(cookieStore);\n\n if (!state || !toggles) return toggles;\n\n return toggles.map((toggle) => {\n const override = state.flags[toggle.name]?.override;\n\n if (!override) return toggle;\n\n if (override.type === 'flag') {\n return {\n ...toggle,\n enabled: override.value,\n variant: override.value ? toggle.variant : { name: 'disabled', enabled: false },\n };\n }\n\n if (override.type === 'variant') {\n return {\n ...toggle,\n enabled: true,\n variant: {\n name: override.variantKey,\n enabled: true,\n payload: toggle.variant?.payload,\n },\n };\n }\n\n return toggle;\n });\n}\n"],"mappings":"AAmCA,IAAa,EAAyB,wBAYtC,SAAgB,EAAkB,GAChC,IAAK,EAAa,OAAO,KAEzB,IACE,OAAO,KAAK,MAAM,mBAAmB,GACvC,CAAA,MACE,OAAO,IACT,CACF,CAKA,SAAgB,EAA2B,GAEzC,OAAO,EADQ,EAAY,IAAI,IACE,MACnC,CAwBA,SAAgB,EACd,EACA,GAEA,MAAM,EAAQ,EAA2B,GAEzC,IAAK,IAAU,EAAa,OAAO,EAGnC,MAAM,EAAW,KAAK,MAAM,KAAK,UAAU,IAEtC,EAAS,WACZ,EAAS,SAAW,IAItB,MAAM,EAAuB,IAAI,IAAI,EAAS,SAAS,IAAK,GAAM,EAAE,OAGpE,EAAS,SAAW,EAAS,SAAS,IAAK,IACzC,MAAM,EAAW,EAAM,MAAM,EAAQ,OAAO,SAE5C,OAAK,EAEiB,SAAlB,EAAS,KAEJ,IACF,EACH,QAAS,EAAS,MAGlB,WAAY,EAAS,MACjB,EAAQ,YAAc,EAAQ,WAAW,OAAS,EAChD,EAAQ,WACR,CAAC,CAAE,KAAM,UAAW,WAAY,CAAC,EAAG,YAAa,KACnD,IAIc,YAAlB,EAAS,MAAsB,EAAQ,SAElC,IACF,EACH,SAAS,EACT,WACE,EAAQ,YAAc,EAAQ,WAAW,OAAS,EAC9C,EAAQ,WACR,CAAC,CAAE,KAAM,UAAW,WAAY,CAAC,EAAG,YAAa,KACvD,SAAU,EAAQ,SAAS,IAAK,IAAA,IAC3B,EACH,OAAQ,EAAE,OAAS,EAAS,WAAa,IAAO,MAK/C,EAjCe,IAqCxB,IAAK,MAAO,EAAU,KAAa,OAAO,QAAQ,EAAM,OACtD,IAAK,EAAqB,IAAI,IAAa,EAAS,SAAU,CAC5D,MAAM,EAAW,EAAS,SAEJ,SAAlB,EAAS,KAEX,EAAS,SAAS,KAAK,CACrB,KAAM,EACN,QAAS,EAAS,MAClB,WAAY,EAAS,MAAQ,CAAC,CAAE,KAAM,UAAW,WAAY,CAAC,EAAG,YAAa,KAAQ,KAE7D,YAAlB,EAAS,MAElB,EAAS,SAAS,KAAK,CACrB,KAAM,EACN,SAAS,EACT,WAAY,CAAC,CAAE,KAAM,UAAW,WAAY,CAAC,EAAG,YAAa,KAC7D,SAAU,CACR,CACE,KAAM,EAAS,WACf,OAAQ,OAKlB,CAGF,OAAO,CACT,CAwBA,SAAgB,EACd,EACA,GAEA,MAAM,EAAQ,EAA2B,GAEzC,OAAK,GAAU,EAER,EAAQ,IAAK,IAClB,MAAM,EAAW,EAAM,MAAM,EAAO,OAAO,SAE3C,OAAK,EAEiB,SAAlB,EAAS,KACJ,IACF,EACH,QAAS,EAAS,MAClB,QAAS,EAAS,MAAQ,EAAO,QAAU,CAAE,KAAM,WAAY,SAAS,IAItD,YAAlB,EAAS,KACJ,IACF,EACH,SAAS,EACT,QAAS,CACP,KAAM,EAAS,WACf,SAAS,EACT,QAAS,EAAO,SAAS,UAKxB,EAtBe,IALO,CA6BjC"}
"use client";
import{UnleashToolbarProvider as o}from"./react.es.js";import{useFlag as r,useFlags as t,useFlagsStatus as e,useUnleashClient as n,useUnleashContext as a,useVariant as i}from"@unleash/proxy-client-react";import"react";import{jsx as s}from"react/jsx-runtime";function c(r){const t={...r.toolbarOptions,enableCookieSync:!0};/* @__PURE__ */
return s(o,{...r,toolbarOptions:t})}export{c as UnleashToolbarProvider,r as useFlag,t as useFlags,e as useFlagsStatus,n as useUnleashClient,a as useUnleashContext,i as useVariant};
//# sourceMappingURL=next.es.js.map
{"version":3,"file":"next.es.js","names":[],"sources":["../src/next/client.tsx"],"sourcesContent":["/**\n * Client-side Next.js integration for Unleash Toolbar\n * \n * This module provides the client-side provider for Next.js applications.\n * Use this in client components marked with \"use client\" directive.\n * Automatically enables cookie synchronization for server-side rendering support.\n */\n'use client';\n\nimport { UnleashToolbarProvider as BaseUnleashToolbarProvider } from '../react/index';\nimport type { InitToolbarOptions } from '../types';\nimport React from 'react';\n\n/**\n * Next.js-specific provider that wraps the official Unleash React SDK's FlagProvider\n * and automatically enables cookie synchronization for server-side rendering support.\n * \n * This ensures toolbar state is available in server components via getToolbarStateFromCookies().\n */\nexport function UnleashToolbarProvider(props: React.ComponentProps<typeof BaseUnleashToolbarProvider>) {\n // Automatically enable cookie sync for Next.js SSR support\n const toolbarOptions: InitToolbarOptions = {\n ...props.toolbarOptions,\n enableCookieSync: true,\n };\n\n return <BaseUnleashToolbarProvider {...props} toolbarOptions={toolbarOptions} />;\n}\n\nexport * from '../react/hooks';\n\n"],"mappings":"kQAmBA,SAAgB,EAAuB,GAErC,MAAM,EAAqC,IACtC,EAAM,eACT,kBAAkB;AAGpB,OAAO,EAAC,EAAD,IAAgC,EAAuB,kBAChE"}
import { UnleashToolbarProvider as BaseUnleashToolbarProvider } from '../react/index';
import { default as React } from 'react';
/**
* Next.js-specific provider that wraps the official Unleash React SDK's FlagProvider
* and automatically enables cookie synchronization for server-side rendering support.
*
* This ensures toolbar state is available in server components via getToolbarStateFromCookies().
*/
export declare function UnleashToolbarProvider(props: React.ComponentProps<typeof BaseUnleashToolbarProvider>): React.JSX.Element;
export * from '../react/hooks';
//# sourceMappingURL=client.d.ts.map
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/next/client.tsx"],"names":[],"mappings":"AASA,OAAO,EAAE,sBAAsB,IAAI,0BAA0B,EAAE,MAAM,gBAAgB,CAAC;AAEtF,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,0BAA0B,CAAC,qBAQpG;AAED,cAAc,gBAAgB,CAAC"}
/**
* Next.js integration for Unleash Toolbar
*
* This package provides both client-side and server-side integration for Next.js:
*
* - Client-side: `@unleash/toolbar/next` (same as React integration)
* - Server-side: `@unleash/toolbar/next/server` (for App Router server components)
*
* @example Client Component
* ```tsx
* 'use client';
* import { UnleashToolbarProvider, useFlag } from '@unleash/toolbar/next';
*
* export function MyComponent() {
* return (
* <UnleashToolbarProvider config={{ ... }}>
* <App />
* </UnleashToolbarProvider>
* );
* }
* ```
*
* @example Server Component
* ```tsx
* import { cookies } from 'next/headers';
* import { getDefinitions, evaluateFlags, flagsClient } from '@unleash/nextjs';
* import { applyToolbarOverrides } from '@unleash/toolbar/next/server';
*
* export default async function Page() {
* const definitions = await getDefinitions();
* const modified = applyToolbarOverrides(definitions, await cookies());
* const { toggles } = evaluateFlags(modified, { sessionId: '123' });
* const flags = flagsClient(toggles);
*
* return <div>{flags.isEnabled('my-flag') ? 'ON' : 'OFF'}</div>;
* }
* ```
*/
export * from '../react/hooks';
export { UnleashToolbarProvider } from './client';
//# sourceMappingURL=index.d.ts.map
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/next/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,cAAc,gBAAgB,CAAC;AAE/B,OAAO,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC"}
import { IToggle } from '@unleash/nextjs';
import { ClientFeaturesResponse } from 'unleash-client';
import { ToolbarState } from '../types';
export declare const UNLEASH_TOOLBAR_COOKIE = "unleash-toolbar-state";
/**
* Cookie store interface compatible with Next.js cookies()
*/
interface CookieStore {
get(name: string): {
value: string;
} | undefined;
}
/**
* Parses toolbar state from cookie value
*/
export declare function parseToolbarState(cookieValue: string | undefined): ToolbarState | null;
/**
* Reads toolbar state from Next.js cookie store
*/
export declare function getToolbarStateFromCookies(cookieStore: CookieStore): ToolbarState | null;
/**
* Applies toolbar overrides to Unleash feature flag definitions.
*
* Use this with getDefinitions() from @unleash/nextjs before evaluating flags
* to ensure server-side evaluations respect toolbar overrides.
*
* @param definitions - Feature flag definitions from getDefinitions()
* @param cookieStore - Next.js cookie store from cookies()
* @returns Modified definitions with overrides applied
*
* @example
* ```tsx
* import { getDefinitions, evaluateFlags } from '@unleash/nextjs';
* import { cookies } from 'next/headers';
* import { applyToolbarOverrides } from '@unleash/toolbar/next/server';
*
* const cookieStore = await cookies();
* const definitions = await getDefinitions();
* const modified = applyToolbarOverrides(definitions, cookieStore);
* const { toggles } = evaluateFlags(modified, context);
* ```
*/
export declare function applyToolbarOverrides(definitions: ClientFeaturesResponse, cookieStore: CookieStore): ClientFeaturesResponse;
/**
* Applies toolbar overrides to evaluated toggles.
*
* Alternative to applyToolbarOverrides() - use this if you already have
* evaluated toggles and want to apply overrides post-evaluation.
*
* @param toggles - Evaluated toggles array from evaluateFlags()
* @param cookieStore - Next.js cookie store from cookies()
* @returns Modified toggles with overrides applied
*
* @example
* ```tsx
* import { getDefinitions, evaluateFlags, flagsClient } from '@unleash/nextjs';
* import { cookies } from 'next/headers';
* import { applyToolbarOverridesToToggles } from '@unleash/toolbar/next/server';
*
* const definitions = await getDefinitions();
* const { toggles } = evaluateFlags(definitions, context);
* const modified = applyToolbarOverridesToToggles(toggles, await cookies());
* const flags = flagsClient(modified);
* ```
*/
export declare function applyToolbarOverridesToToggles(toggles: IToggle[], cookieStore: CookieStore): IToggle[];
export {};
//# sourceMappingURL=server.d.ts.map
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/next/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAE7D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7C,eAAO,MAAM,sBAAsB,0BAA0B,CAAC;AAE9D;;GAEG;AACH,UAAU,WAAW;IACnB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;CAClD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,YAAY,GAAG,IAAI,CAQtF;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,WAAW,EAAE,WAAW,GAAG,YAAY,GAAG,IAAI,CAGxF;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,sBAAsB,EACnC,WAAW,EAAE,WAAW,GACvB,sBAAsB,CAqFxB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,OAAO,EAAE,EAClB,WAAW,EAAE,WAAW,GACvB,OAAO,EAAE,CAgCX"}
import{i as r,r as e,t as o}from"./src-BKCgoQZx.js";import{UnleashClient as t}from"unleash-proxy-client";import{FlagProvider as n}from"@unleash/proxy-client-react";import{useEffect as i,useRef as l}from"react";import{jsx as c}from"react/jsx-runtime";function u({FlagProvider:u=n,config:a,client:s,toolbarOptions:f={},startClient:d=!0,children:p,...h}){if(!a&&!s)throw new Error('UnleashToolbarProvider: Either "config" or "client" prop must be provided');if(a&&s)throw new Error('UnleashToolbarProvider: Provide either "config" or "client" prop, not both');const b=l(null),m=l(null),w=l(null);if(null===w.current){const o=s||new t(a);if(void 0!==f){const t=new r(f.storageMode||"local",f.storageKey||"unleash-toolbar-state",f.sortAlphabetically||!1);m.current=t,f.enableCookieSync&&t.enableCookieSync(),w.current=e(o,t)}else w.current=o}return i(()=>{if(void 0!==f&&!b.current&&m.current&&!w.current?.__toolbar){const r=new o(m.current,w.current,f);w.current.__toolbar=r,b.current=r,"undefined"!=typeof window&&(window.unleashToolbar=r)}return()=>{b.current&&"function"==typeof b.current.destroy&&(b.current.destroy(),b.current=null)}},[]),/* @__PURE__ */c(u,{unleashClient:w.current,startClient:d,...h,children:p})}export{u as UnleashToolbarProvider};
//# sourceMappingURL=react.es.js.map
{"version":3,"file":"react.es.js","names":[],"sources":["../src/react/index.tsx"],"sourcesContent":["import { UnleashClient, type IConfig } from 'unleash-proxy-client';\nimport { FlagProvider as DefaultFlagProvider } from '@unleash/proxy-client-react';\nimport { wrapUnleashClient, ToolbarStateManager, UnleashToolbar } from '../index';\nimport type { InitToolbarOptions } from '../types';\nimport React, { useRef, useEffect } from 'react';\n\n/**\n * Base props shared by both config and client variants\n */\ninterface BaseToolbarProviderProps {\n /**\n * The official FlagProvider component from @unleash/proxy-client-react\n * Optional - defaults to the standard FlagProvider\n */\n FlagProvider?: React.ComponentType<any>;\n \n /**\n * Optional toolbar configuration\n * Set to undefined to disable toolbar in production\n */\n toolbarOptions?: InitToolbarOptions;\n \n /**\n * Whether to automatically start the client\n * Defaults to true\n */\n startClient?: boolean;\n \n /**\n * Children components\n */\n children: React.ReactNode;\n \n /**\n * Any additional props to pass to the official FlagProvider\n */\n [key: string]: any;\n}\n\n/**\n * Props when using config-based initialization\n */\ninterface ConfigBasedProps extends BaseToolbarProviderProps {\n /**\n * Unleash SDK configuration object (same as official React SDK)\n */\n config: IConfig;\n client?: never;\n}\n\n/**\n * Props when using pre-instantiated client\n */\ninterface ClientBasedProps extends BaseToolbarProviderProps {\n /**\n * Pre-instantiated Unleash client (will be wrapped with toolbar)\n */\n client: UnleashClient;\n config?: never;\n}\n\n/**\n * Props for the UnleashToolbarProvider - either config OR client must be provided\n */\ntype UnleashToolbarProviderProps = ConfigBasedProps | ClientBasedProps;\n\n/**\n * Higher-order provider that wraps the official Unleash React SDK's FlagProvider\n * and initializes the toolbar with a wrapped client.\n * \n * Simple usage (no imports needed):\n * ```tsx\n * import { UnleashToolbarProvider } from '@unleash/toolbar/react';\n * \n * function App() {\n * return (\n * <UnleashToolbarProvider\n * config={{\n * url: 'https://your-unleash-instance.com/api/frontend',\n * clientKey: 'your-client-key',\n * appName: 'my-app'\n * }}\n * toolbarOptions={{ themePreset: 'dark' }}\n * >\n * <YourApp />\n * </UnleashToolbarProvider>\n * );\n * }\n * ```\n * \n * Advanced usage with custom FlagProvider:\n * ```tsx\n * import { FlagProvider } from '@unleash/proxy-client-react';\n * \n * <UnleashToolbarProvider\n * FlagProvider={FlagProvider}\n * config={{ ... }}\n * >\n * <YourApp />\n * </UnleashToolbarProvider>\n * ```\n */\nexport function UnleashToolbarProvider({\n FlagProvider = DefaultFlagProvider,\n config,\n client,\n toolbarOptions = {},\n startClient = true,\n children,\n ...flagProviderProps\n}: UnleashToolbarProviderProps) {\n // Validate that either config or client is provided, not both\n if (!config && !client) {\n throw new Error(\n 'UnleashToolbarProvider: Either \"config\" or \"client\" prop must be provided'\n );\n }\n if (config && client) {\n throw new Error(\n 'UnleashToolbarProvider: Provide either \"config\" or \"client\" prop, not both'\n );\n }\n\n const toolbarRef = useRef<any>(null);\n const stateManagerRef = useRef<any>(null);\n \n // Wrap client synchronously (idempotent, captures flag evaluations)\n // This ensures the wrapper intercepts all flag evaluations from the first render\n const wrappedClientRef = useRef<UnleashClient | null>(null);\n \n if (wrappedClientRef.current === null) {\n const unleashClient = client || new UnleashClient(config!);\n \n if (toolbarOptions !== undefined) {\n // Create state manager that will be shared between wrapper and toolbar\n const storageMode = toolbarOptions.storageMode || 'local';\n const storageKey = toolbarOptions.storageKey || 'unleash-toolbar-state';\n const sortAlphabetically = toolbarOptions.sortAlphabetically || false;\n const stateManager = new ToolbarStateManager(storageMode, storageKey, sortAlphabetically);\n stateManagerRef.current = stateManager;\n\n if (toolbarOptions.enableCookieSync) {\n stateManager.enableCookieSync();\n }\n \n // Wrap client synchronously with shared state manager\n wrappedClientRef.current = wrapUnleashClient(unleashClient, stateManager);\n } else {\n // no toolbar - just use original client\n wrappedClientRef.current = unleashClient;\n }\n }\n \n // Create toolbar UI in useEffect (StrictMode-safe)\n useEffect(() => {\n // Only create toolbar if:\n // 1. toolbarOptions is defined\n // 2. No toolbar ref yet\n // 3. State manager exists\n // 4. Wrapped client doesn't already have a toolbar (prevents StrictMode duplicates)\n if (toolbarOptions !== undefined && \n !toolbarRef.current && \n stateManagerRef.current &&\n !(wrappedClientRef.current as any)?.__toolbar) {\n // Create toolbar with the same state manager used for wrapping\n const toolbar = new UnleashToolbar(stateManagerRef.current, wrappedClientRef.current as any, toolbarOptions);\n (wrappedClientRef.current as any).__toolbar = toolbar;\n toolbarRef.current = toolbar;\n \n // Expose globally\n if (typeof window !== 'undefined') {\n (window as any).unleashToolbar = toolbar;\n }\n }\n \n // Cleanup toolbar on unmount\n return () => {\n if (toolbarRef.current && typeof toolbarRef.current.destroy === 'function') {\n toolbarRef.current.destroy();\n toolbarRef.current = null;\n }\n };\n }, []);\n\n return (\n <FlagProvider\n unleashClient={wrappedClientRef.current}\n startClient={startClient}\n {...flagProviderProps}\n >\n {children}\n </FlagProvider>\n );\n}\n"],"mappings":"0PAsGA,SAAgB,GACd,aAAA,EAAe,EAAA,OACf,EAAA,OACA,EAAA,eACA,EAAiB,CAAC,EAAA,YAClB,GAAc,EAAA,SACd,KACG,IAGH,IAAK,IAAW,EACd,MAAM,IAAI,MACR,6EAGJ,GAAI,GAAU,EACZ,MAAM,IAAI,MACR,8EAIJ,MAAM,EAAa,EAAY,MACzB,EAAkB,EAAY,MAI9B,EAAmB,EAA6B,MAEtD,GAAiC,OAA7B,EAAiB,QAAkB,CACrC,MAAM,EAAgB,GAAU,IAAI,EAAc,GAElD,QAAuB,IAAnB,EAA8B,CAKhC,MAAM,EAAe,IAAI,EAHL,EAAe,aAAe,QAC/B,EAAe,YAAc,wBACrB,EAAe,qBAAsB,GAEhE,EAAgB,QAAU,EAEtB,EAAe,kBACjB,EAAa,mBAIf,EAAiB,QAAU,EAAkB,EAAe,EAC9D,MAEE,EAAiB,QAAU,CAE/B,CAiCA,OA9BA,EAAA,KAME,QAAuB,IAAnB,IACC,EAAW,SACZ,EAAgB,UACd,EAAiB,SAAiB,UAAW,CAEjD,MAAM,EAAU,IAAI,EAAe,EAAgB,QAAS,EAAiB,QAAgB,GAC7F,EAAkB,QAAgB,UAAY,EAC9C,EAAW,QAAU,EAGC,oBAAX,SACT,OAAgB,eAAiB,EAErC,CAGA,MAAA,KACM,EAAW,SAAiD,mBAA/B,EAAW,QAAQ,UAClD,EAAW,QAAQ,UACnB,EAAW,QAAU,QAGxB,mBAGD,EAAC,EAAD,CACE,cAAe,EAAiB,QACnB,iBACT,EAEH,YAGP"}
export {};
//# sourceMappingURL=index.test.d.ts.map
{"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../../../src/react/__tests__/index.test.tsx"],"names":[],"mappings":""}
/**
* Re-export hooks from the official Unleash React SDK
* This allows users to import all React hooks from the toolbar package:
*
* import { useFlag, useVariant } from '@unleash/toolbar/react';
*/
export { useFlag, useFlags, useFlagsStatus, useUnleashClient, useUnleashContext, useVariant, } from '@unleash/proxy-client-react';
//# sourceMappingURL=hooks.d.ts.map
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/react/hooks.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EACL,OAAO,EACP,QAAQ,EACR,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,UAAU,GACX,MAAM,6BAA6B,CAAC"}
import { UnleashClient, IConfig } from 'unleash-proxy-client';
import { InitToolbarOptions } from '../types';
import { default as React } from 'react';
/**
* Base props shared by both config and client variants
*/
interface BaseToolbarProviderProps {
/**
* The official FlagProvider component from @unleash/proxy-client-react
* Optional - defaults to the standard FlagProvider
*/
FlagProvider?: React.ComponentType<any>;
/**
* Optional toolbar configuration
* Set to undefined to disable toolbar in production
*/
toolbarOptions?: InitToolbarOptions;
/**
* Whether to automatically start the client
* Defaults to true
*/
startClient?: boolean;
/**
* Children components
*/
children: React.ReactNode;
/**
* Any additional props to pass to the official FlagProvider
*/
[key: string]: any;
}
/**
* Props when using config-based initialization
*/
interface ConfigBasedProps extends BaseToolbarProviderProps {
/**
* Unleash SDK configuration object (same as official React SDK)
*/
config: IConfig;
client?: never;
}
/**
* Props when using pre-instantiated client
*/
interface ClientBasedProps extends BaseToolbarProviderProps {
/**
* Pre-instantiated Unleash client (will be wrapped with toolbar)
*/
client: UnleashClient;
config?: never;
}
/**
* Props for the UnleashToolbarProvider - either config OR client must be provided
*/
type UnleashToolbarProviderProps = ConfigBasedProps | ClientBasedProps;
/**
* Higher-order provider that wraps the official Unleash React SDK's FlagProvider
* and initializes the toolbar with a wrapped client.
*
* Simple usage (no imports needed):
* ```tsx
* import { UnleashToolbarProvider } from '@unleash/toolbar/react';
*
* function App() {
* return (
* <UnleashToolbarProvider
* config={{
* url: 'https://your-unleash-instance.com/api/frontend',
* clientKey: 'your-client-key',
* appName: 'my-app'
* }}
* toolbarOptions={{ themePreset: 'dark' }}
* >
* <YourApp />
* </UnleashToolbarProvider>
* );
* }
* ```
*
* Advanced usage with custom FlagProvider:
* ```tsx
* import { FlagProvider } from '@unleash/proxy-client-react';
*
* <UnleashToolbarProvider
* FlagProvider={FlagProvider}
* config={{ ... }}
* >
* <YourApp />
* </UnleashToolbarProvider>
* ```
*/
export declare function UnleashToolbarProvider({ FlagProvider, config, client, toolbarOptions, startClient, children, ...flagProviderProps }: UnleashToolbarProviderProps): React.JSX.Element;
export {};
//# sourceMappingURL=index.d.ts.map
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,KAAK,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAGnE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AACnD,OAAO,KAA4B,MAAM,OAAO,CAAC;AAEjD;;GAEG;AACH,UAAU,wBAAwB;IAChC;;;OAGG;IACH,YAAY,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;IAExC;;;OAGG;IACH,cAAc,CAAC,EAAE,kBAAkB,CAAC;IAEpC;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;OAEG;IACH,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAE1B;;OAEG;IACH,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED;;GAEG;AACH,UAAU,gBAAiB,SAAQ,wBAAwB;IACzD;;OAEG;IACH,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,KAAK,CAAC;CAChB;AAED;;GAEG;AACH,UAAU,gBAAiB,SAAQ,wBAAwB;IACzD;;OAEG;IACH,MAAM,EAAE,aAAa,CAAC;IACtB,MAAM,CAAC,EAAE,KAAK,CAAC;CAChB;AAED;;GAEG;AACH,KAAK,2BAA2B,GAAG,gBAAgB,GAAG,gBAAgB,CAAC;AAEvE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,YAAkC,EAClC,MAAM,EACN,MAAM,EACN,cAAmB,EACnB,WAAkB,EAClB,QAAQ,EACR,GAAG,iBAAiB,EACrB,EAAE,2BAA2B,qBAmF7B"}
var e=class{listeners=/* @__PURE__ */new Set;subscribe(e){return this.listeners.add(e),()=>this.listeners.delete(e)}emit(e){this.listeners.forEach(t=>{try{t(e)}catch(a){console.error("[Unleash Toolbar] Error in event listener:",a)}})}},t=class{mode;key;enableCookieSync=!1;constructor(e,t){this.mode=e,this.key=t}setCookieSyncEnabled(e){this.enableCookieSync=e}getStorage(){if("undefined"==typeof window)return null;switch(this.mode){case"local":return window.localStorage;case"session":return window.sessionStorage;default:return null}}syncToCookies(e){if(this.enableCookieSync&&"undefined"!=typeof document)try{!async function(e,t){if("undefined"==typeof document)return;const a=encodeURIComponent(t);if("cookieStore"in window)try{return void(await window.cookieStore.set({name:e,value:a,path:"/",sameSite:"lax",expires:Date.now()+6048e5}))}catch{}document.cookie=[`${e}=${a}`,"path=/","max-age=604800","SameSite=Lax"].join("; ")}("unleash-toolbar-state",JSON.stringify(e))}catch(t){console.error("[Unleash Toolbar] Failed to sync state to cookies:",t)}}load(){const e=this.getStorage();if(!e)return null;try{const t=e.getItem(this.key);return t?JSON.parse(t):null}catch(t){return console.error("[Unleash Toolbar] Failed to load state from storage:",t),null}}save(e){const t=this.getStorage();if(t)try{t.setItem(this.key,JSON.stringify(e)),this.syncToCookies(e)}catch(a){console.error("[Unleash Toolbar] Failed to save state to storage:",a)}}clear(){const e=this.getStorage();if(e)try{e.removeItem(this.key),this.enableCookieSync&&async function(e){if("undefined"!=typeof document){if("cookieStore"in window)try{return void(await window.cookieStore.delete(e))}catch{}document.cookie=`${e}=; path=/; max-age=0`}}("unleash-toolbar-state")}catch(t){console.error("[Unleash Toolbar] Failed to clear storage:",t)}}},a=class{state;eventEmitter;storage;sortAlphabetically;constructor(a="local",s="unleash-toolbar-state",r=!1){this.eventEmitter=new e,this.storage=new t(a,s),this.sortAlphabetically=r;const i=this.storage.load();this.state=i||this.getInitialState()}getInitialState(){return{flags:{},contextOverrides:{}}}persist(){this.storage.save(this.state)}applyOverride(e,t){return t?"flag"===t.type?t.value:"variant"===t.type?"object"==typeof e&&null!==e&&"name"in e?{...e,name:t.variantKey,enabled:!0}:{name:t.variantKey,enabled:!0}:t:e}reEvaluateAllFlags(e){Object.keys(this.state.flags).forEach(t=>{const a=this.state.flags[t];if(a)try{const{defaultValue:s,effectiveValue:r}=e(t);this.state.flags[t]={...a,lastDefaultValue:s,lastEffectiveValue:r}}catch(s){console.error(`[Unleash Toolbar] Failed to re-evaluate flag ${t}:`,s)}}),this.persist(),this.eventEmitter.emit({type:"sdk_updated",timestamp:Date.now()})}getState(){return JSON.parse(JSON.stringify(this.state))}subscribe(e){return this.eventEmitter.subscribe(e)}recordEvaluation(e,t,a,s,r){const i=this.state.flags[e],n=!i;this.state.flags[e]={flagType:t,lastDefaultValue:a,lastEffectiveValue:s,lastContext:r,override:i?.override||null},this.persist(),n&&this.eventEmitter.emit({type:"sdk_updated",timestamp:Date.now()})}setFlagOverride(e,t){this.state.flags[e]?(this.state.flags[e].override=t,this.state.flags[e].lastEffectiveValue=this.applyOverride(this.state.flags[e].lastDefaultValue,t)):this.state.flags[e]={flagType:"variant"===t?.type?"variant":"flag",lastDefaultValue:null,lastEffectiveValue:this.applyOverride(null,t),lastContext:null,override:t},this.persist(),this.eventEmitter.emit({type:"flag_override_changed",name:e,override:t,timestamp:Date.now()})}getFlagOverride(e){return this.state.flags[e]?.override||null}setContextOverride(e){this.state.contextOverrides={...this.state.contextOverrides,...e},this.persist(),this.eventEmitter.emit({type:"context_override_changed",contextOverrides:this.state.contextOverrides})}removeContextOverride(e){const t={...this.state.contextOverrides};delete t[e],this.state.contextOverrides=t,this.persist(),this.eventEmitter.emit({type:"context_override_changed",contextOverrides:this.state.contextOverrides})}getMergedContext(e={}){return{...e,...this.state.contextOverrides,properties:{...e.properties||{},...this.state.contextOverrides.properties||{}}}}resetOverrides(){Object.keys(this.state.flags).forEach(e=>{this.state.flags[e].override=null,this.state.flags[e].lastEffectiveValue=this.state.flags[e].lastDefaultValue,this.eventEmitter.emit({type:"flag_override_changed",name:e,override:null,timestamp:Date.now()})}),this.persist()}resetContextOverrides(){this.state.contextOverrides={},this.persist(),this.eventEmitter.emit({type:"context_override_changed",contextOverrides:{}})}setVisibility(e){this.state.isVisible=e,this.persist()}getVisibility(){return this.state.isVisible}setDragPosition(e){this.state.dragPosition=e,this.persist()}getDragPosition(){return this.state.dragPosition}clearPersistence(){this.storage.clear()}getFlagNames(){const e=Object.keys(this.state.flags);return this.sortAlphabetically?e.sort():e}getFlagMetadata(e){return this.state.flags[e]||null}enableCookieSync(){this.storage.setCookieSyncEnabled(!0)}};function s(e,t){if("__original"in e)return e;const a=e.getContext(),s=/* @__PURE__ */new Set;let i;const n={__original:e,isEnabled:function(a){const s=e.getContext(),i=t.getMergedContext(s),n=e.isEnabled(a),o=r(n,t.getFlagOverride(a));return t.recordEvaluation(a,"flag",n,o,i),o},getVariant:function(a){const s=e.getContext(),i=t.getMergedContext(s),n=e.getVariant(a),o=r(n,t.getFlagOverride(a));return t.recordEvaluation(a,"variant",n,o,i),o},getContext:function(){const a=e.getContext();return{appName:"",...t.getMergedContext(a)}},on:function(t,a){return"update"===t&&s.add(a),e.on(t,a),i}};function o(){s.forEach(e=>{try{e()}catch(t){console.error("[Unleash Toolbar] Error in update listener:",t)}})}return e.on("update",()=>{t.reEvaluateAllFlags(a=>{const s="variant"===t.getFlagMetadata(a)?.flagType?e.getVariant(a):e.isEnabled(a);return{defaultValue:s,effectiveValue:r(s,t.getFlagOverride(a))}})}),t.subscribe(s=>{if("context_override_changed"===s.type){const{appName:s,environment:i,...n}=t.getMergedContext(a);e.updateContext(n).then(()=>{t.reEvaluateAllFlags(a=>{const s="variant"===t.getFlagMetadata(a)?.flagType?e.getVariant(a):e.isEnabled(a);return{defaultValue:s,effectiveValue:r(s,t.getFlagOverride(a))}}),o()}).catch(e=>{console.error("[Unleash Toolbar] Failed to update context:",e)})}"flag_override_changed"===s.type&&o()}),i=new Proxy(n,{get(t,a){if(a in t)return Reflect.get(t,a);const s=Reflect.get(e,a);return"function"==typeof s?s.bind(e):s},set:(t,a,s)=>a in t?(Reflect.set(t,a,s),!0):(Reflect.set(e,a,s),!0)}),i}function r(e,t){return t?"flag"===t.type?t.value:"variant"===t.type?"object"==typeof e&&null!==e&&"name"in e?{...e,name:t.variantKey,enabled:!0}:{name:t.variantKey,enabled:!0}:e:e}var i=class{stateManager;ui;client;constructor(e,t,a){this.stateManager=e,this.client=t,this.ui=null,this.initUI(e,t,a)}async initUI(e,t,a){const{ToolbarUI:s}=await import("./ui-DczWUmYE.js");this.ui=new s(e,t,a)}show(){this.ui&&this.ui.show()}hide(){this.ui&&this.ui.hide()}destroy(){this.ui&&this.ui.destroy(),this.stateManager.clearPersistence()}getState(){return this.stateManager.getState()}getFlagNames(){return this.stateManager.getFlagNames()}setFlagOverride(e,t){this.stateManager.setFlagOverride(e,t)}setContextOverride(e){this.stateManager.setContextOverride(e)}removeContextOverride(e){this.stateManager.removeContextOverride(e)}resetOverrides(){this.stateManager.resetOverrides()}resetContextOverrides(){this.stateManager.resetContextOverrides()}};function n(e,t={}){const r=t.enableCookieSync||!1,n=new a(t.storageMode||"local",t.storageKey||"unleash-toolbar-state",t.sortAlphabetically||!1);r&&n.enableCookieSync();const o=s(e,n),l=new i(n,o,t);return"undefined"!=typeof window&&(window.unleashToolbar=l),o}"undefined"!=typeof window&&(window.UnleashToolbar={init:n});export{a as i,n,s as r,i as t};
//# sourceMappingURL=src-BKCgoQZx.js.map
{"version":3,"file":"src-BKCgoQZx.js","names":[],"sources":["../src/state.ts","../src/wrapper.ts","../src/index.ts"],"sourcesContent":["import type {\n DragPosition,\n FlagMetadata,\n FlagOverride,\n FlagValue,\n StorageMode,\n ToolbarEvent,\n ToolbarEventListener,\n ToolbarState,\n UnleashContext,\n UnleashVariant,\n} from './types';\n\n/**\n * Helper to set a cookie with proper encoding\n */\nasync function setCookie(name: string, value: string, maxAgeSeconds: number): Promise<void> {\n if (typeof document === 'undefined') return;\n\n const encodedValue = encodeURIComponent(value);\n\n // Use Cookie Store API if available, fallback to document.cookie\n if ('cookieStore' in window) {\n try {\n await window.cookieStore.set({\n name,\n value: encodedValue,\n path: '/',\n sameSite: 'lax',\n expires: Date.now() + maxAgeSeconds * 1000,\n });\n return;\n } catch {\n // Fallback to document.cookie if Cookie Store API fails\n }\n }\n\n // Fallback for browsers without Cookie Store API\n const cookieParts = [\n `${name}=${encodedValue}`,\n 'path=/',\n `max-age=${maxAgeSeconds}`,\n 'SameSite=Lax',\n ];\n\n // biome-ignore lint/suspicious/noDocumentCookie: Fallback for browsers without Cookie Store API\n document.cookie = cookieParts.join('; ');\n}\n\n/**\n * Helper to delete a cookie\n */\nasync function deleteCookie(name: string): Promise<void> {\n if (typeof document === 'undefined') return;\n\n // Use Cookie Store API if available, fallback to document.cookie\n if ('cookieStore' in window) {\n try {\n await window.cookieStore.delete(name);\n return;\n } catch {\n // Fallback to document.cookie if Cookie Store API fails\n }\n }\n\n // Fallback for browsers without Cookie Store API\n // biome-ignore lint/suspicious/noDocumentCookie: Fallback for browsers without Cookie Store API\n document.cookie = `${name}=; path=/; max-age=0`;\n}\n\n/**\n * Event emitter for toolbar state changes\n */\nclass EventEmitter {\n private listeners: Set<ToolbarEventListener> = new Set();\n\n subscribe(listener: ToolbarEventListener): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n emit(event: ToolbarEvent): void {\n this.listeners.forEach((listener) => {\n try {\n listener(event);\n } catch (error) {\n console.error('[Unleash Toolbar] Error in event listener:', error);\n }\n });\n }\n}\n\n/**\n * Storage abstraction for different persistence modes\n */\nclass StorageAdapter {\n private enableCookieSync: boolean = false;\n\n constructor(\n private mode: StorageMode,\n private key: string,\n ) {}\n\n /**\n * Enable or disable cookie synchronization for SSR support\n * Should be enabled by Next.js integration\n */\n setCookieSyncEnabled(enabled: boolean): void {\n this.enableCookieSync = enabled;\n }\n\n private getStorage(): Storage | null {\n if (typeof window === 'undefined') return null;\n\n switch (this.mode) {\n case 'local':\n return window.localStorage;\n case 'session':\n return window.sessionStorage;\n default:\n return null;\n }\n }\n\n /**\n * Syncs state to cookies for server-side access (Next.js SSR)\n * Only runs when explicitly enabled via setCookieSyncEnabled()\n */\n private syncToCookies(state: ToolbarState): void {\n if (!this.enableCookieSync) return;\n if (typeof document === 'undefined') return;\n\n try {\n const value = JSON.stringify(state);\n // Set cookie with 7 day expiration, accessible from same origin\n setCookie('unleash-toolbar-state', value, 7 * 24 * 60 * 60);\n } catch (error) {\n console.error('[Unleash Toolbar] Failed to sync state to cookies:', error);\n }\n }\n\n load(): ToolbarState | null {\n const storage = this.getStorage();\n if (!storage) return null;\n\n try {\n const data = storage.getItem(this.key);\n return data ? JSON.parse(data) : null;\n } catch (error) {\n console.error('[Unleash Toolbar] Failed to load state from storage:', error);\n return null;\n }\n }\n\n save(state: ToolbarState): void {\n const storage = this.getStorage();\n if (!storage) return;\n\n try {\n storage.setItem(this.key, JSON.stringify(state));\n this.syncToCookies(state);\n } catch (error) {\n console.error('[Unleash Toolbar] Failed to save state to storage:', error);\n }\n }\n\n clear(): void {\n const storage = this.getStorage();\n if (!storage) return;\n\n try {\n storage.removeItem(this.key);\n // Also clear the cookie if sync was enabled\n if (this.enableCookieSync) {\n deleteCookie('unleash-toolbar-state');\n }\n } catch (error) {\n console.error('[Unleash Toolbar] Failed to clear storage:', error);\n }\n }\n}\n\n/**\n * Core state manager for the toolbar\n */\nexport class ToolbarStateManager {\n private state: ToolbarState;\n private eventEmitter: EventEmitter;\n private storage: StorageAdapter;\n private sortAlphabetically: boolean;\n\n constructor(\n storageMode: StorageMode = 'local',\n storageKey: string = 'unleash-toolbar-state',\n sortAlphabetically: boolean = false,\n ) {\n this.eventEmitter = new EventEmitter();\n this.storage = new StorageAdapter(storageMode, storageKey);\n this.sortAlphabetically = sortAlphabetically;\n\n // Try to load persisted state\n const persistedState = this.storage.load();\n this.state = persistedState || this.getInitialState();\n }\n\n private getInitialState(): ToolbarState {\n return {\n flags: {},\n contextOverrides: {},\n };\n }\n\n private persist(): void {\n this.storage.save(this.state);\n }\n\n /**\n * Apply override to a default value (same logic as wrapper)\n */\n private applyOverride(\n defaultValue: boolean | UnleashVariant | null,\n override: FlagOverride | null,\n ): boolean | UnleashVariant | null {\n if (!override) return defaultValue;\n\n if (override.type === 'flag') {\n return override.value;\n }\n\n if (override.type === 'variant') {\n // For variant overrides, create a variant object\n if (typeof defaultValue === 'object' && defaultValue !== null && 'name' in defaultValue) {\n return {\n ...defaultValue,\n name: override.variantKey,\n enabled: true,\n };\n }\n // If default was not a variant, create a new one\n return {\n name: override.variantKey,\n enabled: true,\n };\n }\n\n // Exhaustiveness check (for future-proofing)\n const _exhaustive: never = override;\n return _exhaustive;\n }\n\n /**\n * Re-evaluate all known flags (used when SDK configuration updates)\n */\n reEvaluateAllFlags(\n evaluator: (flagName: string) => { defaultValue: FlagValue; effectiveValue: FlagValue },\n ): void {\n const flagNames = Object.keys(this.state.flags);\n\n flagNames.forEach((flagName) => {\n const existing = this.state.flags[flagName];\n if (!existing) return;\n\n try {\n const { defaultValue, effectiveValue } = evaluator(flagName);\n\n // Update flag metadata with new default value\n this.state.flags[flagName] = {\n ...existing,\n lastDefaultValue: defaultValue,\n lastEffectiveValue: effectiveValue,\n };\n } catch (error) {\n // If evaluation fails, keep existing data\n console.error(`[Unleash Toolbar] Failed to re-evaluate flag ${flagName}:`, error);\n }\n });\n\n this.persist();\n\n this.eventEmitter.emit({\n type: 'sdk_updated',\n timestamp: Date.now(),\n });\n }\n\n /**\n * Get the current state (immutable copy)\n */\n getState(): ToolbarState {\n return JSON.parse(JSON.stringify(this.state));\n }\n\n /**\n * Subscribe to state change events\n */\n subscribe(listener: ToolbarEventListener): () => void {\n return this.eventEmitter.subscribe(listener);\n }\n\n /**\n * Record a flag evaluation (updates state without emitting events)\n */\n recordEvaluation(\n name: string,\n flagType: 'flag' | 'variant',\n defaultValue: boolean | UnleashVariant | null,\n effectiveValue: boolean | UnleashVariant | null,\n context: UnleashContext,\n ): void {\n const existing = this.state.flags[name];\n const isNewFlag = !existing;\n\n this.state.flags[name] = {\n flagType,\n lastDefaultValue: defaultValue,\n lastEffectiveValue: effectiveValue,\n lastContext: context,\n override: existing?.override || null,\n };\n\n this.persist();\n\n // Emit event only for new flags to trigger UI update\n if (isNewFlag) {\n this.eventEmitter.emit({\n type: 'sdk_updated',\n timestamp: Date.now(),\n });\n }\n }\n\n /**\n * Set or clear a flag override\n */\n setFlagOverride(name: string, override: FlagOverride | null): void {\n if (!this.state.flags[name]) {\n // Infer flag type from override type (shouldn't happen in normal flow)\n const flagType = override?.type === 'variant' ? 'variant' : 'flag';\n this.state.flags[name] = {\n flagType,\n lastDefaultValue: null,\n lastEffectiveValue: this.applyOverride(null, override),\n lastContext: null,\n override,\n };\n } else {\n this.state.flags[name].override = override;\n\n // Recalculate effective value based on new override\n const defaultValue = this.state.flags[name].lastDefaultValue;\n this.state.flags[name].lastEffectiveValue = this.applyOverride(defaultValue, override);\n }\n\n this.persist();\n\n this.eventEmitter.emit({\n type: 'flag_override_changed',\n name,\n override,\n timestamp: Date.now(),\n });\n }\n\n /**\n * Get flag override\n */\n getFlagOverride(name: string): FlagOverride | null {\n return this.state.flags[name]?.override || null;\n }\n\n /**\n * Set context overrides\n */\n setContextOverride(context: Partial<UnleashContext>): void {\n this.state.contextOverrides = {\n ...this.state.contextOverrides,\n ...context,\n };\n\n this.persist();\n\n this.eventEmitter.emit({\n type: 'context_override_changed',\n contextOverrides: this.state.contextOverrides,\n });\n }\n\n /**\n * Remove a specific context override field\n */\n removeContextOverride(fieldName: keyof UnleashContext): void {\n const newOverrides = { ...this.state.contextOverrides };\n delete newOverrides[fieldName];\n\n // Replace entire context overrides object\n this.state.contextOverrides = newOverrides;\n this.persist();\n\n this.eventEmitter.emit({\n type: 'context_override_changed',\n contextOverrides: this.state.contextOverrides,\n });\n }\n\n /**\n * Get merged context (original + overrides)\n */\n getMergedContext(baseContext: UnleashContext = {}): UnleashContext {\n return {\n ...baseContext,\n ...this.state.contextOverrides,\n properties: {\n ...(baseContext.properties || {}),\n ...(this.state.contextOverrides.properties || {}),\n },\n };\n }\n\n /**\n * Reset all flag overrides\n */\n resetOverrides(): void {\n Object.keys(this.state.flags).forEach((name) => {\n this.state.flags[name].override = null;\n\n // Recalculate effective value (will match default)\n const defaultValue = this.state.flags[name].lastDefaultValue;\n this.state.flags[name].lastEffectiveValue = defaultValue;\n\n // Emit event for each flag override removal\n this.eventEmitter.emit({\n type: 'flag_override_changed',\n name,\n override: null,\n timestamp: Date.now(),\n });\n });\n\n this.persist();\n }\n\n /**\n * Reset context overrides\n */\n resetContextOverrides(): void {\n this.state.contextOverrides = {};\n\n this.persist();\n\n this.eventEmitter.emit({\n type: 'context_override_changed',\n contextOverrides: {},\n });\n }\n\n /**\n * Set toolbar visibility state\n */\n setVisibility(isVisible: boolean): void {\n this.state.isVisible = isVisible;\n this.persist();\n }\n\n /**\n * Get toolbar visibility state\n */\n getVisibility(): boolean | undefined {\n return this.state.isVisible;\n }\n\n /**\n * Persist the position chosen by dragging the toolbar\n */\n setDragPosition(position: DragPosition): void {\n this.state.dragPosition = position;\n this.persist();\n }\n\n /**\n * Get the persisted drag position (undefined if never dragged)\n */\n getDragPosition(): DragPosition | undefined {\n return this.state.dragPosition;\n }\n\n /**\n * Clear all persisted data\n */\n clearPersistence(): void {\n this.storage.clear();\n }\n\n /**\n * Get all flag names in evaluation order (insertion order) or alphabetically\n */\n getFlagNames(): string[] {\n const names = Object.keys(this.state.flags);\n return this.sortAlphabetically ? names.sort() : names;\n }\n\n /**\n * Get metadata for a specific flag\n */\n getFlagMetadata(name: string): FlagMetadata | null {\n return this.state.flags[name] || null;\n }\n\n /**\n * Enable cookie synchronization for server-side rendering support\n * Should be called by Next.js integration when SSR is needed\n */\n enableCookieSync(): void {\n this.storage.setCookieSyncEnabled(true);\n }\n}\n","import type { UnleashClient } from 'unleash-proxy-client';\nimport type { ToolbarStateManager } from './state';\nimport type { FlagOverride, UnleashVariant, WrappedUnleashClient } from './types';\n\n/**\n * Wrap an Unleash client to intercept evaluations and apply overrides\n */\nexport function wrapUnleashClient(\n baseClient: UnleashClient,\n stateManager: ToolbarStateManager,\n): WrappedUnleashClient {\n // If already wrapped, return as-is\n if (isWrappedClient(baseClient)) {\n return baseClient as WrappedUnleashClient;\n }\n\n // Capture original base context before any updates\n const originalBaseContext = baseClient.getContext();\n\n // Track user-registered 'update' listeners so we can trigger them on toolbar changes\n const updateListeners = new Set<() => void>();\n\n // Reference to the final proxy (will be assigned below)\n let proxyClient: WrappedUnleashClient;\n\n // Create a partial object with only the methods we're intercepting.\n // The Proxy will handle all other methods by forwarding to baseClient.\n const wrappedClient: Partial<WrappedUnleashClient> = {\n __original: baseClient,\n isEnabled,\n getVariant,\n getContext,\n on: onHandler,\n };\n\n function isEnabled(toggleName: string): boolean {\n // Get merged context (toolbar overrides are applied via updateContext)\n const currentContext = baseClient.getContext();\n const mergedContext = stateManager.getMergedContext(currentContext);\n\n // Get default evaluation from base client (uses client's global context)\n const defaultValue = baseClient.isEnabled(toggleName);\n\n // Apply override if exists\n const override = stateManager.getFlagOverride(toggleName);\n const effectiveValue = applyFlagOverride(defaultValue, override);\n\n // Record evaluation with explicit flag type\n stateManager.recordEvaluation(toggleName, 'flag', defaultValue, effectiveValue, mergedContext);\n\n return effectiveValue as boolean;\n }\n\n function getVariant(toggleName: string): UnleashVariant {\n // Get merged context (toolbar overrides are applied via updateContext)\n const currentContext = baseClient.getContext();\n const mergedContext = stateManager.getMergedContext(currentContext);\n\n // Get default evaluation from base client (uses client's global context)\n const defaultValue = baseClient.getVariant(toggleName);\n\n // Apply override if exists\n const override = stateManager.getFlagOverride(toggleName);\n const effectiveValue = applyFlagOverride(defaultValue, override);\n\n // Record evaluation with explicit flag type\n stateManager.recordEvaluation(\n toggleName,\n 'variant',\n defaultValue,\n effectiveValue,\n mergedContext,\n );\n\n return effectiveValue as UnleashVariant;\n }\n\n function getContext() {\n const baseContext = baseClient.getContext();\n const merged = stateManager.getMergedContext(baseContext);\n // Ensure appName exists (required by SDK type)\n return {\n appName: '',\n ...merged,\n };\n }\n\n // Intercept on() method to capture 'update' listeners\n function onHandler(event: string, callback: () => void): WrappedUnleashClient {\n if (event === 'update') {\n updateListeners.add(callback);\n }\n // Forward to base client\n baseClient.on(event, callback);\n // Return the proxy for method chaining\n return proxyClient;\n }\n\n // Helper to trigger all registered 'update' listeners\n function triggerUpdateListeners() {\n updateListeners.forEach((callback) => {\n try {\n callback();\n } catch (error) {\n console.error('[Unleash Toolbar] Error in update listener:', error);\n }\n });\n }\n\n // Listen to SDK 'update' event to re-evaluate flags when config changes\n baseClient.on('update', () => {\n // Re-evaluate all known flags with the new SDK configuration\n stateManager.reEvaluateAllFlags((flagName) => {\n // Get flag metadata to determine type\n const metadata = stateManager.getFlagMetadata(flagName);\n const isVariant = metadata?.flagType === 'variant';\n\n // Get new default value from SDK using correct method\n const defaultValue = isVariant\n ? baseClient.getVariant(flagName)\n : baseClient.isEnabled(flagName);\n\n // Apply override if exists\n const override = stateManager.getFlagOverride(flagName);\n const effectiveValue = applyFlagOverride(defaultValue, override);\n\n return { defaultValue, effectiveValue };\n });\n // Trigger user's 'update' listeners (already called by SDK, but for consistency)\n });\n\n // Listen to toolbar state changes to update client context and trigger re-renders\n stateManager.subscribe((event) => {\n if (event.type === 'context_override_changed') {\n // Update the base client's context with merged context\n // Use original base context (not current client context which includes previous overrides)\n const mergedContext = stateManager.getMergedContext(originalBaseContext);\n\n // Remove appName and environment - they are static and can't be updated\n const { appName: _appName, environment: _environment, ...updatableContext } = mergedContext;\n\n // Update context on the client (this triggers SDK re-evaluation)\n baseClient\n .updateContext(updatableContext)\n .then(() => {\n // Re-evaluate all known flags after context update\n stateManager.reEvaluateAllFlags((flagName) => {\n // Get flag metadata to determine type\n const metadata = stateManager.getFlagMetadata(flagName);\n const isVariant = metadata?.flagType === 'variant';\n\n // Get new default value from SDK with updated context using correct method\n const defaultValue = isVariant\n ? baseClient.getVariant(flagName)\n : baseClient.isEnabled(flagName);\n\n // Apply override if exists\n const override = stateManager.getFlagOverride(flagName);\n const effectiveValue = applyFlagOverride(defaultValue, override);\n\n return { defaultValue, effectiveValue };\n });\n // Trigger user's 'update' listeners after context change\n triggerUpdateListeners();\n })\n .catch((err) => {\n console.error('[Unleash Toolbar] Failed to update context:', err);\n });\n }\n\n // Trigger user's 'update' listeners for flag override changes\n // (flag_override_changed is emitted when override is set or removed, including bulk resets)\n if (event.type === 'flag_override_changed') {\n triggerUpdateListeners();\n }\n });\n\n // Proxy all other methods and properties to the base client\n proxyClient = new Proxy(wrappedClient, {\n get(target, prop) {\n if (prop in target) {\n return Reflect.get(target, prop);\n }\n const value = Reflect.get(baseClient, prop);\n return typeof value === 'function' ? value.bind(baseClient) : value;\n },\n set(target, prop, value) {\n if (prop in target) {\n Reflect.set(target, prop, value);\n return true;\n }\n Reflect.set(baseClient, prop, value);\n return true;\n },\n }) as WrappedUnleashClient;\n\n return proxyClient;\n}\n\n/**\n * Apply flag override to evaluation result\n */\nfunction applyFlagOverride(\n defaultValue: boolean | UnleashVariant | null,\n override: FlagOverride | null,\n): boolean | UnleashVariant | null {\n if (!override) return defaultValue;\n\n if (override.type === 'flag') {\n return override.value;\n }\n\n if (override.type === 'variant') {\n // For variant overrides, create a variant object\n if (typeof defaultValue === 'object' && defaultValue !== null && 'name' in defaultValue) {\n return {\n ...defaultValue,\n name: override.variantKey,\n enabled: true,\n };\n }\n // If default was not a variant, create a new one\n return {\n name: override.variantKey,\n enabled: true,\n };\n }\n\n return defaultValue;\n}\n\n/**\n * Unwrap a client to get the original\n */\nexport function unwrapUnleashClient(client: UnleashClient): UnleashClient {\n if (isWrappedClient(client)) {\n return (client as WrappedUnleashClient).__original;\n }\n return client;\n}\n\n/**\n * Check if a client is wrapped\n */\nexport function isWrappedClient(client: UnleashClient): client is WrappedUnleashClient {\n return '__original' in client;\n}\n","import type { UnleashClient } from 'unleash-proxy-client';\nimport { ToolbarStateManager } from './state';\nimport type {\n FlagOverride,\n InitToolbarOptions,\n IToolbarUI,\n ToolbarState,\n UnleashContext,\n UnleashToolbarInstance,\n WrappedUnleashClient,\n} from './types';\nimport { wrapUnleashClient } from './wrapper';\n\n/**\n * Main toolbar instance implementation\n */\nexport class UnleashToolbar implements UnleashToolbarInstance {\n private stateManager: ToolbarStateManager;\n private ui: IToolbarUI | null;\n public readonly client: WrappedUnleashClient;\n\n constructor(\n stateManager: ToolbarStateManager,\n wrappedClient: WrappedUnleashClient,\n options: InitToolbarOptions,\n ) {\n this.stateManager = stateManager;\n this.client = wrappedClient;\n this.ui = null;\n\n // Initialize UI asynchronously to avoid SSR issues\n this.initUI(stateManager, wrappedClient, options);\n }\n\n private async initUI(\n stateManager: ToolbarStateManager,\n wrappedClient: WrappedUnleashClient,\n options: InitToolbarOptions,\n ) {\n const { ToolbarUI } = await import('./ui');\n this.ui = new ToolbarUI(stateManager, wrappedClient, options);\n }\n\n show(): void {\n if (this.ui) this.ui.show();\n }\n\n hide(): void {\n if (this.ui) this.ui.hide();\n }\n\n destroy(): void {\n if (this.ui) this.ui.destroy();\n this.stateManager.clearPersistence();\n }\n\n getState(): ToolbarState {\n return this.stateManager.getState();\n }\n\n getFlagNames(): string[] {\n return this.stateManager.getFlagNames();\n }\n\n setFlagOverride(name: string, override: FlagOverride | null): void {\n this.stateManager.setFlagOverride(name, override);\n }\n\n setContextOverride(context: Partial<UnleashContext>): void {\n this.stateManager.setContextOverride(context);\n }\n\n removeContextOverride(fieldName: keyof UnleashContext): void {\n this.stateManager.removeContextOverride(fieldName);\n }\n\n resetOverrides(): void {\n this.stateManager.resetOverrides();\n }\n\n resetContextOverrides(): void {\n this.stateManager.resetContextOverrides();\n }\n}\n\n/**\n * Initialize the Unleash Toolbar with a client\n * This is the main entry point - handles both toolbar creation and client wrapping\n * Returns the wrapped client directly for immediate use\n *\n * @param client - The Unleash client to wrap\n * @param options - Toolbar configuration options\n */\nexport function initUnleashToolbar(\n client: UnleashClient,\n options: InitToolbarOptions = {},\n): WrappedUnleashClient {\n const storageMode = options.storageMode || 'local';\n const storageKey = options.storageKey || 'unleash-toolbar-state';\n const sortAlphabetically = options.sortAlphabetically || false;\n const enableCookieSync = options.enableCookieSync || false;\n\n const stateManager = new ToolbarStateManager(storageMode, storageKey, sortAlphabetically);\n\n // Enable cookie sync if requested (for Next.js SSR)\n if (enableCookieSync) {\n stateManager.enableCookieSync();\n }\n\n const wrappedClient = wrapUnleashClient(client, stateManager);\n const toolbar = new UnleashToolbar(stateManager, wrappedClient, options);\n\n // Expose toolbar instance globally for debugging/advanced use\n if (typeof window !== 'undefined') {\n // biome-ignore lint/suspicious/noExplicitAny: no type for window\n (window as any).unleashToolbar = toolbar;\n }\n\n return wrappedClient;\n}\n\n// UMD global export\nif (typeof window !== 'undefined') {\n // biome-ignore lint/suspicious/noExplicitAny: no type for window\n (window as any).UnleashToolbar = {\n init: initUnleashToolbar,\n };\n}\n\nexport { ToolbarStateManager } from './state';\n// Export types\nexport * from './types';\nexport { wrapUnleashClient } from './wrapper';\n"],"mappings":"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"}
import { DragPosition, FlagMetadata, FlagOverride, FlagValue, StorageMode, ToolbarEventListener, ToolbarState, UnleashContext, UnleashVariant } from './types';
/**
* Core state manager for the toolbar
*/
export declare class ToolbarStateManager {
private state;
private eventEmitter;
private storage;
private sortAlphabetically;
constructor(storageMode?: StorageMode, storageKey?: string, sortAlphabetically?: boolean);
private getInitialState;
private persist;
/**
* Apply override to a default value (same logic as wrapper)
*/
private applyOverride;
/**
* Re-evaluate all known flags (used when SDK configuration updates)
*/
reEvaluateAllFlags(evaluator: (flagName: string) => {
defaultValue: FlagValue;
effectiveValue: FlagValue;
}): void;
/**
* Get the current state (immutable copy)
*/
getState(): ToolbarState;
/**
* Subscribe to state change events
*/
subscribe(listener: ToolbarEventListener): () => void;
/**
* Record a flag evaluation (updates state without emitting events)
*/
recordEvaluation(name: string, flagType: 'flag' | 'variant', defaultValue: boolean | UnleashVariant | null, effectiveValue: boolean | UnleashVariant | null, context: UnleashContext): void;
/**
* Set or clear a flag override
*/
setFlagOverride(name: string, override: FlagOverride | null): void;
/**
* Get flag override
*/
getFlagOverride(name: string): FlagOverride | null;
/**
* Set context overrides
*/
setContextOverride(context: Partial<UnleashContext>): void;
/**
* Remove a specific context override field
*/
removeContextOverride(fieldName: keyof UnleashContext): void;
/**
* Get merged context (original + overrides)
*/
getMergedContext(baseContext?: UnleashContext): UnleashContext;
/**
* Reset all flag overrides
*/
resetOverrides(): void;
/**
* Reset context overrides
*/
resetContextOverrides(): void;
/**
* Set toolbar visibility state
*/
setVisibility(isVisible: boolean): void;
/**
* Get toolbar visibility state
*/
getVisibility(): boolean | undefined;
/**
* Persist the position chosen by dragging the toolbar
*/
setDragPosition(position: DragPosition): void;
/**
* Get the persisted drag position (undefined if never dragged)
*/
getDragPosition(): DragPosition | undefined;
/**
* Clear all persisted data
*/
clearPersistence(): void;
/**
* Get all flag names in evaluation order (insertion order) or alphabetically
*/
getFlagNames(): string[];
/**
* Get metadata for a specific flag
*/
getFlagMetadata(name: string): FlagMetadata | null;
/**
* Enable cookie synchronization for server-side rendering support
* Should be called by Next.js integration when SSR is needed
*/
enableCookieSync(): void;
}
//# sourceMappingURL=state.d.ts.map
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,SAAS,EACT,WAAW,EAEX,oBAAoB,EACpB,YAAY,EACZ,cAAc,EACd,cAAc,EACf,MAAM,SAAS,CAAC;AA2KjB;;GAEG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,KAAK,CAAe;IAC5B,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,kBAAkB,CAAU;gBAGlC,WAAW,GAAE,WAAqB,EAClC,UAAU,GAAE,MAAgC,EAC5C,kBAAkB,GAAE,OAAe;IAWrC,OAAO,CAAC,eAAe;IAOvB,OAAO,CAAC,OAAO;IAIf;;OAEG;IACH,OAAO,CAAC,aAAa;IA+BrB;;OAEG;IACH,kBAAkB,CAChB,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK;QAAE,YAAY,EAAE,SAAS,CAAC;QAAC,cAAc,EAAE,SAAS,CAAA;KAAE,GACtF,IAAI;IA8BP;;OAEG;IACH,QAAQ,IAAI,YAAY;IAIxB;;OAEG;IACH,SAAS,CAAC,QAAQ,EAAE,oBAAoB,GAAG,MAAM,IAAI;IAIrD;;OAEG;IACH,gBAAgB,CACd,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,YAAY,EAAE,OAAO,GAAG,cAAc,GAAG,IAAI,EAC7C,cAAc,EAAE,OAAO,GAAG,cAAc,GAAG,IAAI,EAC/C,OAAO,EAAE,cAAc,GACtB,IAAI;IAuBP;;OAEG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,GAAG,IAAI,GAAG,IAAI;IA6BlE;;OAEG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI;IAIlD;;OAEG;IACH,kBAAkB,CAAC,OAAO,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,IAAI;IAc1D;;OAEG;IACH,qBAAqB,CAAC,SAAS,EAAE,MAAM,cAAc,GAAG,IAAI;IAc5D;;OAEG;IACH,gBAAgB,CAAC,WAAW,GAAE,cAAmB,GAAG,cAAc;IAWlE;;OAEG;IACH,cAAc,IAAI,IAAI;IAoBtB;;OAEG;IACH,qBAAqB,IAAI,IAAI;IAW7B;;OAEG;IACH,aAAa,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI;IAKvC;;OAEG;IACH,aAAa,IAAI,OAAO,GAAG,SAAS;IAIpC;;OAEG;IACH,eAAe,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI;IAK7C;;OAEG;IACH,eAAe,IAAI,YAAY,GAAG,SAAS;IAI3C;;OAEG;IACH,gBAAgB,IAAI,IAAI;IAIxB;;OAEG;IACH,YAAY,IAAI,MAAM,EAAE;IAKxB;;OAEG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI;IAIlD;;;OAGG;IACH,gBAAgB,IAAI,IAAI;CAGzB"}
.unleash-toolbar-container{--ut-primary:#6c65e5;--ut-bg:#fff;--ut-text:#1f2021;--ut-border:#e1e1e3;--ut-hover:#f5f6fa;--ut-success:#00b894;--ut-danger:#d63031;--ut-warning:#fdcb6e;--ut-shadow:rgba(0,0,0,.1);--ut-font:-apple-system,BlinkMacSystemFont,"Segoe UI","Roboto","Oxygen","Ubuntu",sans-serif;all:initial;position:fixed;z-index:999998}.unleash-toolbar-container.ut-theme-dark{--ut-primary:#4c4992;--ut-bg:#1a1923;--ut-text:#eeeefc;--ut-border:#39384c;--ut-hover:#3d4446;--ut-success:#00b894;--ut-danger:#ff7675;--ut-warning:#fdcb6e;--ut-shadow:rgba(0,0,0,.3)}.unleash-toolbar button,.unleash-toolbar input,.unleash-toolbar-container{box-sizing:border-box;font-family:inherit;letter-spacing:normal;line-height:inherit;margin:0;text-transform:none;word-spacing:normal}.unleash-toolbar input{background:var(--ut-bg);color:var(--ut-text);margin:0}.unleash-toolbar img{border:none;max-width:none;vertical-align:middle}.unleash-toolbar img,.unleash-toolbar svg{display:inline-block;height:auto;max-width:none}.unleash-toolbar-container.position-top-left{left:20px;top:20px}.unleash-toolbar-container.position-top-right{right:20px;top:20px}.unleash-toolbar-container.position-bottom-left{bottom:20px;left:20px}.unleash-toolbar-container.position-bottom-right{bottom:20px;right:20px}.unleash-toolbar-container.position-left{left:20px;top:50%;transform:translateY(-50%)}.unleash-toolbar-container.position-right{right:20px;top:50%;transform:translateY(-50%)}.unleash-toolbar-container .ut-toggle{all:initial;align-items:center;background:var(--ut-primary);border:none;border-radius:50%;box-shadow:0 4px 12px var(--ut-shadow);cursor:pointer;display:flex;height:48px;justify-content:center;padding:0;position:relative;transition:all .3s ease;width:48px}.unleash-toolbar-container .ut-toggle:hover{box-shadow:0 6px 16px rgba(0,0,0,.2);transform:scale(1.1)}.unleash-toolbar-container .ut-toggle img{height:28px;object-fit:contain;pointer-events:none;user-select:none;width:28px;-webkit-user-drag:none}.unleash-toolbar-container .unleash-toolbar{all:initial;background:var(--ut-bg);border:1px solid var(--ut-border);border-radius:8px;box-shadow:0 4px 12px var(--ut-shadow);box-sizing:border-box;color:var(--ut-text);display:flex;flex-direction:column;font-family:var(--ut-font);font-size:14px;height:700px;line-height:1.5;max-height:85vh;min-height:400px;overflow:hidden;position:relative;width:400px}.unleash-toolbar-container .unleash-toolbar *{box-sizing:border-box}.unleash-toolbar .ut-header{align-items:center;background:var(--ut-primary);border-bottom:1px solid var(--ut-border);color:#fff;display:flex;flex-shrink:0;gap:12px;justify-content:space-between;padding:12px 20px 12px 12px;position:relative}.unleash-toolbar .ut-title{align-items:center;display:flex;flex:1;gap:10px;min-width:0}.unleash-toolbar .ut-title img{flex-shrink:0;height:28px;object-fit:contain;width:28px}.unleash-toolbar .ut-title-main{font-size:14px;font-weight:600;line-height:1.3}.unleash-toolbar .ut-title-sub{font-size:11px;margin-top:1px;opacity:.9}.unleash-toolbar .ut-actions{align-items:center;display:flex;gap:4px}.unleash-toolbar .ut-btn-icon{align-items:center;background:hsla(0,0%,100%,.1);border:1px solid hsla(0,0%,100%,.15);border-radius:4px;color:#fff;cursor:pointer;display:flex;flex-shrink:0;font-size:16px;height:24px;justify-content:center;line-height:1;padding:0;transition:all .2s;width:24px}.unleash-toolbar .ut-btn-icon:hover{background:hsla(0,0%,100%,.2);border-color:hsla(0,0%,100%,.25)}.unleash-toolbar .ut-btn-small{background:hsla(0,0%,100%,.15);border:1px solid hsla(0,0%,100%,.2);color:#fff;white-space:nowrap}.unleash-toolbar .ut-btn-small:hover{background:hsla(0,0%,100%,.25);border-color:hsla(0,0%,100%,.3)}.unleash-toolbar .ut-btn{background:hsla(0,0%,100%,.2);border:none;border-radius:4px;color:#fff;cursor:pointer;font-family:inherit;font-size:12px;padding:6px 12px;transition:background .2s}.unleash-toolbar .ut-btn:hover{background:hsla(0,0%,100%,.3)}.unleash-toolbar .ut-btn-close{align-items:center;background-color:var(--ut-primary);border:none;color:#fff;cursor:pointer;display:flex;flex-shrink:0;font-size:18px;height:24px;justify-content:center;line-height:1;padding:0;transition:all .2s;width:24px}.unleash-toolbar .ut-btn-close:hover{background:rgba(0,0,0,.3);border-color:hsla(0,0%,100%,.2)}.unleash-toolbar .ut-header-actions{align-items:center;display:flex;flex-shrink:0;gap:4px}.unleash-toolbar .ut-minimize-glyph{background:currentColor;border-radius:1px;display:block;height:2px;width:10px}.unleash-toolbar-container .ut-toggle.ut-draggable{cursor:grab;touch-action:none}.unleash-toolbar-container .ut-toggle.ut-draggable:active{cursor:grabbing}.unleash-toolbar-container.ut-dragging{transition:none;user-select:none}.unleash-toolbar-container.ut-dragging .ut-toggle{transform:none;transition:none}.unleash-toolbar-container.ut-snapping{transition:left .22s ease,top .22s ease}.unleash-toolbar .ut-banner{background:var(--ut-hover);border-bottom:1px solid var(--ut-border);border-left:3px solid var(--ut-primary);color:var(--ut-text);flex-shrink:0;font-size:12px;line-height:1.45;padding:10px 12px}.unleash-toolbar .ut-banner-text{white-space:pre-wrap;word-break:break-word}.unleash-toolbar .ut-banner-link{color:var(--ut-primary);font-weight:500;text-decoration:underline;white-space:nowrap}.unleash-toolbar .ut-banner-link:hover{text-decoration:none}.unleash-toolbar .ut-tabs{background:var(--ut-bg);display:flex;flex-shrink:0}.unleash-toolbar .ut-tab{background:none;border:none;border-bottom:2px solid transparent;color:var(--ut-text);cursor:pointer;flex:1;font-family:inherit;font-size:13px;padding:12px;transition:all .2s}.unleash-toolbar .ut-tab:hover{background:var(--ut-hover)}.unleash-toolbar .ut-tab.active{border-bottom-color:var(--ut-primary);font-weight:600}.unleash-toolbar .ut-content{display:flex;flex:1;flex-direction:column;overflow-y:auto}.unleash-toolbar .ut-tab-header{align-items:center;background:var(--ut-bg);display:flex;flex-shrink:0;gap:12px;padding:12px 16px}.unleash-toolbar .ut-search-container{flex:1;min-width:0}.unleash-toolbar .ut-search-input{border:1px solid var(--ut-border);border-radius:6px;font-family:inherit;font-size:13px;padding:8px 12px;transition:border-color .2s;width:100%}.unleash-toolbar .ut-search-input:focus{border-color:var(--ut-primary);outline:none}.unleash-toolbar .ut-search-input::placeholder{color:var(--ut-text);opacity:.5}.unleash-toolbar .ut-tab-header .ut-btn{background:var(--ut-primary);border:none;border-radius:6px;color:#fff;cursor:pointer;flex-shrink:0;font-family:inherit;font-size:13px;font-weight:500;padding:8px 16px;transition:all .2s;white-space:nowrap}.unleash-toolbar .ut-tab-header .ut-btn:hover{box-shadow:0 2px 4px rgba(0,0,0,.1);opacity:.9;transform:translateY(-1px)}.unleash-toolbar .ut-flag-list{display:flex;flex:1;flex-direction:column;gap:8px;overflow-y:auto;padding:16px}.unleash-toolbar .ut-flag-item{align-items:center;background:var(--ut-bg);border:1px solid var(--ut-border);border-radius:6px;display:flex;gap:12px;min-height:48px;padding:10px 12px}.unleash-toolbar .ut-flag-main{flex:1;min-width:0}.unleash-toolbar .ut-flag-header{align-items:flex-start;display:flex;flex-direction:column;gap:6px}.unleash-toolbar .ut-flag-title-row{align-items:center;display:flex;flex-wrap:wrap;gap:6px}.unleash-toolbar .ut-flag-name{flex-shrink:0;font-size:13px;font-weight:600;word-break:break-word}.unleash-toolbar .ut-flag-meta{align-items:center;display:flex;flex-wrap:wrap;font-size:11px;gap:8px}.unleash-toolbar .ut-flag-default-value{align-items:center;color:#636e72;display:flex;font-size:11px;gap:4px}.unleash-toolbar .ut-override-indicator{align-items:center;color:var(--ut-primary);display:flex;font-weight:500;gap:4px}.unleash-toolbar .ut-eval-count{font-size:10px;opacity:.6}.unleash-toolbar .ut-flag-control{flex-shrink:0}.unleash-toolbar .ut-badge{border-radius:3px;font-size:10px;font-weight:600;padding:2px 6px}.unleash-toolbar .ut-badge-success{background:#d4edda;color:#155724}.unleash-toolbar .ut-badge-danger{background:#f8d7da;color:#721c24}.unleash-toolbar .ut-badge-default{background:#e2e3e5;color:#383d41}.unleash-toolbar .ut-toggle-group{background:var(--ut-hover);border:1px solid var(--ut-border);border-radius:5px;display:flex;gap:3px;padding:2px}.unleash-toolbar .ut-toggle-btn{background:transparent;border:none;border-radius:4px;color:var(--ut-text);cursor:pointer;font-family:inherit;font-size:11px;font-weight:500;min-width:36px;padding:4px 10px;transition:all .15s ease;white-space:nowrap}.unleash-toolbar .ut-toggle-btn:hover:not(.active){background:hsla(0,0%,100%,.5)}.unleash-toolbar .ut-toggle-btn.active{background:#fff;box-shadow:0 1px 3px rgba(0,0,0,.1);color:var(--ut-primary);font-weight:600}.unleash-toolbar .ut-variant-control{display:flex;flex-direction:column;gap:6px;min-width:120px}.unleash-toolbar .ut-variant-override-toggle{align-items:center;border-radius:4px;cursor:pointer;display:flex;font-size:12px;gap:6px;padding:6px 10px;transition:background .15s}.unleash-toolbar .ut-variant-override-toggle:hover{background:var(--ut-hover)}.unleash-toolbar .ut-variant-override-toggle input[type=checkbox]{cursor:pointer}.unleash-toolbar .ut-input-small{border:1px solid var(--ut-border);border-radius:4px;font-family:inherit;font-size:11px;padding:4px 8px;width:100%}.unleash-toolbar .ut-input-small:focus{border-color:var(--ut-primary);outline:none}.unleash-toolbar .ut-btn-small{font-weight:500;padding:4px 10px;transition:all .15s}.unleash-toolbar .ut-btn-small.active{background:var(--ut-primary);border-color:var(--ut-primary);color:#fff}.unleash-toolbar .ut-override-control{display:flex;gap:8px;margin-top:8px}.unleash-toolbar .ut-btn-small{background:var(--ut-hover);border:1px solid var(--ut-border);border-radius:4px;color:var(--ut-text);cursor:pointer;font-family:inherit;font-size:11px;padding:6px 10px;transition:all .2s}.unleash-toolbar .ut-btn-small:hover{background:var(--ut-border)}.unleash-toolbar .ut-context-form{display:flex;flex:1;flex-direction:column;gap:12px;overflow-y:auto;padding:16px}.unleash-toolbar .ut-form-group{display:flex;flex-direction:column;gap:4px;position:relative}.unleash-toolbar .ut-label{align-items:center;color:var(--ut-text);display:flex;font-size:12px;font-weight:600;gap:6px}.unleash-toolbar .ut-readonly-label{font-size:11px;opacity:.6}.unleash-toolbar .ut-input-with-reset{display:block;position:relative;width:100%}.unleash-toolbar .ut-input-with-reset .ut-input{padding-right:32px;width:100%}.unleash-toolbar .ut-reset-field{align-items:center;background:var(--ut-hover);border:1px solid var(--ut-border);border-radius:4px;bottom:4px;color:var(--ut-text);cursor:pointer;display:flex;font-size:14px;justify-content:center;line-height:1;margin:auto 0;padding:0;position:absolute;right:4px;top:4px;transition:all .15s;width:24px}.unleash-toolbar .ut-reset-field:hover{background:var(--ut-border);border-color:var(--ut-primary);color:var(--ut-primary)}.unleash-toolbar .ut-property-actions{display:flex;flex-shrink:0;gap:4px}.unleash-toolbar .ut-btn-remove{background:var(--ut-hover);border:1px solid var(--ut-border);border-radius:4px;color:#d63031;cursor:pointer;flex-shrink:0;font-size:16px;font-weight:700;height:32px;line-height:1;padding:0;transition:all .15s;width:24px}.unleash-toolbar .ut-btn-remove:hover{background:#fee;border-color:#d63031;color:#d63031}.unleash-toolbar .ut-input{border:1px solid var(--ut-border);border-radius:4px;font-family:inherit;font-size:13px;padding:8px 12px}.unleash-toolbar .ut-input:focus{border-color:var(--ut-primary);outline:none}.unleash-toolbar .ut-input-readonly{cursor:not-allowed;opacity:.7}.unleash-toolbar .ut-properties{display:flex;flex-direction:column;gap:8px}.unleash-toolbar .ut-property-row{align-items:center;display:flex;gap:8px;min-width:0}.unleash-toolbar .ut-property-key{background:var(--ut-bg-secondary);border-radius:4px;color:var(--ut-text);flex:0 0 auto;font-size:13px;max-width:200px;min-width:120px;opacity:.8;overflow:hidden;padding:8px 12px;text-overflow:ellipsis;white-space:nowrap}.unleash-toolbar .ut-property-row .ut-input-with-reset{flex:1;min-width:0}.unleash-toolbar .ut-empty{color:#636e72;font-size:13px;padding:40px 20px;text-align:center}.unleash-toolbar .ut-empty-properties{color:var(--ut-text);font-size:12px;margin-bottom:8px}.unleash-toolbar .ut-stats{display:grid;gap:8px;grid-template-columns:repeat(2,1fr);margin-bottom:16px}.unleash-toolbar .ut-stat-card{background:var(--ut-hover);border-radius:6px;padding:12px;text-align:center}.unleash-toolbar .ut-stat-value{color:var(--ut-primary);font-size:24px;font-weight:700}.unleash-toolbar .ut-stat-label{color:#636e72;font-size:11px;margin-top:4px}.unleash-toolbar .ut-content::-webkit-scrollbar{width:10px}.unleash-toolbar .ut-content::-webkit-scrollbar-track{background:var(--ut-hover);border-radius:5px}.unleash-toolbar .ut-content::-webkit-scrollbar-thumb{background:var(--ut-primary);border:2px solid var(--ut-bg);border-radius:5px}.unleash-toolbar .ut-content::-webkit-scrollbar-thumb:hover{background:var(--ut-primary);opacity:.8}.unleash-toolbar .ut-flag-list::-webkit-scrollbar{width:10px}.unleash-toolbar .ut-flag-list::-webkit-scrollbar-track{background:var(--ut-hover);border-radius:5px}.unleash-toolbar .ut-flag-list::-webkit-scrollbar-thumb{background:var(--ut-primary);border:2px solid var(--ut-bg);border-radius:5px}.unleash-toolbar .ut-flag-list::-webkit-scrollbar-thumb:hover{background:var(--ut-primary);opacity:.8}
import { UnleashClient } from 'unleash-proxy-client';
/**
* Unleash context used for feature flag evaluation
*/
export interface UnleashContext {
userId?: string;
sessionId?: string;
remoteAddress?: string;
environment?: string;
appName?: string;
properties?: Record<string, string>;
}
/**
* Unleash variant structure
*/
export interface UnleashVariant {
name: string;
enabled: boolean;
payload?: {
type: string;
value: string;
};
}
/**
* Flag override types
*/
export type FlagOverride = {
type: 'flag';
value: boolean;
} | {
type: 'variant';
variantKey: string;
};
/**
* Metadata for a single flag evaluation
*/
export interface FlagMetadata {
flagType: 'flag' | 'variant';
lastDefaultValue: FlagValue;
lastEffectiveValue: FlagValue;
lastContext: UnleashContext | null;
override: FlagOverride | null;
}
export type FlagValue = boolean | UnleashVariant | null;
/**
* Complete toolbar state
*/
export interface ToolbarState {
flags: {
[featureName: string]: FlagMetadata;
};
contextOverrides: Partial<UnleashContext>;
isVisible?: boolean;
/** Persisted position set by dragging the toolbar (overrides the init `position` option) */
dragPosition?: DragPosition;
}
/**
* A toolbar position set by dragging.
*
* The toolbar is constrained to one of the four window edges; `offset` is a
* fraction (0..1) describing where along that edge it sits, so the position
* stays proportional when the window is resized.
*/
export interface DragPosition {
edge: 'top' | 'right' | 'bottom' | 'left';
offset: number;
}
/**
* Storage mode options
*
* - **local**: Persists across browser tabs and page reloads. Best for development
* as overrides remain active across the entire browser session and even after
* closing/reopening the browser. (DEFAULT)
*
* - **session**: Persists only within the current browser tab. Overrides survive
* page reloads but are lost when the tab is closed. Useful when testing different
* configurations in different tabs without interference.
*
* - **memory**: No persistence - overrides lost on page reload. Useful for
* quick temporary testing or when you need complete isolation between page loads.
* Also appropriate for strict security/privacy requirements where no data should
* be written to disk.
*/
export type StorageMode = 'memory' | 'session' | 'local';
/**
* Theme customization options
*/
export interface ToolbarThemeOptions {
primaryColor?: string;
backgroundColor?: string;
textColor?: string;
borderColor?: string;
fontFamily?: string;
}
/**
* Built-in theme presets
*/
export type ThemePreset = 'light' | 'dark';
/**
* Initialization options for the toolbar
*/
export interface InitToolbarOptions {
/** Storage persistence mode (default: 'local') */
storageMode?: StorageMode;
/** Storage key for persisted state (default: 'unleash-toolbar-state') */
storageKey?: string;
/** Built-in theme preset (default: 'light') */
themePreset?: ThemePreset;
/** Custom theme colors (overrides themePreset if provided) */
theme?: ToolbarThemeOptions;
/** Container element (default: document.body) */
container?: HTMLElement | null;
/** Toolbar position (default: 'bottom-right') */
position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'left' | 'right';
/** Whether toolbar is visible on initialization (default: true, but respects persisted state if available) */
initiallyVisible?: boolean;
/**
* Allow the user to drag the floating toggle icon to reposition the toolbar
* along any window edge. The chosen position is persisted. (default: true)
*/
draggable?: boolean;
/**
* Optional informational message shown as a banner below the toolbar header.
* Useful for clarifying the toolbar's scope/limitations to your team
* (e.g. "Only client-side flags are overridable here"). Empty by default.
*/
banner?: string;
/**
* Optional URL shown as a link next to the banner message. Only rendered when
* `banner` is also set. Opens in a new tab.
*/
bannerLink?: string;
/**
* Text for the `bannerLink` (default: "Read more"). Only used when
* `bannerLink` is set.
*/
bannerLinkText?: string;
/** Sort flags alphabetically instead of by evaluation order (default: false) */
sortAlphabetically?: boolean;
/** Enable cookie synchronization for server-side rendering (Next.js) (default: false) */
enableCookieSync?: boolean;
}
/**
* Toolbar event types (internal use only - not part of public API)
* @internal
*/
export type ToolbarEvent = {
type: 'flag_override_changed';
name: string;
override: FlagOverride | null;
timestamp: number;
} | {
type: 'context_override_changed';
contextOverrides: Partial<UnleashContext>;
} | {
type: 'sdk_updated';
timestamp: number;
};
/**
* Event listener function (internal use only - not part of public API)
* @internal
*/
export type ToolbarEventListener = (event: ToolbarEvent) => void;
/**
* Toolbar UI interface (implemented by UI modules)
*/
export interface IToolbarUI {
show(): void;
hide(): void;
destroy(): void;
}
/**
* Main toolbar instance API
*/
export interface UnleashToolbarInstance {
readonly client: WrappedUnleashClient;
show(): void;
hide(): void;
destroy(): void;
getState(): ToolbarState;
getFlagNames(): string[];
setFlagOverride(name: string, override: FlagOverride | null): void;
setContextOverride(context: Partial<UnleashContext>): void;
removeContextOverride(fieldName: keyof UnleashContext): void;
resetOverrides(): void;
resetContextOverrides(): void;
}
/**
* Wrapped Unleash client with override support.
* Extends the SDK client type and adds the __original property.
*/
export interface WrappedUnleashClient extends UnleashClient {
__original: UnleashClient;
__toolbar?: UnleashToolbarInstance;
}
//# sourceMappingURL=types.d.ts.map
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
var t=globalThis,e=t=>t,i=t.trustedTypes,s=i?i.createPolicy("lit-html",{createHTML:t=>t}):void 0,r="$lit$",n=`lit$${Math.random().toFixed(9).slice(2)}$`,a="?"+n,o=`<${a}>`,l=document,d=()=>l.createComment(""),h=t=>null===t||"object"!=typeof t&&"function"!=typeof t,u=Array.isArray,c="[ \t\n\f\r]",g=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,p=/-->/g,v=/>/g,m=RegExp(`>|${c}(?:([^\\s"'>=/]+)(${c}*=${c}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,"g"),$=/'/g,f=/"/g,b=/^(?:script|style|textarea|title)$/i,y=t=>(e,...i)=>({_$litType$:t,strings:e,values:i}),A=y(1),_=(y(2),y(3),Symbol.for("lit-noChange")),x=Symbol.for("lit-nothing"),C=/* @__PURE__ */new WeakMap,T=l.createTreeWalker(l,129);function M(t,e){if(!u(t)||!t.hasOwnProperty("raw"))throw Error("invalid template strings array");return void 0!==s?s.createHTML(e):e}var w=(t,e)=>{const i=t.length-1,s=[];let a,l=2===e?"<svg>":3===e?"<math>":"",d=g;for(let h=0;h<i;h++){const e=t[h];let i,u,c=-1,y=0;for(;y<e.length&&(d.lastIndex=y,u=d.exec(e),null!==u);)y=d.lastIndex,d===g?"!--"===u[1]?d=p:void 0!==u[1]?d=v:void 0!==u[2]?(b.test(u[2])&&(a=RegExp("</"+u[2],"g")),d=m):void 0!==u[3]&&(d=m):d===m?">"===u[0]?(d=a??g,c=-1):void 0===u[1]?c=-2:(c=d.lastIndex-u[2].length,i=u[1],d=void 0===u[3]?m:'"'===u[3]?f:$):d===f||d===$?d=m:d===p||d===v?d=g:(d=m,a=void 0);const A=d===m&&t[h+1].startsWith("/>")?" ":"";l+=d===g?e+o:c>=0?(s.push(i),e.slice(0,c)+r+e.slice(c)+n+A):e+n+(-2===c?h:A)}return[M(t,l+(t[i]||"<?>")+(2===e?"</svg>":3===e?"</math>":"")),s]},O=class t{constructor({strings:e,_$litType$:s},o){let l;this.parts=[];let h=0,u=0;const c=e.length-1,g=this.parts,[p,v]=w(e,s);if(this.el=t.createElement(p,o),T.currentNode=this.el.content,2===s||3===s){const t=this.el.content.firstChild;t.replaceWith(...t.childNodes)}for(;null!==(l=T.nextNode())&&g.length<c;){if(1===l.nodeType){if(l.hasAttributes())for(const t of l.getAttributeNames())if(t.endsWith(r)){const e=v[u++],i=l.getAttribute(t).split(n),s=/([.?@])?(.*)/.exec(e);g.push({type:1,index:h,name:s[2],strings:i,ctor:"."===s[1]?P:"?"===s[1]?L:"@"===s[1]?E:N}),l.removeAttribute(t)}else t.startsWith(n)&&(g.push({type:6,index:h}),l.removeAttribute(t));if(b.test(l.tagName)){const t=l.textContent.split(n),e=t.length-1;if(e>0){l.textContent=i?i.emptyScript:"";for(let i=0;i<e;i++)l.append(t[i],d()),T.nextNode(),g.push({type:2,index:++h});l.append(t[e],d())}}}else if(8===l.nodeType)if(l.data===a)g.push({type:2,index:h});else{let t=-1;for(;-1!==(t=l.data.indexOf(n,t+1));)g.push({type:7,index:h}),t+=n.length-1}h++}}static createElement(t,e){const i=l.createElement("template");return i.innerHTML=t,i}};function k(t,e,i=t,s){if(e===_)return e;let r=void 0!==s?i._$Co?.[s]:i._$Cl;const n=h(e)?void 0:e._$litDirective$;return r?.constructor!==n&&(r?._$AO?.(!1),void 0===n?r=void 0:(r=new n(t),r._$AT(t,i,s)),void 0!==s?(i._$Co??=[])[s]=r:i._$Cl=r),void 0!==r&&(e=k(t,r._$AS(t,e.values),r,s)),e}var F=class{constructor(t,e){this._$AV=[],this._$AN=void 0,this._$AD=t,this._$AM=e}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(t){const{el:{content:e},parts:i}=this._$AD,s=(t?.creationScope??l).importNode(e,!0);T.currentNode=s;let r=T.nextNode(),n=0,a=0,o=i[0];for(;void 0!==o;){if(n===o.index){let e;2===o.type?e=new H(r,r.nextSibling,this,t):1===o.type?e=new o.ctor(r,o.name,o.strings,this,t):6===o.type&&(e=new S(r,this,t)),this._$AV.push(e),o=i[++a]}n!==o?.index&&(r=T.nextNode(),n++)}return T.currentNode=l,s}p(t){let e=0;for(const i of this._$AV)void 0!==i&&(void 0!==i.strings?(i._$AI(t,i,e),e+=i.strings.length-2):i._$AI(t[e])),e++}},H=class t{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(t,e,i,s){this.type=2,this._$AH=x,this._$AN=void 0,this._$AA=t,this._$AB=e,this._$AM=i,this.options=s,this._$Cv=s?.isConnected??!0}get parentNode(){let t=this._$AA.parentNode;const e=this._$AM;return void 0!==e&&11===t?.nodeType&&(t=e.parentNode),t}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(t,e=this){t=k(this,t,e),h(t)?t===x||null==t||""===t?(this._$AH!==x&&this._$AR(),this._$AH=x):t!==this._$AH&&t!==_&&this._(t):void 0!==t._$litType$?this.$(t):void 0!==t.nodeType?this.T(t):(t=>u(t)||"function"==typeof t?.[Symbol.iterator])(t)?this.k(t):this._(t)}O(t){return this._$AA.parentNode.insertBefore(t,this._$AB)}T(t){this._$AH!==t&&(this._$AR(),this._$AH=this.O(t))}_(t){this._$AH!==x&&h(this._$AH)?this._$AA.nextSibling.data=t:this.T(l.createTextNode(t)),this._$AH=t}$(t){const{values:e,_$litType$:i}=t,s="number"==typeof i?this._$AC(t):(void 0===i.el&&(i.el=O.createElement(M(i.h,i.h[0]),this.options)),i);if(this._$AH?._$AD===s)this._$AH.p(e);else{const t=new F(s,this),i=t.u(this.options);t.p(e),this.T(i),this._$AH=t}}_$AC(t){let e=C.get(t.strings);return void 0===e&&C.set(t.strings,e=new O(t)),e}k(e){u(this._$AH)||(this._$AH=[],this._$AR());const i=this._$AH;let s,r=0;for(const n of e)r===i.length?i.push(s=new t(this.O(d()),this.O(d()),this,this.options)):s=i[r],s._$AI(n),r++;r<i.length&&(this._$AR(s&&s._$AB.nextSibling,r),i.length=r)}_$AR(t=this._$AA.nextSibling,i){for(this._$AP?.(!1,!0,i);t!==this._$AB;){const i=e(t).nextSibling;e(t).remove(),t=i}}setConnected(t){void 0===this._$AM&&(this._$Cv=t,this._$AP?.(t))}},N=class{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(t,e,i,s,r){this.type=1,this._$AH=x,this._$AN=void 0,this.element=t,this.name=e,this._$AM=s,this.options=r,i.length>2||""!==i[0]||""!==i[1]?(this._$AH=Array(i.length-1).fill(/* @__PURE__ */new String),this.strings=i):this._$AH=x}_$AI(t,e=this,i,s){const r=this.strings;let n=!1;if(void 0===r)t=k(this,t,e,0),n=!h(t)||t!==this._$AH&&t!==_,n&&(this._$AH=t);else{const s=t;let a,o;for(t=r[0],a=0;a<r.length-1;a++)o=k(this,s[i+a],e,a),o===_&&(o=this._$AH[a]),n||=!h(o)||o!==this._$AH[a],o===x?t=x:t!==x&&(t+=(o??"")+r[a+1]),this._$AH[a]=o}n&&!s&&this.j(t)}j(t){t===x?this.element.removeAttribute(this.name):this.element.setAttribute(this.name,t??"")}},P=class extends N{constructor(){super(...arguments),this.type=3}j(t){this.element[this.name]=t===x?void 0:t}},L=class extends N{constructor(){super(...arguments),this.type=4}j(t){this.element.toggleAttribute(this.name,!!t&&t!==x)}},E=class extends N{constructor(t,e,i,s,r){super(t,e,i,s,r),this.type=5}_$AI(t,e=this){if((t=k(this,t,e,0)??x)===_)return;const i=this._$AH,s=t===x&&i!==x||t.capture!==i.capture||t.once!==i.once||t.passive!==i.passive,r=t!==x&&(i===x||s);s&&this.element.removeEventListener(this.name,this,i),r&&this.element.addEventListener(this.name,this,t),this._$AH=t}handleEvent(t){"function"==typeof this._$AH?this._$AH.call(this.options?.host??this.element,t):this._$AH.handleEvent(t)}},S=class{constructor(t,e,i){this.element=t,this.type=6,this._$AN=void 0,this._$AM=e,this.options=i}get _$AU(){return this._$AM._$AU}_$AI(t){k(this,t)}},V=t.litHtmlPolyfillSupport;V?.(O,H),(t.litHtmlVersions??=[]).push("3.3.3");var I=20,D=48,U=["position-top-left","position-top-right","position-bottom-left","position-bottom-right","position-left","position-right"],R=(t,e,i)=>Math.max(e,Math.min(i,t)),B=class{root;state;config;callbacks;isDragging=!1;dragMoved=!1;suppressClick=!1;dragGrabX=0;dragGrabY=0;dragStartX=0;dragStartY=0;snapTimer;constructor(t,e,i,s){this.root=t,this.state=e,this.config=i,this.callbacks=s,"undefined"!=typeof window&&window.addEventListener("resize",this.handleResize)}handleResize=()=>{this.isDragging||this.apply()};apply(){const t=this.root,e=this.config.draggable?this.state.getDragPosition():void 0;if(t.style.top="",t.style.bottom="",t.style.left="",t.style.right="",t.classList.remove(...U),!e)return void t.classList.add(`position-${this.config.position}`);const{left:i,top:s}=this.state.getVisibility()?this.computePanelCoords(e):this.computeIconCoords(e);t.style.left=`${i}px`,t.style.top=`${s}px`}computeIconCoords(t){const e=window.innerWidth,i=window.innerHeight,s=R(t.offset*(e-D),I,e-D-I),r=R(t.offset*(i-D),I,i-D-I);switch(t.edge){case"top":return{left:s,top:I};case"bottom":return{left:s,top:i-D-I};case"left":return{left:I,top:r};default:return{left:e-D-I,top:r}}}computePanelCoords(t){const e=window.innerWidth,i=window.innerHeight,s=Math.min(700,.85*i),r=t.offset*(i-D),n=R(t.offset*(e-D)+24-200,I,e-400-I),a=R(r+24-s/2,I,i-s-I);switch(t.edge){case"top":return{left:n,top:I};case"bottom":return{left:n,top:i-s-I};case"left":return{left:I,top:a};default:return{left:e-400-I,top:a}}}onToggleClick(){this.suppressClick?this.suppressClick=!1:this.callbacks.onOpen()}onPointerDown(t){if(!this.config.draggable||0!==t.button)return;void 0!==this.snapTimer&&(clearTimeout(this.snapTimer),this.snapTimer=void 0),this.root.classList.remove("ut-snapping");const e=this.root.getBoundingClientRect();this.dragGrabX=t.clientX-e.left,this.dragGrabY=t.clientY-e.top,this.dragStartX=t.clientX,this.dragStartY=t.clientY,this.isDragging=!0,this.dragMoved=!1,document.addEventListener("pointermove",this.onPointerMove),document.addEventListener("pointerup",this.onPointerUp)}onPointerMove=t=>{if(!this.isDragging)return;if(!this.dragMoved){if(Math.hypot(t.clientX-this.dragStartX,t.clientY-this.dragStartY)<4)return;this.dragMoved=!0,this.root.classList.add("ut-dragging"),this.root.classList.remove(...U)}const e=window.innerWidth,i=window.innerHeight,s=R(t.clientX-this.dragGrabX,I,e-D-I),r=R(t.clientY-this.dragGrabY,I,i-D-I),n=this.root;n.style.right="",n.style.bottom="",n.style.left=`${s}px`,n.style.top=`${r}px`};onPointerUp=()=>{if(!this.isDragging)return;if(this.isDragging=!1,this.removeDragListeners(),this.root.classList.remove("ut-dragging"),!this.dragMoved)return;this.suppressClick=!0;const t=this.root.getBoundingClientRect(),e=function(t,e,i,s,r,n){const a=t+i/2,o=e+s/2,l=a,d=o,h=n-o,u=Math.min(l,r-a,d,h),c=r>i?R(t/(r-i),0,1):0,g=n>s?R(e/(n-s),0,1):0;return u===d?{edge:"top",offset:c}:u===h?{edge:"bottom",offset:c}:u===l?{edge:"left",offset:g}:{edge:"right",offset:g}}(t.left,t.top,t.width||D,t.height||D,window.innerWidth,window.innerHeight);this.root.classList.add("ut-snapping"),this.snapTimer=setTimeout(()=>{this.root.classList.remove("ut-snapping"),this.snapTimer=void 0},250),this.state.setDragPosition(e),this.callbacks.requestRender()};removeDragListeners(){document.removeEventListener("pointermove",this.onPointerMove),document.removeEventListener("pointerup",this.onPointerUp)}destroy(){"undefined"!=typeof window&&window.removeEventListener("resize",this.handleResize),void 0!==this.snapTimer&&clearTimeout(this.snapTimer),this.removeDragListeners()}},z="https://cdn.getunleash.io/docs-assets/unleash_logo_icon.svg",j=class{container;rootElement;stateManager;currentTab="flags";position;themePreset;customTheme;originalBaseContext;searchQuery="";draggable;drag;hiddenCompletely=!1;banner;bannerLink;bannerLinkText;constructor(t,e,i={}){this.stateManager=t,this.position=i.position||"bottom-right",this.themePreset=i.themePreset||"light",this.customTheme=i.theme,this.draggable=i.draggable??!0,this.banner=i.banner,this.bannerLink=i.bannerLink,this.bannerLinkText=i.bannerLinkText,this.originalBaseContext=e.__original.getContext();const s=this.stateManager.getVisibility();void 0===s&&this.stateManager.setVisibility(void 0!==s?s:i.initiallyVisible??!1),this.rootElement=document.createElement("div"),this.rootElement.className="unleash-toolbar-container","dark"===this.themePreset&&this.rootElement.classList.add("ut-theme-dark"),this.applyCustomTheme(this.rootElement),this.container=i.container||document.body,this.container.appendChild(this.rootElement),this.drag=new B(this.rootElement,this.stateManager,{draggable:this.draggable,position:this.position},{onOpen:()=>this.show(),requestRender:()=>this.render()}),this.stateManager.subscribe(()=>{this.render()}),this.render()}applyCustomTheme(t){if(!this.customTheme)return;const e=t.style;this.customTheme.primaryColor&&e.setProperty("--ut-primary",this.customTheme.primaryColor),this.customTheme.backgroundColor&&e.setProperty("--ut-bg",this.customTheme.backgroundColor),this.customTheme.textColor&&e.setProperty("--ut-text",this.customTheme.textColor),this.customTheme.borderColor&&e.setProperty("--ut-border",this.customTheme.borderColor),this.customTheme.fontFamily&&e.setProperty("--ut-font",this.customTheme.fontFamily)}show(){this.hiddenCompletely=!1,this.stateManager.setVisibility(!0),this.render()}hide(){this.stateManager.setVisibility(!1),this.render()}minimize(){this.hide()}hideCompletely(){this.hiddenCompletely=!0,this.stateManager.setVisibility(!1),this.render()}destroy(){this.drag.destroy(),this.rootElement.remove()}render(){const t=this.stateManager.getState(),e=this.stateManager.getFlagNames(),i=this.stateManager.getVisibility();((t,e)=>{let i=e._$litPart$;if(void 0===i){const t=null;e._$litPart$=i=new H(e.insertBefore(d(),t),t,void 0,{})}i._$AI(t)})(A`
<button
class="ut-toggle${this.draggable?" ut-draggable":""}"
style=${i||this.hiddenCompletely?"display: none;":"display: flex;"}
@pointerdown=${t=>this.drag.onPointerDown(t)}
@click=${()=>this.drag.onToggleClick()}
title=${this.draggable?"Open Unleash Toolbar (drag to move)":"Open Unleash Toolbar"}
>
<img src="${z}" alt="Unleash" draggable="false" />
</button>
<div
class="unleash-toolbar"
style=${i&&!this.hiddenCompletely?"display: flex;":"display: none;"}
>
${this.renderHeader(t)}
${this.renderBanner()}
${this.renderTabsNavigation()}
<div class="ut-content">
<div style=${"flags"===this.currentTab?"":"display: none;"}>
${this.renderFlagsTab(e)}
</div>
<div style=${"context"===this.currentTab?"":"display: none;"}>
${this.renderContextTab(t.contextOverrides)}
</div>
</div>
</div>
`,this.rootElement),this.drag.apply()}renderHeader(t){return A`
<div class="ut-header">
<div class="ut-title">
<img src="${z}" alt="Unleash" />
<div>
<div class="ut-title-main">Unleash Toolbar</div>
<div class="ut-title-sub">${Object.keys(t.flags).length} flags • ${Object.values(t.flags).filter(t=>null!==t.override).length} overrides</div>
</div>
</div>
<div class="ut-header-actions">
<button
class="ut-btn-close ut-btn-minimize"
@click=${()=>this.minimize()}
title="Minimize to floating icon"
aria-label="Minimize toolbar"
><span class="ut-minimize-glyph"></span></button>
<button
class="ut-btn-close"
@click=${()=>this.hideCompletely()}
title="Hide until page refresh"
aria-label="Hide toolbar"
>×</button>
</div>
</div>
`}renderBanner(){return this.banner?A`
<div class="ut-banner" role="note">
<span class="ut-banner-text">${this.banner}</span>
${this.bannerLink?A`<a
class="ut-banner-link"
href=${this.bannerLink}
target="_blank"
rel="noopener noreferrer"
>${this.bannerLinkText||"Read more"}</a>`:null}
</div>
`:null}renderTabsNavigation(){return A`
<div class="ut-tabs">
<button
class=${"ut-tab "+("flags"===this.currentTab?"active":"")}
@click=${()=>this.switchTab("flags")}
>
Feature Flags
</button>
<button
class=${"ut-tab "+("context"===this.currentTab?"active":"")}
@click=${()=>this.switchTab("context")}
>
Context
</button>
</div>
`}switchTab(t){this.currentTab=t,this.render()}renderFlagsTab(t){if(0===t.length)return A`
<div class="ut-empty">
No flags evaluated yet. Use feature flags in your app to see them here.
</div>
`;const e=this.searchQuery?t.filter(t=>t.toLowerCase().includes(this.searchQuery.toLowerCase())):t;return A`
<div class="ut-tab-header">
<div class="ut-search-container">
<input
type="text"
class="ut-search-input"
placeholder="Search flags..."
.value=${this.searchQuery}
@input=${t=>this.updateSearch(t.target.value)}
/>
</div>
<button class="ut-btn" @click=${()=>this.stateManager.resetOverrides()}>
Reset All Overrides
</button>
</div>
<div class="ut-flag-list">
${e.length>0?e.map(t=>this.renderFlagItem(t)):A`<div class="ut-empty">No flags match "${this.searchQuery}"</div>`}
</div>
`}updateSearch(t){this.searchQuery=t,this.render()}renderFlagItem(t){const e=this.stateManager.getFlagMetadata(t);if(!e)return null;const i="variant"===e.flagType,s=null!==e.override;let r="default";return s&&"flag"===e.override?.type&&(r=e.override.value?"on":"off"),A`
<div class="ut-flag-item">
<div class="ut-flag-main">
<div class="ut-flag-header">
<div class="ut-flag-title-row">
<div class="ut-flag-name">${t}</div>
</div>
<div class="ut-flag-meta">
<div class="ut-flag-default-value" title="Default value from Unleash">
${this.renderValueBadge(e.lastDefaultValue)}
</div>
${s?A`
<span class="ut-override-indicator" title="Override value (overriding the default)">
→ ${this.renderValueBadge(e.lastEffectiveValue)}
</span>
`:null}
</div>
</div>
</div>
<div class="ut-flag-control">
${i?A`
<div class="ut-variant-control">
${s&&"variant"===e.override?.type?A`
<input
type="text"
class="ut-input-small"
placeholder="Variant name"
.value=${e.override.variantKey}
@input=${e=>this.setVariant(t,e.target.value)}
title="Enter variant name to override with"
/>
<button
class="ut-btn-small active"
@click=${()=>this.toggleVariantOverride(t)}
title="Clear variant override"
>Clear Override</button>
`:A`
<button
class="ut-btn-small"
@click=${()=>this.toggleVariantOverride(t)}
title="Set a variant override"
>Override Variant</button>
`}
</div>
`:A`
<div class="ut-toggle-group">
<button
class=${"ut-toggle-btn "+("off"===r?"active":"")}
@click=${()=>this.setFlagOverride(t,"off")}
title="Force this flag to OFF"
>OFF</button>
<button
class=${"ut-toggle-btn "+("default"===r?"active":"")}
@click=${()=>this.setFlagOverride(t,"default")}
title="Use default value from Unleash (no override)"
>—</button>
<button
class=${"ut-toggle-btn "+("on"===r?"active":"")}
@click=${()=>this.setFlagOverride(t,"on")}
title="Force this flag to ON"
>ON</button>
</div>
`}
</div>
</div>
`}renderValueBadge(t){return"boolean"==typeof t?A`<span class=${"ut-badge ut-badge-"+(t?"success":"danger")}>${t?"ON":"OFF"}</span>`:t&&"object"==typeof t&&"name"in t?A`<span class="ut-badge ut-badge-default">${t.name}</span>`:A`<span class="ut-badge ut-badge-default">null</span>`}setFlagOverride(t,e){"default"===e?this.stateManager.setFlagOverride(t,null):"on"===e?this.stateManager.setFlagOverride(t,{type:"flag",value:!0}):"off"===e&&this.stateManager.setFlagOverride(t,{type:"flag",value:!1})}toggleVariantOverride(t){this.stateManager.getFlagMetadata(t)?.override?this.stateManager.setFlagOverride(t,null):this.stateManager.setFlagOverride(t,{type:"variant",variantKey:"default"})}setVariant(t,e){this.stateManager.setFlagOverride(t,{type:"variant",variantKey:e})}isFieldOverridden(t,e,i){if("properties"===t)return!1;const s=i[t];return void 0!==s&&s!==e[t]}renderContextField(t,e,i,s,r,n=!1){return A`
<div class="ut-form-group">
<label class="ut-label">
${t}${n?A` <span class="ut-readonly-label">(read-only)</span>`:null}
</label>
<div class="ut-input-with-reset">
<input
type="text"
class=${n?"ut-input ut-input-readonly":"ut-input"}
placeholder=${i}
.value=${s}
@input=${n?null:t=>this.updateContextField(e,t.target.value)}
?readonly=${n}
title=${n?"This context field is static and cannot be modified.":""}
/>
${r&&!n?A`
<button
class="ut-reset-field"
@click=${()=>this.resetContextField(e)}
title="Reset to original value"
>↻</button>
`:null}
</div>
</div>
`}updateContextField(t,e){this.stateManager.setContextOverride({[t]:e||void 0})}resetContextField(t){this.stateManager.removeContextOverride(t)}renderContextTab(t){const e=this.originalBaseContext,i={...e,...t},s=["userId","sessionId","remoteAddress","environment","appName","properties"],r=e.properties||{},n=t.properties||{},a={...r,...n},o=Object.entries(a).filter(([t,e])=>!s.includes(t)&&""!==e),l=Object.fromEntries(o);return A`
<div class="ut-tab-header">
<button class="ut-btn" @click=${()=>this.stateManager.resetContextOverrides()}>
Reset All Context
</button>
</div>
<div class="ut-context-form">
${this.renderContextField("User ID","userId","user-123",i.userId||"",this.isFieldOverridden("userId",e,t))}
${this.renderContextField("Session ID","sessionId","session-456",i.sessionId||"",this.isFieldOverridden("sessionId",e,t))}
${this.renderContextField("Remote Address","remoteAddress","192.168.1.1",i.remoteAddress||"",this.isFieldOverridden("remoteAddress",e,t))}
${this.renderContextField("Environment","environment","development",i.environment||"",!1,!0)}
${this.renderContextField("App Name","appName","my-app",i.appName||"",!1,!0)}
<div class="ut-form-group">
<div class="ut-label">Custom Properties</div>
<div class="ut-properties">
${this.renderProperties(l||{},r)}
</div>
</div>
</div>
`}renderProperties(t,e={}){const i=Object.entries(t);return 0===i.length?A`
<div class="ut-empty-properties">
No custom properties defined in base context
</div>
`:A`
${i.map(([t,i])=>{const s=e[t],r=void 0!==s&&s!==i;return A`
<div class="ut-property-row">
<div class="ut-property-key" title="Property key (read-only)">${t}</div>
<div class="ut-input-with-reset">
<input
type="text"
class="ut-input"
placeholder="Value"
.value=${i}
@input=${e=>this.updatePropertyValue(t,e.target.value)}
title=${r?`Original: ${s}`:""}
/>
${r?A`
<button
class="ut-reset-field"
@click=${()=>this.resetProperty(t)}
title="Reset to original value"
>↻</button>
`:null}
</div>
</div>
`})}
`}updatePropertyValue(t,e){const i={...this.stateManager.getState().contextOverrides.properties||{},[t]:e};this.stateManager.setContextOverride({properties:i})}resetProperty(t){const e=this.originalBaseContext.properties||{},i={...this.stateManager.getState().contextOverrides.properties||{}};void 0!==e[t]?i[t]=e[t]:delete i[t],this.stateManager.setContextOverride({properties:i})}};export{j as ToolbarUI};
//# sourceMappingURL=ui-DczWUmYE.js.map
{"version":3,"file":"ui-DczWUmYE.js","names":[],"sources":["../node_modules/lit-html/lit-html.js","../src/drag-controller.ts","../src/ui.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\nconst t=globalThis,i=t=>t,s=t.trustedTypes,e=s?s.createPolicy(\"lit-html\",{createHTML:t=>t}):void 0,h=\"$lit$\",o=`lit$${Math.random().toFixed(9).slice(2)}$`,n=\"?\"+o,r=`<${n}>`,l=document,c=()=>l.createComment(\"\"),a=t=>null===t||\"object\"!=typeof t&&\"function\"!=typeof t,u=Array.isArray,d=t=>u(t)||\"function\"==typeof t?.[Symbol.iterator],f=\"[ \\t\\n\\f\\r]\",v=/<(?:(!--|\\/[^a-zA-Z])|(\\/?[a-zA-Z][^>\\s]*)|(\\/?$))/g,_=/-->/g,m=/>/g,p=RegExp(`>|${f}(?:([^\\\\s\"'>=/]+)(${f}*=${f}*(?:[^ \\t\\n\\f\\r\"'\\`<>=]|(\"|')|))|$)`,\"g\"),g=/'/g,$=/\"/g,y=/^(?:script|style|textarea|title)$/i,x=t=>(i,...s)=>({_$litType$:t,strings:i,values:s}),b=x(1),w=x(2),T=x(3),E=Symbol.for(\"lit-noChange\"),A=Symbol.for(\"lit-nothing\"),C=new WeakMap,P=l.createTreeWalker(l,129);function V(t,i){if(!u(t)||!t.hasOwnProperty(\"raw\"))throw Error(\"invalid template strings array\");return void 0!==e?e.createHTML(i):i}const N=(t,i)=>{const s=t.length-1,e=[];let n,l=2===i?\"<svg>\":3===i?\"<math>\":\"\",c=v;for(let i=0;i<s;i++){const s=t[i];let a,u,d=-1,f=0;for(;f<s.length&&(c.lastIndex=f,u=c.exec(s),null!==u);)f=c.lastIndex,c===v?\"!--\"===u[1]?c=_:void 0!==u[1]?c=m:void 0!==u[2]?(y.test(u[2])&&(n=RegExp(\"</\"+u[2],\"g\")),c=p):void 0!==u[3]&&(c=p):c===p?\">\"===u[0]?(c=n??v,d=-1):void 0===u[1]?d=-2:(d=c.lastIndex-u[2].length,a=u[1],c=void 0===u[3]?p:'\"'===u[3]?$:g):c===$||c===g?c=p:c===_||c===m?c=v:(c=p,n=void 0);const x=c===p&&t[i+1].startsWith(\"/>\")?\" \":\"\";l+=c===v?s+r:d>=0?(e.push(a),s.slice(0,d)+h+s.slice(d)+o+x):s+o+(-2===d?i:x)}return[V(t,l+(t[s]||\"<?>\")+(2===i?\"</svg>\":3===i?\"</math>\":\"\")),e]};class S{constructor({strings:t,_$litType$:i},e){let r;this.parts=[];let l=0,a=0;const u=t.length-1,d=this.parts,[f,v]=N(t,i);if(this.el=S.createElement(f,e),P.currentNode=this.el.content,2===i||3===i){const t=this.el.content.firstChild;t.replaceWith(...t.childNodes)}for(;null!==(r=P.nextNode())&&d.length<u;){if(1===r.nodeType){if(r.hasAttributes())for(const t of r.getAttributeNames())if(t.endsWith(h)){const i=v[a++],s=r.getAttribute(t).split(o),e=/([.?@])?(.*)/.exec(i);d.push({type:1,index:l,name:e[2],strings:s,ctor:\".\"===e[1]?I:\"?\"===e[1]?L:\"@\"===e[1]?z:H}),r.removeAttribute(t)}else t.startsWith(o)&&(d.push({type:6,index:l}),r.removeAttribute(t));if(y.test(r.tagName)){const t=r.textContent.split(o),i=t.length-1;if(i>0){r.textContent=s?s.emptyScript:\"\";for(let s=0;s<i;s++)r.append(t[s],c()),P.nextNode(),d.push({type:2,index:++l});r.append(t[i],c())}}}else if(8===r.nodeType)if(r.data===n)d.push({type:2,index:l});else{let t=-1;for(;-1!==(t=r.data.indexOf(o,t+1));)d.push({type:7,index:l}),t+=o.length-1}l++}}static createElement(t,i){const s=l.createElement(\"template\");return s.innerHTML=t,s}}function M(t,i,s=t,e){if(i===E)return i;let h=void 0!==e?s._$Co?.[e]:s._$Cl;const o=a(i)?void 0:i._$litDirective$;return h?.constructor!==o&&(h?._$AO?.(!1),void 0===o?h=void 0:(h=new o(t),h._$AT(t,s,e)),void 0!==e?(s._$Co??=[])[e]=h:s._$Cl=h),void 0!==h&&(i=M(t,h._$AS(t,i.values),h,e)),i}class R{constructor(t,i){this._$AV=[],this._$AN=void 0,this._$AD=t,this._$AM=i}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(t){const{el:{content:i},parts:s}=this._$AD,e=(t?.creationScope??l).importNode(i,!0);P.currentNode=e;let h=P.nextNode(),o=0,n=0,r=s[0];for(;void 0!==r;){if(o===r.index){let i;2===r.type?i=new k(h,h.nextSibling,this,t):1===r.type?i=new r.ctor(h,r.name,r.strings,this,t):6===r.type&&(i=new Z(h,this,t)),this._$AV.push(i),r=s[++n]}o!==r?.index&&(h=P.nextNode(),o++)}return P.currentNode=l,e}p(t){let i=0;for(const s of this._$AV)void 0!==s&&(void 0!==s.strings?(s._$AI(t,s,i),i+=s.strings.length-2):s._$AI(t[i])),i++}}class k{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(t,i,s,e){this.type=2,this._$AH=A,this._$AN=void 0,this._$AA=t,this._$AB=i,this._$AM=s,this.options=e,this._$Cv=e?.isConnected??!0}get parentNode(){let t=this._$AA.parentNode;const i=this._$AM;return void 0!==i&&11===t?.nodeType&&(t=i.parentNode),t}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(t,i=this){t=M(this,t,i),a(t)?t===A||null==t||\"\"===t?(this._$AH!==A&&this._$AR(),this._$AH=A):t!==this._$AH&&t!==E&&this._(t):void 0!==t._$litType$?this.$(t):void 0!==t.nodeType?this.T(t):d(t)?this.k(t):this._(t)}O(t){return this._$AA.parentNode.insertBefore(t,this._$AB)}T(t){this._$AH!==t&&(this._$AR(),this._$AH=this.O(t))}_(t){this._$AH!==A&&a(this._$AH)?this._$AA.nextSibling.data=t:this.T(l.createTextNode(t)),this._$AH=t}$(t){const{values:i,_$litType$:s}=t,e=\"number\"==typeof s?this._$AC(t):(void 0===s.el&&(s.el=S.createElement(V(s.h,s.h[0]),this.options)),s);if(this._$AH?._$AD===e)this._$AH.p(i);else{const t=new R(e,this),s=t.u(this.options);t.p(i),this.T(s),this._$AH=t}}_$AC(t){let i=C.get(t.strings);return void 0===i&&C.set(t.strings,i=new S(t)),i}k(t){u(this._$AH)||(this._$AH=[],this._$AR());const i=this._$AH;let s,e=0;for(const h of t)e===i.length?i.push(s=new k(this.O(c()),this.O(c()),this,this.options)):s=i[e],s._$AI(h),e++;e<i.length&&(this._$AR(s&&s._$AB.nextSibling,e),i.length=e)}_$AR(t=this._$AA.nextSibling,s){for(this._$AP?.(!1,!0,s);t!==this._$AB;){const s=i(t).nextSibling;i(t).remove(),t=s}}setConnected(t){void 0===this._$AM&&(this._$Cv=t,this._$AP?.(t))}}class H{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(t,i,s,e,h){this.type=1,this._$AH=A,this._$AN=void 0,this.element=t,this.name=i,this._$AM=e,this.options=h,s.length>2||\"\"!==s[0]||\"\"!==s[1]?(this._$AH=Array(s.length-1).fill(new String),this.strings=s):this._$AH=A}_$AI(t,i=this,s,e){const h=this.strings;let o=!1;if(void 0===h)t=M(this,t,i,0),o=!a(t)||t!==this._$AH&&t!==E,o&&(this._$AH=t);else{const e=t;let n,r;for(t=h[0],n=0;n<h.length-1;n++)r=M(this,e[s+n],i,n),r===E&&(r=this._$AH[n]),o||=!a(r)||r!==this._$AH[n],r===A?t=A:t!==A&&(t+=(r??\"\")+h[n+1]),this._$AH[n]=r}o&&!e&&this.j(t)}j(t){t===A?this.element.removeAttribute(this.name):this.element.setAttribute(this.name,t??\"\")}}class I extends H{constructor(){super(...arguments),this.type=3}j(t){this.element[this.name]=t===A?void 0:t}}class L extends H{constructor(){super(...arguments),this.type=4}j(t){this.element.toggleAttribute(this.name,!!t&&t!==A)}}class z extends H{constructor(t,i,s,e,h){super(t,i,s,e,h),this.type=5}_$AI(t,i=this){if((t=M(this,t,i,0)??A)===E)return;const s=this._$AH,e=t===A&&s!==A||t.capture!==s.capture||t.once!==s.once||t.passive!==s.passive,h=t!==A&&(s===A||e);e&&this.element.removeEventListener(this.name,this,s),h&&this.element.addEventListener(this.name,this,t),this._$AH=t}handleEvent(t){\"function\"==typeof this._$AH?this._$AH.call(this.options?.host??this.element,t):this._$AH.handleEvent(t)}}class Z{constructor(t,i,s){this.element=t,this.type=6,this._$AN=void 0,this._$AM=i,this.options=s}get _$AU(){return this._$AM._$AU}_$AI(t){M(this,t)}}const j={M:h,P:o,A:n,C:1,L:N,R,D:d,V:M,I:k,H,N:L,U:z,B:I,F:Z},B=t.litHtmlPolyfillSupport;B?.(S,k),(t.litHtmlVersions??=[]).push(\"3.3.3\");const D=(t,i,s)=>{const e=s?.renderBefore??i;let h=e._$litPart$;if(void 0===h){const t=s?.renderBefore??null;e._$litPart$=h=new k(i.insertBefore(c(),t),t,void 0,s??{})}return h._$AI(t),h};export{j as _$LH,b as html,T as mathml,E as noChange,A as nothing,D as render,w as svg};\n//# sourceMappingURL=lit-html.js.map\n","import type { ToolbarStateManager } from './state';\nimport type { DragPosition } from './types';\n\n// Layout constants shared by drag/positioning logic\nconst EDGE_MARGIN = 20; // px gap kept between the toolbar and the window edge\nconst TOGGLE_SIZE = 48; // px width/height of the floating toggle icon\nconst PANEL_WIDTH = 400; // px width of the expanded panel (matches CSS)\nconst DRAG_THRESHOLD = 4; // px of movement before a pointer-drag begins\n\nconst POSITION_CLASSES = [\n 'position-top-left',\n 'position-top-right',\n 'position-bottom-left',\n 'position-bottom-right',\n 'position-left',\n 'position-right',\n];\n\nconst clamp = (value: number, min: number, max: number): number =>\n Math.max(min, Math.min(max, value));\n\n/**\n * Determine which window edge a dragged toolbar should snap to, and where along\n * that edge it sits. Pure function so it can be unit-tested independently.\n *\n * @param left/top - top-left corner of the dragged element (viewport coords)\n * @param width/height - size of the dragged element\n * @param vw/vh - viewport dimensions\n */\nexport function computeDragPosition(\n left: number,\n top: number,\n width: number,\n height: number,\n vw: number,\n vh: number,\n): DragPosition {\n const centerX = left + width / 2;\n const centerY = top + height / 2;\n\n const distLeft = centerX;\n const distRight = vw - centerX;\n const distTop = centerY;\n const distBottom = vh - centerY;\n const nearest = Math.min(distLeft, distRight, distTop, distBottom);\n\n // Offsets are stored as a fraction of the available travel along the edge so\n // the position stays proportional when the window is resized.\n const offsetX = vw > width ? clamp(left / (vw - width), 0, 1) : 0;\n const offsetY = vh > height ? clamp(top / (vh - height), 0, 1) : 0;\n\n if (nearest === distTop) return { edge: 'top', offset: offsetX };\n if (nearest === distBottom) return { edge: 'bottom', offset: offsetX };\n if (nearest === distLeft) return { edge: 'left', offset: offsetY };\n return { edge: 'right', offset: offsetY };\n}\n\n/** Static config the controller needs to position the toolbar */\nexport interface DragControllerConfig {\n /** Whether the floating icon can be dragged */\n draggable: boolean;\n /** Preset position used when the toolbar has not been dragged */\n position: string;\n}\n\n/** Callbacks the controller uses to talk back to the owning UI */\nexport interface DragControllerCallbacks {\n /** Open the toolbar panel (a plain click on the floating icon) */\n onOpen: () => void;\n /** Ask the owning UI to re-render (after the drag position changes) */\n requestRender: () => void;\n}\n\n/**\n * Owns toolbar placement and the drag-to-move interaction for the floating\n * icon. It manipulates the root container's position (preset class or inline\n * coordinates) and tracks pointer state during a drag, then snaps to the\n * nearest window edge on release.\n *\n * It depends only on the root element, the state manager, static config, and a\n * pair of callbacks — so it stays decoupled from the rest of the UI rendering.\n */\nexport class DragController {\n private isDragging = false;\n private dragMoved = false;\n private suppressClick = false;\n private dragGrabX = 0;\n private dragGrabY = 0;\n private dragStartX = 0;\n private dragStartY = 0;\n private snapTimer?: ReturnType<typeof setTimeout>;\n\n constructor(\n private root: HTMLElement,\n private state: ToolbarStateManager,\n private config: DragControllerConfig,\n private callbacks: DragControllerCallbacks,\n ) {\n // Keep a dragged position on-screen when the window is resized\n if (typeof window !== 'undefined') {\n window.addEventListener('resize', this.handleResize);\n }\n }\n\n private handleResize = (): void => {\n if (!this.isDragging) this.apply();\n };\n\n /**\n * Apply the toolbar position to the root container. When the user has dragged\n * the toolbar, position via inline coordinates; otherwise fall back to the\n * preset position-* class from the `position` option.\n */\n apply(): void {\n const root = this.root;\n // A persisted drag position only applies while dragging is enabled, so\n // toggling `draggable: false` reverts to the configured preset position.\n const drag = this.config.draggable ? this.state.getDragPosition() : undefined;\n\n // Reset any inline coordinates before re-applying\n root.style.top = '';\n root.style.bottom = '';\n root.style.left = '';\n root.style.right = '';\n root.classList.remove(...POSITION_CLASSES);\n\n if (!drag) {\n root.classList.add(`position-${this.config.position}`);\n return;\n }\n\n // Always position via left/top (never right/bottom) so the snap-to-edge\n // animation moves through a single, continuous coordinate space.\n const { left, top } = this.state.getVisibility()\n ? this.computePanelCoords(drag)\n : this.computeIconCoords(drag);\n root.style.left = `${left}px`;\n root.style.top = `${top}px`;\n }\n\n /** Inline coordinates for the collapsed floating icon at a dragged position */\n private computeIconCoords(drag: DragPosition): { left: number; top: number } {\n const vw = window.innerWidth;\n const vh = window.innerHeight;\n const alongX = clamp(\n drag.offset * (vw - TOGGLE_SIZE),\n EDGE_MARGIN,\n vw - TOGGLE_SIZE - EDGE_MARGIN,\n );\n const alongY = clamp(\n drag.offset * (vh - TOGGLE_SIZE),\n EDGE_MARGIN,\n vh - TOGGLE_SIZE - EDGE_MARGIN,\n );\n\n switch (drag.edge) {\n case 'top':\n return { left: alongX, top: EDGE_MARGIN };\n case 'bottom':\n return { left: alongX, top: vh - TOGGLE_SIZE - EDGE_MARGIN };\n case 'left':\n return { left: EDGE_MARGIN, top: alongY };\n default:\n return { left: vw - TOGGLE_SIZE - EDGE_MARGIN, top: alongY };\n }\n }\n\n /**\n * Inline coordinates for the expanded panel at a dragged position. The panel\n * hugs the same edge as the icon and is centered near the icon's offset, then\n * clamped so the 400px-wide panel never overflows the viewport.\n */\n private computePanelCoords(drag: DragPosition): { left: number; top: number } {\n const vw = window.innerWidth;\n const vh = window.innerHeight;\n const panelHeight = Math.min(700, vh * 0.85);\n\n const iconLeft = drag.offset * (vw - TOGGLE_SIZE);\n const iconTop = drag.offset * (vh - TOGGLE_SIZE);\n const left = clamp(\n iconLeft + TOGGLE_SIZE / 2 - PANEL_WIDTH / 2,\n EDGE_MARGIN,\n vw - PANEL_WIDTH - EDGE_MARGIN,\n );\n const top = clamp(\n iconTop + TOGGLE_SIZE / 2 - panelHeight / 2,\n EDGE_MARGIN,\n vh - panelHeight - EDGE_MARGIN,\n );\n\n switch (drag.edge) {\n case 'top':\n return { left, top: EDGE_MARGIN };\n case 'bottom':\n return { left, top: vh - panelHeight - EDGE_MARGIN };\n case 'left':\n return { left: EDGE_MARGIN, top };\n default:\n return { left: vw - PANEL_WIDTH - EDGE_MARGIN, top };\n }\n }\n\n // --- Floating toggle: click to open + optional drag-to-move ---\n\n onToggleClick(): void {\n // A drag just finished — swallow the click so it doesn't open the panel\n if (this.suppressClick) {\n this.suppressClick = false;\n return;\n }\n this.callbacks.onOpen();\n }\n\n onPointerDown(e: PointerEvent): void {\n if (!this.config.draggable || e.button !== 0) return;\n\n // Cancel any in-flight snap animation so the icon tracks the pointer immediately\n if (this.snapTimer !== undefined) {\n clearTimeout(this.snapTimer);\n this.snapTimer = undefined;\n }\n this.root.classList.remove('ut-snapping');\n\n const rect = this.root.getBoundingClientRect();\n this.dragGrabX = e.clientX - rect.left;\n this.dragGrabY = e.clientY - rect.top;\n this.dragStartX = e.clientX;\n this.dragStartY = e.clientY;\n this.isDragging = true;\n this.dragMoved = false;\n\n document.addEventListener('pointermove', this.onPointerMove);\n document.addEventListener('pointerup', this.onPointerUp);\n }\n\n private onPointerMove = (e: PointerEvent): void => {\n if (!this.isDragging) return;\n\n if (!this.dragMoved) {\n const dx = e.clientX - this.dragStartX;\n const dy = e.clientY - this.dragStartY;\n if (Math.hypot(dx, dy) < DRAG_THRESHOLD) return;\n this.dragMoved = true;\n this.root.classList.add('ut-dragging');\n this.root.classList.remove(...POSITION_CLASSES);\n }\n\n const vw = window.innerWidth;\n const vh = window.innerHeight;\n const left = clamp(e.clientX - this.dragGrabX, EDGE_MARGIN, vw - TOGGLE_SIZE - EDGE_MARGIN);\n const top = clamp(e.clientY - this.dragGrabY, EDGE_MARGIN, vh - TOGGLE_SIZE - EDGE_MARGIN);\n\n const root = this.root;\n root.style.right = '';\n root.style.bottom = '';\n root.style.left = `${left}px`;\n root.style.top = `${top}px`;\n };\n\n private onPointerUp = (): void => {\n if (!this.isDragging) return;\n this.isDragging = false;\n this.removeDragListeners();\n this.root.classList.remove('ut-dragging');\n\n if (!this.dragMoved) return; // treat as a plain click → onToggleClick opens it\n\n this.suppressClick = true;\n const rect = this.root.getBoundingClientRect();\n const position = computeDragPosition(\n rect.left,\n rect.top,\n rect.width || TOGGLE_SIZE,\n rect.height || TOGGLE_SIZE,\n window.innerWidth,\n window.innerHeight,\n );\n\n // Animate the snap from the drop point to the edge, then drop the\n // transition class so later renders/resizes reposition instantly.\n this.root.classList.add('ut-snapping');\n this.snapTimer = setTimeout(() => {\n this.root.classList.remove('ut-snapping');\n this.snapTimer = undefined;\n }, 250);\n\n this.state.setDragPosition(position);\n this.callbacks.requestRender();\n };\n\n private removeDragListeners(): void {\n document.removeEventListener('pointermove', this.onPointerMove);\n document.removeEventListener('pointerup', this.onPointerUp);\n }\n\n /** Remove all listeners and cancel any pending snap animation */\n destroy(): void {\n if (typeof window !== 'undefined') {\n window.removeEventListener('resize', this.handleResize);\n }\n if (this.snapTimer !== undefined) clearTimeout(this.snapTimer);\n this.removeDragListeners();\n }\n}\n","import { html, render } from 'lit-html';\nimport { DragController } from './drag-controller';\nimport type { ToolbarStateManager } from './state';\nimport type {\n FlagValue,\n InitToolbarOptions,\n IToolbarUI,\n ToolbarState,\n UnleashContext,\n WrappedUnleashClient,\n} from './types';\n\n// Re-exported so existing importers (and tests) can keep using it from here\nexport { computeDragPosition } from './drag-controller';\n\n// Unleash logo from CDN\nconst UNLEASH_LOGO = 'https://cdn.getunleash.io/docs-assets/unleash_logo_icon.svg';\n\n/**\n * Create the toolbar UI component using Lit\n */\nexport class ToolbarUI implements IToolbarUI {\n private container: HTMLElement;\n private rootElement: HTMLElement;\n private stateManager: ToolbarStateManager;\n private currentTab: 'flags' | 'context' = 'flags';\n private position: string;\n private themePreset: 'light' | 'dark';\n private customTheme?: InitToolbarOptions['theme'];\n private originalBaseContext: Partial<UnleashContext>;\n private searchQuery: string = '';\n private draggable: boolean;\n\n // Owns toolbar placement + the drag-to-move interaction\n private drag: DragController;\n\n // Ephemeral \"fully hidden\" state (NOT persisted): the toolbar reappears on\n // the next page load. Set via the header's close (×) button.\n private hiddenCompletely = false;\n\n // Custom banner\n private banner?: string;\n private bannerLink?: string;\n private bannerLinkText?: string;\n\n constructor(\n stateManager: ToolbarStateManager,\n wrappedClient: WrappedUnleashClient,\n options: InitToolbarOptions = {},\n ) {\n this.stateManager = stateManager;\n this.position = options.position || 'bottom-right';\n this.themePreset = options.themePreset || 'light';\n this.customTheme = options.theme;\n this.draggable = options.draggable ?? true;\n this.banner = options.banner;\n this.bannerLink = options.bannerLink;\n this.bannerLinkText = options.bannerLinkText;\n\n // Capture original base context before any overrides are applied\n this.originalBaseContext = wrappedClient.__original.getContext();\n\n // Initialize visibility from persisted state, or use initiallyVisible option\n const persistedVisibility = this.stateManager.getVisibility();\n const isVisible =\n persistedVisibility !== undefined ? persistedVisibility : (options.initiallyVisible ?? false);\n\n // Persist the initial visibility if not already set\n if (persistedVisibility === undefined) {\n this.stateManager.setVisibility(isVisible);\n }\n\n // Create single root container. The position (preset class or dragged\n // coordinates) is managed by applyPosition(), called from render().\n this.rootElement = document.createElement('div');\n this.rootElement.className = 'unleash-toolbar-container';\n if (this.themePreset === 'dark') {\n this.rootElement.classList.add('ut-theme-dark');\n }\n this.applyCustomTheme(this.rootElement);\n\n // Attach to container or body\n this.container = options.container || document.body;\n this.container.appendChild(this.rootElement);\n\n // Placement + drag-to-move are delegated to the DragController. It calls\n // back to open the panel (a plain click) and to request a re-render.\n this.drag = new DragController(\n this.rootElement,\n this.stateManager,\n { draggable: this.draggable, position: this.position },\n { onOpen: () => this.show(), requestRender: () => this.render() },\n );\n\n // Subscribe to state changes\n this.stateManager.subscribe(() => {\n this.render();\n });\n\n // Initial render\n this.render();\n }\n\n private applyCustomTheme(element: HTMLElement): void {\n if (!this.customTheme) return;\n\n const style = element.style;\n if (this.customTheme.primaryColor)\n style.setProperty('--ut-primary', this.customTheme.primaryColor);\n if (this.customTheme.backgroundColor)\n style.setProperty('--ut-bg', this.customTheme.backgroundColor);\n if (this.customTheme.textColor) style.setProperty('--ut-text', this.customTheme.textColor);\n if (this.customTheme.borderColor)\n style.setProperty('--ut-border', this.customTheme.borderColor);\n if (this.customTheme.fontFamily) style.setProperty('--ut-font', this.customTheme.fontFamily);\n }\n\n show(): void {\n this.hiddenCompletely = false;\n this.stateManager.setVisibility(true);\n this.render();\n }\n\n hide(): void {\n this.stateManager.setVisibility(false);\n this.render();\n }\n\n /**\n * Collapse the panel down to the floating toggle icon (persisted).\n * Triggered by the header's minimize (_) button.\n */\n private minimize(): void {\n this.hide();\n }\n\n /**\n * Hide the toolbar entirely — both panel and floating icon. The \"everything\n * hidden\" state is ephemeral and NOT persisted, so a page refresh brings the\n * toolbar back. We do persist visibility as collapsed, so on reload it\n * returns minimized (the floating icon) rather than fully open. Triggered by\n * the header's close (×) button.\n */\n private hideCompletely(): void {\n this.hiddenCompletely = true;\n this.stateManager.setVisibility(false);\n this.render();\n }\n\n destroy(): void {\n this.drag.destroy();\n this.rootElement.remove();\n }\n\n private render(): void {\n const state = this.stateManager.getState();\n const flagNames = this.stateManager.getFlagNames();\n const isVisible = this.stateManager.getVisibility();\n\n // Three states: fully hidden (nothing shown), collapsed (toggle icon), open (panel)\n const showToggle = !isVisible && !this.hiddenCompletely;\n const showPanel = isVisible && !this.hiddenCompletely;\n\n // Single unified template for everything\n const template = html`\n <button\n class=\"ut-toggle${this.draggable ? ' ut-draggable' : ''}\"\n style=${showToggle ? 'display: flex;' : 'display: none;'}\n @pointerdown=${(e: PointerEvent) => this.drag.onPointerDown(e)}\n @click=${() => this.drag.onToggleClick()}\n title=${this.draggable ? 'Open Unleash Toolbar (drag to move)' : 'Open Unleash Toolbar'}\n >\n <img src=\"${UNLEASH_LOGO}\" alt=\"Unleash\" draggable=\"false\" />\n </button>\n\n <div\n class=\"unleash-toolbar\"\n style=${showPanel ? 'display: flex;' : 'display: none;'}\n >\n ${this.renderHeader(state)}\n ${this.renderBanner()}\n ${this.renderTabsNavigation()}\n <div class=\"ut-content\">\n <div style=${this.currentTab === 'flags' ? '' : 'display: none;'}>\n ${this.renderFlagsTab(flagNames)}\n </div>\n <div style=${this.currentTab === 'context' ? '' : 'display: none;'}>\n ${this.renderContextTab(state.contextOverrides)}\n </div>\n </div>\n </div>\n `;\n\n render(template, this.rootElement);\n this.drag.apply();\n }\n\n private renderHeader(state: ToolbarState) {\n const flagCount = Object.keys(state.flags).length;\n const overrideCount = Object.values(state.flags).filter((f) => f.override !== null).length;\n\n return html`\n <div class=\"ut-header\">\n <div class=\"ut-title\">\n <img src=\"${UNLEASH_LOGO}\" alt=\"Unleash\" />\n <div>\n <div class=\"ut-title-main\">Unleash Toolbar</div>\n <div class=\"ut-title-sub\">${flagCount} flags • ${overrideCount} overrides</div>\n </div>\n </div>\n <div class=\"ut-header-actions\">\n <button\n class=\"ut-btn-close ut-btn-minimize\"\n @click=${() => this.minimize()}\n title=\"Minimize to floating icon\"\n aria-label=\"Minimize toolbar\"\n ><span class=\"ut-minimize-glyph\"></span></button>\n <button\n class=\"ut-btn-close\"\n @click=${() => this.hideCompletely()}\n title=\"Hide until page refresh\"\n aria-label=\"Hide toolbar\"\n >×</button>\n </div>\n </div>\n `;\n }\n\n private renderBanner() {\n if (!this.banner) return null;\n\n const linkText = this.bannerLinkText || 'Read more';\n\n return html`\n <div class=\"ut-banner\" role=\"note\">\n <span class=\"ut-banner-text\">${this.banner}</span>\n ${\n this.bannerLink\n ? html`<a\n class=\"ut-banner-link\"\n href=${this.bannerLink}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >${linkText}</a>`\n : null\n }\n </div>\n `;\n }\n\n private renderTabsNavigation() {\n return html`\n <div class=\"ut-tabs\">\n <button \n class=${`ut-tab ${this.currentTab === 'flags' ? 'active' : ''}`}\n @click=${() => this.switchTab('flags')}\n >\n Feature Flags\n </button>\n <button \n class=${`ut-tab ${this.currentTab === 'context' ? 'active' : ''}`}\n @click=${() => this.switchTab('context')}\n >\n Context\n </button>\n </div>\n `;\n }\n\n private switchTab(tab: 'flags' | 'context'): void {\n this.currentTab = tab;\n this.render();\n }\n\n private renderFlagsTab(flagNames: string[]) {\n if (flagNames.length === 0) {\n return html`\n <div class=\"ut-empty\">\n No flags evaluated yet. Use feature flags in your app to see them here.\n </div>\n `;\n }\n\n // Filter flags based on search query\n const filteredFlags = this.searchQuery\n ? flagNames.filter((name) => name.toLowerCase().includes(this.searchQuery.toLowerCase()))\n : flagNames;\n\n return html`\n <div class=\"ut-tab-header\">\n <div class=\"ut-search-container\">\n <input\n type=\"text\"\n class=\"ut-search-input\"\n placeholder=\"Search flags...\"\n .value=${this.searchQuery}\n @input=${(e: Event) => this.updateSearch((e.target as HTMLInputElement).value)}\n />\n </div>\n <button class=\"ut-btn\" @click=${() => this.stateManager.resetOverrides()}>\n Reset All Overrides\n </button>\n </div>\n <div class=\"ut-flag-list\">\n ${\n filteredFlags.length > 0\n ? filteredFlags.map((name) => this.renderFlagItem(name))\n : html`<div class=\"ut-empty\">No flags match \"${this.searchQuery}\"</div>`\n }\n </div>\n `;\n }\n\n private updateSearch(query: string): void {\n this.searchQuery = query;\n this.render();\n }\n\n private renderFlagItem(name: string) {\n const metadata = this.stateManager.getFlagMetadata(name);\n if (!metadata) return null;\n\n // Use the explicitly stored flag type\n const isVariant = metadata.flagType === 'variant';\n const hasOverride = metadata.override !== null;\n\n // Determine current state for toggle\n let toggleState = 'default';\n if (hasOverride && metadata.override?.type === 'flag') {\n toggleState = metadata.override.value ? 'on' : 'off';\n }\n\n return html`\n <div class=\"ut-flag-item\">\n <div class=\"ut-flag-main\">\n <div class=\"ut-flag-header\">\n <div class=\"ut-flag-title-row\">\n <div class=\"ut-flag-name\">${name}</div>\n </div>\n <div class=\"ut-flag-meta\">\n <div class=\"ut-flag-default-value\" title=\"Default value from Unleash\">\n ${this.renderValueBadge(metadata.lastDefaultValue)}\n </div>\n ${\n hasOverride\n ? html`\n <span class=\"ut-override-indicator\" title=\"Override value (overriding the default)\">\n → ${this.renderValueBadge(metadata.lastEffectiveValue)}\n </span>\n `\n : null\n }\n </div>\n </div>\n </div>\n \n <div class=\"ut-flag-control\">\n ${\n !isVariant\n ? html`\n <div class=\"ut-toggle-group\">\n <button \n class=${`ut-toggle-btn ${toggleState === 'off' ? 'active' : ''}`}\n @click=${() => this.setFlagOverride(name, 'off')}\n title=\"Force this flag to OFF\"\n >OFF</button>\n <button \n class=${`ut-toggle-btn ${toggleState === 'default' ? 'active' : ''}`}\n @click=${() => this.setFlagOverride(name, 'default')}\n title=\"Use default value from Unleash (no override)\"\n >—</button>\n <button \n class=${`ut-toggle-btn ${toggleState === 'on' ? 'active' : ''}`}\n @click=${() => this.setFlagOverride(name, 'on')}\n title=\"Force this flag to ON\"\n >ON</button>\n </div>\n `\n : html`\n <div class=\"ut-variant-control\">\n ${\n hasOverride && metadata.override?.type === 'variant'\n ? html`\n <input \n type=\"text\" \n class=\"ut-input-small\" \n placeholder=\"Variant name\" \n .value=${metadata.override.variantKey}\n @input=${(e: Event) => this.setVariant(name, (e.target as HTMLInputElement).value)}\n title=\"Enter variant name to override with\"\n />\n <button \n class=\"ut-btn-small active\" \n @click=${() => this.toggleVariantOverride(name)}\n title=\"Clear variant override\"\n >Clear Override</button>\n `\n : html`\n <button \n class=\"ut-btn-small\" \n @click=${() => this.toggleVariantOverride(name)}\n title=\"Set a variant override\"\n >Override Variant</button>\n `\n }\n </div>\n `\n }\n </div>\n </div>\n `;\n }\n\n private renderValueBadge(value: FlagValue) {\n if (typeof value === 'boolean') {\n return html`<span class=${`ut-badge ut-badge-${value ? 'success' : 'danger'}`}>${value ? 'ON' : 'OFF'}</span>`;\n }\n if (value && typeof value === 'object' && 'name' in value) {\n return html`<span class=\"ut-badge ut-badge-default\">${value.name}</span>`;\n }\n return html`<span class=\"ut-badge ut-badge-default\">null</span>`;\n }\n\n private setFlagOverride(flagName: string, value: 'on' | 'off' | 'default'): void {\n if (value === 'default') {\n this.stateManager.setFlagOverride(flagName, null);\n } else if (value === 'on') {\n this.stateManager.setFlagOverride(flagName, { type: 'flag', value: true });\n } else if (value === 'off') {\n this.stateManager.setFlagOverride(flagName, { type: 'flag', value: false });\n }\n }\n\n private toggleVariantOverride(flagName: string): void {\n const metadata = this.stateManager.getFlagMetadata(flagName);\n\n if (metadata?.override) {\n // Clear override\n this.stateManager.setFlagOverride(flagName, null);\n } else {\n // Set default variant override\n this.stateManager.setFlagOverride(flagName, { type: 'variant', variantKey: 'default' });\n }\n }\n\n private setVariant(flagName: string, variantKey: string): void {\n this.stateManager.setFlagOverride(flagName, { type: 'variant', variantKey });\n }\n\n private isFieldOverridden(\n fieldName: string,\n baseContext: Partial<UnleashContext>,\n contextOverrides: Partial<UnleashContext>,\n ): boolean {\n if (fieldName === 'properties') {\n return false; // Handle properties separately\n }\n const baseValue = baseContext[fieldName as keyof UnleashContext];\n const overrideValue = contextOverrides[fieldName as keyof UnleashContext];\n\n // Only consider it overridden if there's an override AND it differs from base\n return overrideValue !== undefined && overrideValue !== baseValue;\n }\n\n private renderContextField(\n label: string,\n fieldName: string,\n placeholder: string,\n value: string,\n isOverridden: boolean,\n readonly = false,\n ) {\n return html`\n <div class=\"ut-form-group\">\n <label class=\"ut-label\">\n ${label}${readonly ? html` <span class=\"ut-readonly-label\">(read-only)</span>` : null}\n </label>\n <div class=\"ut-input-with-reset\">\n <input \n type=\"text\" \n class=${readonly ? 'ut-input ut-input-readonly' : 'ut-input'}\n placeholder=${placeholder}\n .value=${value}\n @input=${readonly ? null : (e: Event) => this.updateContextField(fieldName, (e.target as HTMLInputElement).value)}\n ?readonly=${readonly}\n title=${readonly ? 'This context field is static and cannot be modified.' : ''}\n />\n ${\n isOverridden && !readonly\n ? html`\n <button \n class=\"ut-reset-field\" \n @click=${() => this.resetContextField(fieldName)}\n title=\"Reset to original value\"\n >↻</button>\n `\n : null\n }\n </div>\n </div>\n `;\n }\n\n private updateContextField(field: string, value: string): void {\n this.stateManager.setContextOverride({ [field]: value || undefined });\n }\n\n private resetContextField(field: string): void {\n this.stateManager.removeContextOverride(field as keyof UnleashContext);\n }\n\n private renderContextTab(contextOverrides: Partial<UnleashContext>) {\n // Use original base context (not current client context which includes overrides)\n const baseContext = this.originalBaseContext;\n const mergedContext = { ...baseContext, ...contextOverrides };\n\n // Standard context fields that should not appear in custom properties\n const standardFields = [\n 'userId',\n 'sessionId',\n 'remoteAddress',\n 'environment',\n 'appName',\n 'properties',\n ];\n\n // Merge properties and exclude any that are standard fields\n const baseProperties = baseContext.properties || {};\n const overrideProperties = contextOverrides.properties || {};\n const mergedProperties = { ...baseProperties, ...overrideProperties };\n\n // Filter out standard fields and show only non-empty properties\n const customPropertiesArray = Object.entries(mergedProperties).filter(([key, value]) => {\n if (standardFields.includes(key)) return false;\n // Only show properties that have a non-empty value\n return value !== '';\n });\n\n const customProperties = Object.fromEntries(customPropertiesArray);\n\n return html`\n <div class=\"ut-tab-header\">\n <button class=\"ut-btn\" @click=${() => this.stateManager.resetContextOverrides()}>\n Reset All Context\n </button>\n </div>\n <div class=\"ut-context-form\">\n ${this.renderContextField('User ID', 'userId', 'user-123', mergedContext.userId || '', this.isFieldOverridden('userId', baseContext, contextOverrides))}\n ${this.renderContextField('Session ID', 'sessionId', 'session-456', mergedContext.sessionId || '', this.isFieldOverridden('sessionId', baseContext, contextOverrides))}\n ${this.renderContextField('Remote Address', 'remoteAddress', '192.168.1.1', mergedContext.remoteAddress || '', this.isFieldOverridden('remoteAddress', baseContext, contextOverrides))}\n ${this.renderContextField('Environment', 'environment', 'development', mergedContext.environment || '', false, true)}\n ${this.renderContextField('App Name', 'appName', 'my-app', mergedContext.appName || '', false, true)}\n\n <div class=\"ut-form-group\">\n <div class=\"ut-label\">Custom Properties</div>\n <div class=\"ut-properties\">\n ${this.renderProperties(customProperties || {}, baseProperties)}\n </div>\n </div>\n </div>\n `;\n }\n\n private renderProperties(\n properties: Record<string, string>,\n baseProperties: Record<string, string> = {},\n ) {\n const entries = Object.entries(properties);\n\n if (entries.length === 0) {\n return html`\n <div class=\"ut-empty-properties\">\n No custom properties defined in base context\n </div>\n `;\n }\n\n return html`\n ${entries.map(([key, value]) => {\n const baseValue = baseProperties[key];\n const isOverridden = baseValue !== undefined && baseValue !== value;\n return html`\n <div class=\"ut-property-row\">\n <div class=\"ut-property-key\" title=\"Property key (read-only)\">${key}</div>\n <div class=\"ut-input-with-reset\">\n <input \n type=\"text\" \n class=\"ut-input\" \n placeholder=\"Value\"\n .value=${value}\n @input=${(e: Event) => this.updatePropertyValue(key, (e.target as HTMLInputElement).value)}\n title=${isOverridden ? `Original: ${baseValue}` : ''}\n />\n ${\n isOverridden\n ? html`\n <button \n class=\"ut-reset-field\" \n @click=${() => this.resetProperty(key)}\n title=\"Reset to original value\"\n >↻</button>\n `\n : null\n }\n </div>\n </div>\n `;\n })}\n `;\n }\n\n private updatePropertyValue(key: string, value: string): void {\n const state = this.stateManager.getState();\n const properties = { ...(state.contextOverrides.properties || {}), [key]: value };\n this.stateManager.setContextOverride({ properties });\n }\n\n private resetProperty(key: string): void {\n const baseProperties = this.originalBaseContext.properties || {};\n const state = this.stateManager.getState();\n const properties = { ...(state.contextOverrides.properties || {}) };\n\n // Restore to base value\n if (baseProperties[key] !== undefined) {\n properties[key] = baseProperties[key];\n } else {\n delete properties[key];\n }\n\n this.stateManager.setContextOverride({ properties });\n }\n}\n"],"x_google_ignoreList":[0],"mappings":"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"}
import { ToolbarStateManager } from './state';
import { InitToolbarOptions, IToolbarUI, WrappedUnleashClient } from './types';
export { computeDragPosition } from './drag-controller';
/**
* Create the toolbar UI component using Lit
*/
export declare class ToolbarUI implements IToolbarUI {
private container;
private rootElement;
private stateManager;
private currentTab;
private position;
private themePreset;
private customTheme?;
private originalBaseContext;
private searchQuery;
private draggable;
private drag;
private hiddenCompletely;
private banner?;
private bannerLink?;
private bannerLinkText?;
constructor(stateManager: ToolbarStateManager, wrappedClient: WrappedUnleashClient, options?: InitToolbarOptions);
private applyCustomTheme;
show(): void;
hide(): void;
/**
* Collapse the panel down to the floating toggle icon (persisted).
* Triggered by the header's minimize (_) button.
*/
private minimize;
/**
* Hide the toolbar entirely — both panel and floating icon. The "everything
* hidden" state is ephemeral and NOT persisted, so a page refresh brings the
* toolbar back. We do persist visibility as collapsed, so on reload it
* returns minimized (the floating icon) rather than fully open. Triggered by
* the header's close (×) button.
*/
private hideCompletely;
destroy(): void;
private render;
private renderHeader;
private renderBanner;
private renderTabsNavigation;
private switchTab;
private renderFlagsTab;
private updateSearch;
private renderFlagItem;
private renderValueBadge;
private setFlagOverride;
private toggleVariantOverride;
private setVariant;
private isFieldOverridden;
private renderContextField;
private updateContextField;
private resetContextField;
private renderContextTab;
private renderProperties;
private updatePropertyValue;
private resetProperty;
}
//# sourceMappingURL=ui.d.ts.map
{"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../src/ui.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,KAAK,EAEV,kBAAkB,EAClB,UAAU,EAGV,oBAAoB,EACrB,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAKxD;;GAEG;AACH,qBAAa,SAAU,YAAW,UAAU;IAC1C,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,YAAY,CAAsB;IAC1C,OAAO,CAAC,UAAU,CAAgC;IAClD,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,WAAW,CAAmB;IACtC,OAAO,CAAC,WAAW,CAAC,CAA8B;IAClD,OAAO,CAAC,mBAAmB,CAA0B;IACrD,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,SAAS,CAAU;IAG3B,OAAO,CAAC,IAAI,CAAiB;IAI7B,OAAO,CAAC,gBAAgB,CAAS;IAGjC,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,UAAU,CAAC,CAAS;IAC5B,OAAO,CAAC,cAAc,CAAC,CAAS;gBAG9B,YAAY,EAAE,mBAAmB,EACjC,aAAa,EAAE,oBAAoB,EACnC,OAAO,GAAE,kBAAuB;IAuDlC,OAAO,CAAC,gBAAgB;IAcxB,IAAI,IAAI,IAAI;IAMZ,IAAI,IAAI,IAAI;IAKZ;;;OAGG;IACH,OAAO,CAAC,QAAQ;IAIhB;;;;;;OAMG;IACH,OAAO,CAAC,cAAc;IAMtB,OAAO,IAAI,IAAI;IAKf,OAAO,CAAC,MAAM;IA2Cd,OAAO,CAAC,YAAY;IA+BpB,OAAO,CAAC,YAAY;IAsBpB,OAAO,CAAC,oBAAoB;IAmB5B,OAAO,CAAC,SAAS;IAKjB,OAAO,CAAC,cAAc;IAuCtB,OAAO,CAAC,YAAY;IAKpB,OAAO,CAAC,cAAc;IA+FtB,OAAO,CAAC,gBAAgB;IAUxB,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,qBAAqB;IAY7B,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,iBAAiB;IAezB,OAAO,CAAC,kBAAkB;IAuC1B,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,iBAAiB;IAIzB,OAAO,CAAC,gBAAgB;IAoDxB,OAAO,CAAC,gBAAgB;IAgDxB,OAAO,CAAC,mBAAmB;IAM3B,OAAO,CAAC,aAAa;CActB"}
import { UnleashClient } from 'unleash-proxy-client';
import { ToolbarStateManager } from './state';
import { WrappedUnleashClient } from './types';
/**
* Wrap an Unleash client to intercept evaluations and apply overrides
*/
export declare function wrapUnleashClient(baseClient: UnleashClient, stateManager: ToolbarStateManager): WrappedUnleashClient;
/**
* Unwrap a client to get the original
*/
export declare function unwrapUnleashClient(client: UnleashClient): UnleashClient;
/**
* Check if a client is wrapped
*/
export declare function isWrappedClient(client: UnleashClient): client is WrappedUnleashClient;
//# sourceMappingURL=wrapper.d.ts.map
{"version":3,"file":"wrapper.d.ts","sourceRoot":"","sources":["../src/wrapper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,KAAK,EAAgC,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAElF;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,aAAa,EACzB,YAAY,EAAE,mBAAmB,GAChC,oBAAoB,CA2LtB;AAkCD;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,aAAa,GAAG,aAAa,CAKxE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,IAAI,oBAAoB,CAErF"}
+2
-1
{
"name": "@unleash/toolbar",
"version": "1.1.0",
"version": "1.1.1",
"description": "Client-side override toolbar for Unleash JavaScript SDKs",

@@ -34,2 +34,3 @@ "type": "module",

"build": "tsc && vite build",
"prepare": "npm run build",
"type-check": "tsc --noEmit",

@@ -36,0 +37,0 @@ "lint": "biome check .",