@unleash/toolbar
Advanced tools
| 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":"AAyEA,IAAM,EAAN,MACE,yBAA+C,IAAI,IAEnD,SAAA,CAAU,GAER,OADA,KAAK,UAAU,IAAI,GACnB,IAAa,KAAK,UAAU,OAAO,EACrC,CAEA,IAAA,CAAK,GACH,KAAK,UAAU,QAAS,IACtB,IACE,EAAS,EACX,CAAA,MAAS,GACP,QAAQ,MAAM,6CAA8C,EAC9D,GAEJ,GAMI,EAAN,MAIY,KACA,IAJV,kBAAoC,EAEpC,WAAA,CACE,EACA,GADQ,KAAA,KAAA,EACA,KAAA,IAAA,CACP,CAMH,oBAAA,CAAqB,GACnB,KAAK,iBAAmB,CAC1B,CAEA,UAAA,GACE,GAAsB,oBAAX,OAAwB,OAAO,KAE1C,OAAQ,KAAK,MACX,IAAK,QACH,OAAO,OAAO,aAChB,IAAK,UACH,OAAO,OAAO,eAChB,QACE,OAAO,KAEb,CAMA,aAAA,CAAsB,GACpB,GAAK,KAAK,kBACc,oBAAb,SAEX,KApHJ,eAAyB,EAAc,GACrC,GAAwB,oBAAb,SAA0B,OAErC,MAAM,EAAe,mBAAmB,GAGxC,GAAI,gBAAiB,OACnB,IAQE,kBAPM,OAAO,YAAY,IAAI,CAC3B,OACA,MAAO,EACP,KAAM,IACN,SAAU,MACV,QAAS,KAAK,MAAQ,SAG1B,CAAA,MAEA,CAYF,SAAS,OARW,CAClB,GAAG,KAAQ,IACX,SACA,iBACA,gBAI4B,KAAK,KACrC,CAwFM,CAAU,wBAFI,KAAK,UAAU,GAG/B,CAAA,MAAS,GACP,QAAQ,MAAM,qDAAsD,EACtE,CACF,CAEA,IAAA,GACE,MAAM,EAAU,KAAK,aACrB,IAAK,EAAS,OAAO,KAErB,IACE,MAAM,EAAO,EAAQ,QAAQ,KAAK,KAClC,OAAO,EAAO,KAAK,MAAM,GAAQ,IACnC,CAAA,MAAS,GAEP,OADA,QAAQ,MAAM,uDAAwD,GAC/D,IACT,CACF,CAEA,IAAA,CAAK,GACH,MAAM,EAAU,KAAK,aACrB,GAAK,EAEL,IACE,EAAQ,QAAQ,KAAK,IAAK,KAAK,UAAU,IACzC,KAAK,cAAc,EACrB,CAAA,MAAS,GACP,QAAQ,MAAM,qDAAsD,EACtE,CACF,CAEA,KAAA,GACE,MAAM,EAAU,KAAK,aACrB,GAAK,EAEL,IACE,EAAQ,WAAW,KAAK,KAEpB,KAAK,kBAzHf,eAA4B,GAC1B,GAAwB,oBAAb,SAAX,CAGA,GAAI,gBAAiB,OACnB,IAEE,kBADM,OAAO,YAAY,OAAO,GAElC,CAAA,MAEA,CAKF,SAAS,OAAS,GAAG,uBAdgB,CAevC,CA0GQ,CAAa,wBAEjB,CAAA,MAAS,GACP,QAAQ,MAAM,6CAA8C,EAC9D,CACF,GAMW,EAAb,MACE,MACA,aACA,QACA,mBAEA,WAAA,CACE,EAA2B,QAC3B,EAAqB,wBACrB,GAA8B,GAE9B,KAAK,aAAe,IAAI,EACxB,KAAK,QAAU,IAAI,EAAe,EAAa,GAC/C,KAAK,mBAAqB,EAG1B,MAAM,EAAiB,KAAK,QAAQ,OACpC,KAAK,MAAQ,GAAkB,KAAK,iBACtC,CAEA,eAAA,GACE,MAAO,CACL,MAAO,CAAC,EACR,iBAAkB,CAAC,EAEvB,CAEA,OAAA,GACE,KAAK,QAAQ,KAAK,KAAK,MACzB,CAKA,aAAA,CACE,EACA,GAEA,OAAK,EAEiB,SAAlB,EAAS,KACJ,EAAS,MAGI,YAAlB,EAAS,KAEiB,iBAAjB,GAA8C,OAAjB,GAAyB,SAAU,EAClE,IACF,EACH,KAAM,EAAS,WACf,SAAS,GAIN,CACL,KAAM,EAAS,WACf,SAAS,GAMN,EAxBe,CAyBxB,CAKA,kBAAA,CACE,GAIA,OAFyB,KAAK,KAAK,MAAM,OAE/B,QAAS,IACjB,MAAM,EAAW,KAAK,MAAM,MAAM,GAClC,GAAK,EAEL,IACE,MAAM,aAAE,EAAA,eAAc,GAAmB,EAAU,GAGnD,KAAK,MAAM,MAAM,GAAY,IACxB,EACH,iBAAkB,EAClB,mBAAoB,EAExB,CAAA,MAAS,GAEP,QAAQ,MAAM,gDAAgD,KAAa,EAC7E,IAGF,KAAK,UAEL,KAAK,aAAa,KAAK,CACrB,KAAM,cACN,UAAW,KAAK,OAEpB,CAKA,QAAA,GACE,OAAO,KAAK,MAAM,KAAK,UAAU,KAAK,OACxC,CAKA,SAAA,CAAU,GACR,OAAO,KAAK,aAAa,UAAU,EACrC,CAKA,gBAAA,CACE,EACA,EACA,EACA,EACA,GAEA,MAAM,EAAW,KAAK,MAAM,MAAM,GAC5B,GAAa,EAEnB,KAAK,MAAM,MAAM,GAAQ,CACvB,WACA,iBAAkB,EAClB,mBAAoB,EACpB,YAAa,EACb,SAAU,GAAU,UAAY,MAGlC,KAAK,UAGD,GACF,KAAK,aAAa,KAAK,CACrB,KAAM,cACN,UAAW,KAAK,OAGtB,CAKA,eAAA,CAAgB,EAAc,GACvB,KAAK,MAAM,MAAM,IAWpB,KAAK,MAAM,MAAM,GAAM,SAAW,EAIlC,KAAK,MAAM,MAAM,GAAM,mBAAqB,KAAK,cAD5B,KAAK,MAAM,MAAM,GAAM,iBACiC,IAZ7E,KAAK,MAAM,MAAM,GAAQ,CACvB,SAFkC,YAAnB,GAAU,KAAqB,UAAY,OAG1D,iBAAkB,KAClB,mBAAoB,KAAK,cAAc,KAAM,GAC7C,YAAa,KACb,YAUJ,KAAK,UAEL,KAAK,aAAa,KAAK,CACrB,KAAM,wBACN,OACA,WACA,UAAW,KAAK,OAEpB,CAKA,eAAA,CAAgB,GACd,OAAO,KAAK,MAAM,MAAM,IAAO,UAAY,IAC7C,CAKA,kBAAA,CAAmB,GACjB,KAAK,MAAM,iBAAmB,IACzB,KAAK,MAAM,oBACX,GAGL,KAAK,UAEL,KAAK,aAAa,KAAK,CACrB,KAAM,2BACN,iBAAkB,KAAK,MAAM,kBAEjC,CAKA,qBAAA,CAAsB,GACpB,MAAM,EAAe,IAAK,KAAK,MAAM,yBAC9B,EAAa,GAGpB,KAAK,MAAM,iBAAmB,EAC9B,KAAK,UAEL,KAAK,aAAa,KAAK,CACrB,KAAM,2BACN,iBAAkB,KAAK,MAAM,kBAEjC,CAKA,gBAAA,CAAiB,EAA8B,CAAC,GAC9C,MAAO,IACF,KACA,KAAK,MAAM,iBACd,WAAY,IACN,EAAY,YAAc,CAAC,KAC3B,KAAK,MAAM,iBAAiB,YAAc,CAAC,GAGrD,CAKA,cAAA,GACE,OAAO,KAAK,KAAK,MAAM,OAAO,QAAS,IACrC,KAAK,MAAM,MAAM,GAAM,SAAW,KAIlC,KAAK,MAAM,MAAM,GAAM,mBADF,KAAK,MAAM,MAAM,GAAM,iBAI5C,KAAK,aAAa,KAAK,CACrB,KAAM,wBACN,OACA,SAAU,KACV,UAAW,KAAK,UAIpB,KAAK,SACP,CAKA,qBAAA,GACE,KAAK,MAAM,iBAAmB,CAAC,EAE/B,KAAK,UAEL,KAAK,aAAa,KAAK,CACrB,KAAM,2BACN,iBAAkB,CAAC,GAEvB,CAKA,aAAA,CAAc,GACZ,KAAK,MAAM,UAAY,EACvB,KAAK,SACP,CAKA,aAAA,GACE,OAAO,KAAK,MAAM,SACpB,CAKA,eAAA,CAAgB,GACd,KAAK,MAAM,aAAe,EAC1B,KAAK,SACP,CAKA,eAAA,GACE,OAAO,KAAK,MAAM,YACpB,CAKA,gBAAA,GACE,KAAK,QAAQ,OACf,CAKA,YAAA,GACE,MAAM,EAAQ,OAAO,KAAK,KAAK,MAAM,OACrC,OAAO,KAAK,mBAAqB,EAAM,OAAS,CAClD,CAKA,eAAA,CAAgB,GACd,OAAO,KAAK,MAAM,MAAM,IAAS,IACnC,CAMA,gBAAA,GACE,KAAK,QAAQ,sBAAqB,EACpC,GC1fF,SAAgB,EACd,EACA,GAGA,GAyOO,eAzOa,EAClB,OAAO,EAIT,MAAM,EAAsB,EAAW,aAGjC,iBAAkB,IAAI,IAG5B,IAAI,EAIJ,MAAM,EAA+C,CACnD,WAAY,EACZ,UAMF,SAAmB,GAEjB,MAAM,EAAiB,EAAW,aAC5B,EAAgB,EAAa,iBAAiB,GAG9C,EAAe,EAAW,UAAU,GAIpC,EAAiB,EAAkB,EADxB,EAAa,gBAAgB,IAM9C,OAFA,EAAa,iBAAiB,EAAY,OAAQ,EAAc,EAAgB,GAEzE,CACT,EArBE,WAuBF,SAAoB,GAElB,MAAM,EAAiB,EAAW,aAC5B,EAAgB,EAAa,iBAAiB,GAG9C,EAAe,EAAW,WAAW,GAIrC,EAAiB,EAAkB,EADxB,EAAa,gBAAgB,IAY9C,OARA,EAAa,iBACX,EACA,UACA,EACA,EACA,GAGK,CACT,EA5CE,WA8CF,WACE,MAAM,EAAc,EAAW,aAG/B,MAAO,CACL,QAAS,MAHI,EAAa,iBAAiB,GAM/C,EArDE,GAwDF,SAAmB,EAAe,GAOhC,MANc,WAAV,GACF,EAAgB,IAAI,GAGtB,EAAW,GAAG,EAAO,GAEd,CACT,GAGA,SAAS,IACP,EAAgB,QAAS,IACvB,IACE,GACF,CAAA,MAAS,GACP,QAAQ,MAAM,8CAA+C,EAC/D,GAEJ,CAyFA,OAtFA,EAAW,GAAG,SAAA,KAEZ,EAAa,mBAAoB,IAM/B,MAAM,EAHmC,YADxB,EAAa,gBAAgB,IAClB,SAIxB,EAAW,WAAW,GACtB,EAAW,UAAU,GAMzB,MAAO,CAAE,eAAc,eAFA,EAAkB,EADxB,EAAa,gBAAgB,SASlD,EAAa,UAAW,IACtB,GAAmB,6BAAf,EAAM,KAAqC,CAM7C,MAAQ,QAAS,EAAU,YAAa,KAAiB,GAHnC,EAAa,iBAAiB,GAMpD,EACG,cAAc,GACd,KAAA,KAEC,EAAa,mBAAoB,IAM/B,MAAM,EAHmC,YADxB,EAAa,gBAAgB,IAClB,SAIxB,EAAW,WAAW,GACtB,EAAW,UAAU,GAMzB,MAAO,CAAE,eAAc,eAFA,EAAkB,EADxB,EAAa,gBAAgB,OAMhD,MAED,MAAO,IACN,QAAQ,MAAM,8CAA+C,IAEnE,CAImB,0BAAf,EAAM,MACR,MAKJ,EAAc,IAAI,MAAM,EAAe,CACrC,GAAA,CAAI,EAAQ,GACV,GAAI,KAAQ,EACV,OAAO,QAAQ,IAAI,EAAQ,GAE7B,MAAM,EAAQ,QAAQ,IAAI,EAAY,GACtC,MAAwB,mBAAV,EAAuB,EAAM,KAAK,GAAc,CAChE,EACA,IAAA,CAAI,EAAQ,EAAM,IACZ,KAAQ,GACV,QAAQ,IAAI,EAAQ,EAAM,IACnB,IAET,QAAQ,IAAI,EAAY,EAAM,IACvB,KAIJ,CACT,CAKA,SAAS,EACP,EACA,GAEA,OAAK,EAEiB,SAAlB,EAAS,KACJ,EAAS,MAGI,YAAlB,EAAS,KAEiB,iBAAjB,GAA8C,OAAjB,GAAyB,SAAU,EAClE,IACF,EACH,KAAM,EAAS,WACf,SAAS,GAIN,CACL,KAAM,EAAS,WACf,SAAS,GAIN,EAtBe,CAuBxB,CCrNA,IAAa,EAAb,MACE,aACA,GACA,OAEA,WAAA,CACE,EACA,EACA,GAEA,KAAK,aAAe,EACpB,KAAK,OAAS,EACd,KAAK,GAAK,KAGV,KAAK,OAAO,EAAc,EAAe,EAC3C,CAEA,YAAc,CACZ,EACA,EACA,GAEA,MAAM,UAAE,SAAoB,OAAO,oBACnC,KAAK,GAAK,IAAI,EAAU,EAAc,EAAe,EACvD,CAEA,IAAA,GACM,KAAK,IAAI,KAAK,GAAG,MACvB,CAEA,IAAA,GACM,KAAK,IAAI,KAAK,GAAG,MACvB,CAEA,OAAA,GACM,KAAK,IAAI,KAAK,GAAG,UACrB,KAAK,aAAa,kBACpB,CAEA,QAAA,GACE,OAAO,KAAK,aAAa,UAC3B,CAEA,YAAA,GACE,OAAO,KAAK,aAAa,cAC3B,CAEA,eAAA,CAAgB,EAAc,GAC5B,KAAK,aAAa,gBAAgB,EAAM,EAC1C,CAEA,kBAAA,CAAmB,GACjB,KAAK,aAAa,mBAAmB,EACvC,CAEA,qBAAA,CAAsB,GACpB,KAAK,aAAa,sBAAsB,EAC1C,CAEA,cAAA,GACE,KAAK,aAAa,gBACpB,CAEA,qBAAA,GACE,KAAK,aAAa,uBACpB,GAWF,SAAgB,EACd,EACA,EAA8B,CAAC,GAE/B,MAGM,EAAmB,EAAQ,mBAAoB,EAE/C,EAAe,IAAI,EALL,EAAQ,aAAe,QACxB,EAAQ,YAAc,wBACd,EAAQ,qBAAsB,GAMrD,GACF,EAAa,mBAGf,MAAM,EAAgB,EAAkB,EAAQ,GAC1C,EAAU,IAAI,EAAe,EAAc,EAAe,GAQhE,MALsB,oBAAX,SAET,OAAgB,eAAiB,GAG5B,CACT,CAGsB,oBAAX,SAET,OAAgB,eAAiB,CAC/B,KAAM"} |
| 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} |
+196
| 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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"} |
+62
| 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 .", |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 2 instances
Mixed license
LicensePackage contains multiple licenses.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
Empty package
Supply chain riskPackage does not contain any code. It may be removed, is name squatting, or the result of a faulty package publish.
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
225356
612.75%41
1266.67%1031
Infinity%0
-100%1
-50%1
Infinity%4
Infinity%1
Infinity%