@usero/sdk 0.3.1 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/plugins/session-replay.cjs +324 -67
- package/dist/plugins/session-replay.cjs.map +1 -1
- package/dist/plugins/session-replay.d.cts +33 -11
- package/dist/plugins/session-replay.d.ts +33 -11
- package/dist/plugins/session-replay.js +324 -68
- package/dist/plugins/session-replay.js.map +1 -1
- package/dist/plugins/user-test.cjs +528 -0
- package/dist/plugins/user-test.cjs.map +1 -0
- package/dist/plugins/user-test.d.cts +63 -0
- package/dist/plugins/user-test.d.ts +63 -0
- package/dist/plugins/user-test.js +525 -0
- package/dist/plugins/user-test.js.map +1 -0
- package/dist/react.cjs +12 -0
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +2 -0
- package/dist/react.d.ts +2 -0
- package/dist/react.js +12 -0
- package/dist/react.js.map +1 -1
- package/dist/usero.iife.js +27 -27
- package/dist/usero.iife.js.map +1 -1
- package/dist/vanilla.cjs +12 -0
- package/dist/vanilla.cjs.map +1 -1
- package/dist/vanilla.d.cts +2 -0
- package/dist/vanilla.d.ts +2 -0
- package/dist/vanilla.js +12 -0
- package/dist/vanilla.js.map +1 -1
- package/package.json +6 -1
package/dist/vanilla.cjs
CHANGED
|
@@ -780,6 +780,17 @@ function initUseroFeedbackWidget(props) {
|
|
|
780
780
|
host.style.cssText = "all: initial;";
|
|
781
781
|
document.body.appendChild(host);
|
|
782
782
|
const root = host.attachShadow({ mode: "open" });
|
|
783
|
+
function notifyShadowUpdate(reason) {
|
|
784
|
+
try {
|
|
785
|
+
window.dispatchEvent(
|
|
786
|
+
new CustomEvent("usero:shadow-update", {
|
|
787
|
+
detail: { host, root, reason }
|
|
788
|
+
})
|
|
789
|
+
);
|
|
790
|
+
} catch {
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
notifyShadowUpdate("mount");
|
|
783
794
|
const style = document.createElement("style");
|
|
784
795
|
style.textContent = FEEDBACK_CSS;
|
|
785
796
|
root.appendChild(style);
|
|
@@ -806,6 +817,7 @@ function initUseroFeedbackWidget(props) {
|
|
|
806
817
|
apiClient.ping();
|
|
807
818
|
onOpen?.();
|
|
808
819
|
render();
|
|
820
|
+
notifyShadowUpdate("panel-open");
|
|
809
821
|
}
|
|
810
822
|
async function handleScreenshotFile(file) {
|
|
811
823
|
screenshotError = null;
|
package/dist/vanilla.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts","../src/api.ts","../src/colorUtils.ts","../src/plugin.ts","../src/validation.ts","../src/widgetCss.ts","../src/vanilla.ts"],"names":[],"mappings":"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AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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","file":"vanilla.cjs","sourcesContent":["// Shared types used by both the vanilla and React entry points.\n// Keep this file framework-free so the vanilla bundle never pulls react.\n\nexport type FeedbackRating = 1 | 2 | 3 | 4\n\nexport interface FeedbackMetadata {\n\tpageUrl: string\n\tpageTitle: string\n\treferrer?: string\n\ttimestamp: number\n}\n\nexport interface ScreenshotData {\n\tfileName: string\n\turl: string\n\tfileSize: number\n\twidth?: number\n\theight?: number\n\tmimeType: string\n}\n\nexport interface FeedbackSubmission {\n\tclientId: string\n\trating?: FeedbackRating\n\tcomment?: string\n\tuserEmail?: string\n\tpageUrl: string\n\tpageTitle: string\n\treferrer?: string\n\tenvironment?: string\n\tscreenshots?: ScreenshotData[]\n\tmetadata?: Record<string, unknown>\n\t// Gzipped + base64-encoded rrweb event stream attached by the\n\t// session-replay plugin. Optional, only present when that plugin is\n\t// installed and has buffered events at submission time.\n\treplayEvents?: string\n}\n\nexport interface FeedbackData {\n\trating?: FeedbackRating\n\tcomment?: string\n\tuserEmail?: string\n\tscreenshots?: ScreenshotData[]\n\tmetadata: FeedbackMetadata\n}\n\nexport type WidgetPosition = 'right' | 'left'\n\nexport interface WidgetTheme {\n\tprimary: string\n\tbackground: string\n\ttext: string\n\tborder: string\n\tshadow: string\n}\n\n// Forward-declared to avoid a circular import. The plugin module imports\n// FeedbackSubmission from this file, so we can't import UseroPlugin back\n// up here without a cycle. Keeping the prop typed as an opaque object with\n// the minimal shape the widget actually inspects works fine for consumers.\nexport interface FeedbackWidgetProps {\n\tclientId: string\n\tposition?: WidgetPosition\n\ttheme?: Partial<WidgetTheme>\n\ttitle?: string\n\tplaceholder?: string\n\tshowEmailOption?: boolean\n\tshowScreenshotOption?: boolean\n\tenvironment?: string\n\tbaseUrl?: string\n\tmetadata?: Record<string, unknown>\n\tplugins?: ReadonlyArray<import('./plugin').UseroPlugin>\n\tonSubmit?: (feedback: FeedbackData) => void\n\tonError?: (error: Error) => void\n\tonOpen?: () => void\n\tonClose?: () => void\n}\n\nexport interface SubmissionResponse {\n\tsuccess: boolean\n\terror?: string\n\tid?: string\n\tmessage?: string\n\tdata?: unknown\n}\n\nexport const EMOJI_MAP: Record<FeedbackRating, string> = {\n\t1: '😞',\n\t2: '😐',\n\t3: '😊',\n\t4: '🤩',\n}\n\nexport const RATING_LABELS: Record<FeedbackRating, string> = {\n\t1: 'Needs work',\n\t2: \"It's okay\",\n\t3: 'Pretty good',\n\t4: 'Amazing!',\n}\n\nexport const EMOJI_BACKGROUNDS: Record<FeedbackRating, string> = {\n\t1: 'linear-gradient(135deg,#ff6b6b14,#ff6b6b1f)',\n\t2: 'linear-gradient(135deg,#9ca3af0f,#9ca3af1a)',\n\t3: 'linear-gradient(135deg,#3b82f614,#3b82f61f)',\n\t4: 'linear-gradient(135deg,#f59e0b14,#f59e0b1f)',\n}\n\nexport const DEFAULT_API_URL = 'https://usero.io'\n\nexport const DEFAULT_THEME: WidgetTheme = {\n\tprimary: '#2563eb',\n\tbackground: '#ffffff',\n\ttext: '#374151',\n\tborder: '#e5e7eb',\n\tshadow:\n\t\t'0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',\n}\n\nexport const DARK_THEME: WidgetTheme = {\n\tprimary: '#2563eb',\n\tbackground: '#1f2937',\n\ttext: '#f9fafb',\n\tborder: '#374151',\n\tshadow:\n\t\t'0 10px 15px -3px rgba(0, 0, 0, 0.3), 0 4px 6px -2px rgba(0, 0, 0, 0.2)',\n}\n\nexport function mergeTheme(customTheme: Partial<WidgetTheme> = {}): WidgetTheme {\n\treturn { ...DEFAULT_THEME, ...customTheme }\n}\n","import {\n\tDEFAULT_API_URL,\n\ttype FeedbackSubmission,\n\ttype ScreenshotData,\n\ttype SubmissionResponse,\n} from './types'\n\ninterface JsonErrorBody {\n\terror?: string\n}\n\nfunction isJsonErrorBody(value: unknown): value is JsonErrorBody {\n\treturn typeof value === 'object' && value !== null && 'error' in value\n}\n\ninterface ScreenshotUploadResponseBody {\n\tsuccess: boolean\n\terror?: string\n\tscreenshot?: ScreenshotData\n}\n\nfunction parseScreenshotUploadBody(\n\tvalue: unknown,\n): ScreenshotUploadResponseBody {\n\tif (typeof value !== 'object' || value === null) {\n\t\treturn { success: false, error: 'Invalid response' }\n\t}\n\tconst obj = value as Record<string, unknown>\n\tconst success = obj.success === true\n\tconst error = typeof obj.error === 'string' ? obj.error : undefined\n\tconst rawShot = obj.screenshot\n\tlet screenshot: ScreenshotData | undefined\n\tif (typeof rawShot === 'object' && rawShot !== null) {\n\t\tconst s = rawShot as Record<string, unknown>\n\t\tif (\n\t\t\ttypeof s.fileName === 'string' &&\n\t\t\ttypeof s.url === 'string' &&\n\t\t\ttypeof s.fileSize === 'number' &&\n\t\t\ttypeof s.mimeType === 'string'\n\t\t) {\n\t\t\tscreenshot = {\n\t\t\t\tfileName: s.fileName,\n\t\t\t\turl: s.url,\n\t\t\t\tfileSize: s.fileSize,\n\t\t\t\tmimeType: s.mimeType,\n\t\t\t\twidth: typeof s.width === 'number' ? s.width : undefined,\n\t\t\t\theight: typeof s.height === 'number' ? s.height : undefined,\n\t\t\t}\n\t\t}\n\t}\n\treturn { success, error, screenshot }\n}\n\nexport class FeedbackApiClient {\n\tprivate baseUrl: string\n\n\tconstructor(baseUrl: string = DEFAULT_API_URL) {\n\t\tthis.baseUrl = baseUrl.replace(/\\/$/, '')\n\t}\n\n\tasync submitFeedback(data: FeedbackSubmission): Promise<SubmissionResponse> {\n\t\ttry {\n\t\t\tconst response = await fetch(`${this.baseUrl}/api/feedback`, {\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders: {\n\t\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t\tAccept: 'application/json',\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify(data),\n\t\t\t\tsignal: AbortSignal.timeout(10000),\n\t\t\t})\n\n\t\t\tif (!response.ok) {\n\t\t\t\tlet errorMessage = `HTTP ${response.status}: ${response.statusText}`\n\t\t\t\ttry {\n\t\t\t\t\tconst errorData: unknown = await response.json()\n\t\t\t\t\tif (isJsonErrorBody(errorData) && typeof errorData.error === 'string') {\n\t\t\t\t\t\terrorMessage = errorData.error\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// Ignore JSON parse errors\n\t\t\t\t}\n\t\t\t\tthrow new Error(errorMessage)\n\t\t\t}\n\n\t\t\tconst result: unknown = await response.json()\n\t\t\tconst message =\n\t\t\t\ttypeof result === 'object' &&\n\t\t\t\tresult !== null &&\n\t\t\t\t'message' in result &&\n\t\t\t\ttypeof (result as { message: unknown }).message === 'string'\n\t\t\t\t\t? (result as { message: string }).message\n\t\t\t\t\t: 'Feedback submitted successfully'\n\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tdata: result,\n\t\t\t\tmessage,\n\t\t\t}\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror:\n\t\t\t\t\terror instanceof Error ? error.message : 'An unexpected error occurred',\n\t\t\t}\n\t\t}\n\t}\n\n\tasync uploadScreenshot(\n\t\tfile: File,\n\t\tclientId: string,\n\t): Promise<ScreenshotData> {\n\t\tconst formData = new FormData()\n\t\tformData.append('screenshot', file)\n\t\tformData.append('clientId', clientId)\n\n\t\tconst response = await fetch(`${this.baseUrl}/api/screenshots`, {\n\t\t\tmethod: 'POST',\n\t\t\tbody: formData,\n\t\t\tsignal: AbortSignal.timeout(30000),\n\t\t})\n\n\t\tlet body: ScreenshotUploadResponseBody = { success: false }\n\t\ttry {\n\t\t\tconst raw: unknown = await response.json()\n\t\t\tbody = parseScreenshotUploadBody(raw)\n\t\t} catch {\n\t\t\t// fall through to error handling below\n\t\t}\n\n\t\tif (!response.ok || !body.success || !body.screenshot) {\n\t\t\tconst message =\n\t\t\t\tbody.error ?? `HTTP ${response.status}: ${response.statusText}`\n\t\t\tthrow new Error(message)\n\t\t}\n\n\t\treturn body.screenshot\n\t}\n\n\tping(): void {\n\t\tfetch(`${this.baseUrl}/api/ping`, {\n\t\t\tsignal: AbortSignal.timeout(5000),\n\t\t}).catch(() => {})\n\t}\n}\n","export function colorNameToHex(color: string): string {\n\tif (color.startsWith('#')) return color\n\tif (typeof document === 'undefined') return color\n\n\tconst canvas = document.createElement('canvas')\n\tconst ctx = canvas.getContext('2d')\n\tif (!ctx) return color\n\n\tctx.fillStyle = color\n\treturn ctx.fillStyle\n}\n\nexport function getGradientEnd(color: string): string {\n\tconst hex = colorNameToHex(color)\n\tif (!hex.startsWith('#') || hex.length < 7) return hex\n\tconst r = parseInt(hex.slice(1, 3), 16)\n\tconst g = parseInt(hex.slice(3, 5), 16)\n\tconst b = parseInt(hex.slice(5, 7), 16)\n\tconst shiftedR = Math.max(0, r - 60)\n\tconst shiftedG = Math.min(255, g + 40)\n\tconst shiftedB = Math.min(255, b + 20)\n\treturn `#${[shiftedR, shiftedG, shiftedB]\n\t\t.map(x => x.toString(16).padStart(2, '0'))\n\t\t.join('')}`\n}\n","// Plugin contract for the Usero widget.\n//\n// Plugins are opt-in modules that hook into the widget lifecycle to enrich\n// feedback submissions or react to widget events. They live in subpath\n// exports (e.g. `@usero/sdk/plugins/session-replay`) so consumers who don't\n// import them pay zero bundle cost.\n//\n// Design rules:\n// 1. The plugin contract MUST stay framework-free (no React types).\n// 2. `onInit` runs fire-and-forget so a slow plugin never blocks the\n// widget from rendering. Plugins that need to be ready before the\n// first interaction are responsible for their own gating internally.\n// 3. `onFeedbackSubmit` is awaited and its return value is merged into\n// the outgoing payload. Top-level keys are shallow-merged (later\n// plugins win wholesale); `metadata` is deep-merged one level so two\n// plugins can both contribute keys without clobbering each other.\n// Plugins MUST return quickly (a few hundred ms at most) or risk users\n// abandoning the submit.\n// 4. Plugin errors are caught and logged; they never block a submission.\n\nimport type { FeedbackSubmission } from './types'\n\nexport interface PluginLogger {\n\tdebug: (...args: unknown[]) => void\n\tinfo: (...args: unknown[]) => void\n\twarn: (...args: unknown[]) => void\n\terror: (...args: unknown[]) => void\n}\n\nexport interface PluginContext {\n\tclientId: string\n\tbaseUrl: string\n\t// Per-plugin scratch store. Plugins can stash state across hook calls\n\t// without leaking into globals. The key is the plugin's `name`.\n\tgetStore: <T>() => T | undefined\n\tsetStore: <T>(value: T) => void\n\tlogger: PluginLogger\n}\n\nexport interface UseroPlugin {\n\t// Stable, unique identifier. Used as the store key and in log prefixes.\n\t// Convention: lowercase kebab-case (e.g. `session-replay`).\n\tname: string\n\tonInit?: (ctx: PluginContext) => void | Promise<void>\n\t// Returns a partial submission patch that gets merged into the outgoing\n\t// payload. Top-level keys are shallow-merged (later plugins win on\n\t// conflict); `metadata` is deep-merged one level so multiple plugins\n\t// can each attach their own metadata keys without clobbering. Return\n\t// `undefined` to contribute nothing.\n\tonFeedbackSubmit?: (\n\t\tctx: PluginContext,\n\t\tsubmission: FeedbackSubmission,\n\t) => Promise<Partial<FeedbackSubmission> | undefined> | Partial<FeedbackSubmission> | undefined\n\tonDestroy?: (ctx: PluginContext) => void\n}\n\nexport function createPluginLogger(name: string): PluginLogger {\n\tconst prefix = `[usero:${name}]`\n\treturn {\n\t\tdebug: (...args) => {\n\t\t\tif (typeof console !== 'undefined') console.debug(prefix, ...args)\n\t\t},\n\t\tinfo: (...args) => {\n\t\t\tif (typeof console !== 'undefined') console.info(prefix, ...args)\n\t\t},\n\t\twarn: (...args) => {\n\t\t\tif (typeof console !== 'undefined') console.warn(prefix, ...args)\n\t\t},\n\t\terror: (...args) => {\n\t\t\tif (typeof console !== 'undefined') console.error(prefix, ...args)\n\t\t},\n\t}\n}\n","import type { FeedbackSubmission } from './types'\n\nexport interface ValidationResult {\n\tisValid: boolean\n\terrors: string[]\n}\n\nexport function validateFeedbackSubmission(\n\tdata: Partial<FeedbackSubmission>,\n): ValidationResult {\n\tconst errors: string[] = []\n\tconst hasRating = data.rating != null\n\tconst hasComment = !!data.comment?.trim()\n\n\tif (!hasRating && !hasComment) {\n\t\terrors.push('Add rating or comment')\n\t}\n\tif (hasRating && data.rating !== undefined && ![1, 2, 3, 4].includes(data.rating)) {\n\t\terrors.push('Invalid rating')\n\t}\n\tif (hasComment && data.comment !== undefined) {\n\t\tif (data.comment.length > 1000) {\n\t\t\terrors.push('Comment too long')\n\t\t}\n\t\tif (/<script[^>]*>.*?<\\/script>/gi.test(data.comment)) {\n\t\t\terrors.push('Invalid comment')\n\t\t}\n\t}\n\n\treturn {\n\t\tisValid: errors.length === 0,\n\t\terrors,\n\t}\n}\n","// CSS used by both entry points.\n//\n// React entry injects it once into <head> via injectFeedbackCSS().\n// Vanilla entry injects it inside a shadow root, so host page styles\n// can't bleed in and our class names can't collide with the host.\n\nexport const FEEDBACK_CSS = `\n@keyframes spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n}\n\n.fb-es {\n display: flex;\n justify-content: center;\n gap: 12px;\n padding-bottom: 8px;\n}\n\n.fb-ec {\n border-radius: 16px;\n padding: 0 5px;\n transition: all 300ms cubic-bezier(0.68, -0.55, 0.265, 1.55);\n border: 3px solid transparent;\n cursor: pointer;\n text-align: center;\n}\n\n.fb-ec--sel {\n border-color: #2563eb;\n transform: scale(1.05);\n box-shadow: 0 4px 15px rgba(37, 99, 235, 0.2);\n}\n\n.fb-ec--hov:not(.fb-ec--sel) {\n transform: scale(1.05);\n}\n\n.fb-eb {\n background: transparent;\n border: none;\n cursor: pointer;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 2px;\n width: 100%;\n padding: 0;\n transition: all 200ms ease;\n}\n\n.fb-ei {\n font-size: 36px;\n transition: transform 200ms ease;\n}\n\n.fb-ei--hov {\n transform: scale(1.1);\n}\n\n.fb-el {\n font-size: 13px;\n font-weight: 600;\n color: currentColor;\n line-height: 1.2;\n}\n\n.fb-hdr {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding-bottom: 4px;\n margin-bottom: 10px;\n}\n\n.fb-msg {\n font-size: 14px;\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px;\n margin-bottom: 8px;\n border-radius: 6px;\n}\n\n.fb-msg--header {\n font-size: 12px;\n padding: 4px 8px;\n margin-bottom: 0;\n margin-left: auto;\n margin-right: 8px;\n}\n\n.fb-msg--ok {\n background-color: #f0fdf4;\n border: 1px solid #bbf7d0;\n color: #16a34a;\n}\n\n.fb-msg--err {\n background-color: #fef2f2;\n border: 1px solid #fecaca;\n color: #dc2626;\n}\n\n.fb-sub {\n width: 100%;\n padding: 12px 24px;\n border: none;\n border-radius: 12px;\n font-size: 15px;\n font-weight: 600;\n cursor: pointer;\n transition: all 200ms ease;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n}\n\n.fb-sub--dis {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.fb-spin {\n width: 16px;\n height: 16px;\n border: 2px solid transparent;\n border-top: 2px solid currentColor;\n border-radius: 50%;\n animation: spin 1s linear infinite;\n}\n\n.fb-cnt {\n padding: 20px 24px 16px;\n overflow: auto;\n max-height: calc(90vh - 48px);\n}\n\n.fb-ttl {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n}\n\n.fb-ta {\n width: 100%;\n min-height: 80px;\n padding: 10px;\n border-radius: 8px;\n font-size: 14px;\n font-family: inherit;\n outline: none;\n resize: vertical;\n transition: border-color 150ms ease;\n margin-bottom: 2px;\n box-sizing: border-box;\n}\n\n.fb-toolrow {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n margin-bottom: 8px;\n}\n\n.fb-charcount {\n font-size: 12px;\n margin-left: auto;\n text-align: right;\n}\n\n.fb-charcount--low {\n color: #dc2626;\n}\n\n.fb-email {\n display: flex;\n flex-direction: column;\n gap: 6px;\n margin-bottom: 10px;\n}\n\n.fb-email-lbl {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n}\n\n.fb-email-cb {\n margin: 0;\n cursor: pointer;\n}\n\n.fb-email-inp {\n width: 100%;\n padding: 8px 12px;\n border-radius: 4px;\n font-size: 14px;\n outline: none;\n transition: border-color 150ms ease;\n box-sizing: border-box;\n}\n\n.fb-btn {\n position: fixed;\n width: 50px;\n height: 50px;\n border: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 18px;\n transition: all 300ms cubic-bezier(0.68, -0.55, 0.265, 1.55);\n z-index: 9998;\n color: #ffffff;\n top: 50%;\n transform: translateY(-50%);\n box-shadow: 0 4px 15px rgba(37, 99, 235, 0.3);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Roboto\", \"Helvetica Neue\", Arial, sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n box-sizing: border-box;\n}\n\n.fb-btn--right {\n right: -25px;\n border-radius: 40px 0 0 40px;\n padding-right: 8px;\n box-shadow: -4px 0 15px rgba(37, 99, 235, 0.3);\n}\n\n.fb-btn--left {\n left: -25px;\n border-radius: 0 40px 40px 0;\n padding-left: 8px;\n box-shadow: 4px 0 15px rgba(37, 99, 235, 0.3);\n}\n\n.fb-btn--right.fb-btn--open {\n right: -15px;\n transform: translateY(-50%) scale(1.05);\n}\n\n.fb-btn--left.fb-btn--open {\n left: -15px;\n transform: translateY(-50%) scale(1.05);\n}\n\n.fb-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: rgba(0, 0, 0, 0.3);\n transition: opacity 300ms ease;\n z-index: 9999;\n backdrop-filter: blur(8px);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Roboto\", \"Helvetica Neue\", Arial, sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n box-sizing: border-box;\n}\n\n.fb-pnl-base {\n position: fixed;\n top: 10vh;\n width: 400px;\n max-width: 90vw;\n max-height: 60vh;\n box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);\n transition: transform 300ms cubic-bezier(0.25, 0.46, 0.45, 0.94);\n z-index: 10000;\n display: flex;\n flex-direction: column;\n overflow-y: auto;\n overflow-x: hidden;\n border-radius: 16px;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Roboto\", \"Helvetica Neue\", Arial, sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n box-sizing: border-box;\n}\n\n.fb-pnl--right { right: 0; }\n.fb-pnl--right.fb-pnl--open { transform: translateX(0px); }\n.fb-pnl--right.fb-pnl--closed { transform: translateX(100%); }\n\n.fb-pnl--left { left: 0; }\n.fb-pnl--left.fb-pnl--open { transform: translateX(0px); }\n.fb-pnl--left.fb-pnl--closed { transform: translateX(-100%); }\n\n.fb-close-btn {\n background: none;\n border: none;\n font-size: 24px;\n cursor: pointer;\n opacity: 0.7;\n padding: 0;\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 4px;\n transition: background-color 150ms ease;\n}\n\n.fb-up {\n display: flex;\n flex-direction: column;\n gap: 6px;\n margin-bottom: 8px;\n}\n\n.fb-upb {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n align-self: flex-start;\n padding: 8px 12px;\n border-radius: 8px;\n background: transparent;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: background-color 150ms ease, opacity 150ms ease;\n font-family: inherit;\n}\n\n.fb-upb:hover:not(.fb-upb--dis) {\n background-color: rgba(37, 99, 235, 0.06);\n}\n\n.fb-upb--dis {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.fb-ups {\n width: 12px;\n height: 12px;\n border: 2px solid transparent;\n border-top: 2px solid currentColor;\n border-radius: 50%;\n animation: spin 1s linear infinite;\n display: inline-block;\n}\n\n.fb-up-extras {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.fb-upe {\n font-size: 12px;\n color: #dc2626;\n}\n\n.fb-ss {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.fb-sp {\n position: relative;\n width: 64px;\n height: 64px;\n border-radius: 6px;\n overflow: hidden;\n border: 1px solid rgba(0, 0, 0, 0.08);\n}\n\n.fb-si {\n width: 100%;\n height: 100%;\n object-fit: cover;\n display: block;\n}\n\n.fb-sr {\n position: absolute;\n top: 2px;\n right: 2px;\n width: 18px;\n height: 18px;\n border-radius: 50%;\n border: none;\n background: rgba(0, 0, 0, 0.65);\n color: #fff;\n font-size: 11px;\n line-height: 1;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n}\n\n.fb-sr:hover {\n background: rgba(0, 0, 0, 0.85);\n}\n\n.fb-sl {\n font-size: 11px;\n opacity: 0.6;\n}\n\n@media (max-width: 768px) {\n .fb-pnl-base {\n width: 100% !important;\n max-width: none !important;\n top: 4vh !important;\n max-height: 92vh !important;\n }\n .fb-cnt { padding: 16px 18px 14px !important; max-height: calc(100vh - 40px) !important; }\n .fb-ta { font-size: 16px !important; min-height: 64px !important; }\n .fb-ttl { font-size: 18px !important; }\n .fb-ei { font-size: 24px !important; }\n .fb-el { font-size: 11px !important; }\n .fb-sub { padding: 12px 20px !important; font-size: 16px !important; }\n}\n`\n\nexport function injectFeedbackCSS(): void {\n\tif (typeof document === 'undefined') return\n\tconst styleId = 'usero-feedback-widget-css'\n\tif (document.getElementById(styleId)) return\n\tconst style = document.createElement('style')\n\tstyle.id = styleId\n\tstyle.textContent = FEEDBACK_CSS\n\tdocument.head.appendChild(style)\n}\n","// Framework-free Usero widget. Renders into a shadow root attached to a\n// container <div> on document.body so host page styles cannot bleed in\n// and our class names cannot collide with the host's.\n//\n// API:\n// const widget = initUseroFeedbackWidget({ clientId: '...' })\n// widget.destroy()\n//\n// The endpoint and request shape match the React widget exactly so a\n// feedback row created here is indistinguishable from one created via React.\n\nimport { FeedbackApiClient } from './api'\nimport { getGradientEnd } from './colorUtils'\nimport {\n\tcreatePluginLogger,\n\ttype PluginContext,\n\ttype UseroPlugin,\n} from './plugin'\nimport { DEFAULT_API_URL } from './types'\nimport {\n\tDARK_THEME,\n\tDEFAULT_THEME,\n\tEMOJI_BACKGROUNDS,\n\tEMOJI_MAP,\n\ttype FeedbackData,\n\ttype FeedbackRating,\n\ttype FeedbackSubmission,\n\ttype FeedbackWidgetProps,\n\tmergeTheme,\n\tRATING_LABELS,\n\ttype ScreenshotData,\n\ttype WidgetPosition,\n\ttype WidgetTheme,\n} from './types'\nimport { validateFeedbackSubmission } from './validation'\nimport { FEEDBACK_CSS } from './widgetCss'\n\nexport {\n\tDARK_THEME,\n\tDEFAULT_THEME,\n\tmergeTheme,\n}\n\n// Pick the base theme to merge user overrides onto, based on the OS color\n// scheme. Defaults to dark when matchMedia is unavailable (SSR, old browsers)\n// or when neither dark nor light is explicitly preferred.\nfunction resolveBaseTheme(): WidgetTheme {\n\tif (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {\n\t\treturn DARK_THEME\n\t}\n\tif (window.matchMedia('(prefers-color-scheme: dark)').matches) return DARK_THEME\n\tif (window.matchMedia('(prefers-color-scheme: light)').matches) return DEFAULT_THEME\n\treturn DARK_THEME\n}\n\n// Resolve the effective theme. If the caller passed a partial theme, it wins\n// per-key over the OS-resolved base. If they passed nothing, we just use the\n// OS-resolved base directly.\nexport function resolveTheme(userTheme: Partial<WidgetTheme> | undefined): WidgetTheme {\n\tconst base = resolveBaseTheme()\n\tif (!userTheme) return base\n\treturn { ...base, ...userTheme }\n}\nexport type {\n\tFeedbackData,\n\tFeedbackRating,\n\tFeedbackSubmission,\n\tFeedbackWidgetProps,\n\tScreenshotData,\n\tWidgetPosition,\n\tWidgetTheme,\n} from './types'\nexport type {\n\tPluginContext,\n\tPluginLogger,\n\tUseroPlugin,\n} from './plugin'\n\nexport interface UseroWidgetHandle {\n\tdestroy: () => void\n\topen: () => void\n\tclose: () => void\n\t// Hot-swap any subset of props EXCEPT `clientId` and `baseUrl`. Changing\n\t// those requires destroy + re-init (the API client is bound to baseUrl,\n\t// and clientId is the identity of the widget). Callers (e.g. the React\n\t// wrapper) typically route callbacks through this so identity changes on\n\t// re-render don't force a tear-down.\n\tupdate: (next: Partial<Omit<FeedbackWidgetProps, 'clientId' | 'baseUrl'>>) => void\n\t// Resolves once every plugin's `onInit` promise has settled (fulfilled\n\t// OR rejected). Intended for end-to-end tests and dogfooding scripts\n\t// that want to trigger a synthetic submit only after plugins are live.\n\t// Plugins with synchronous `onInit` make this resolve on the next\n\t// microtask. If no plugins are registered, it resolves immediately.\n\twhenReady: () => Promise<void>\n}\n\nconst EMAIL_STORAGE_KEY = 'feedback_user_email'\n\nfunction escapeHtml(value: string): string {\n\treturn value.replace(/[&<>\"']/g, ch => {\n\t\tswitch (ch) {\n\t\t\tcase '&':\n\t\t\t\treturn '&'\n\t\t\tcase '<':\n\t\t\t\treturn '<'\n\t\t\tcase '>':\n\t\t\t\treturn '>'\n\t\t\tcase '\"':\n\t\t\t\treturn '"'\n\t\t\tcase \"'\":\n\t\t\t\treturn '''\n\t\t\tdefault:\n\t\t\t\treturn ch\n\t\t}\n\t})\n}\n\n// Merge plugin onFeedbackSubmit patches into a base submission.\n//\n// Top-level keys: shallow-merge, later patches win wholesale.\n// `metadata`: deep-merge one level. Earlier keys are preserved when later\n// patches don't set them; later keys win on conflict. This means two\n// plugins can both contribute `metadata: { ... }` without either erasing\n// the other's keys.\nexport function mergePluginPatches(\n\tbase: FeedbackSubmission,\n\tpatches: ReadonlyArray<Partial<FeedbackSubmission> | undefined>,\n): FeedbackSubmission {\n\tlet result: FeedbackSubmission = base\n\tfor (const patch of patches) {\n\t\tif (!patch || typeof patch !== 'object') continue\n\t\tconst { metadata: patchMetadata, ...rest } = patch\n\t\tresult = { ...result, ...rest }\n\t\tif (patchMetadata && typeof patchMetadata === 'object') {\n\t\t\tresult.metadata = {\n\t\t\t\t...(result.metadata ?? {}),\n\t\t\t\t...patchMetadata,\n\t\t\t}\n\t\t}\n\t}\n\treturn result\n}\n\nfunction readStoredEmail(): string {\n\tif (typeof window === 'undefined') return ''\n\ttry {\n\t\treturn window.localStorage.getItem(EMAIL_STORAGE_KEY) ?? ''\n\t} catch {\n\t\treturn ''\n\t}\n}\n\nfunction writeStoredEmail(email: string): void {\n\ttry {\n\t\twindow.localStorage.setItem(EMAIL_STORAGE_KEY, email)\n\t} catch {\n\t\t// ignore\n\t}\n}\n\nexport function initUseroFeedbackWidget(\n\tprops: FeedbackWidgetProps,\n): UseroWidgetHandle {\n\tif (typeof document === 'undefined') {\n\t\treturn {\n\t\t\tdestroy: () => {},\n\t\t\topen: () => {},\n\t\t\tclose: () => {},\n\t\t\tupdate: () => {},\n\t\t\twhenReady: () => Promise.resolve(),\n\t\t}\n\t}\n\n\tconst { clientId, baseUrl } = props\n\n\tif (!clientId || clientId.length < 3) {\n\t\tconst err = new Error('Invalid config. Contact admin.')\n\t\tprops.onError?.(err)\n\t\treturn {\n\t\t\tdestroy: () => {},\n\t\t\topen: () => {},\n\t\t\tclose: () => {},\n\t\t\tupdate: () => {},\n\t\t\twhenReady: () => Promise.resolve(),\n\t\t}\n\t}\n\n\t// Mutable view of every prop that can be hot-swapped via update(). Read\n\t// these at render time, never destructure into local const above the\n\t// render closures or you'll capture stale values.\n\tlet position: WidgetPosition = props.position ?? 'right'\n\tlet userThemeOverride: Partial<WidgetTheme> | undefined = props.theme\n\tlet theme: WidgetTheme = resolveTheme(userThemeOverride)\n\tlet title: string = props.title ?? 'Share Feedback'\n\tlet placeholder: string = props.placeholder ?? 'Tell us what you think... (optional)'\n\tlet showEmailOption: boolean = props.showEmailOption ?? true\n\tlet showScreenshotOption: boolean = props.showScreenshotOption ?? true\n\tlet environment: string | undefined = props.environment\n\tlet metadata: Record<string, unknown> | undefined = props.metadata\n\tlet onSubmit: FeedbackWidgetProps['onSubmit'] = props.onSubmit\n\tlet onError: FeedbackWidgetProps['onError'] = props.onError\n\tlet onOpen: FeedbackWidgetProps['onOpen'] = props.onOpen\n\tlet onClose: FeedbackWidgetProps['onClose'] = props.onClose\n\n\tconst apiClient = new FeedbackApiClient(baseUrl)\n\n\t// Plugin registry. Each plugin gets its own context with a private store.\n\t// `onInit` is fired non-blocking so a slow plugin can't delay the first\n\t// paint. Errors are caught so a misbehaving plugin can't tear the widget\n\t// down or block submissions.\n\tconst pluginList: ReadonlyArray<UseroPlugin> = props.plugins ?? []\n\tconst pluginStores = new Map<string, unknown>()\n\tconst pluginContexts = new Map<string, PluginContext>()\n\t// Tracks every onInit's settlement so `whenReady()` can resolve only\n\t// after all plugins have finished initializing. Synchronous onInits\n\t// resolve on the next microtask via Promise.resolve().\n\tconst initPromises: Promise<void>[] = []\n\tfor (const plugin of pluginList) {\n\t\tconst ctx: PluginContext = {\n\t\t\tclientId,\n\t\t\tbaseUrl: baseUrl ?? DEFAULT_API_URL,\n\t\t\tlogger: createPluginLogger(plugin.name),\n\t\t\tgetStore: <T,>() => pluginStores.get(plugin.name) as T | undefined,\n\t\t\tsetStore: <T,>(value: T) => {\n\t\t\t\tpluginStores.set(plugin.name, value)\n\t\t\t},\n\t\t}\n\t\tpluginContexts.set(plugin.name, ctx)\n\t\tif (plugin.onInit) {\n\t\t\tconst settled = (async () => {\n\t\t\t\ttry {\n\t\t\t\t\tawait plugin.onInit?.(ctx)\n\t\t\t\t} catch (err) {\n\t\t\t\t\tctx.logger.error('onInit threw', err)\n\t\t\t\t}\n\t\t\t})()\n\t\t\tinitPromises.push(settled)\n\t\t}\n\t}\n\tconst readyPromise: Promise<void> =\n\t\tinitPromises.length === 0 ? Promise.resolve() : Promise.all(initPromises).then(() => {})\n\n\t// State\n\tlet isOpen = false\n\tlet selectedRating: FeedbackRating | undefined = undefined\n\tlet comment = ''\n\tlet shareEmail = false\n\tlet userEmail = readStoredEmail()\n\tlet isSubmitting = false\n\tlet submitMessage: { type: 'success' | 'error'; text: string } | null = null\n\tlet screenshots: ScreenshotData[] = []\n\tlet isUploadingScreenshot = false\n\tlet screenshotError: string | null = null\n\n\tconst MAX_SCREENSHOTS = 3\n\tconst MAX_SCREENSHOT_BYTES = 10 * 1024 * 1024 // 10MB, matches old React widget\n\n\t// Host element on the page. ShadowRoot keeps host CSS isolated.\n\tconst host = document.createElement('div')\n\thost.setAttribute('data-usero-widget', '')\n\t// position: static so the host element doesn't take any space; the\n\t// fixed-position children inside the shadow root anchor to the viewport.\n\thost.style.cssText = 'all: initial;'\n\tdocument.body.appendChild(host)\n\tconst root = host.attachShadow({ mode: 'open' })\n\n\t// Inject styles once into the shadow root.\n\tconst style = document.createElement('style')\n\tstyle.textContent = FEEDBACK_CSS\n\troot.appendChild(style)\n\n\t// Containers\n\tconst buttonEl = document.createElement('button')\n\tconst backdropEl = document.createElement('div')\n\tconst panelEl = document.createElement('div')\n\troot.appendChild(buttonEl)\n\troot.appendChild(backdropEl)\n\troot.appendChild(panelEl)\n\n\tfunction setSubmitMessage(\n\t\tnext: { type: 'success' | 'error'; text: string } | null,\n\t): void {\n\t\tsubmitMessage = next\n\t\trender()\n\t}\n\n\tfunction open(): void {\n\t\tif (isOpen) return\n\t\tisOpen = true\n\t\t// Reset transient state\n\t\tselectedRating = undefined\n\t\tcomment = ''\n\t\tshareEmail = false\n\t\tsubmitMessage = null\n\t\tscreenshots = []\n\t\tscreenshotError = null\n\t\tisUploadingScreenshot = false\n\t\tapiClient.ping()\n\t\tonOpen?.()\n\t\trender()\n\t}\n\n\tasync function handleScreenshotFile(file: File): Promise<void> {\n\t\tscreenshotError = null\n\t\tif (!file.type.startsWith('image/')) {\n\t\t\tscreenshotError = 'Image files only'\n\t\t\trender()\n\t\t\treturn\n\t\t}\n\t\tif (file.size > MAX_SCREENSHOT_BYTES) {\n\t\t\tscreenshotError = 'Max 10MB'\n\t\t\trender()\n\t\t\treturn\n\t\t}\n\t\tif (screenshots.length >= MAX_SCREENSHOTS) {\n\t\t\tscreenshotError = `Max ${MAX_SCREENSHOTS} screenshots`\n\t\t\trender()\n\t\t\treturn\n\t\t}\n\n\t\tisUploadingScreenshot = true\n\t\trender()\n\t\ttry {\n\t\t\tconst uploaded = await apiClient.uploadScreenshot(file, clientId)\n\t\t\tscreenshots = [...screenshots, uploaded]\n\t\t} catch (err) {\n\t\t\tscreenshotError = err instanceof Error ? err.message : 'Upload failed'\n\t\t} finally {\n\t\t\tisUploadingScreenshot = false\n\t\t\trender()\n\t\t}\n\t}\n\n\tfunction removeScreenshot(index: number): void {\n\t\tscreenshots = screenshots.filter((_, i) => i !== index)\n\t\trender()\n\t}\n\n\tfunction close(): void {\n\t\tif (!isOpen) return\n\t\tisOpen = false\n\t\tonClose?.()\n\t\trender()\n\t}\n\n\tasync function submitForm(): Promise<void> {\n\t\tif (isSubmitting) return\n\t\tisSubmitting = true\n\t\tsubmitMessage = null\n\t\trender()\n\n\t\tconst feedbackData: FeedbackData = {\n\t\t\trating: selectedRating,\n\t\t\tcomment: comment.trim() || undefined,\n\t\t\tuserEmail: shareEmail ? userEmail : undefined,\n\t\t\tscreenshots: screenshots.length > 0 ? screenshots : undefined,\n\t\t\tmetadata: {\n\t\t\t\tpageUrl: window.location.href,\n\t\t\t\tpageTitle: document.title || 'Untitled Page',\n\t\t\t\treferrer: document.referrer || undefined,\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t},\n\t\t}\n\n\t\tconst submission: FeedbackSubmission = {\n\t\t\tclientId,\n\t\t\trating: feedbackData.rating,\n\t\t\tcomment: feedbackData.comment,\n\t\t\tuserEmail: feedbackData.userEmail,\n\t\t\tpageUrl: feedbackData.metadata.pageUrl,\n\t\t\tpageTitle: feedbackData.metadata.pageTitle,\n\t\t\treferrer: feedbackData.metadata.referrer,\n\t\t\tenvironment,\n\t\t}\n\t\tif (screenshots.length > 0) submission.screenshots = screenshots\n\t\tif (metadata !== undefined) submission.metadata = metadata\n\n\t\tconst validation = validateFeedbackSubmission(submission)\n\t\tif (!validation.isValid) {\n\t\t\tisSubmitting = false\n\t\t\tsetSubmitMessage({ type: 'error', text: validation.errors.join(', ') })\n\t\t\treturn\n\t\t}\n\n\t\t// Run plugin onFeedbackSubmit hooks in parallel and merge the\n\t\t// returned partial payloads into the outgoing submission. A plugin\n\t\t// that throws or rejects is logged and skipped — never blocks submit.\n\t\t//\n\t\t// Merge policy:\n\t\t// - `metadata` is DEEP-merged (one level): later plugins' keys\n\t\t// win on conflict, but non-conflicting keys from earlier\n\t\t// plugins are preserved. metadata is the natural collision\n\t\t// point (every plugin wants to attach context) so deep merge\n\t\t// is what users expect.\n\t\t// - Every other top-level key is shallow-merged: later plugins\n\t\t// win wholesale. This is fine in practice because dedicated\n\t\t// keys like `replayEvents` have a single writer.\n\t\tlet enrichedSubmission: FeedbackSubmission = submission\n\t\tif (pluginList.length > 0) {\n\t\t\tconst patchPromises = pluginList.map(async plugin => {\n\t\t\t\tif (!plugin.onFeedbackSubmit) return undefined\n\t\t\t\tconst ctx = pluginContexts.get(plugin.name)\n\t\t\t\tif (!ctx) return undefined\n\t\t\t\ttry {\n\t\t\t\t\treturn await plugin.onFeedbackSubmit(ctx, submission)\n\t\t\t\t} catch (err) {\n\t\t\t\t\tctx.logger.error('onFeedbackSubmit threw', err)\n\t\t\t\t\treturn undefined\n\t\t\t\t}\n\t\t\t})\n\t\t\tconst patches = await Promise.all(patchPromises)\n\t\t\tenrichedSubmission = mergePluginPatches(submission, patches)\n\t\t}\n\n\t\ttry {\n\t\t\tconst response = await apiClient.submitFeedback(enrichedSubmission)\n\t\t\tif (response.success) {\n\t\t\t\tif (shareEmail && userEmail) writeStoredEmail(userEmail)\n\t\t\t\tonSubmit?.(feedbackData)\n\t\t\t\tselectedRating = undefined\n\t\t\t\tcomment = ''\n\t\t\t\tshareEmail = false\n\t\t\t\tscreenshots = []\n\t\t\t\tscreenshotError = null\n\t\t\t\tsubmitMessage = { type: 'success', text: 'Thank you!' }\n\t\t\t} else {\n\t\t\t\tconst msg = response.error ?? 'Error occurred. Try again.'\n\t\t\t\tonError?.(new Error(msg))\n\t\t\t\tsubmitMessage = { type: 'error', text: msg }\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tconst msg = err instanceof Error ? err.message : 'Error occurred. Try again.'\n\t\t\tonError?.(new Error(msg))\n\t\t\tsubmitMessage = { type: 'error', text: msg }\n\t\t} finally {\n\t\t\tisSubmitting = false\n\t\t\trender()\n\t\t}\n\t}\n\n\t// Static button content + styles (only style.background changes once)\n\tfunction renderButton(): void {\n\t\tbuttonEl.className = `fb-btn fb-btn--${position} ${isOpen ? 'fb-btn--open' : ''}`\n\t\tbuttonEl.setAttribute('aria-label', 'Open feedback')\n\t\tbuttonEl.type = 'button'\n\t\tbuttonEl.style.background = `linear-gradient(135deg, ${theme.primary}, ${getGradientEnd(theme.primary)})`\n\t\tbuttonEl.innerHTML = isOpen\n\t\t\t? `<span style=\"font-size:20px;\">✕</span>`\n\t\t\t: ''\n\t}\n\n\tfunction renderBackdrop(): void {\n\t\tbackdropEl.className = 'fb-backdrop'\n\t\tbackdropEl.style.display = isOpen ? 'block' : 'none'\n\t\tbackdropEl.setAttribute('aria-label', 'Close modal')\n\t}\n\n\tfunction renderPanel(): void {\n\t\tpanelEl.className = `fb-pnl-base fb-pnl--${position} ${\n\t\t\tisOpen ? 'fb-pnl--open' : 'fb-pnl--closed'\n\t\t}`\n\t\tpanelEl.style.backgroundColor = theme.background\n\t\tif (position === 'right') {\n\t\t\tpanelEl.style.borderLeft = `1px solid ${theme.border}`\n\t\t\tpanelEl.style.borderRight = ''\n\t\t} else {\n\t\t\tpanelEl.style.borderRight = `1px solid ${theme.border}`\n\t\t\tpanelEl.style.borderLeft = ''\n\t\t}\n\t\tpanelEl.setAttribute('role', 'dialog')\n\t\tpanelEl.setAttribute('aria-modal', 'true')\n\t\tpanelEl.setAttribute('aria-labelledby', 'usero-feedback-title')\n\n\t\tconst remaining = 1000 - comment.length\n\t\tconst lowChars = remaining < 50\n\n\t\tconst ratingsHtml = ([1, 2, 3, 4] as FeedbackRating[])\n\t\t\t.map(r => {\n\t\t\t\tconst sel = selectedRating === r\n\t\t\t\tconst bg = EMOJI_BACKGROUNDS[r]\n\t\t\t\tconst cls = ['fb-ec', sel && 'fb-ec--sel'].filter(Boolean).join(' ')\n\t\t\t\t// Set color on the button so .fb-el (color: currentColor) inherits\n\t\t\t\t// the themed foreground. Without this it falls back to the UA\n\t\t\t\t// default for <button>, which is black on dark backgrounds.\n\t\t\t\treturn `\n\t\t\t\t\t<div class=\"${cls}\" style=\"background:${bg}\">\n\t\t\t\t\t\t<button type=\"button\" class=\"fb-eb\" data-rating=\"${r}\" role=\"radio\" aria-checked=\"${sel}\" aria-label=\"${r}: ${RATING_LABELS[r]}\" style=\"color:${theme.text}\">\n\t\t\t\t\t\t\t<div class=\"fb-ei\"><span role=\"img\" aria-label=\"${RATING_LABELS[r]}\">${EMOJI_MAP[r]}</span></div>\n\t\t\t\t\t\t\t<div class=\"fb-el\" style=\"color:${theme.text}\">${RATING_LABELS[r]}</div>\n\t\t\t\t\t\t</button>\n\t\t\t\t\t</div>\n\t\t\t\t`\n\t\t\t})\n\t\t\t.join('')\n\n\t\tconst messageHtml = submitMessage\n\t\t\t? `<div class=\"fb-msg fb-msg--header ${submitMessage.type === 'success' ? 'fb-msg--ok' : 'fb-msg--err'}\">${submitMessage.type === 'success' ? '✓' : '⚠'} ${escapeHtml(submitMessage.text)}</div>`\n\t\t\t: ''\n\n\t\t// The upload button + char counter share a single horizontal row to\n\t\t// keep the panel compact (matches the legacy react-feedback-collector\n\t\t// layout). Upload extras (error message, previews, max limit) live on\n\t\t// their own row beneath, so they can wrap freely.\n\t\tconst uploadBtnHtml = showScreenshotOption\n\t\t\t? (() => {\n\t\t\t\t\tconst atMax = screenshots.length >= MAX_SCREENSHOTS\n\t\t\t\t\tconst btnDisabled = isUploadingScreenshot || atMax\n\t\t\t\t\treturn `\n\t\t\t\t\t\t<input type=\"file\" accept=\"image/*\" data-role=\"screenshot-input\" style=\"display:none;\" aria-label=\"Choose screenshot\" />\n\t\t\t\t\t\t<button type=\"button\" class=\"fb-upb ${btnDisabled ? 'fb-upb--dis' : ''}\" data-role=\"screenshot-pick\" ${btnDisabled ? 'disabled' : ''} style=\"border:1px solid ${theme.border};color:${theme.text};\">\n\t\t\t\t\t\t\t${\n\t\t\t\t\t\t\t\tisUploadingScreenshot\n\t\t\t\t\t\t\t\t\t? '<span class=\"fb-ups\"></span> Uploading...'\n\t\t\t\t\t\t\t\t\t: '📷 Add screenshot'\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</button>\n\t\t\t\t\t`\n\t\t\t\t})()\n\t\t\t: ''\n\t\tconst uploadExtrasHtml = showScreenshotOption\n\t\t\t? (() => {\n\t\t\t\t\tconst atMax = screenshots.length >= MAX_SCREENSHOTS\n\t\t\t\t\tconst previewsHtml = screenshots\n\t\t\t\t\t\t.map(\n\t\t\t\t\t\t\t(shot, i) => `\n\t\t\t\t\t\t\t\t<div class=\"fb-sp\">\n\t\t\t\t\t\t\t\t\t<img src=\"${escapeHtml(shot.url)}\" alt=\"Screenshot ${i + 1}\" class=\"fb-si\" />\n\t\t\t\t\t\t\t\t\t<button type=\"button\" class=\"fb-sr\" data-role=\"screenshot-remove\" data-index=\"${i}\" aria-label=\"Remove screenshot\">✕</button>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t`,\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.join('')\n\t\t\t\t\tconst errorHtml = screenshotError\n\t\t\t\t\t\t? `<div class=\"fb-upe\">⚠ ${escapeHtml(screenshotError)}</div>`\n\t\t\t\t\t\t: ''\n\t\t\t\t\tconst limitHtml = atMax\n\t\t\t\t\t\t? `<div class=\"fb-sl\">Max ${MAX_SCREENSHOTS}</div>`\n\t\t\t\t\t\t: ''\n\t\t\t\t\treturn screenshotError || screenshots.length > 0 || atMax\n\t\t\t\t\t\t? `<div class=\"fb-up-extras\">${errorHtml}${\n\t\t\t\t\t\t\t\tscreenshots.length > 0\n\t\t\t\t\t\t\t\t\t? `<div class=\"fb-ss\">${previewsHtml}</div>`\n\t\t\t\t\t\t\t\t\t: ''\n\t\t\t\t\t\t\t}${limitHtml}</div>`\n\t\t\t\t\t\t: ''\n\t\t\t\t})()\n\t\t\t: ''\n\n\t\tconst emailBlockHtml = showEmailOption\n\t\t\t? `\n\t\t\t\t<div class=\"fb-email\">\n\t\t\t\t\t<label class=\"fb-email-lbl\" style=\"color:${theme.text}\">\n\t\t\t\t\t\t<input type=\"checkbox\" class=\"fb-email-cb\" data-role=\"share-email\" ${shareEmail ? 'checked' : ''} aria-label=\"Share email\" />\n\t\t\t\t\t\t<span>Share my email</span>\n\t\t\t\t\t</label>\n\t\t\t\t\t${\n\t\t\t\t\t\tshareEmail\n\t\t\t\t\t\t\t? `<input type=\"email\" class=\"fb-email-inp\" data-role=\"email-input\" value=\"${escapeHtml(userEmail)}\" placeholder=\"your.email@example.com\" aria-label=\"Email\" maxlength=\"254\" autocomplete=\"email\" style=\"border:1px solid ${theme.border};color:${theme.text};background-color:${theme.background};\" />`\n\t\t\t\t\t\t\t: ''\n\t\t\t\t\t}\n\t\t\t\t</div>\n\t\t\t`\n\t\t\t: ''\n\n\t\tconst submitDisabled = isSubmitting\n\t\tconst submitStyle = `background:linear-gradient(135deg, ${theme.primary}, ${getGradientEnd(theme.primary)});color:#ffffff;${submitDisabled ? 'opacity:0.6;cursor:not-allowed;' : ''}`\n\n\t\tpanelEl.innerHTML = `\n\t\t\t<div class=\"fb-cnt\">\n\t\t\t\t<div class=\"fb-hdr\" style=\"border-bottom:1px solid ${theme.border}\">\n\t\t\t\t\t<h2 id=\"usero-feedback-title\" class=\"fb-ttl\" style=\"color:${theme.text}\">${escapeHtml(title)}</h2>\n\t\t\t\t\t${messageHtml}\n\t\t\t\t\t<button class=\"fb-close-btn\" data-role=\"close\" style=\"color:${theme.text}\" aria-label=\"Close\" type=\"button\">✕</button>\n\t\t\t\t</div>\n\t\t\t\t<form data-role=\"form\">\n\t\t\t\t\t<div class=\"fb-es\" role=\"radiogroup\" aria-label=\"Rate experience\">${ratingsHtml}</div>\n\t\t\t\t\t<textarea class=\"fb-ta\" data-role=\"comment\" placeholder=\"${escapeHtml(placeholder)}\" aria-label=\"Comments\" maxlength=\"1000\" rows=\"2\" style=\"border:1px solid ${theme.border};color:${theme.text};background-color:${theme.background};\">${escapeHtml(comment)}</textarea>\n\t\t\t\t\t<div class=\"fb-toolrow\">\n\t\t\t\t\t\t${uploadBtnHtml}\n\t\t\t\t\t\t<div class=\"fb-charcount${lowChars ? ' fb-charcount--low' : ''}\" data-role=\"charcount\" style=\"color:${lowChars ? '#dc2626' : theme.text};opacity:${lowChars ? 1 : 0.6};\">${remaining} chars remaining</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t${uploadExtrasHtml ? `<div class=\"fb-up\">${uploadExtrasHtml}</div>` : ''}\n\t\t\t\t\t${emailBlockHtml}\n\t\t\t\t\t<button class=\"fb-sub ${submitDisabled ? 'fb-sub--dis' : ''}\" type=\"submit\" aria-label=\"Submit\" ${submitDisabled ? 'disabled' : ''} style=\"${submitStyle}\">\n\t\t\t\t\t\t${isSubmitting ? '<span class=\"fb-spin\"></span>' : ''}\n\t\t\t\t\t\t${isSubmitting ? 'Submitting...' : 'Send Feedback 🚀'}\n\t\t\t\t\t</button>\n\t\t\t\t</form>\n\t\t\t</div>\n\t\t`\n\n\t\t// Wire up panel-internal events\n\t\tconst form = panelEl.querySelector<HTMLFormElement>('form[data-role=\"form\"]')\n\t\tform?.addEventListener('submit', e => {\n\t\t\te.preventDefault()\n\t\t\tvoid submitForm()\n\t\t})\n\n\t\tpanelEl\n\t\t\t.querySelector<HTMLButtonElement>('button[data-role=\"close\"]')\n\t\t\t?.addEventListener('click', close)\n\n\t\tpanelEl\n\t\t\t.querySelectorAll<HTMLButtonElement>('button[data-rating]')\n\t\t\t.forEach(btn => {\n\t\t\t\tbtn.addEventListener('click', () => {\n\t\t\t\t\tconst value = btn.dataset.rating\n\t\t\t\t\tif (value === '1' || value === '2' || value === '3' || value === '4') {\n\t\t\t\t\t\tselectedRating = Number(value) as FeedbackRating\n\t\t\t\t\t\trender()\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t})\n\n\t\tconst textarea = panelEl.querySelector<HTMLTextAreaElement>(\n\t\t\t'textarea[data-role=\"comment\"]',\n\t\t)\n\t\tif (textarea) {\n\t\t\ttextarea.addEventListener('input', () => {\n\t\t\t\tif (textarea.value.length <= 1000) {\n\t\t\t\t\tcomment = textarea.value\n\t\t\t\t\t// Update char count without full rerender to avoid losing focus.\n\t\t\t\t\t// IMPORTANT: target by stable class. A previous selector\n\t\t\t\t\t// `.fb-cnt form > div > div` matched the first rating tile,\n\t\t\t\t\t// hijacking it with the char-count text on every keystroke.\n\t\t\t\t\tconst counter = panelEl.querySelector<HTMLDivElement>(\n\t\t\t\t\t\t'[data-role=\"charcount\"]',\n\t\t\t\t\t)\n\t\t\t\t\tif (counter) {\n\t\t\t\t\t\tconst left = 1000 - comment.length\n\t\t\t\t\t\tcounter.textContent = `${left} chars remaining`\n\t\t\t\t\t\tcounter.style.color = left < 50 ? '#dc2626' : theme.text\n\t\t\t\t\t\tcounter.style.opacity = left < 50 ? '1' : '0.6'\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\n\t\tconst shareCb = panelEl.querySelector<HTMLInputElement>(\n\t\t\t'input[data-role=\"share-email\"]',\n\t\t)\n\t\tshareCb?.addEventListener('change', () => {\n\t\t\tshareEmail = shareCb.checked\n\t\t\trender()\n\t\t})\n\n\t\tconst emailInp = panelEl.querySelector<HTMLInputElement>(\n\t\t\t'input[data-role=\"email-input\"]',\n\t\t)\n\t\temailInp?.addEventListener('input', () => {\n\t\t\tif (emailInp.value.length <= 254) {\n\t\t\t\tuserEmail = emailInp.value\n\t\t\t}\n\t\t})\n\n\t\tconst fileInput = panelEl.querySelector<HTMLInputElement>(\n\t\t\t'input[data-role=\"screenshot-input\"]',\n\t\t)\n\t\tconst pickBtn = panelEl.querySelector<HTMLButtonElement>(\n\t\t\t'button[data-role=\"screenshot-pick\"]',\n\t\t)\n\t\tpickBtn?.addEventListener('click', () => {\n\t\t\tfileInput?.click()\n\t\t})\n\t\tfileInput?.addEventListener('change', () => {\n\t\t\tconst file = fileInput.files?.[0]\n\t\t\tif (!file) return\n\t\t\tvoid handleScreenshotFile(file).finally(() => {\n\t\t\t\tif (fileInput) fileInput.value = ''\n\t\t\t})\n\t\t})\n\t\tpanelEl\n\t\t\t.querySelectorAll<HTMLButtonElement>(\n\t\t\t\t'button[data-role=\"screenshot-remove\"]',\n\t\t\t)\n\t\t\t.forEach(btn => {\n\t\t\t\tbtn.addEventListener('click', () => {\n\t\t\t\t\tconst idx = Number(btn.dataset.index)\n\t\t\t\t\tif (Number.isInteger(idx)) removeScreenshot(idx)\n\t\t\t\t})\n\t\t\t})\n\t}\n\n\tfunction render(): void {\n\t\trenderButton()\n\t\trenderBackdrop()\n\t\trenderPanel()\n\t}\n\n\t// Top-level event listeners\n\tbuttonEl.addEventListener('click', () => {\n\t\tif (isOpen) close()\n\t\telse open()\n\t})\n\tbackdropEl.addEventListener('click', close)\n\n\tconst onKeyDown = (e: KeyboardEvent): void => {\n\t\tif (!isOpen) return\n\t\tif (e.key === 'Escape') close()\n\t\tif (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) {\n\t\t\te.preventDefault()\n\t\t\tvoid submitForm()\n\t\t}\n\t}\n\tdocument.addEventListener('keydown', onKeyDown)\n\n\t// Live OS color-scheme tracking. Only active while the caller has not\n\t// provided an explicit `theme` prop. If they later pass one via update(),\n\t// we detach. If they later clear it (set to undefined), we re-attach.\n\tlet darkMql: MediaQueryList | null = null\n\tlet mqlListener: ((ev: MediaQueryListEvent) => void) | null = null\n\n\tfunction detachMqlListener(): void {\n\t\tif (darkMql && mqlListener) {\n\t\t\tdarkMql.removeEventListener('change', mqlListener)\n\t\t}\n\t\tdarkMql = null\n\t\tmqlListener = null\n\t}\n\n\tfunction attachMqlListener(): void {\n\t\tif (darkMql) return\n\t\tif (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return\n\t\tdarkMql = window.matchMedia('(prefers-color-scheme: dark)')\n\t\tmqlListener = () => {\n\t\t\t// Only react if user still hasn't overridden the theme.\n\t\t\tif (userThemeOverride !== undefined) return\n\t\t\ttheme = resolveTheme(undefined)\n\t\t\trender()\n\t\t}\n\t\tdarkMql.addEventListener('change', mqlListener)\n\t}\n\n\tif (userThemeOverride === undefined) attachMqlListener()\n\n\t// Initial paint\n\trender()\n\n\tlet destroyed = false\n\treturn {\n\t\tdestroy: () => {\n\t\t\tif (destroyed) return\n\t\t\tdestroyed = true\n\t\t\tdocument.removeEventListener('keydown', onKeyDown)\n\t\t\tdetachMqlListener()\n\t\t\tfor (const plugin of pluginList) {\n\t\t\t\tif (!plugin.onDestroy) continue\n\t\t\t\tconst ctx = pluginContexts.get(plugin.name)\n\t\t\t\tif (!ctx) continue\n\t\t\t\ttry {\n\t\t\t\t\tplugin.onDestroy(ctx)\n\t\t\t\t} catch (err) {\n\t\t\t\t\tctx.logger.error('onDestroy threw', err)\n\t\t\t\t}\n\t\t\t}\n\t\t\tpluginStores.clear()\n\t\t\tpluginContexts.clear()\n\t\t\thost.remove()\n\t\t},\n\t\topen,\n\t\tclose,\n\t\twhenReady: () => readyPromise,\n\t\tupdate: next => {\n\t\t\tif (destroyed) return\n\t\t\tlet needsRender = false\n\t\t\tif (next.position !== undefined && next.position !== position) {\n\t\t\t\tposition = next.position\n\t\t\t\tneedsRender = true\n\t\t\t}\n\t\t\tif ('theme' in next) {\n\t\t\t\t// Caller opted in/out of explicit theme control. Track the\n\t\t\t\t// override so the matchMedia listener and any further\n\t\t\t\t// resolutions know whether the user is in charge.\n\t\t\t\tuserThemeOverride = next.theme\n\t\t\t\ttheme = resolveTheme(userThemeOverride)\n\t\t\t\tif (userThemeOverride === undefined) attachMqlListener()\n\t\t\t\telse detachMqlListener()\n\t\t\t\tneedsRender = true\n\t\t\t}\n\t\t\tif (next.title !== undefined && next.title !== title) {\n\t\t\t\ttitle = next.title\n\t\t\t\tneedsRender = true\n\t\t\t}\n\t\t\tif (next.placeholder !== undefined && next.placeholder !== placeholder) {\n\t\t\t\tplaceholder = next.placeholder\n\t\t\t\tneedsRender = true\n\t\t\t}\n\t\t\tif (\n\t\t\t\tnext.showEmailOption !== undefined &&\n\t\t\t\tnext.showEmailOption !== showEmailOption\n\t\t\t) {\n\t\t\t\tshowEmailOption = next.showEmailOption\n\t\t\t\tneedsRender = true\n\t\t\t}\n\t\t\tif (\n\t\t\t\tnext.showScreenshotOption !== undefined &&\n\t\t\t\tnext.showScreenshotOption !== showScreenshotOption\n\t\t\t) {\n\t\t\t\tshowScreenshotOption = next.showScreenshotOption\n\t\t\t\tneedsRender = true\n\t\t\t}\n\t\t\t// Non-render-affecting props: just swap refs.\n\t\t\tif ('environment' in next) environment = next.environment\n\t\t\tif ('metadata' in next) metadata = next.metadata\n\t\t\tif ('onSubmit' in next) onSubmit = next.onSubmit\n\t\t\tif ('onError' in next) onError = next.onError\n\t\t\tif ('onOpen' in next) onOpen = next.onOpen\n\t\t\tif ('onClose' in next) onClose = next.onClose\n\t\t\tif (needsRender) render()\n\t\t},\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/api.ts","../src/colorUtils.ts","../src/plugin.ts","../src/validation.ts","../src/widgetCss.ts","../src/vanilla.ts"],"names":[],"mappings":"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AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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","file":"vanilla.cjs","sourcesContent":["// Shared types used by both the vanilla and React entry points.\n// Keep this file framework-free so the vanilla bundle never pulls react.\n\nexport type FeedbackRating = 1 | 2 | 3 | 4\n\nexport interface FeedbackMetadata {\n\tpageUrl: string\n\tpageTitle: string\n\treferrer?: string\n\ttimestamp: number\n}\n\nexport interface ScreenshotData {\n\tfileName: string\n\turl: string\n\tfileSize: number\n\twidth?: number\n\theight?: number\n\tmimeType: string\n}\n\nexport interface FeedbackSubmission {\n\tclientId: string\n\trating?: FeedbackRating\n\tcomment?: string\n\tuserEmail?: string\n\tpageUrl: string\n\tpageTitle: string\n\treferrer?: string\n\tenvironment?: string\n\tscreenshots?: ScreenshotData[]\n\tmetadata?: Record<string, unknown>\n\t// Legacy gzipped + base64-encoded rrweb event stream. The pre-chunked\n\t// session-replay plugin attached this on submit. The chunked-upload\n\t// plugin (>= 0.4.0) does NOT set this — it ships events out-of-band\n\t// via the chunk endpoints and points at the resulting session replay\n\t// via `sessionReplayId` + `replayOffsetMs`. Kept on the wire one\n\t// release for backward compat with old SaaS deployments that only\n\t// know how to ingest the legacy field.\n\treplayEvents?: string\n\t// Pointer to a SessionReplay row created by the session-replay\n\t// plugin's chunked-upload pipeline, plus the offset within that\n\t// recording at submit time so the dashboard can deep-link.\n\tsessionReplayId?: string\n\treplayOffsetMs?: number\n}\n\nexport interface FeedbackData {\n\trating?: FeedbackRating\n\tcomment?: string\n\tuserEmail?: string\n\tscreenshots?: ScreenshotData[]\n\tmetadata: FeedbackMetadata\n}\n\nexport type WidgetPosition = 'right' | 'left'\n\nexport interface WidgetTheme {\n\tprimary: string\n\tbackground: string\n\ttext: string\n\tborder: string\n\tshadow: string\n}\n\n// Forward-declared to avoid a circular import. The plugin module imports\n// FeedbackSubmission from this file, so we can't import UseroPlugin back\n// up here without a cycle. Keeping the prop typed as an opaque object with\n// the minimal shape the widget actually inspects works fine for consumers.\nexport interface FeedbackWidgetProps {\n\tclientId: string\n\tposition?: WidgetPosition\n\ttheme?: Partial<WidgetTheme>\n\ttitle?: string\n\tplaceholder?: string\n\tshowEmailOption?: boolean\n\tshowScreenshotOption?: boolean\n\tenvironment?: string\n\tbaseUrl?: string\n\tmetadata?: Record<string, unknown>\n\tplugins?: ReadonlyArray<import('./plugin').UseroPlugin>\n\tonSubmit?: (feedback: FeedbackData) => void\n\tonError?: (error: Error) => void\n\tonOpen?: () => void\n\tonClose?: () => void\n}\n\nexport interface SubmissionResponse {\n\tsuccess: boolean\n\terror?: string\n\tid?: string\n\tmessage?: string\n\tdata?: unknown\n}\n\nexport const EMOJI_MAP: Record<FeedbackRating, string> = {\n\t1: '😞',\n\t2: '😐',\n\t3: '😊',\n\t4: '🤩',\n}\n\nexport const RATING_LABELS: Record<FeedbackRating, string> = {\n\t1: 'Needs work',\n\t2: \"It's okay\",\n\t3: 'Pretty good',\n\t4: 'Amazing!',\n}\n\nexport const EMOJI_BACKGROUNDS: Record<FeedbackRating, string> = {\n\t1: 'linear-gradient(135deg,#ff6b6b14,#ff6b6b1f)',\n\t2: 'linear-gradient(135deg,#9ca3af0f,#9ca3af1a)',\n\t3: 'linear-gradient(135deg,#3b82f614,#3b82f61f)',\n\t4: 'linear-gradient(135deg,#f59e0b14,#f59e0b1f)',\n}\n\nexport const DEFAULT_API_URL = 'https://usero.io'\n\nexport const DEFAULT_THEME: WidgetTheme = {\n\tprimary: '#2563eb',\n\tbackground: '#ffffff',\n\ttext: '#374151',\n\tborder: '#e5e7eb',\n\tshadow:\n\t\t'0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',\n}\n\nexport const DARK_THEME: WidgetTheme = {\n\tprimary: '#2563eb',\n\tbackground: '#1f2937',\n\ttext: '#f9fafb',\n\tborder: '#374151',\n\tshadow:\n\t\t'0 10px 15px -3px rgba(0, 0, 0, 0.3), 0 4px 6px -2px rgba(0, 0, 0, 0.2)',\n}\n\nexport function mergeTheme(customTheme: Partial<WidgetTheme> = {}): WidgetTheme {\n\treturn { ...DEFAULT_THEME, ...customTheme }\n}\n","import {\n\tDEFAULT_API_URL,\n\ttype FeedbackSubmission,\n\ttype ScreenshotData,\n\ttype SubmissionResponse,\n} from './types'\n\ninterface JsonErrorBody {\n\terror?: string\n}\n\nfunction isJsonErrorBody(value: unknown): value is JsonErrorBody {\n\treturn typeof value === 'object' && value !== null && 'error' in value\n}\n\ninterface ScreenshotUploadResponseBody {\n\tsuccess: boolean\n\terror?: string\n\tscreenshot?: ScreenshotData\n}\n\nfunction parseScreenshotUploadBody(\n\tvalue: unknown,\n): ScreenshotUploadResponseBody {\n\tif (typeof value !== 'object' || value === null) {\n\t\treturn { success: false, error: 'Invalid response' }\n\t}\n\tconst obj = value as Record<string, unknown>\n\tconst success = obj.success === true\n\tconst error = typeof obj.error === 'string' ? obj.error : undefined\n\tconst rawShot = obj.screenshot\n\tlet screenshot: ScreenshotData | undefined\n\tif (typeof rawShot === 'object' && rawShot !== null) {\n\t\tconst s = rawShot as Record<string, unknown>\n\t\tif (\n\t\t\ttypeof s.fileName === 'string' &&\n\t\t\ttypeof s.url === 'string' &&\n\t\t\ttypeof s.fileSize === 'number' &&\n\t\t\ttypeof s.mimeType === 'string'\n\t\t) {\n\t\t\tscreenshot = {\n\t\t\t\tfileName: s.fileName,\n\t\t\t\turl: s.url,\n\t\t\t\tfileSize: s.fileSize,\n\t\t\t\tmimeType: s.mimeType,\n\t\t\t\twidth: typeof s.width === 'number' ? s.width : undefined,\n\t\t\t\theight: typeof s.height === 'number' ? s.height : undefined,\n\t\t\t}\n\t\t}\n\t}\n\treturn { success, error, screenshot }\n}\n\nexport class FeedbackApiClient {\n\tprivate baseUrl: string\n\n\tconstructor(baseUrl: string = DEFAULT_API_URL) {\n\t\tthis.baseUrl = baseUrl.replace(/\\/$/, '')\n\t}\n\n\tasync submitFeedback(data: FeedbackSubmission): Promise<SubmissionResponse> {\n\t\ttry {\n\t\t\tconst response = await fetch(`${this.baseUrl}/api/feedback`, {\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders: {\n\t\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t\tAccept: 'application/json',\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify(data),\n\t\t\t\tsignal: AbortSignal.timeout(10000),\n\t\t\t})\n\n\t\t\tif (!response.ok) {\n\t\t\t\tlet errorMessage = `HTTP ${response.status}: ${response.statusText}`\n\t\t\t\ttry {\n\t\t\t\t\tconst errorData: unknown = await response.json()\n\t\t\t\t\tif (isJsonErrorBody(errorData) && typeof errorData.error === 'string') {\n\t\t\t\t\t\terrorMessage = errorData.error\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// Ignore JSON parse errors\n\t\t\t\t}\n\t\t\t\tthrow new Error(errorMessage)\n\t\t\t}\n\n\t\t\tconst result: unknown = await response.json()\n\t\t\tconst message =\n\t\t\t\ttypeof result === 'object' &&\n\t\t\t\tresult !== null &&\n\t\t\t\t'message' in result &&\n\t\t\t\ttypeof (result as { message: unknown }).message === 'string'\n\t\t\t\t\t? (result as { message: string }).message\n\t\t\t\t\t: 'Feedback submitted successfully'\n\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tdata: result,\n\t\t\t\tmessage,\n\t\t\t}\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror:\n\t\t\t\t\terror instanceof Error ? error.message : 'An unexpected error occurred',\n\t\t\t}\n\t\t}\n\t}\n\n\tasync uploadScreenshot(\n\t\tfile: File,\n\t\tclientId: string,\n\t): Promise<ScreenshotData> {\n\t\tconst formData = new FormData()\n\t\tformData.append('screenshot', file)\n\t\tformData.append('clientId', clientId)\n\n\t\tconst response = await fetch(`${this.baseUrl}/api/screenshots`, {\n\t\t\tmethod: 'POST',\n\t\t\tbody: formData,\n\t\t\tsignal: AbortSignal.timeout(30000),\n\t\t})\n\n\t\tlet body: ScreenshotUploadResponseBody = { success: false }\n\t\ttry {\n\t\t\tconst raw: unknown = await response.json()\n\t\t\tbody = parseScreenshotUploadBody(raw)\n\t\t} catch {\n\t\t\t// fall through to error handling below\n\t\t}\n\n\t\tif (!response.ok || !body.success || !body.screenshot) {\n\t\t\tconst message =\n\t\t\t\tbody.error ?? `HTTP ${response.status}: ${response.statusText}`\n\t\t\tthrow new Error(message)\n\t\t}\n\n\t\treturn body.screenshot\n\t}\n\n\tping(): void {\n\t\tfetch(`${this.baseUrl}/api/ping`, {\n\t\t\tsignal: AbortSignal.timeout(5000),\n\t\t}).catch(() => {})\n\t}\n}\n","export function colorNameToHex(color: string): string {\n\tif (color.startsWith('#')) return color\n\tif (typeof document === 'undefined') return color\n\n\tconst canvas = document.createElement('canvas')\n\tconst ctx = canvas.getContext('2d')\n\tif (!ctx) return color\n\n\tctx.fillStyle = color\n\treturn ctx.fillStyle\n}\n\nexport function getGradientEnd(color: string): string {\n\tconst hex = colorNameToHex(color)\n\tif (!hex.startsWith('#') || hex.length < 7) return hex\n\tconst r = parseInt(hex.slice(1, 3), 16)\n\tconst g = parseInt(hex.slice(3, 5), 16)\n\tconst b = parseInt(hex.slice(5, 7), 16)\n\tconst shiftedR = Math.max(0, r - 60)\n\tconst shiftedG = Math.min(255, g + 40)\n\tconst shiftedB = Math.min(255, b + 20)\n\treturn `#${[shiftedR, shiftedG, shiftedB]\n\t\t.map(x => x.toString(16).padStart(2, '0'))\n\t\t.join('')}`\n}\n","// Plugin contract for the Usero widget.\n//\n// Plugins are opt-in modules that hook into the widget lifecycle to enrich\n// feedback submissions or react to widget events. They live in subpath\n// exports (e.g. `@usero/sdk/plugins/session-replay`) so consumers who don't\n// import them pay zero bundle cost.\n//\n// Design rules:\n// 1. The plugin contract MUST stay framework-free (no React types).\n// 2. `onInit` runs fire-and-forget so a slow plugin never blocks the\n// widget from rendering. Plugins that need to be ready before the\n// first interaction are responsible for their own gating internally.\n// 3. `onFeedbackSubmit` is awaited and its return value is merged into\n// the outgoing payload. Top-level keys are shallow-merged (later\n// plugins win wholesale); `metadata` is deep-merged one level so two\n// plugins can both contribute keys without clobbering each other.\n// Plugins MUST return quickly (a few hundred ms at most) or risk users\n// abandoning the submit.\n// 4. Plugin errors are caught and logged; they never block a submission.\n\nimport type { FeedbackSubmission } from './types'\n\nexport interface PluginLogger {\n\tdebug: (...args: unknown[]) => void\n\tinfo: (...args: unknown[]) => void\n\twarn: (...args: unknown[]) => void\n\terror: (...args: unknown[]) => void\n}\n\nexport interface PluginContext {\n\tclientId: string\n\tbaseUrl: string\n\t// Per-plugin scratch store. Plugins can stash state across hook calls\n\t// without leaking into globals. The key is the plugin's `name`.\n\tgetStore: <T>() => T | undefined\n\tsetStore: <T>(value: T) => void\n\tlogger: PluginLogger\n}\n\nexport interface UseroPlugin {\n\t// Stable, unique identifier. Used as the store key and in log prefixes.\n\t// Convention: lowercase kebab-case (e.g. `session-replay`).\n\tname: string\n\tonInit?: (ctx: PluginContext) => void | Promise<void>\n\t// Returns a partial submission patch that gets merged into the outgoing\n\t// payload. Top-level keys are shallow-merged (later plugins win on\n\t// conflict); `metadata` is deep-merged one level so multiple plugins\n\t// can each attach their own metadata keys without clobbering. Return\n\t// `undefined` to contribute nothing.\n\tonFeedbackSubmit?: (\n\t\tctx: PluginContext,\n\t\tsubmission: FeedbackSubmission,\n\t) => Promise<Partial<FeedbackSubmission> | undefined> | Partial<FeedbackSubmission> | undefined\n\tonDestroy?: (ctx: PluginContext) => void\n}\n\nexport function createPluginLogger(name: string): PluginLogger {\n\tconst prefix = `[usero:${name}]`\n\treturn {\n\t\tdebug: (...args) => {\n\t\t\tif (typeof console !== 'undefined') console.debug(prefix, ...args)\n\t\t},\n\t\tinfo: (...args) => {\n\t\t\tif (typeof console !== 'undefined') console.info(prefix, ...args)\n\t\t},\n\t\twarn: (...args) => {\n\t\t\tif (typeof console !== 'undefined') console.warn(prefix, ...args)\n\t\t},\n\t\terror: (...args) => {\n\t\t\tif (typeof console !== 'undefined') console.error(prefix, ...args)\n\t\t},\n\t}\n}\n","import type { FeedbackSubmission } from './types'\n\nexport interface ValidationResult {\n\tisValid: boolean\n\terrors: string[]\n}\n\nexport function validateFeedbackSubmission(\n\tdata: Partial<FeedbackSubmission>,\n): ValidationResult {\n\tconst errors: string[] = []\n\tconst hasRating = data.rating != null\n\tconst hasComment = !!data.comment?.trim()\n\n\tif (!hasRating && !hasComment) {\n\t\terrors.push('Add rating or comment')\n\t}\n\tif (hasRating && data.rating !== undefined && ![1, 2, 3, 4].includes(data.rating)) {\n\t\terrors.push('Invalid rating')\n\t}\n\tif (hasComment && data.comment !== undefined) {\n\t\tif (data.comment.length > 1000) {\n\t\t\terrors.push('Comment too long')\n\t\t}\n\t\tif (/<script[^>]*>.*?<\\/script>/gi.test(data.comment)) {\n\t\t\terrors.push('Invalid comment')\n\t\t}\n\t}\n\n\treturn {\n\t\tisValid: errors.length === 0,\n\t\terrors,\n\t}\n}\n","// CSS used by both entry points.\n//\n// React entry injects it once into <head> via injectFeedbackCSS().\n// Vanilla entry injects it inside a shadow root, so host page styles\n// can't bleed in and our class names can't collide with the host.\n\nexport const FEEDBACK_CSS = `\n@keyframes spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n}\n\n.fb-es {\n display: flex;\n justify-content: center;\n gap: 12px;\n padding-bottom: 8px;\n}\n\n.fb-ec {\n border-radius: 16px;\n padding: 0 5px;\n transition: all 300ms cubic-bezier(0.68, -0.55, 0.265, 1.55);\n border: 3px solid transparent;\n cursor: pointer;\n text-align: center;\n}\n\n.fb-ec--sel {\n border-color: #2563eb;\n transform: scale(1.05);\n box-shadow: 0 4px 15px rgba(37, 99, 235, 0.2);\n}\n\n.fb-ec--hov:not(.fb-ec--sel) {\n transform: scale(1.05);\n}\n\n.fb-eb {\n background: transparent;\n border: none;\n cursor: pointer;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 2px;\n width: 100%;\n padding: 0;\n transition: all 200ms ease;\n}\n\n.fb-ei {\n font-size: 36px;\n transition: transform 200ms ease;\n}\n\n.fb-ei--hov {\n transform: scale(1.1);\n}\n\n.fb-el {\n font-size: 13px;\n font-weight: 600;\n color: currentColor;\n line-height: 1.2;\n}\n\n.fb-hdr {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding-bottom: 4px;\n margin-bottom: 10px;\n}\n\n.fb-msg {\n font-size: 14px;\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px;\n margin-bottom: 8px;\n border-radius: 6px;\n}\n\n.fb-msg--header {\n font-size: 12px;\n padding: 4px 8px;\n margin-bottom: 0;\n margin-left: auto;\n margin-right: 8px;\n}\n\n.fb-msg--ok {\n background-color: #f0fdf4;\n border: 1px solid #bbf7d0;\n color: #16a34a;\n}\n\n.fb-msg--err {\n background-color: #fef2f2;\n border: 1px solid #fecaca;\n color: #dc2626;\n}\n\n.fb-sub {\n width: 100%;\n padding: 12px 24px;\n border: none;\n border-radius: 12px;\n font-size: 15px;\n font-weight: 600;\n cursor: pointer;\n transition: all 200ms ease;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n}\n\n.fb-sub--dis {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.fb-spin {\n width: 16px;\n height: 16px;\n border: 2px solid transparent;\n border-top: 2px solid currentColor;\n border-radius: 50%;\n animation: spin 1s linear infinite;\n}\n\n.fb-cnt {\n padding: 20px 24px 16px;\n overflow: auto;\n max-height: calc(90vh - 48px);\n}\n\n.fb-ttl {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n}\n\n.fb-ta {\n width: 100%;\n min-height: 80px;\n padding: 10px;\n border-radius: 8px;\n font-size: 14px;\n font-family: inherit;\n outline: none;\n resize: vertical;\n transition: border-color 150ms ease;\n margin-bottom: 2px;\n box-sizing: border-box;\n}\n\n.fb-toolrow {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n margin-bottom: 8px;\n}\n\n.fb-charcount {\n font-size: 12px;\n margin-left: auto;\n text-align: right;\n}\n\n.fb-charcount--low {\n color: #dc2626;\n}\n\n.fb-email {\n display: flex;\n flex-direction: column;\n gap: 6px;\n margin-bottom: 10px;\n}\n\n.fb-email-lbl {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n}\n\n.fb-email-cb {\n margin: 0;\n cursor: pointer;\n}\n\n.fb-email-inp {\n width: 100%;\n padding: 8px 12px;\n border-radius: 4px;\n font-size: 14px;\n outline: none;\n transition: border-color 150ms ease;\n box-sizing: border-box;\n}\n\n.fb-btn {\n position: fixed;\n width: 50px;\n height: 50px;\n border: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 18px;\n transition: all 300ms cubic-bezier(0.68, -0.55, 0.265, 1.55);\n z-index: 9998;\n color: #ffffff;\n top: 50%;\n transform: translateY(-50%);\n box-shadow: 0 4px 15px rgba(37, 99, 235, 0.3);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Roboto\", \"Helvetica Neue\", Arial, sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n box-sizing: border-box;\n}\n\n.fb-btn--right {\n right: -25px;\n border-radius: 40px 0 0 40px;\n padding-right: 8px;\n box-shadow: -4px 0 15px rgba(37, 99, 235, 0.3);\n}\n\n.fb-btn--left {\n left: -25px;\n border-radius: 0 40px 40px 0;\n padding-left: 8px;\n box-shadow: 4px 0 15px rgba(37, 99, 235, 0.3);\n}\n\n.fb-btn--right.fb-btn--open {\n right: -15px;\n transform: translateY(-50%) scale(1.05);\n}\n\n.fb-btn--left.fb-btn--open {\n left: -15px;\n transform: translateY(-50%) scale(1.05);\n}\n\n.fb-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: rgba(0, 0, 0, 0.3);\n transition: opacity 300ms ease;\n z-index: 9999;\n backdrop-filter: blur(8px);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Roboto\", \"Helvetica Neue\", Arial, sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n box-sizing: border-box;\n}\n\n.fb-pnl-base {\n position: fixed;\n top: 10vh;\n width: 400px;\n max-width: 90vw;\n max-height: 60vh;\n box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);\n transition: transform 300ms cubic-bezier(0.25, 0.46, 0.45, 0.94);\n z-index: 10000;\n display: flex;\n flex-direction: column;\n overflow-y: auto;\n overflow-x: hidden;\n border-radius: 16px;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Roboto\", \"Helvetica Neue\", Arial, sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n box-sizing: border-box;\n}\n\n.fb-pnl--right { right: 0; }\n.fb-pnl--right.fb-pnl--open { transform: translateX(0px); }\n.fb-pnl--right.fb-pnl--closed { transform: translateX(100%); }\n\n.fb-pnl--left { left: 0; }\n.fb-pnl--left.fb-pnl--open { transform: translateX(0px); }\n.fb-pnl--left.fb-pnl--closed { transform: translateX(-100%); }\n\n.fb-close-btn {\n background: none;\n border: none;\n font-size: 24px;\n cursor: pointer;\n opacity: 0.7;\n padding: 0;\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 4px;\n transition: background-color 150ms ease;\n}\n\n.fb-up {\n display: flex;\n flex-direction: column;\n gap: 6px;\n margin-bottom: 8px;\n}\n\n.fb-upb {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n align-self: flex-start;\n padding: 8px 12px;\n border-radius: 8px;\n background: transparent;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: background-color 150ms ease, opacity 150ms ease;\n font-family: inherit;\n}\n\n.fb-upb:hover:not(.fb-upb--dis) {\n background-color: rgba(37, 99, 235, 0.06);\n}\n\n.fb-upb--dis {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.fb-ups {\n width: 12px;\n height: 12px;\n border: 2px solid transparent;\n border-top: 2px solid currentColor;\n border-radius: 50%;\n animation: spin 1s linear infinite;\n display: inline-block;\n}\n\n.fb-up-extras {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.fb-upe {\n font-size: 12px;\n color: #dc2626;\n}\n\n.fb-ss {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.fb-sp {\n position: relative;\n width: 64px;\n height: 64px;\n border-radius: 6px;\n overflow: hidden;\n border: 1px solid rgba(0, 0, 0, 0.08);\n}\n\n.fb-si {\n width: 100%;\n height: 100%;\n object-fit: cover;\n display: block;\n}\n\n.fb-sr {\n position: absolute;\n top: 2px;\n right: 2px;\n width: 18px;\n height: 18px;\n border-radius: 50%;\n border: none;\n background: rgba(0, 0, 0, 0.65);\n color: #fff;\n font-size: 11px;\n line-height: 1;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n}\n\n.fb-sr:hover {\n background: rgba(0, 0, 0, 0.85);\n}\n\n.fb-sl {\n font-size: 11px;\n opacity: 0.6;\n}\n\n@media (max-width: 768px) {\n .fb-pnl-base {\n width: 100% !important;\n max-width: none !important;\n top: 4vh !important;\n max-height: 92vh !important;\n }\n .fb-cnt { padding: 16px 18px 14px !important; max-height: calc(100vh - 40px) !important; }\n .fb-ta { font-size: 16px !important; min-height: 64px !important; }\n .fb-ttl { font-size: 18px !important; }\n .fb-ei { font-size: 24px !important; }\n .fb-el { font-size: 11px !important; }\n .fb-sub { padding: 12px 20px !important; font-size: 16px !important; }\n}\n`\n\nexport function injectFeedbackCSS(): void {\n\tif (typeof document === 'undefined') return\n\tconst styleId = 'usero-feedback-widget-css'\n\tif (document.getElementById(styleId)) return\n\tconst style = document.createElement('style')\n\tstyle.id = styleId\n\tstyle.textContent = FEEDBACK_CSS\n\tdocument.head.appendChild(style)\n}\n","// Framework-free Usero widget. Renders into a shadow root attached to a\n// container <div> on document.body so host page styles cannot bleed in\n// and our class names cannot collide with the host's.\n//\n// API:\n// const widget = initUseroFeedbackWidget({ clientId: '...' })\n// widget.destroy()\n//\n// The endpoint and request shape match the React widget exactly so a\n// feedback row created here is indistinguishable from one created via React.\n\nimport { FeedbackApiClient } from './api'\nimport { getGradientEnd } from './colorUtils'\nimport {\n\tcreatePluginLogger,\n\ttype PluginContext,\n\ttype UseroPlugin,\n} from './plugin'\nimport { DEFAULT_API_URL } from './types'\nimport {\n\tDARK_THEME,\n\tDEFAULT_THEME,\n\tEMOJI_BACKGROUNDS,\n\tEMOJI_MAP,\n\ttype FeedbackData,\n\ttype FeedbackRating,\n\ttype FeedbackSubmission,\n\ttype FeedbackWidgetProps,\n\tmergeTheme,\n\tRATING_LABELS,\n\ttype ScreenshotData,\n\ttype WidgetPosition,\n\ttype WidgetTheme,\n} from './types'\nimport { validateFeedbackSubmission } from './validation'\nimport { FEEDBACK_CSS } from './widgetCss'\n\nexport {\n\tDARK_THEME,\n\tDEFAULT_THEME,\n\tmergeTheme,\n}\n\n// Pick the base theme to merge user overrides onto, based on the OS color\n// scheme. Defaults to dark when matchMedia is unavailable (SSR, old browsers)\n// or when neither dark nor light is explicitly preferred.\nfunction resolveBaseTheme(): WidgetTheme {\n\tif (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {\n\t\treturn DARK_THEME\n\t}\n\tif (window.matchMedia('(prefers-color-scheme: dark)').matches) return DARK_THEME\n\tif (window.matchMedia('(prefers-color-scheme: light)').matches) return DEFAULT_THEME\n\treturn DARK_THEME\n}\n\n// Resolve the effective theme. If the caller passed a partial theme, it wins\n// per-key over the OS-resolved base. If they passed nothing, we just use the\n// OS-resolved base directly.\nexport function resolveTheme(userTheme: Partial<WidgetTheme> | undefined): WidgetTheme {\n\tconst base = resolveBaseTheme()\n\tif (!userTheme) return base\n\treturn { ...base, ...userTheme }\n}\nexport type {\n\tFeedbackData,\n\tFeedbackRating,\n\tFeedbackSubmission,\n\tFeedbackWidgetProps,\n\tScreenshotData,\n\tWidgetPosition,\n\tWidgetTheme,\n} from './types'\nexport type {\n\tPluginContext,\n\tPluginLogger,\n\tUseroPlugin,\n} from './plugin'\n\nexport interface UseroWidgetHandle {\n\tdestroy: () => void\n\topen: () => void\n\tclose: () => void\n\t// Hot-swap any subset of props EXCEPT `clientId` and `baseUrl`. Changing\n\t// those requires destroy + re-init (the API client is bound to baseUrl,\n\t// and clientId is the identity of the widget). Callers (e.g. the React\n\t// wrapper) typically route callbacks through this so identity changes on\n\t// re-render don't force a tear-down.\n\tupdate: (next: Partial<Omit<FeedbackWidgetProps, 'clientId' | 'baseUrl'>>) => void\n\t// Resolves once every plugin's `onInit` promise has settled (fulfilled\n\t// OR rejected). Intended for end-to-end tests and dogfooding scripts\n\t// that want to trigger a synthetic submit only after plugins are live.\n\t// Plugins with synchronous `onInit` make this resolve on the next\n\t// microtask. If no plugins are registered, it resolves immediately.\n\twhenReady: () => Promise<void>\n}\n\nconst EMAIL_STORAGE_KEY = 'feedback_user_email'\n\nfunction escapeHtml(value: string): string {\n\treturn value.replace(/[&<>\"']/g, ch => {\n\t\tswitch (ch) {\n\t\t\tcase '&':\n\t\t\t\treturn '&'\n\t\t\tcase '<':\n\t\t\t\treturn '<'\n\t\t\tcase '>':\n\t\t\t\treturn '>'\n\t\t\tcase '\"':\n\t\t\t\treturn '"'\n\t\t\tcase \"'\":\n\t\t\t\treturn '''\n\t\t\tdefault:\n\t\t\t\treturn ch\n\t\t}\n\t})\n}\n\n// Merge plugin onFeedbackSubmit patches into a base submission.\n//\n// Top-level keys: shallow-merge, later patches win wholesale.\n// `metadata`: deep-merge one level. Earlier keys are preserved when later\n// patches don't set them; later keys win on conflict. This means two\n// plugins can both contribute `metadata: { ... }` without either erasing\n// the other's keys.\nexport function mergePluginPatches(\n\tbase: FeedbackSubmission,\n\tpatches: ReadonlyArray<Partial<FeedbackSubmission> | undefined>,\n): FeedbackSubmission {\n\tlet result: FeedbackSubmission = base\n\tfor (const patch of patches) {\n\t\tif (!patch || typeof patch !== 'object') continue\n\t\tconst { metadata: patchMetadata, ...rest } = patch\n\t\tresult = { ...result, ...rest }\n\t\tif (patchMetadata && typeof patchMetadata === 'object') {\n\t\t\tresult.metadata = {\n\t\t\t\t...(result.metadata ?? {}),\n\t\t\t\t...patchMetadata,\n\t\t\t}\n\t\t}\n\t}\n\treturn result\n}\n\nfunction readStoredEmail(): string {\n\tif (typeof window === 'undefined') return ''\n\ttry {\n\t\treturn window.localStorage.getItem(EMAIL_STORAGE_KEY) ?? ''\n\t} catch {\n\t\treturn ''\n\t}\n}\n\nfunction writeStoredEmail(email: string): void {\n\ttry {\n\t\twindow.localStorage.setItem(EMAIL_STORAGE_KEY, email)\n\t} catch {\n\t\t// ignore\n\t}\n}\n\nexport function initUseroFeedbackWidget(\n\tprops: FeedbackWidgetProps,\n): UseroWidgetHandle {\n\tif (typeof document === 'undefined') {\n\t\treturn {\n\t\t\tdestroy: () => {},\n\t\t\topen: () => {},\n\t\t\tclose: () => {},\n\t\t\tupdate: () => {},\n\t\t\twhenReady: () => Promise.resolve(),\n\t\t}\n\t}\n\n\tconst { clientId, baseUrl } = props\n\n\tif (!clientId || clientId.length < 3) {\n\t\tconst err = new Error('Invalid config. Contact admin.')\n\t\tprops.onError?.(err)\n\t\treturn {\n\t\t\tdestroy: () => {},\n\t\t\topen: () => {},\n\t\t\tclose: () => {},\n\t\t\tupdate: () => {},\n\t\t\twhenReady: () => Promise.resolve(),\n\t\t}\n\t}\n\n\t// Mutable view of every prop that can be hot-swapped via update(). Read\n\t// these at render time, never destructure into local const above the\n\t// render closures or you'll capture stale values.\n\tlet position: WidgetPosition = props.position ?? 'right'\n\tlet userThemeOverride: Partial<WidgetTheme> | undefined = props.theme\n\tlet theme: WidgetTheme = resolveTheme(userThemeOverride)\n\tlet title: string = props.title ?? 'Share Feedback'\n\tlet placeholder: string = props.placeholder ?? 'Tell us what you think... (optional)'\n\tlet showEmailOption: boolean = props.showEmailOption ?? true\n\tlet showScreenshotOption: boolean = props.showScreenshotOption ?? true\n\tlet environment: string | undefined = props.environment\n\tlet metadata: Record<string, unknown> | undefined = props.metadata\n\tlet onSubmit: FeedbackWidgetProps['onSubmit'] = props.onSubmit\n\tlet onError: FeedbackWidgetProps['onError'] = props.onError\n\tlet onOpen: FeedbackWidgetProps['onOpen'] = props.onOpen\n\tlet onClose: FeedbackWidgetProps['onClose'] = props.onClose\n\n\tconst apiClient = new FeedbackApiClient(baseUrl)\n\n\t// Plugin registry. Each plugin gets its own context with a private store.\n\t// `onInit` is fired non-blocking so a slow plugin can't delay the first\n\t// paint. Errors are caught so a misbehaving plugin can't tear the widget\n\t// down or block submissions.\n\tconst pluginList: ReadonlyArray<UseroPlugin> = props.plugins ?? []\n\tconst pluginStores = new Map<string, unknown>()\n\tconst pluginContexts = new Map<string, PluginContext>()\n\t// Tracks every onInit's settlement so `whenReady()` can resolve only\n\t// after all plugins have finished initializing. Synchronous onInits\n\t// resolve on the next microtask via Promise.resolve().\n\tconst initPromises: Promise<void>[] = []\n\tfor (const plugin of pluginList) {\n\t\tconst ctx: PluginContext = {\n\t\t\tclientId,\n\t\t\tbaseUrl: baseUrl ?? DEFAULT_API_URL,\n\t\t\tlogger: createPluginLogger(plugin.name),\n\t\t\tgetStore: <T,>() => pluginStores.get(plugin.name) as T | undefined,\n\t\t\tsetStore: <T,>(value: T) => {\n\t\t\t\tpluginStores.set(plugin.name, value)\n\t\t\t},\n\t\t}\n\t\tpluginContexts.set(plugin.name, ctx)\n\t\tif (plugin.onInit) {\n\t\t\tconst settled = (async () => {\n\t\t\t\ttry {\n\t\t\t\t\tawait plugin.onInit?.(ctx)\n\t\t\t\t} catch (err) {\n\t\t\t\t\tctx.logger.error('onInit threw', err)\n\t\t\t\t}\n\t\t\t})()\n\t\t\tinitPromises.push(settled)\n\t\t}\n\t}\n\tconst readyPromise: Promise<void> =\n\t\tinitPromises.length === 0 ? Promise.resolve() : Promise.all(initPromises).then(() => {})\n\n\t// State\n\tlet isOpen = false\n\tlet selectedRating: FeedbackRating | undefined = undefined\n\tlet comment = ''\n\tlet shareEmail = false\n\tlet userEmail = readStoredEmail()\n\tlet isSubmitting = false\n\tlet submitMessage: { type: 'success' | 'error'; text: string } | null = null\n\tlet screenshots: ScreenshotData[] = []\n\tlet isUploadingScreenshot = false\n\tlet screenshotError: string | null = null\n\n\tconst MAX_SCREENSHOTS = 3\n\tconst MAX_SCREENSHOT_BYTES = 10 * 1024 * 1024 // 10MB, matches old React widget\n\n\t// Host element on the page. ShadowRoot keeps host CSS isolated.\n\tconst host = document.createElement('div')\n\thost.setAttribute('data-usero-widget', '')\n\t// position: static so the host element doesn't take any space; the\n\t// fixed-position children inside the shadow root anchor to the viewport.\n\thost.style.cssText = 'all: initial;'\n\tdocument.body.appendChild(host)\n\tconst root = host.attachShadow({ mode: 'open' })\n\n\t// Notify recording plugins (e.g. session-replay) that a shadow root they\n\t// need to observe has just been mounted into the page. rrweb's automatic\n\t// shadow-root traversal only catches roots that exist at record-start\n\t// time (via the initial full snapshot) OR that get attached as part of\n\t// a new node addition observed by its MutationObserver. Our widget host\n\t// is appended to <body> first and `attachShadow` is called immediately\n\t// after, so the observed mutation does not yet have a shadowRoot. The\n\t// session-replay plugin handles this signal by re-taking a full\n\t// snapshot, which causes rrweb to walk into and start observing this\n\t// shadow tree. Dispatched as a CustomEvent on window so the plugin\n\t// stays decoupled from the widget.\n\tfunction notifyShadowUpdate(reason: 'mount' | 'panel-open'): void {\n\t\ttry {\n\t\t\twindow.dispatchEvent(\n\t\t\t\tnew CustomEvent('usero:shadow-update', {\n\t\t\t\t\tdetail: { host, root, reason },\n\t\t\t\t}),\n\t\t\t)\n\t\t} catch {\n\t\t\t// Older browsers without CustomEvent / dispatchEvent: best-effort.\n\t\t}\n\t}\n\tnotifyShadowUpdate('mount')\n\n\t// Inject styles once into the shadow root.\n\tconst style = document.createElement('style')\n\tstyle.textContent = FEEDBACK_CSS\n\troot.appendChild(style)\n\n\t// Containers\n\tconst buttonEl = document.createElement('button')\n\tconst backdropEl = document.createElement('div')\n\tconst panelEl = document.createElement('div')\n\troot.appendChild(buttonEl)\n\troot.appendChild(backdropEl)\n\troot.appendChild(panelEl)\n\n\tfunction setSubmitMessage(\n\t\tnext: { type: 'success' | 'error'; text: string } | null,\n\t): void {\n\t\tsubmitMessage = next\n\t\trender()\n\t}\n\n\tfunction open(): void {\n\t\tif (isOpen) return\n\t\tisOpen = true\n\t\t// Reset transient state\n\t\tselectedRating = undefined\n\t\tcomment = ''\n\t\tshareEmail = false\n\t\tsubmitMessage = null\n\t\tscreenshots = []\n\t\tscreenshotError = null\n\t\tisUploadingScreenshot = false\n\t\tapiClient.ping()\n\t\tonOpen?.()\n\t\trender()\n\t\t// The panel's interactive content is `innerHTML`-ed inside the shadow\n\t\t// root on first render, which IS observable by rrweb's MutationObserver\n\t\t// as long as the shadow root is registered. Re-fire the signal so a\n\t\t// recorder that started before the widget mounted (or before the panel\n\t\t// rendered its first interactive markup) re-snapshots and observes the\n\t\t// shadow root from this point on.\n\t\tnotifyShadowUpdate('panel-open')\n\t}\n\n\tasync function handleScreenshotFile(file: File): Promise<void> {\n\t\tscreenshotError = null\n\t\tif (!file.type.startsWith('image/')) {\n\t\t\tscreenshotError = 'Image files only'\n\t\t\trender()\n\t\t\treturn\n\t\t}\n\t\tif (file.size > MAX_SCREENSHOT_BYTES) {\n\t\t\tscreenshotError = 'Max 10MB'\n\t\t\trender()\n\t\t\treturn\n\t\t}\n\t\tif (screenshots.length >= MAX_SCREENSHOTS) {\n\t\t\tscreenshotError = `Max ${MAX_SCREENSHOTS} screenshots`\n\t\t\trender()\n\t\t\treturn\n\t\t}\n\n\t\tisUploadingScreenshot = true\n\t\trender()\n\t\ttry {\n\t\t\tconst uploaded = await apiClient.uploadScreenshot(file, clientId)\n\t\t\tscreenshots = [...screenshots, uploaded]\n\t\t} catch (err) {\n\t\t\tscreenshotError = err instanceof Error ? err.message : 'Upload failed'\n\t\t} finally {\n\t\t\tisUploadingScreenshot = false\n\t\t\trender()\n\t\t}\n\t}\n\n\tfunction removeScreenshot(index: number): void {\n\t\tscreenshots = screenshots.filter((_, i) => i !== index)\n\t\trender()\n\t}\n\n\tfunction close(): void {\n\t\tif (!isOpen) return\n\t\tisOpen = false\n\t\tonClose?.()\n\t\trender()\n\t}\n\n\tasync function submitForm(): Promise<void> {\n\t\tif (isSubmitting) return\n\t\tisSubmitting = true\n\t\tsubmitMessage = null\n\t\trender()\n\n\t\tconst feedbackData: FeedbackData = {\n\t\t\trating: selectedRating,\n\t\t\tcomment: comment.trim() || undefined,\n\t\t\tuserEmail: shareEmail ? userEmail : undefined,\n\t\t\tscreenshots: screenshots.length > 0 ? screenshots : undefined,\n\t\t\tmetadata: {\n\t\t\t\tpageUrl: window.location.href,\n\t\t\t\tpageTitle: document.title || 'Untitled Page',\n\t\t\t\treferrer: document.referrer || undefined,\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t},\n\t\t}\n\n\t\tconst submission: FeedbackSubmission = {\n\t\t\tclientId,\n\t\t\trating: feedbackData.rating,\n\t\t\tcomment: feedbackData.comment,\n\t\t\tuserEmail: feedbackData.userEmail,\n\t\t\tpageUrl: feedbackData.metadata.pageUrl,\n\t\t\tpageTitle: feedbackData.metadata.pageTitle,\n\t\t\treferrer: feedbackData.metadata.referrer,\n\t\t\tenvironment,\n\t\t}\n\t\tif (screenshots.length > 0) submission.screenshots = screenshots\n\t\tif (metadata !== undefined) submission.metadata = metadata\n\n\t\tconst validation = validateFeedbackSubmission(submission)\n\t\tif (!validation.isValid) {\n\t\t\tisSubmitting = false\n\t\t\tsetSubmitMessage({ type: 'error', text: validation.errors.join(', ') })\n\t\t\treturn\n\t\t}\n\n\t\t// Run plugin onFeedbackSubmit hooks in parallel and merge the\n\t\t// returned partial payloads into the outgoing submission. A plugin\n\t\t// that throws or rejects is logged and skipped — never blocks submit.\n\t\t//\n\t\t// Merge policy:\n\t\t// - `metadata` is DEEP-merged (one level): later plugins' keys\n\t\t// win on conflict, but non-conflicting keys from earlier\n\t\t// plugins are preserved. metadata is the natural collision\n\t\t// point (every plugin wants to attach context) so deep merge\n\t\t// is what users expect.\n\t\t// - Every other top-level key is shallow-merged: later plugins\n\t\t// win wholesale. This is fine in practice because dedicated\n\t\t// keys like `replayEvents` have a single writer.\n\t\tlet enrichedSubmission: FeedbackSubmission = submission\n\t\tif (pluginList.length > 0) {\n\t\t\tconst patchPromises = pluginList.map(async plugin => {\n\t\t\t\tif (!plugin.onFeedbackSubmit) return undefined\n\t\t\t\tconst ctx = pluginContexts.get(plugin.name)\n\t\t\t\tif (!ctx) return undefined\n\t\t\t\ttry {\n\t\t\t\t\treturn await plugin.onFeedbackSubmit(ctx, submission)\n\t\t\t\t} catch (err) {\n\t\t\t\t\tctx.logger.error('onFeedbackSubmit threw', err)\n\t\t\t\t\treturn undefined\n\t\t\t\t}\n\t\t\t})\n\t\t\tconst patches = await Promise.all(patchPromises)\n\t\t\tenrichedSubmission = mergePluginPatches(submission, patches)\n\t\t}\n\n\t\ttry {\n\t\t\tconst response = await apiClient.submitFeedback(enrichedSubmission)\n\t\t\tif (response.success) {\n\t\t\t\tif (shareEmail && userEmail) writeStoredEmail(userEmail)\n\t\t\t\tonSubmit?.(feedbackData)\n\t\t\t\tselectedRating = undefined\n\t\t\t\tcomment = ''\n\t\t\t\tshareEmail = false\n\t\t\t\tscreenshots = []\n\t\t\t\tscreenshotError = null\n\t\t\t\tsubmitMessage = { type: 'success', text: 'Thank you!' }\n\t\t\t} else {\n\t\t\t\tconst msg = response.error ?? 'Error occurred. Try again.'\n\t\t\t\tonError?.(new Error(msg))\n\t\t\t\tsubmitMessage = { type: 'error', text: msg }\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tconst msg = err instanceof Error ? err.message : 'Error occurred. Try again.'\n\t\t\tonError?.(new Error(msg))\n\t\t\tsubmitMessage = { type: 'error', text: msg }\n\t\t} finally {\n\t\t\tisSubmitting = false\n\t\t\trender()\n\t\t}\n\t}\n\n\t// Static button content + styles (only style.background changes once)\n\tfunction renderButton(): void {\n\t\tbuttonEl.className = `fb-btn fb-btn--${position} ${isOpen ? 'fb-btn--open' : ''}`\n\t\tbuttonEl.setAttribute('aria-label', 'Open feedback')\n\t\tbuttonEl.type = 'button'\n\t\tbuttonEl.style.background = `linear-gradient(135deg, ${theme.primary}, ${getGradientEnd(theme.primary)})`\n\t\tbuttonEl.innerHTML = isOpen\n\t\t\t? `<span style=\"font-size:20px;\">✕</span>`\n\t\t\t: ''\n\t}\n\n\tfunction renderBackdrop(): void {\n\t\tbackdropEl.className = 'fb-backdrop'\n\t\tbackdropEl.style.display = isOpen ? 'block' : 'none'\n\t\tbackdropEl.setAttribute('aria-label', 'Close modal')\n\t}\n\n\tfunction renderPanel(): void {\n\t\tpanelEl.className = `fb-pnl-base fb-pnl--${position} ${\n\t\t\tisOpen ? 'fb-pnl--open' : 'fb-pnl--closed'\n\t\t}`\n\t\tpanelEl.style.backgroundColor = theme.background\n\t\tif (position === 'right') {\n\t\t\tpanelEl.style.borderLeft = `1px solid ${theme.border}`\n\t\t\tpanelEl.style.borderRight = ''\n\t\t} else {\n\t\t\tpanelEl.style.borderRight = `1px solid ${theme.border}`\n\t\t\tpanelEl.style.borderLeft = ''\n\t\t}\n\t\tpanelEl.setAttribute('role', 'dialog')\n\t\tpanelEl.setAttribute('aria-modal', 'true')\n\t\tpanelEl.setAttribute('aria-labelledby', 'usero-feedback-title')\n\n\t\tconst remaining = 1000 - comment.length\n\t\tconst lowChars = remaining < 50\n\n\t\tconst ratingsHtml = ([1, 2, 3, 4] as FeedbackRating[])\n\t\t\t.map(r => {\n\t\t\t\tconst sel = selectedRating === r\n\t\t\t\tconst bg = EMOJI_BACKGROUNDS[r]\n\t\t\t\tconst cls = ['fb-ec', sel && 'fb-ec--sel'].filter(Boolean).join(' ')\n\t\t\t\t// Set color on the button so .fb-el (color: currentColor) inherits\n\t\t\t\t// the themed foreground. Without this it falls back to the UA\n\t\t\t\t// default for <button>, which is black on dark backgrounds.\n\t\t\t\treturn `\n\t\t\t\t\t<div class=\"${cls}\" style=\"background:${bg}\">\n\t\t\t\t\t\t<button type=\"button\" class=\"fb-eb\" data-rating=\"${r}\" role=\"radio\" aria-checked=\"${sel}\" aria-label=\"${r}: ${RATING_LABELS[r]}\" style=\"color:${theme.text}\">\n\t\t\t\t\t\t\t<div class=\"fb-ei\"><span role=\"img\" aria-label=\"${RATING_LABELS[r]}\">${EMOJI_MAP[r]}</span></div>\n\t\t\t\t\t\t\t<div class=\"fb-el\" style=\"color:${theme.text}\">${RATING_LABELS[r]}</div>\n\t\t\t\t\t\t</button>\n\t\t\t\t\t</div>\n\t\t\t\t`\n\t\t\t})\n\t\t\t.join('')\n\n\t\tconst messageHtml = submitMessage\n\t\t\t? `<div class=\"fb-msg fb-msg--header ${submitMessage.type === 'success' ? 'fb-msg--ok' : 'fb-msg--err'}\">${submitMessage.type === 'success' ? '✓' : '⚠'} ${escapeHtml(submitMessage.text)}</div>`\n\t\t\t: ''\n\n\t\t// The upload button + char counter share a single horizontal row to\n\t\t// keep the panel compact (matches the legacy react-feedback-collector\n\t\t// layout). Upload extras (error message, previews, max limit) live on\n\t\t// their own row beneath, so they can wrap freely.\n\t\tconst uploadBtnHtml = showScreenshotOption\n\t\t\t? (() => {\n\t\t\t\t\tconst atMax = screenshots.length >= MAX_SCREENSHOTS\n\t\t\t\t\tconst btnDisabled = isUploadingScreenshot || atMax\n\t\t\t\t\treturn `\n\t\t\t\t\t\t<input type=\"file\" accept=\"image/*\" data-role=\"screenshot-input\" style=\"display:none;\" aria-label=\"Choose screenshot\" />\n\t\t\t\t\t\t<button type=\"button\" class=\"fb-upb ${btnDisabled ? 'fb-upb--dis' : ''}\" data-role=\"screenshot-pick\" ${btnDisabled ? 'disabled' : ''} style=\"border:1px solid ${theme.border};color:${theme.text};\">\n\t\t\t\t\t\t\t${\n\t\t\t\t\t\t\t\tisUploadingScreenshot\n\t\t\t\t\t\t\t\t\t? '<span class=\"fb-ups\"></span> Uploading...'\n\t\t\t\t\t\t\t\t\t: '📷 Add screenshot'\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</button>\n\t\t\t\t\t`\n\t\t\t\t})()\n\t\t\t: ''\n\t\tconst uploadExtrasHtml = showScreenshotOption\n\t\t\t? (() => {\n\t\t\t\t\tconst atMax = screenshots.length >= MAX_SCREENSHOTS\n\t\t\t\t\tconst previewsHtml = screenshots\n\t\t\t\t\t\t.map(\n\t\t\t\t\t\t\t(shot, i) => `\n\t\t\t\t\t\t\t\t<div class=\"fb-sp\">\n\t\t\t\t\t\t\t\t\t<img src=\"${escapeHtml(shot.url)}\" alt=\"Screenshot ${i + 1}\" class=\"fb-si\" />\n\t\t\t\t\t\t\t\t\t<button type=\"button\" class=\"fb-sr\" data-role=\"screenshot-remove\" data-index=\"${i}\" aria-label=\"Remove screenshot\">✕</button>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t`,\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.join('')\n\t\t\t\t\tconst errorHtml = screenshotError\n\t\t\t\t\t\t? `<div class=\"fb-upe\">⚠ ${escapeHtml(screenshotError)}</div>`\n\t\t\t\t\t\t: ''\n\t\t\t\t\tconst limitHtml = atMax\n\t\t\t\t\t\t? `<div class=\"fb-sl\">Max ${MAX_SCREENSHOTS}</div>`\n\t\t\t\t\t\t: ''\n\t\t\t\t\treturn screenshotError || screenshots.length > 0 || atMax\n\t\t\t\t\t\t? `<div class=\"fb-up-extras\">${errorHtml}${\n\t\t\t\t\t\t\t\tscreenshots.length > 0\n\t\t\t\t\t\t\t\t\t? `<div class=\"fb-ss\">${previewsHtml}</div>`\n\t\t\t\t\t\t\t\t\t: ''\n\t\t\t\t\t\t\t}${limitHtml}</div>`\n\t\t\t\t\t\t: ''\n\t\t\t\t})()\n\t\t\t: ''\n\n\t\tconst emailBlockHtml = showEmailOption\n\t\t\t? `\n\t\t\t\t<div class=\"fb-email\">\n\t\t\t\t\t<label class=\"fb-email-lbl\" style=\"color:${theme.text}\">\n\t\t\t\t\t\t<input type=\"checkbox\" class=\"fb-email-cb\" data-role=\"share-email\" ${shareEmail ? 'checked' : ''} aria-label=\"Share email\" />\n\t\t\t\t\t\t<span>Share my email</span>\n\t\t\t\t\t</label>\n\t\t\t\t\t${\n\t\t\t\t\t\tshareEmail\n\t\t\t\t\t\t\t? `<input type=\"email\" class=\"fb-email-inp\" data-role=\"email-input\" value=\"${escapeHtml(userEmail)}\" placeholder=\"your.email@example.com\" aria-label=\"Email\" maxlength=\"254\" autocomplete=\"email\" style=\"border:1px solid ${theme.border};color:${theme.text};background-color:${theme.background};\" />`\n\t\t\t\t\t\t\t: ''\n\t\t\t\t\t}\n\t\t\t\t</div>\n\t\t\t`\n\t\t\t: ''\n\n\t\tconst submitDisabled = isSubmitting\n\t\tconst submitStyle = `background:linear-gradient(135deg, ${theme.primary}, ${getGradientEnd(theme.primary)});color:#ffffff;${submitDisabled ? 'opacity:0.6;cursor:not-allowed;' : ''}`\n\n\t\tpanelEl.innerHTML = `\n\t\t\t<div class=\"fb-cnt\">\n\t\t\t\t<div class=\"fb-hdr\" style=\"border-bottom:1px solid ${theme.border}\">\n\t\t\t\t\t<h2 id=\"usero-feedback-title\" class=\"fb-ttl\" style=\"color:${theme.text}\">${escapeHtml(title)}</h2>\n\t\t\t\t\t${messageHtml}\n\t\t\t\t\t<button class=\"fb-close-btn\" data-role=\"close\" style=\"color:${theme.text}\" aria-label=\"Close\" type=\"button\">✕</button>\n\t\t\t\t</div>\n\t\t\t\t<form data-role=\"form\">\n\t\t\t\t\t<div class=\"fb-es\" role=\"radiogroup\" aria-label=\"Rate experience\">${ratingsHtml}</div>\n\t\t\t\t\t<textarea class=\"fb-ta\" data-role=\"comment\" placeholder=\"${escapeHtml(placeholder)}\" aria-label=\"Comments\" maxlength=\"1000\" rows=\"2\" style=\"border:1px solid ${theme.border};color:${theme.text};background-color:${theme.background};\">${escapeHtml(comment)}</textarea>\n\t\t\t\t\t<div class=\"fb-toolrow\">\n\t\t\t\t\t\t${uploadBtnHtml}\n\t\t\t\t\t\t<div class=\"fb-charcount${lowChars ? ' fb-charcount--low' : ''}\" data-role=\"charcount\" style=\"color:${lowChars ? '#dc2626' : theme.text};opacity:${lowChars ? 1 : 0.6};\">${remaining} chars remaining</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t${uploadExtrasHtml ? `<div class=\"fb-up\">${uploadExtrasHtml}</div>` : ''}\n\t\t\t\t\t${emailBlockHtml}\n\t\t\t\t\t<button class=\"fb-sub ${submitDisabled ? 'fb-sub--dis' : ''}\" type=\"submit\" aria-label=\"Submit\" ${submitDisabled ? 'disabled' : ''} style=\"${submitStyle}\">\n\t\t\t\t\t\t${isSubmitting ? '<span class=\"fb-spin\"></span>' : ''}\n\t\t\t\t\t\t${isSubmitting ? 'Submitting...' : 'Send Feedback 🚀'}\n\t\t\t\t\t</button>\n\t\t\t\t</form>\n\t\t\t</div>\n\t\t`\n\n\t\t// Wire up panel-internal events\n\t\tconst form = panelEl.querySelector<HTMLFormElement>('form[data-role=\"form\"]')\n\t\tform?.addEventListener('submit', e => {\n\t\t\te.preventDefault()\n\t\t\tvoid submitForm()\n\t\t})\n\n\t\tpanelEl\n\t\t\t.querySelector<HTMLButtonElement>('button[data-role=\"close\"]')\n\t\t\t?.addEventListener('click', close)\n\n\t\tpanelEl\n\t\t\t.querySelectorAll<HTMLButtonElement>('button[data-rating]')\n\t\t\t.forEach(btn => {\n\t\t\t\tbtn.addEventListener('click', () => {\n\t\t\t\t\tconst value = btn.dataset.rating\n\t\t\t\t\tif (value === '1' || value === '2' || value === '3' || value === '4') {\n\t\t\t\t\t\tselectedRating = Number(value) as FeedbackRating\n\t\t\t\t\t\trender()\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t})\n\n\t\tconst textarea = panelEl.querySelector<HTMLTextAreaElement>(\n\t\t\t'textarea[data-role=\"comment\"]',\n\t\t)\n\t\tif (textarea) {\n\t\t\ttextarea.addEventListener('input', () => {\n\t\t\t\tif (textarea.value.length <= 1000) {\n\t\t\t\t\tcomment = textarea.value\n\t\t\t\t\t// Update char count without full rerender to avoid losing focus.\n\t\t\t\t\t// IMPORTANT: target by stable class. A previous selector\n\t\t\t\t\t// `.fb-cnt form > div > div` matched the first rating tile,\n\t\t\t\t\t// hijacking it with the char-count text on every keystroke.\n\t\t\t\t\tconst counter = panelEl.querySelector<HTMLDivElement>(\n\t\t\t\t\t\t'[data-role=\"charcount\"]',\n\t\t\t\t\t)\n\t\t\t\t\tif (counter) {\n\t\t\t\t\t\tconst left = 1000 - comment.length\n\t\t\t\t\t\tcounter.textContent = `${left} chars remaining`\n\t\t\t\t\t\tcounter.style.color = left < 50 ? '#dc2626' : theme.text\n\t\t\t\t\t\tcounter.style.opacity = left < 50 ? '1' : '0.6'\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\n\t\tconst shareCb = panelEl.querySelector<HTMLInputElement>(\n\t\t\t'input[data-role=\"share-email\"]',\n\t\t)\n\t\tshareCb?.addEventListener('change', () => {\n\t\t\tshareEmail = shareCb.checked\n\t\t\trender()\n\t\t})\n\n\t\tconst emailInp = panelEl.querySelector<HTMLInputElement>(\n\t\t\t'input[data-role=\"email-input\"]',\n\t\t)\n\t\temailInp?.addEventListener('input', () => {\n\t\t\tif (emailInp.value.length <= 254) {\n\t\t\t\tuserEmail = emailInp.value\n\t\t\t}\n\t\t})\n\n\t\tconst fileInput = panelEl.querySelector<HTMLInputElement>(\n\t\t\t'input[data-role=\"screenshot-input\"]',\n\t\t)\n\t\tconst pickBtn = panelEl.querySelector<HTMLButtonElement>(\n\t\t\t'button[data-role=\"screenshot-pick\"]',\n\t\t)\n\t\tpickBtn?.addEventListener('click', () => {\n\t\t\tfileInput?.click()\n\t\t})\n\t\tfileInput?.addEventListener('change', () => {\n\t\t\tconst file = fileInput.files?.[0]\n\t\t\tif (!file) return\n\t\t\tvoid handleScreenshotFile(file).finally(() => {\n\t\t\t\tif (fileInput) fileInput.value = ''\n\t\t\t})\n\t\t})\n\t\tpanelEl\n\t\t\t.querySelectorAll<HTMLButtonElement>(\n\t\t\t\t'button[data-role=\"screenshot-remove\"]',\n\t\t\t)\n\t\t\t.forEach(btn => {\n\t\t\t\tbtn.addEventListener('click', () => {\n\t\t\t\t\tconst idx = Number(btn.dataset.index)\n\t\t\t\t\tif (Number.isInteger(idx)) removeScreenshot(idx)\n\t\t\t\t})\n\t\t\t})\n\t}\n\n\tfunction render(): void {\n\t\trenderButton()\n\t\trenderBackdrop()\n\t\trenderPanel()\n\t}\n\n\t// Top-level event listeners\n\tbuttonEl.addEventListener('click', () => {\n\t\tif (isOpen) close()\n\t\telse open()\n\t})\n\tbackdropEl.addEventListener('click', close)\n\n\tconst onKeyDown = (e: KeyboardEvent): void => {\n\t\tif (!isOpen) return\n\t\tif (e.key === 'Escape') close()\n\t\tif (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) {\n\t\t\te.preventDefault()\n\t\t\tvoid submitForm()\n\t\t}\n\t}\n\tdocument.addEventListener('keydown', onKeyDown)\n\n\t// Live OS color-scheme tracking. Only active while the caller has not\n\t// provided an explicit `theme` prop. If they later pass one via update(),\n\t// we detach. If they later clear it (set to undefined), we re-attach.\n\tlet darkMql: MediaQueryList | null = null\n\tlet mqlListener: ((ev: MediaQueryListEvent) => void) | null = null\n\n\tfunction detachMqlListener(): void {\n\t\tif (darkMql && mqlListener) {\n\t\t\tdarkMql.removeEventListener('change', mqlListener)\n\t\t}\n\t\tdarkMql = null\n\t\tmqlListener = null\n\t}\n\n\tfunction attachMqlListener(): void {\n\t\tif (darkMql) return\n\t\tif (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return\n\t\tdarkMql = window.matchMedia('(prefers-color-scheme: dark)')\n\t\tmqlListener = () => {\n\t\t\t// Only react if user still hasn't overridden the theme.\n\t\t\tif (userThemeOverride !== undefined) return\n\t\t\ttheme = resolveTheme(undefined)\n\t\t\trender()\n\t\t}\n\t\tdarkMql.addEventListener('change', mqlListener)\n\t}\n\n\tif (userThemeOverride === undefined) attachMqlListener()\n\n\t// Initial paint\n\trender()\n\n\tlet destroyed = false\n\treturn {\n\t\tdestroy: () => {\n\t\t\tif (destroyed) return\n\t\t\tdestroyed = true\n\t\t\tdocument.removeEventListener('keydown', onKeyDown)\n\t\t\tdetachMqlListener()\n\t\t\tfor (const plugin of pluginList) {\n\t\t\t\tif (!plugin.onDestroy) continue\n\t\t\t\tconst ctx = pluginContexts.get(plugin.name)\n\t\t\t\tif (!ctx) continue\n\t\t\t\ttry {\n\t\t\t\t\tplugin.onDestroy(ctx)\n\t\t\t\t} catch (err) {\n\t\t\t\t\tctx.logger.error('onDestroy threw', err)\n\t\t\t\t}\n\t\t\t}\n\t\t\tpluginStores.clear()\n\t\t\tpluginContexts.clear()\n\t\t\thost.remove()\n\t\t},\n\t\topen,\n\t\tclose,\n\t\twhenReady: () => readyPromise,\n\t\tupdate: next => {\n\t\t\tif (destroyed) return\n\t\t\tlet needsRender = false\n\t\t\tif (next.position !== undefined && next.position !== position) {\n\t\t\t\tposition = next.position\n\t\t\t\tneedsRender = true\n\t\t\t}\n\t\t\tif ('theme' in next) {\n\t\t\t\t// Caller opted in/out of explicit theme control. Track the\n\t\t\t\t// override so the matchMedia listener and any further\n\t\t\t\t// resolutions know whether the user is in charge.\n\t\t\t\tuserThemeOverride = next.theme\n\t\t\t\ttheme = resolveTheme(userThemeOverride)\n\t\t\t\tif (userThemeOverride === undefined) attachMqlListener()\n\t\t\t\telse detachMqlListener()\n\t\t\t\tneedsRender = true\n\t\t\t}\n\t\t\tif (next.title !== undefined && next.title !== title) {\n\t\t\t\ttitle = next.title\n\t\t\t\tneedsRender = true\n\t\t\t}\n\t\t\tif (next.placeholder !== undefined && next.placeholder !== placeholder) {\n\t\t\t\tplaceholder = next.placeholder\n\t\t\t\tneedsRender = true\n\t\t\t}\n\t\t\tif (\n\t\t\t\tnext.showEmailOption !== undefined &&\n\t\t\t\tnext.showEmailOption !== showEmailOption\n\t\t\t) {\n\t\t\t\tshowEmailOption = next.showEmailOption\n\t\t\t\tneedsRender = true\n\t\t\t}\n\t\t\tif (\n\t\t\t\tnext.showScreenshotOption !== undefined &&\n\t\t\t\tnext.showScreenshotOption !== showScreenshotOption\n\t\t\t) {\n\t\t\t\tshowScreenshotOption = next.showScreenshotOption\n\t\t\t\tneedsRender = true\n\t\t\t}\n\t\t\t// Non-render-affecting props: just swap refs.\n\t\t\tif ('environment' in next) environment = next.environment\n\t\t\tif ('metadata' in next) metadata = next.metadata\n\t\t\tif ('onSubmit' in next) onSubmit = next.onSubmit\n\t\t\tif ('onError' in next) onError = next.onError\n\t\t\tif ('onOpen' in next) onOpen = next.onOpen\n\t\t\tif ('onClose' in next) onClose = next.onClose\n\t\t\tif (needsRender) render()\n\t\t},\n\t}\n}\n"]}
|
package/dist/vanilla.d.cts
CHANGED
package/dist/vanilla.d.ts
CHANGED
package/dist/vanilla.js
CHANGED
|
@@ -778,6 +778,17 @@ function initUseroFeedbackWidget(props) {
|
|
|
778
778
|
host.style.cssText = "all: initial;";
|
|
779
779
|
document.body.appendChild(host);
|
|
780
780
|
const root = host.attachShadow({ mode: "open" });
|
|
781
|
+
function notifyShadowUpdate(reason) {
|
|
782
|
+
try {
|
|
783
|
+
window.dispatchEvent(
|
|
784
|
+
new CustomEvent("usero:shadow-update", {
|
|
785
|
+
detail: { host, root, reason }
|
|
786
|
+
})
|
|
787
|
+
);
|
|
788
|
+
} catch {
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
notifyShadowUpdate("mount");
|
|
781
792
|
const style = document.createElement("style");
|
|
782
793
|
style.textContent = FEEDBACK_CSS;
|
|
783
794
|
root.appendChild(style);
|
|
@@ -804,6 +815,7 @@ function initUseroFeedbackWidget(props) {
|
|
|
804
815
|
apiClient.ping();
|
|
805
816
|
onOpen?.();
|
|
806
817
|
render();
|
|
818
|
+
notifyShadowUpdate("panel-open");
|
|
807
819
|
}
|
|
808
820
|
async function handleScreenshotFile(file) {
|
|
809
821
|
screenshotError = null;
|