@usero/sdk 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -58,13 +58,17 @@ The widget includes a screenshot upload button by default. Users can attach up t
58
58
 
59
59
  `unpkg` and `jsDelivr` both serve the IIFE bundle automatically. No separate hosting needed.
60
60
 
61
+ ## Theme
62
+
63
+ The widget auto-detects the OS color scheme via `prefers-color-scheme`. It picks the built-in dark theme on dark systems and the light theme on light systems, and swaps live if the user toggles modes while the widget is open. When no preference is reported (older browsers, SSR), it defaults to dark. Pass an explicit `theme` to override; explicit values always win, and partial overrides merge on top of the OS-resolved base.
64
+
61
65
  ## Options
62
66
 
63
67
  | Option | Type | Default | Description |
64
68
  | ---------------------- | ----------------------------- | --------------------------------------------- | ------------------------------------------ |
65
69
  | `clientId` | `string` | required | Your Usero client ID |
66
70
  | `position` | `'left' \| 'right'` | `'right'` | Which side of the viewport the tab sits on |
67
- | `theme` | `Partial<WidgetTheme>` | light theme | Override colors |
71
+ | `theme` | `Partial<WidgetTheme>` | auto (OS color scheme, dark fallback) | Override colors. Wins over auto-detection |
68
72
  | `title` | `string` | `'Share Feedback'` | Panel header |
69
73
  | `placeholder` | `string` | `'Tell us what you think... (optional)'` | Comment placeholder |
70
74
  | `showEmailOption` | `boolean` | `true` | Show the "share my email" checkbox |
package/dist/react.cjs CHANGED
@@ -608,6 +608,19 @@ var FEEDBACK_CSS = `
608
608
  `;
609
609
 
610
610
  // src/vanilla.ts
611
+ function resolveBaseTheme() {
612
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
613
+ return DARK_THEME;
614
+ }
615
+ if (window.matchMedia("(prefers-color-scheme: dark)").matches) return DARK_THEME;
616
+ if (window.matchMedia("(prefers-color-scheme: light)").matches) return DEFAULT_THEME;
617
+ return DARK_THEME;
618
+ }
619
+ function resolveTheme(userTheme) {
620
+ const base = resolveBaseTheme();
621
+ if (!userTheme) return base;
622
+ return { ...base, ...userTheme };
623
+ }
611
624
  var EMAIL_STORAGE_KEY = "feedback_user_email";
612
625
  function escapeHtml(value) {
613
626
  return value.replace(/[&<>"']/g, (ch) => {
@@ -670,7 +683,8 @@ function initUseroFeedbackWidget(props) {
670
683
  };
671
684
  }
672
685
  let position = props.position ?? "right";
673
- let theme = mergeTheme(props.theme);
686
+ let userThemeOverride = props.theme;
687
+ let theme = resolveTheme(userThemeOverride);
674
688
  let title = props.title ?? "Share Feedback";
675
689
  let placeholder = props.placeholder ?? "Tell us what you think... (optional)";
676
690
  let showEmailOption = props.showEmailOption ?? true;
@@ -911,11 +925,7 @@ function initUseroFeedbackWidget(props) {
911
925
  <form data-role="form">
912
926
  <div class="fb-es" role="radiogroup" aria-label="Rate experience">${ratingsHtml}</div>
913
927
  <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>
914
- <div style="display:flex;justify-content:flex-end;margin-bottom:8px;">
915
- <div style="font-size:12px;color:${lowChars ? "#dc2626" : theme.text};opacity:${lowChars ? 1 : 0.6};margin-left:auto;">
916
- ${remaining} chars remaining
917
- </div>
918
- </div>
928
+ <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>
919
929
  ${screenshotBlockHtml}
920
930
  ${emailBlockHtml}
921
931
  <button class="fb-sub ${submitDisabled ? "fb-sub--dis" : ""}" type="submit" aria-label="Submit" ${submitDisabled ? "disabled" : ""} style="${submitStyle}">
@@ -948,7 +958,7 @@ function initUseroFeedbackWidget(props) {
948
958
  if (textarea.value.length <= 1e3) {
949
959
  comment = textarea.value;
950
960
  const counter = panelEl.querySelector(
951
- ".fb-cnt form > div > div"
961
+ '[data-role="charcount"]'
952
962
  );
953
963
  if (counter) {
954
964
  const left = 1e3 - comment.length;
@@ -1018,6 +1028,27 @@ function initUseroFeedbackWidget(props) {
1018
1028
  }
1019
1029
  };
1020
1030
  document.addEventListener("keydown", onKeyDown);
1031
+ let darkMql = null;
1032
+ let mqlListener = null;
1033
+ function detachMqlListener() {
1034
+ if (darkMql && mqlListener) {
1035
+ darkMql.removeEventListener("change", mqlListener);
1036
+ }
1037
+ darkMql = null;
1038
+ mqlListener = null;
1039
+ }
1040
+ function attachMqlListener() {
1041
+ if (darkMql) return;
1042
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
1043
+ darkMql = window.matchMedia("(prefers-color-scheme: dark)");
1044
+ mqlListener = () => {
1045
+ if (userThemeOverride !== void 0) return;
1046
+ theme = resolveTheme(void 0);
1047
+ render();
1048
+ };
1049
+ darkMql.addEventListener("change", mqlListener);
1050
+ }
1051
+ if (userThemeOverride === void 0) attachMqlListener();
1021
1052
  render();
1022
1053
  let destroyed = false;
1023
1054
  return {
@@ -1025,6 +1056,7 @@ function initUseroFeedbackWidget(props) {
1025
1056
  if (destroyed) return;
1026
1057
  destroyed = true;
1027
1058
  document.removeEventListener("keydown", onKeyDown);
1059
+ detachMqlListener();
1028
1060
  host.remove();
1029
1061
  },
1030
1062
  open,
@@ -1036,8 +1068,11 @@ function initUseroFeedbackWidget(props) {
1036
1068
  position = next.position;
1037
1069
  needsRender = true;
1038
1070
  }
1039
- if (next.theme !== void 0) {
1040
- theme = mergeTheme(next.theme);
1071
+ if ("theme" in next) {
1072
+ userThemeOverride = next.theme;
1073
+ theme = resolveTheme(userThemeOverride);
1074
+ if (userThemeOverride === void 0) attachMqlListener();
1075
+ else detachMqlListener();
1041
1076
  needsRender = true;
1042
1077
  }
1043
1078
  if (next.title !== void 0 && next.title !== title) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts","../src/api.ts","../src/colorUtils.ts","../src/validation.ts","../src/widgetCss.ts","../src/vanilla.ts","../src/react.tsx"],"names":["useRef","useEffect"],"mappings":"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","file":"react.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}\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\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\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","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: 15px;\n padding-bottom: 10px;\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: 16px 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: 24px;\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: 100px;\n padding: 12px;\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: 4px;\n box-sizing: border-box;\n}\n\n.fb-charcount {\n font-size: 12px;\n margin-left: auto;\n margin-bottom: 8px;\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: 8px;\n margin-bottom: 16px;\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: 8px;\n margin-bottom: 12px;\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: 5vh !important;\n max-height: 70vh !important;\n }\n .fb-cnt { padding: 20px !important; max-height: calc(100vh - 80px) !important; }\n .fb-ta { font-size: 16px !important; min-height: 80px !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: 14px 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\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}\nexport type {\n\tFeedbackData,\n\tFeedbackRating,\n\tFeedbackSubmission,\n\tFeedbackWidgetProps,\n\tScreenshotData,\n\tWidgetPosition,\n\tWidgetTheme,\n} from './types'\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}\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 '&amp;'\n\t\t\tcase '<':\n\t\t\t\treturn '&lt;'\n\t\t\tcase '>':\n\t\t\t\treturn '&gt;'\n\t\t\tcase '\"':\n\t\t\t\treturn '&quot;'\n\t\t\tcase \"'\":\n\t\t\t\treturn '&#x27;'\n\t\t\tdefault:\n\t\t\t\treturn ch\n\t\t}\n\t})\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}\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}\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 theme: WidgetTheme = mergeTheme(props.theme)\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// 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\ttry {\n\t\t\tconst response = await apiClient.submitFeedback(submission)\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\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]}\">\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\">${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\tconst screenshotBlockHtml = 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\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\tconst extrasHtml =\n\t\t\t\t\t\tscreenshotError || screenshots.length > 0 || atMax\n\t\t\t\t\t\t\t? `<div class=\"fb-up-extras\">${errorHtml}${\n\t\t\t\t\t\t\t\t\tscreenshots.length > 0\n\t\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\t: ''\n\t\t\t\t\t\t\t\t}${limitHtml}</div>`\n\t\t\t\t\t\t\t: ''\n\t\t\t\t\treturn `\n\t\t\t\t\t\t<div class=\"fb-up\">\n\t\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\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\t${\n\t\t\t\t\t\t\t\t\tisUploadingScreenshot\n\t\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\t: '📷 Add screenshot'\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t${extrasHtml}\n\t\t\t\t\t\t</div>\n\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 style=\"display:flex;justify-content:flex-end;margin-bottom:8px;\">\n\t\t\t\t\t\t<div style=\"font-size:12px;color:${lowChars ? '#dc2626' : theme.text};opacity:${lowChars ? 1 : 0.6};margin-left:auto;\">\n\t\t\t\t\t\t\t${remaining} chars remaining\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t${screenshotBlockHtml}\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\tconst counter = panelEl.querySelector<HTMLDivElement>(\n\t\t\t\t\t\t'.fb-cnt form > div > div',\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// 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\thost.remove()\n\t\t},\n\t\topen,\n\t\tclose,\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 (next.theme !== undefined) {\n\t\t\t\ttheme = mergeTheme(next.theme)\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","// Thin React wrapper around the framework-free vanilla widget. Renders\n// nothing into the React tree; the widget mounts a host <div> on\n// document.body and renders into a shadow root. This keeps the React\n// bundle tiny (just the wrapper) and means there is one source of truth\n// for widget UX, the vanilla implementation.\n\nimport { useEffect, useRef } from 'react'\nimport {\n\tDARK_THEME,\n\tDEFAULT_THEME,\n\tinitUseroFeedbackWidget,\n\tmergeTheme,\n\ttype UseroWidgetHandle,\n} from './vanilla'\nimport type { FeedbackData, FeedbackWidgetProps } from './types'\n\nexport {\n\tDARK_THEME,\n\tDEFAULT_THEME,\n\tmergeTheme,\n}\nexport type {\n\tFeedbackData,\n\tFeedbackRating,\n\tFeedbackSubmission,\n\tFeedbackWidgetProps,\n\tScreenshotData,\n\tWidgetPosition,\n\tWidgetTheme,\n} from './types'\nexport type { UseroWidgetHandle } from './vanilla'\n\nexport function UseroFeedbackWidget(props: FeedbackWidgetProps): null {\n\tconst handleRef = useRef<UseroWidgetHandle | null>(null)\n\n\t// Latest callbacks live in a ref so identity changes (a new arrow each\n\t// render) never re-init the widget.\n\tconst callbacksRef = useRef({\n\t\tonSubmit: props.onSubmit,\n\t\tonError: props.onError,\n\t\tonOpen: props.onOpen,\n\t\tonClose: props.onClose,\n\t})\n\tcallbacksRef.current = {\n\t\tonSubmit: props.onSubmit,\n\t\tonError: props.onError,\n\t\tonOpen: props.onOpen,\n\t\tonClose: props.onClose,\n\t}\n\n\tconst { clientId, baseUrl } = props\n\n\t// Init / tear-down. We only re-init when clientId or baseUrl change,\n\t// because the API client + widget identity are bound to those.\n\tuseEffect(() => {\n\t\tconst handle = initUseroFeedbackWidget({\n\t\t\t...props,\n\t\t\tonSubmit: (data: FeedbackData) => callbacksRef.current.onSubmit?.(data),\n\t\t\tonError: (err: Error) => callbacksRef.current.onError?.(err),\n\t\t\tonOpen: () => callbacksRef.current.onOpen?.(),\n\t\t\tonClose: () => callbacksRef.current.onClose?.(),\n\t\t})\n\t\thandleRef.current = handle\n\t\treturn () => {\n\t\t\thandle.destroy()\n\t\t\thandleRef.current = null\n\t\t}\n\t\t// Intentionally narrow deps. All other prop changes flow through the\n\t\t// update() effect below.\n\t\t// eslint-disable-next-line react-hooks/exhaustive-deps\n\t}, [clientId, baseUrl])\n\n\t// Hot-swap render-affecting props without re-init.\n\tconst themeJson = JSON.stringify(props.theme ?? null)\n\tconst metadataJson = JSON.stringify(props.metadata ?? null)\n\tuseEffect(() => {\n\t\tconst handle = handleRef.current\n\t\tif (!handle) return\n\t\tconst updates: Partial<Omit<FeedbackWidgetProps, 'clientId' | 'baseUrl'>> = {}\n\t\tif (props.position !== undefined) updates.position = props.position\n\t\tif (props.theme !== undefined) updates.theme = props.theme\n\t\tif (props.title !== undefined) updates.title = props.title\n\t\tif (props.placeholder !== undefined) updates.placeholder = props.placeholder\n\t\tif (props.showEmailOption !== undefined) {\n\t\t\tupdates.showEmailOption = props.showEmailOption\n\t\t}\n\t\tif (props.showScreenshotOption !== undefined) {\n\t\t\tupdates.showScreenshotOption = props.showScreenshotOption\n\t\t}\n\t\tif (props.environment !== undefined) updates.environment = props.environment\n\t\tif (props.metadata !== undefined) updates.metadata = props.metadata\n\t\thandle.update(updates)\n\t\t// theme/metadata compared by serialized identity since they're\n\t\t// objects; primitives use direct dep tracking.\n\t}, [\n\t\tprops.position,\n\t\tthemeJson,\n\t\tprops.title,\n\t\tprops.placeholder,\n\t\tprops.showEmailOption,\n\t\tprops.showScreenshotOption,\n\t\tprops.environment,\n\t\tmetadataJson,\n\t])\n\n\treturn null\n}\n"]}
1
+ {"version":3,"sources":["../src/types.ts","../src/api.ts","../src/colorUtils.ts","../src/validation.ts","../src/widgetCss.ts","../src/vanilla.ts","../src/react.tsx"],"names":["useRef","useEffect"],"mappings":"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","file":"react.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}\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\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\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","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: 15px;\n padding-bottom: 10px;\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: 16px 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: 24px;\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: 100px;\n padding: 12px;\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: 4px;\n box-sizing: border-box;\n}\n\n.fb-charcount {\n font-size: 12px;\n margin-left: auto;\n margin-bottom: 8px;\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: 8px;\n margin-bottom: 16px;\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: 8px;\n margin-bottom: 12px;\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: 5vh !important;\n max-height: 70vh !important;\n }\n .fb-cnt { padding: 20px !important; max-height: calc(100vh - 80px) !important; }\n .fb-ta { font-size: 16px !important; min-height: 80px !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: 14px 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\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'\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}\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 '&amp;'\n\t\t\tcase '<':\n\t\t\t\treturn '&lt;'\n\t\t\tcase '>':\n\t\t\t\treturn '&gt;'\n\t\t\tcase '\"':\n\t\t\t\treturn '&quot;'\n\t\t\tcase \"'\":\n\t\t\t\treturn '&#x27;'\n\t\t\tdefault:\n\t\t\t\treturn ch\n\t\t}\n\t})\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}\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}\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// 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\ttry {\n\t\t\tconst response = await apiClient.submitFeedback(submission)\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\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]}\">\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\">${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\tconst screenshotBlockHtml = 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\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\tconst extrasHtml =\n\t\t\t\t\t\tscreenshotError || screenshots.length > 0 || atMax\n\t\t\t\t\t\t\t? `<div class=\"fb-up-extras\">${errorHtml}${\n\t\t\t\t\t\t\t\t\tscreenshots.length > 0\n\t\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\t: ''\n\t\t\t\t\t\t\t\t}${limitHtml}</div>`\n\t\t\t\t\t\t\t: ''\n\t\t\t\t\treturn `\n\t\t\t\t\t\t<div class=\"fb-up\">\n\t\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\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\t${\n\t\t\t\t\t\t\t\t\tisUploadingScreenshot\n\t\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\t: '📷 Add screenshot'\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t${extrasHtml}\n\t\t\t\t\t\t</div>\n\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-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${screenshotBlockHtml}\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\thost.remove()\n\t\t},\n\t\topen,\n\t\tclose,\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","// Thin React wrapper around the framework-free vanilla widget. Renders\n// nothing into the React tree; the widget mounts a host <div> on\n// document.body and renders into a shadow root. This keeps the React\n// bundle tiny (just the wrapper) and means there is one source of truth\n// for widget UX, the vanilla implementation.\n\nimport { useEffect, useRef } from 'react'\nimport {\n\tDARK_THEME,\n\tDEFAULT_THEME,\n\tinitUseroFeedbackWidget,\n\tmergeTheme,\n\ttype UseroWidgetHandle,\n} from './vanilla'\nimport type { FeedbackData, FeedbackWidgetProps } from './types'\n\nexport {\n\tDARK_THEME,\n\tDEFAULT_THEME,\n\tmergeTheme,\n}\nexport type {\n\tFeedbackData,\n\tFeedbackRating,\n\tFeedbackSubmission,\n\tFeedbackWidgetProps,\n\tScreenshotData,\n\tWidgetPosition,\n\tWidgetTheme,\n} from './types'\nexport type { UseroWidgetHandle } from './vanilla'\n\nexport function UseroFeedbackWidget(props: FeedbackWidgetProps): null {\n\tconst handleRef = useRef<UseroWidgetHandle | null>(null)\n\n\t// Latest callbacks live in a ref so identity changes (a new arrow each\n\t// render) never re-init the widget.\n\tconst callbacksRef = useRef({\n\t\tonSubmit: props.onSubmit,\n\t\tonError: props.onError,\n\t\tonOpen: props.onOpen,\n\t\tonClose: props.onClose,\n\t})\n\tcallbacksRef.current = {\n\t\tonSubmit: props.onSubmit,\n\t\tonError: props.onError,\n\t\tonOpen: props.onOpen,\n\t\tonClose: props.onClose,\n\t}\n\n\tconst { clientId, baseUrl } = props\n\n\t// Init / tear-down. We only re-init when clientId or baseUrl change,\n\t// because the API client + widget identity are bound to those.\n\tuseEffect(() => {\n\t\tconst handle = initUseroFeedbackWidget({\n\t\t\t...props,\n\t\t\tonSubmit: (data: FeedbackData) => callbacksRef.current.onSubmit?.(data),\n\t\t\tonError: (err: Error) => callbacksRef.current.onError?.(err),\n\t\t\tonOpen: () => callbacksRef.current.onOpen?.(),\n\t\t\tonClose: () => callbacksRef.current.onClose?.(),\n\t\t})\n\t\thandleRef.current = handle\n\t\treturn () => {\n\t\t\thandle.destroy()\n\t\t\thandleRef.current = null\n\t\t}\n\t\t// Intentionally narrow deps. All other prop changes flow through the\n\t\t// update() effect below.\n\t\t// eslint-disable-next-line react-hooks/exhaustive-deps\n\t}, [clientId, baseUrl])\n\n\t// Hot-swap render-affecting props without re-init.\n\tconst themeJson = JSON.stringify(props.theme ?? null)\n\tconst metadataJson = JSON.stringify(props.metadata ?? null)\n\tuseEffect(() => {\n\t\tconst handle = handleRef.current\n\t\tif (!handle) return\n\t\tconst updates: Partial<Omit<FeedbackWidgetProps, 'clientId' | 'baseUrl'>> = {}\n\t\tif (props.position !== undefined) updates.position = props.position\n\t\tif (props.theme !== undefined) updates.theme = props.theme\n\t\tif (props.title !== undefined) updates.title = props.title\n\t\tif (props.placeholder !== undefined) updates.placeholder = props.placeholder\n\t\tif (props.showEmailOption !== undefined) {\n\t\t\tupdates.showEmailOption = props.showEmailOption\n\t\t}\n\t\tif (props.showScreenshotOption !== undefined) {\n\t\t\tupdates.showScreenshotOption = props.showScreenshotOption\n\t\t}\n\t\tif (props.environment !== undefined) updates.environment = props.environment\n\t\tif (props.metadata !== undefined) updates.metadata = props.metadata\n\t\thandle.update(updates)\n\t\t// theme/metadata compared by serialized identity since they're\n\t\t// objects; primitives use direct dep tracking.\n\t}, [\n\t\tprops.position,\n\t\tthemeJson,\n\t\tprops.title,\n\t\tprops.placeholder,\n\t\tprops.showEmailOption,\n\t\tprops.showScreenshotOption,\n\t\tprops.environment,\n\t\tmetadataJson,\n\t])\n\n\treturn null\n}\n"]}
package/dist/react.js CHANGED
@@ -606,6 +606,19 @@ var FEEDBACK_CSS = `
606
606
  `;
607
607
 
608
608
  // src/vanilla.ts
609
+ function resolveBaseTheme() {
610
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
611
+ return DARK_THEME;
612
+ }
613
+ if (window.matchMedia("(prefers-color-scheme: dark)").matches) return DARK_THEME;
614
+ if (window.matchMedia("(prefers-color-scheme: light)").matches) return DEFAULT_THEME;
615
+ return DARK_THEME;
616
+ }
617
+ function resolveTheme(userTheme) {
618
+ const base = resolveBaseTheme();
619
+ if (!userTheme) return base;
620
+ return { ...base, ...userTheme };
621
+ }
609
622
  var EMAIL_STORAGE_KEY = "feedback_user_email";
610
623
  function escapeHtml(value) {
611
624
  return value.replace(/[&<>"']/g, (ch) => {
@@ -668,7 +681,8 @@ function initUseroFeedbackWidget(props) {
668
681
  };
669
682
  }
670
683
  let position = props.position ?? "right";
671
- let theme = mergeTheme(props.theme);
684
+ let userThemeOverride = props.theme;
685
+ let theme = resolveTheme(userThemeOverride);
672
686
  let title = props.title ?? "Share Feedback";
673
687
  let placeholder = props.placeholder ?? "Tell us what you think... (optional)";
674
688
  let showEmailOption = props.showEmailOption ?? true;
@@ -909,11 +923,7 @@ function initUseroFeedbackWidget(props) {
909
923
  <form data-role="form">
910
924
  <div class="fb-es" role="radiogroup" aria-label="Rate experience">${ratingsHtml}</div>
911
925
  <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>
912
- <div style="display:flex;justify-content:flex-end;margin-bottom:8px;">
913
- <div style="font-size:12px;color:${lowChars ? "#dc2626" : theme.text};opacity:${lowChars ? 1 : 0.6};margin-left:auto;">
914
- ${remaining} chars remaining
915
- </div>
916
- </div>
926
+ <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>
917
927
  ${screenshotBlockHtml}
918
928
  ${emailBlockHtml}
919
929
  <button class="fb-sub ${submitDisabled ? "fb-sub--dis" : ""}" type="submit" aria-label="Submit" ${submitDisabled ? "disabled" : ""} style="${submitStyle}">
@@ -946,7 +956,7 @@ function initUseroFeedbackWidget(props) {
946
956
  if (textarea.value.length <= 1e3) {
947
957
  comment = textarea.value;
948
958
  const counter = panelEl.querySelector(
949
- ".fb-cnt form > div > div"
959
+ '[data-role="charcount"]'
950
960
  );
951
961
  if (counter) {
952
962
  const left = 1e3 - comment.length;
@@ -1016,6 +1026,27 @@ function initUseroFeedbackWidget(props) {
1016
1026
  }
1017
1027
  };
1018
1028
  document.addEventListener("keydown", onKeyDown);
1029
+ let darkMql = null;
1030
+ let mqlListener = null;
1031
+ function detachMqlListener() {
1032
+ if (darkMql && mqlListener) {
1033
+ darkMql.removeEventListener("change", mqlListener);
1034
+ }
1035
+ darkMql = null;
1036
+ mqlListener = null;
1037
+ }
1038
+ function attachMqlListener() {
1039
+ if (darkMql) return;
1040
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
1041
+ darkMql = window.matchMedia("(prefers-color-scheme: dark)");
1042
+ mqlListener = () => {
1043
+ if (userThemeOverride !== void 0) return;
1044
+ theme = resolveTheme(void 0);
1045
+ render();
1046
+ };
1047
+ darkMql.addEventListener("change", mqlListener);
1048
+ }
1049
+ if (userThemeOverride === void 0) attachMqlListener();
1019
1050
  render();
1020
1051
  let destroyed = false;
1021
1052
  return {
@@ -1023,6 +1054,7 @@ function initUseroFeedbackWidget(props) {
1023
1054
  if (destroyed) return;
1024
1055
  destroyed = true;
1025
1056
  document.removeEventListener("keydown", onKeyDown);
1057
+ detachMqlListener();
1026
1058
  host.remove();
1027
1059
  },
1028
1060
  open,
@@ -1034,8 +1066,11 @@ function initUseroFeedbackWidget(props) {
1034
1066
  position = next.position;
1035
1067
  needsRender = true;
1036
1068
  }
1037
- if (next.theme !== void 0) {
1038
- theme = mergeTheme(next.theme);
1069
+ if ("theme" in next) {
1070
+ userThemeOverride = next.theme;
1071
+ theme = resolveTheme(userThemeOverride);
1072
+ if (userThemeOverride === void 0) attachMqlListener();
1073
+ else detachMqlListener();
1039
1074
  needsRender = true;
1040
1075
  }
1041
1076
  if (next.title !== void 0 && next.title !== title) {