@product7/feedback-sdk 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"feedback-sdk.min.js","sources":["../src/utils/errors.js","../src/core/APIService.js","../src/core/EventBus.js","../src/utils/helpers.js","../src/widgets/BaseWidget.js","../src/widgets/ButtonWidget.js","../src/widgets/InlineWidget.js","../src/widgets/TabWidget.js","../src/widgets/WidgetFactory.js","../src/core/FeedbackSDK.js","../src/index.js","../src/styles/styles.js"],"sourcesContent":["export class SDKError extends Error {\n\tconstructor(message, cause) {\n\t\tsuper(message);\n\t\tthis.name = 'SDKError';\n\t\tthis.cause = cause;\n\n\t\tif (Error.captureStackTrace) {\n\t\t\tError.captureStackTrace(this, SDKError);\n\t\t}\n\t}\n}\n\nexport class APIError extends Error {\n\tconstructor(status, message, response) {\n\t\tsuper(message);\n\t\tthis.name = 'APIError';\n\t\tthis.status = status;\n\t\tthis.response = response;\n\n\t\tif (Error.captureStackTrace) {\n\t\t\tError.captureStackTrace(this, APIError);\n\t\t}\n\t}\n\n\tisNetworkError() {\n\t\treturn this.status === 0;\n\t}\n\n\tisClientError() {\n\t\treturn this.status >= 400 && this.status < 500;\n\t}\n\n\tisServerError() {\n\t\treturn this.status >= 500 && this.status < 600;\n\t}\n}\n\nexport class WidgetError extends Error {\n\tconstructor(message, widgetType, widgetId) {\n\t\tsuper(message);\n\t\tthis.name = 'WidgetError';\n\t\tthis.widgetType = widgetType;\n\t\tthis.widgetId = widgetId;\n\n\t\tif (Error.captureStackTrace) {\n\t\t\tError.captureStackTrace(this, WidgetError);\n\t\t}\n\t}\n}\n\nexport class ConfigError extends Error {\n\tconstructor(message, configKey) {\n\t\tsuper(message);\n\t\tthis.name = 'ConfigError';\n\t\tthis.configKey = configKey;\n\n\t\tif (Error.captureStackTrace) {\n\t\t\tError.captureStackTrace(this, ConfigError);\n\t\t}\n\t}\n}\n\nexport class ValidationError extends Error {\n\tconstructor(message, field, value) {\n\t\tsuper(message);\n\t\tthis.name = 'ValidationError';\n\t\tthis.field = field;\n\t\tthis.value = value;\n\n\t\tif (Error.captureStackTrace) {\n\t\t\tError.captureStackTrace(this, ValidationError);\n\t\t}\n\t}\n}\n\nexport class ErrorHandler {\n\tconstructor(debug = false) {\n\t\tthis.debug = debug;\n\t}\n\n\thandle(error, context = '') {\n\t\tconst errorInfo = {\n\t\t\tname: error.name,\n\t\t\tmessage: error.message,\n\t\t\tcontext,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t};\n\n\t\tif (error instanceof APIError) {\n\t\t\terrorInfo.status = error.status;\n\t\t\terrorInfo.type = 'api';\n\t\t} else if (error instanceof WidgetError) {\n\t\t\terrorInfo.widgetType = error.widgetType;\n\t\t\terrorInfo.widgetId = error.widgetId;\n\t\t\terrorInfo.type = 'widget';\n\t\t} else if (error instanceof ConfigError) {\n\t\t\terrorInfo.configKey = error.configKey;\n\t\t\terrorInfo.type = 'config';\n\t\t} else if (error instanceof ValidationError) {\n\t\t\terrorInfo.field = error.field;\n\t\t\terrorInfo.value = error.value;\n\t\t\terrorInfo.type = 'validation';\n\t\t} else {\n\t\t\terrorInfo.type = 'unknown';\n\t\t}\n\n\t\tif (this.debug) {\n\t\t\tconsole.error('[FeedbackSDK Error]', errorInfo, error);\n\t\t} else {\n\t\t\tconsole.error('[FeedbackSDK Error]', error.message);\n\t\t}\n\n\t\treturn errorInfo;\n\t}\n\n\tgetUserMessage(error) {\n\t\tif (error instanceof APIError) {\n\t\t\tif (error.isNetworkError()) {\n\t\t\t\treturn 'Network error. Please check your connection and try again.';\n\t\t\t} else if (error.isClientError()) {\n\t\t\t\treturn 'Invalid request. Please check your input and try again.';\n\t\t\t} else if (error.isServerError()) {\n\t\t\t\treturn 'Server error. Please try again later.';\n\t\t\t}\n\t\t\treturn 'Failed to submit feedback. Please try again.';\n\t\t}\n\n\t\tif (error instanceof ValidationError) {\n\t\t\treturn `Please check your ${error.field}: ${error.message}`;\n\t\t}\n\n\t\tif (error instanceof ConfigError) {\n\t\t\treturn 'Configuration error. Please check your SDK setup.';\n\t\t}\n\n\t\tif (error instanceof WidgetError) {\n\t\t\treturn 'Widget error. Please try refreshing the page.';\n\t\t}\n\n\t\treturn 'An unexpected error occurred. Please try again.';\n\t}\n}\n","import { APIError } from '../utils/errors.js';\n\nexport class APIService {\n\tconstructor(config = {}) {\n\t\tthis.workspace = config.workspace;\n\t\tthis.sessionToken = null;\n\t\tthis.sessionExpiry = null;\n\t\tthis.userContext = config.userContext || null;\n\n\t\t// Construct workspace-specific API URL\n\t\tif (config.apiUrl) {\n\t\t\t// If explicitly provided, use it\n\t\t\tthis.baseURL = config.apiUrl;\n\t\t} else if (this.workspace) {\n\t\t\t// Construct from workspace: workspace.api.staging.product7.io/api/v1\n\t\t\tthis.baseURL = `https://${this.workspace}.api.staging.product7.io/api/v1`;\n\t\t} else {\n\t\t\t// Fallback to default\n\t\t\tthis.baseURL = 'https://api.staging.product7.io/api/v1';\n\t\t}\n\n\t\tconsole.log('[APIService] Using API URL:', this.baseURL);\n\n\t\t// Try to load existing session from localStorage\n\t\tthis._loadStoredSession();\n\t}\n\n\tasync init(userContext = null) {\n\t\tconsole.log('[APIService] Starting initialization...');\n\n\t\tif (userContext) {\n\t\t\tthis.userContext = userContext;\n\t\t}\n\n\t\t// Check if we have a valid session token\n\t\tif (this.isSessionValid()) {\n\t\t\tconsole.log('[APIService] Found valid existing session');\n\t\t\treturn { sessionToken: this.sessionToken };\n\t\t}\n\n\t\t// Try to get user context from various sources if not provided\n\t\tif (!this.userContext) {\n\t\t\tconsole.log(\n\t\t\t\t'[APIService] No user context provided, attempting auto-detection...'\n\t\t\t);\n\t\t\tthis.userContext = this._getUserContextFromStorage();\n\t\t}\n\n\t\tif (!this.userContext || !this.workspace) {\n\t\t\tconst error = `Missing ${!this.workspace ? 'workspace' : 'user context'} for initialization`;\n\t\t\tconsole.error('[APIService]', error);\n\t\t\tthrow new APIError(400, error);\n\t\t}\n\n\t\tconsole.log('[APIService] User context detected:', this.userContext);\n\n\t\tconst payload = {\n\t\t\tworkspace: this.workspace,\n\t\t\tuser: this.userContext,\n\t\t};\n\n\t\tconsole.log(\n\t\t\t'[APIService] Making init request to:',\n\t\t\t`${this.baseURL}/widget/init`\n\t\t);\n\t\tconsole.log('[APIService] Payload:', payload);\n\n\t\ttry {\n\t\t\tconst response = await this._makeRequest('/widget/init', {\n\t\t\t\tmethod: 'POST',\n\t\t\t\tbody: JSON.stringify(payload),\n\t\t\t\theaders: {\n\t\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tconsole.log('[APIService] Init response:', response);\n\n\t\t\t// Store session token and expiry\n\t\t\tthis.sessionToken = response.session_token;\n\t\t\tthis.sessionExpiry = new Date(Date.now() + response.expires_in * 1000);\n\n\t\t\t// Store session in localStorage for persistence\n\t\t\tthis._storeSession();\n\n\t\t\treturn {\n\t\t\t\tsessionToken: this.sessionToken,\n\t\t\t\tconfig: response.config || {},\n\t\t\t\texpiresIn: response.expires_in,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tconsole.error('[APIService] Init failed:', error);\n\t\t\tthrow new APIError(\n\t\t\t\terror.status || 500,\n\t\t\t\t`Failed to initialize widget: ${error.message}`,\n\t\t\t\terror.response\n\t\t\t);\n\t\t}\n\t}\n\n\tasync submitFeedback(feedbackData) {\n\t\t// Ensure we have a valid session\n\t\tif (!this.isSessionValid()) {\n\t\t\tawait this.init();\n\t\t}\n\n\t\tif (!this.sessionToken) {\n\t\t\tthrow new APIError(401, 'No valid session token available');\n\t\t}\n\n\t\tconst payload = {\n\t\t\tboard:\n\t\t\t\tfeedbackData.board_id || feedbackData.board || feedbackData.boardId,\n\t\t\ttitle: feedbackData.title,\n\t\t\tcontent: feedbackData.content,\n\t\t\tattachments: feedbackData.attachments || [],\n\t\t};\n\n\t\ttry {\n\t\t\tconst response = await this._makeRequest('/widget/feedback', {\n\t\t\t\tmethod: 'POST',\n\t\t\t\tbody: JSON.stringify(payload),\n\t\t\t\theaders: {\n\t\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t\tAuthorization: `Bearer ${this.sessionToken}`,\n\t\t\t\t},\n\t\t\t});\n\n\t\t\treturn response;\n\t\t} catch (error) {\n\t\t\t// If session expired, try to reinitialize once\n\t\t\tif (error.status === 401) {\n\t\t\t\tthis.sessionToken = null;\n\t\t\t\tthis.sessionExpiry = null;\n\t\t\t\tawait this.init();\n\n\t\t\t\t// Retry the request with new session\n\t\t\t\treturn this.submitFeedback(feedbackData);\n\t\t\t}\n\n\t\t\tthrow new APIError(\n\t\t\t\terror.status || 500,\n\t\t\t\t`Failed to submit feedback: ${error.message}`,\n\t\t\t\terror.response\n\t\t\t);\n\t\t}\n\t}\n\n\tisSessionValid() {\n\t\treturn (\n\t\t\tthis.sessionToken && this.sessionExpiry && new Date() < this.sessionExpiry\n\t\t);\n\t}\n\n\tsetUserContext(userContext) {\n\t\tthis.userContext = userContext;\n\t\t// Store in localStorage for persistence\n\t\tif (typeof localStorage !== 'undefined') {\n\t\t\tlocalStorage.setItem(\n\t\t\t\t'feedbackSDK_userContext',\n\t\t\t\tJSON.stringify(userContext)\n\t\t\t);\n\t\t}\n\t}\n\n\tgetUserContext() {\n\t\treturn this.userContext;\n\t}\n\n\tclearSession() {\n\t\tthis.sessionToken = null;\n\t\tthis.sessionExpiry = null;\n\t\tif (typeof localStorage !== 'undefined') {\n\t\t\tlocalStorage.removeItem('feedbackSDK_session');\n\t\t}\n\t}\n\n\t_getUserContextFromStorage() {\n\t\tif (typeof localStorage === 'undefined') return null;\n\n\t\tconsole.log('[APIService] Attempting to detect user from storage...');\n\n\t\ttry {\n\t\t\t// Try to get from feedbackSDK specific storage first\n\t\t\tconst stored = localStorage.getItem('feedbackSDK_userContext');\n\t\t\tif (stored) {\n\t\t\t\tconsole.log('[APIService] Found user context in feedbackSDK storage');\n\t\t\t\treturn JSON.parse(stored);\n\t\t\t}\n\n\t\t\t// Try to get from window object (if set by parent application)\n\t\t\tif (typeof window !== 'undefined' && window.FeedbackSDKUserContext) {\n\t\t\t\tconsole.log(\n\t\t\t\t\t'[APIService] Found user context in window.FeedbackSDKUserContext'\n\t\t\t\t);\n\t\t\t\treturn window.FeedbackSDKUserContext;\n\t\t\t}\n\n\t\t\t// Check window.currentUser\n\t\t\tif (typeof window !== 'undefined' && window.currentUser) {\n\t\t\t\tconsole.log('[APIService] Found user context in window.currentUser');\n\t\t\t\treturn this._mapUserData(window.currentUser);\n\t\t\t}\n\n\t\t\t// Try to extract from existing session storage\n\t\t\tconst authSources = ['auth', 'currentUser', 'userSession', 'user'];\n\n\t\t\tfor (const key of authSources) {\n\t\t\t\tconst sessionData = localStorage.getItem(key);\n\t\t\t\tif (sessionData) {\n\t\t\t\t\tconsole.log(`[APIService] Found data in localStorage.${key}`);\n\t\t\t\t\tconst parsed = JSON.parse(sessionData);\n\n\t\t\t\t\t// Handle nested user data (like {user: {...}, token: ...})\n\t\t\t\t\tconst userData = parsed.user || parsed;\n\n\t\t\t\t\tif (userData && (userData.id || userData.user_id || userData.email)) {\n\t\t\t\t\t\tconsole.log('[APIService] Successfully mapped user data');\n\t\t\t\t\t\treturn this._mapUserData(userData);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconsole.log('[APIService] No user context found in any storage location');\n\t\t\treturn null;\n\t\t} catch (error) {\n\t\t\tconsole.warn(\n\t\t\t\t'[FeedbackSDK] Failed to load user context from storage:',\n\t\t\t\terror\n\t\t\t);\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t_mapUserData(userData) {\n\t\tconsole.log('[APIService] Mapping user data:', userData);\n\n\t\tconst mapped = {\n\t\t\tuser_id: userData.id || userData.user_id || userData.userId,\n\t\t\temail: userData.email,\n\t\t\tname: userData.name || userData.displayName || userData.full_name,\n\t\t\tcustom_fields: {},\n\t\t\tcompany: {},\n\t\t};\n\n\t\t// Map company data if available\n\t\tif (userData.company || userData.organization) {\n\t\t\tconst company = userData.company || userData.organization;\n\t\t\tmapped.company = {\n\t\t\t\tid: company.id || company.company_id,\n\t\t\t\tname: company.name || company.company_name,\n\t\t\t\tmonthly_spend: company.monthly_spend || company.spend,\n\t\t\t};\n\t\t}\n\n\t\t// Map any additional custom fields\n\t\tconst customFieldKeys = ['plan', 'role', 'tier', 'subscription'];\n\t\tcustomFieldKeys.forEach((key) => {\n\t\t\tif (userData[key]) {\n\t\t\t\tmapped.custom_fields[key] = userData[key];\n\t\t\t}\n\t\t});\n\n\t\tconsole.log('[APIService] Mapped result:', mapped);\n\t\treturn mapped;\n\t}\n\n\t_storeSession() {\n\t\tif (typeof localStorage === 'undefined') return;\n\n\t\ttry {\n\t\t\tconst sessionData = {\n\t\t\t\ttoken: this.sessionToken,\n\t\t\t\texpiry: this.sessionExpiry.toISOString(),\n\t\t\t\tworkspace: this.workspace,\n\t\t\t};\n\t\t\tlocalStorage.setItem('feedbackSDK_session', JSON.stringify(sessionData));\n\t\t} catch (error) {\n\t\t\tconsole.warn('[FeedbackSDK] Failed to store session:', error);\n\t\t}\n\t}\n\n\t_loadStoredSession() {\n\t\tif (typeof localStorage === 'undefined') return false;\n\n\t\ttry {\n\t\t\tconst stored = localStorage.getItem('feedbackSDK_session');\n\t\t\tif (!stored) return false;\n\n\t\t\tconst sessionData = JSON.parse(stored);\n\t\t\tthis.sessionToken = sessionData.token;\n\t\t\tthis.sessionExpiry = new Date(sessionData.expiry);\n\n\t\t\treturn this.isSessionValid();\n\t\t} catch (error) {\n\t\t\tconsole.warn('[FeedbackSDK] Failed to load stored session:', error);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tasync _makeRequest(endpoint, options = {}) {\n\t\tconst url = `${this.baseURL}${endpoint}`;\n\t\tconsole.log('[APIService] Making request to:', url);\n\n\t\ttry {\n\t\t\tconst response = await fetch(url, options);\n\n\t\t\tif (!response.ok) {\n\t\t\t\tlet errorMessage = `HTTP ${response.status}`;\n\t\t\t\tlet responseData = null;\n\n\t\t\t\ttry {\n\t\t\t\t\tresponseData = await response.json();\n\t\t\t\t\terrorMessage =\n\t\t\t\t\t\tresponseData.message || responseData.error || errorMessage;\n\t\t\t\t} catch (e) {\n\t\t\t\t\terrorMessage = (await response.text()) || errorMessage;\n\t\t\t\t}\n\n\t\t\t\tthrow new APIError(response.status, errorMessage, responseData);\n\t\t\t}\n\n\t\t\tconst contentType = response.headers.get('content-type');\n\t\t\tif (contentType && contentType.includes('application/json')) {\n\t\t\t\treturn await response.json();\n\t\t\t}\n\n\t\t\treturn await response.text();\n\t\t} catch (error) {\n\t\t\tif (error instanceof APIError) {\n\t\t\t\tthrow error;\n\t\t\t}\n\n\t\t\t// Network or other errors\n\t\t\tthrow new APIError(0, error.message, null);\n\t\t}\n\t}\n}\n","export class EventBus {\n\tconstructor() {\n\t\tthis.events = new Map();\n\t}\n\n\ton(event, callback) {\n\t\tif (!this.events.has(event)) {\n\t\t\tthis.events.set(event, []);\n\t\t}\n\t\tthis.events.get(event).push(callback);\n\n\t\treturn () => this.off(event, callback);\n\t}\n\n\toff(event, callback) {\n\t\tconst callbacks = this.events.get(event);\n\t\tif (callbacks) {\n\t\t\tconst index = callbacks.indexOf(callback);\n\t\t\tif (index > -1) {\n\t\t\t\tcallbacks.splice(index, 1);\n\t\t\t}\n\t\t}\n\t}\n\n\temit(event, data) {\n\t\tconst callbacks = this.events.get(event);\n\t\tif (callbacks) {\n\t\t\tcallbacks.forEach((callback) => {\n\t\t\t\ttry {\n\t\t\t\t\tcallback(data);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconsole.error('[FeedbackSDK] Event callback error:', error);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\tonce(event, callback) {\n\t\tconst unsubscribe = this.on(event, (data) => {\n\t\t\tcallback(data);\n\t\t\tunsubscribe();\n\t\t});\n\t\treturn unsubscribe;\n\t}\n\n\tclear() {\n\t\tthis.events.clear();\n\t}\n\n\tgetListenerCount(event) {\n\t\tconst callbacks = this.events.get(event);\n\t\treturn callbacks ? callbacks.length : 0;\n\t}\n}\n","export function generateId(prefix = 'feedback') {\n\tconst timestamp = Date.now();\n\tconst random = Math.random().toString(36).substring(2, 9);\n\treturn `${prefix}_${timestamp}_${random}`;\n}\n\nexport function deepMerge(target, source) {\n\tconst result = { ...target };\n\n\tfor (const key in source) {\n\t\tif (source.hasOwnProperty(key)) {\n\t\t\tif (\n\t\t\t\tsource[key] &&\n\t\t\t\ttypeof source[key] === 'object' &&\n\t\t\t\t!Array.isArray(source[key])\n\t\t\t) {\n\t\t\t\tresult[key] = deepMerge(target[key] || {}, source[key]);\n\t\t\t} else {\n\t\t\t\tresult[key] = source[key];\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result;\n}\n\nexport function debounce(func, wait) {\n\tlet timeout;\n\treturn function executedFunction(...args) {\n\t\tconst later = () => {\n\t\t\tclearTimeout(timeout);\n\t\t\tfunc(...args);\n\t\t};\n\t\tclearTimeout(timeout);\n\t\ttimeout = setTimeout(later, wait);\n\t};\n}\n\nexport function throttle(func, limit) {\n\tlet lastFunc;\n\tlet lastRan;\n\treturn function (...args) {\n\t\tif (!lastRan) {\n\t\t\tfunc(...args);\n\t\t\tlastRan = Date.now();\n\t\t} else {\n\t\t\tclearTimeout(lastFunc);\n\t\t\tlastFunc = setTimeout(\n\t\t\t\t() => {\n\t\t\t\t\tif (Date.now() - lastRan >= limit) {\n\t\t\t\t\t\tfunc(...args);\n\t\t\t\t\t\tlastRan = Date.now();\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tlimit - (Date.now() - lastRan)\n\t\t\t);\n\t\t}\n\t};\n}\n\nexport function isValidEmail(email) {\n\tif (!email || typeof email !== 'string') return false;\n\n\tconst emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n\treturn emailRegex.test(email.trim());\n}\n\nexport function sanitizeHTML(str) {\n\tif (!str || typeof str !== 'string') return '';\n\n\tconst div = document.createElement('div');\n\tdiv.textContent = str;\n\treturn div.innerHTML;\n}\n\nexport function getCSSProperty(element, property, fallback = '') {\n\tif (!element || !property) return fallback;\n\n\ttry {\n\t\tconst style = window.getComputedStyle(element);\n\t\treturn style.getPropertyValue(property) || fallback;\n\t} catch (error) {\n\t\treturn fallback;\n\t}\n}\n\nexport function isInViewport(element) {\n\tif (!element) return false;\n\n\tconst rect = element.getBoundingClientRect();\n\treturn (\n\t\trect.top >= 0 &&\n\t\trect.left >= 0 &&\n\t\trect.bottom <=\n\t\t\t(window.innerHeight || document.documentElement.clientHeight) &&\n\t\trect.right <= (window.innerWidth || document.documentElement.clientWidth)\n\t);\n}\n\nexport function scrollToElement(element, options = {}) {\n\tif (!element) return;\n\n\tconst defaultOptions = {\n\t\tbehavior: 'smooth',\n\t\tblock: 'center',\n\t\tinline: 'nearest',\n\t};\n\n\telement.scrollIntoView({ ...defaultOptions, ...options });\n}\n\nexport function getBrowserInfo() {\n\tconst userAgent = navigator.userAgent;\n\tconst platform = navigator.platform;\n\n\treturn {\n\t\tuserAgent,\n\t\tplatform,\n\t\tlanguage: navigator.language || navigator.userLanguage,\n\t\tcookieEnabled: navigator.cookieEnabled,\n\t\tscreenResolution: `${screen.width}x${screen.height}`,\n\t\twindowSize: `${window.innerWidth}x${window.innerHeight}`,\n\t\ttimezone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n\t};\n}\n\nexport function formatFileSize(bytes) {\n\tif (bytes === 0) return '0 Bytes';\n\n\tconst k = 1024;\n\tconst sizes = ['Bytes', 'KB', 'MB', 'GB'];\n\tconst i = Math.floor(Math.log(bytes) / Math.log(k));\n\n\treturn parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];\n}\n\nexport function delay(ms) {\n\treturn new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport function safeJsonParse(str, fallback = null) {\n\ttry {\n\t\treturn JSON.parse(str);\n\t} catch (error) {\n\t\treturn fallback;\n\t}\n}\n\nexport function escapeRegex(string) {\n\treturn string.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nexport function getNestedProperty(obj, path, defaultValue = undefined) {\n\tif (!obj || !path) return defaultValue;\n\n\tconst keys = path.split('.');\n\tlet current = obj;\n\n\tfor (const key of keys) {\n\t\tif (current === null || current === undefined || !(key in current)) {\n\t\t\treturn defaultValue;\n\t\t}\n\t\tcurrent = current[key];\n\t}\n\n\treturn current;\n}\n\nexport function setNestedProperty(obj, path, value) {\n\tif (!obj || !path) return obj;\n\n\tconst keys = path.split('.');\n\tconst lastKey = keys.pop();\n\tlet current = obj;\n\n\tfor (const key of keys) {\n\t\tif (!(key in current) || typeof current[key] !== 'object') {\n\t\t\tcurrent[key] = {};\n\t\t}\n\t\tcurrent = current[key];\n\t}\n\n\tcurrent[lastKey] = value;\n\treturn obj;\n}\n\nexport function isBrowser() {\n\treturn typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\nexport function isMobile() {\n\tif (!isBrowser()) return false;\n\n\treturn (\n\t\t/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(\n\t\t\tnavigator.userAgent\n\t\t) || window.innerWidth <= 768\n\t);\n}\n\nexport function getCurrentTimestamp() {\n\treturn new Date().toISOString();\n}\n\nexport function validateConfig(config, required = []) {\n\tconst missing = [];\n\n\tfor (const key of required) {\n\t\tif (!config[key]) {\n\t\t\tmissing.push(key);\n\t\t}\n\t}\n\n\tif (missing.length > 0) {\n\t\tthrow new Error(`Missing required configuration: ${missing.join(', ')}`);\n\t}\n\n\treturn true;\n}\n","export class BaseWidget {\n\tconstructor(options = {}) {\n\t\tthis.id = options.id;\n\t\tthis.sdk = options.sdk;\n\t\tthis.apiService = options.apiService;\n\t\tthis.type = options.type || 'base';\n\n\t\tthis.options = {\n\t\t\tcontainer: null,\n\t\t\tposition: this.sdk.config.position,\n\t\t\ttheme: this.sdk.config.theme,\n\t\t\tboardId: this.sdk.config.boardId,\n\t\t\tautoShow: false,\n\t\t\tcustomStyles: {},\n\t\t\t...options,\n\t\t};\n\n\t\tthis.element = null;\n\t\tthis.modalElement = null;\n\t\tthis.mounted = false;\n\t\tthis.destroyed = false;\n\n\t\tthis.state = {\n\t\t\tisOpen: false,\n\t\t\tisSubmitting: false,\n\t\t\ttitle: '',\n\t\t\tcontent: '',\n\t\t\temail: '',\n\t\t\tattachments: [],\n\t\t\terrors: {},\n\t\t};\n\n\t\tthis._bindMethods();\n\t}\n\n\tmount(container) {\n\t\tif (this.mounted || this.destroyed) return this;\n\n\t\tif (typeof container === 'string') {\n\t\t\tcontainer = document.querySelector(container);\n\t\t}\n\n\t\tif (!container) {\n\t\t\tcontainer = document.body;\n\t\t}\n\n\t\tthis.container = container;\n\t\tthis.element = this._render();\n\t\tthis.container.appendChild(this.element);\n\n\t\tthis.mounted = true;\n\t\tthis._attachEvents();\n\t\tthis.onMount();\n\n\t\tif (this.options.autoShow) {\n\t\t\tthis.show();\n\t\t}\n\n\t\tthis.sdk.eventBus.emit('widget:mounted', { widget: this });\n\t\treturn this;\n\t}\n\n\tshow() {\n\t\tif (this.element) {\n\t\t\tthis.element.style.display = 'block';\n\t\t}\n\t\treturn this;\n\t}\n\n\thide() {\n\t\tif (this.element) {\n\t\t\tthis.element.style.display = 'none';\n\t\t}\n\t\treturn this;\n\t}\n\n\topenModal() {\n\t\tthis.state.isOpen = true;\n\t\tthis._renderModal();\n\t}\n\n\tcloseModal() {\n\t\tthis.state.isOpen = false;\n\t\tif (this.modalElement) {\n\t\t\tthis.modalElement.remove();\n\t\t\tthis.modalElement = null;\n\t\t}\n\t\tthis._resetForm();\n\t}\n\n\tasync submitFeedback() {\n\t\tif (this.state.isSubmitting) return;\n\n\t\ttry {\n\t\t\tthis.state.isSubmitting = true;\n\t\t\tthis._updateSubmitButton();\n\n\t\t\tconst payload = {\n\t\t\t\ttitle: this.state.title || 'Feedback',\n\t\t\t\tcontent: this.state.content,\n\t\t\t\temail: this.state.email,\n\t\t\t\tboard_id: this.options.boardId,\n\t\t\t\tattachments: this.state.attachments,\n\t\t\t};\n\n\t\t\tif (!this.state.content.trim()) {\n\t\t\t\tthis._showError('Please enter your feedback message.');\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst response = await this.apiService.submitFeedback(payload);\n\n\t\t\tthis._showSuccessMessage();\n\t\t\tthis.closeModal();\n\n\t\t\tthis.sdk.eventBus.emit('feedback:submitted', {\n\t\t\t\twidget: this,\n\t\t\t\tfeedback: response,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tthis._showError('Failed to submit feedback. Please try again.');\n\t\t\tthis.sdk.eventBus.emit('feedback:error', { widget: this, error });\n\t\t} finally {\n\t\t\tthis.state.isSubmitting = false;\n\t\t\tthis._updateSubmitButton();\n\t\t}\n\t}\n\n\thandleConfigUpdate(newConfig) {\n\t\tthis.options.theme = newConfig.theme;\n\t\tif (this.element) {\n\t\t\tthis._updateTheme();\n\t\t}\n\t}\n\n\tdestroy() {\n\t\tif (this.destroyed) return;\n\n\t\tthis.onDestroy();\n\t\tthis.closeModal();\n\n\t\tif (this.element && this.element.parentNode) {\n\t\t\tthis.element.parentNode.removeChild(this.element);\n\t\t}\n\n\t\tthis.destroyed = true;\n\t\tthis.mounted = false;\n\t\tthis.sdk.eventBus.emit('widget:destroyed', { widget: this });\n\t}\n\n\tonMount() {}\n\tonDestroy() {}\n\n\t_render() {\n\t\tthrow new Error('_render() must be implemented by concrete widget');\n\t}\n\n\t_attachEvents() {\n\t\t// Override in concrete widgets\n\t}\n\n\t_bindMethods() {\n\t\tthis.openModal = this.openModal.bind(this);\n\t\tthis.closeModal = this.closeModal.bind(this);\n\t\tthis.submitFeedback = this.submitFeedback.bind(this);\n\t}\n\n\t_renderModal() {\n\t\tif (this.modalElement) return;\n\n\t\tthis.modalElement = document.createElement('div');\n\t\tthis.modalElement.className = `feedback-modal theme-${this.options.theme}`;\n\t\tthis.modalElement.innerHTML = this._getModalHTML();\n\n\t\tdocument.body.appendChild(this.modalElement);\n\t\tthis._attachModalEvents();\n\n\t\tconst firstInput = this.modalElement.querySelector('input, textarea');\n\t\tif (firstInput) {\n\t\t\tsetTimeout(() => firstInput.focus(), 100);\n\t\t}\n\t}\n\n\t_getModalHTML() {\n\t\treturn `\n <div class=\"feedback-modal-overlay\">\n <div class=\"feedback-modal-content\">\n <div class=\"feedback-modal-header\">\n <h3>Send Feedback</h3>\n <button class=\"feedback-modal-close\" type=\"button\">&times;</button>\n </div>\n <form class=\"feedback-form\">\n <div class=\"feedback-form-group\">\n <label for=\"feedback-title-${this.id}\">Title</label>\n <input \n type=\"text\" \n id=\"feedback-title-${this.id}\" \n name=\"title\" \n placeholder=\"Brief description of your feedback\"\n value=\"${this.state.title}\"\n />\n </div>\n <div class=\"feedback-form-group\">\n <label for=\"feedback-content-${this.id}\">Message *</label>\n <textarea \n id=\"feedback-content-${this.id}\" \n name=\"content\" \n placeholder=\"Tell us more about your feedback...\"\n required\n >${this.state.content}</textarea>\n </div>\n <div class=\"feedback-form-actions\">\n <button type=\"button\" class=\"feedback-btn feedback-btn-cancel\">Cancel</button>\n <button type=\"submit\" class=\"feedback-btn feedback-btn-submit\">\n ${this.state.isSubmitting ? 'Sending...' : 'Send Feedback'}\n </button>\n </div>\n <div class=\"feedback-error\" style=\"display: none;\"></div>\n </form>\n </div>\n </div>\n `;\n\t}\n\n\t_attachModalEvents() {\n\t\tconst modal = this.modalElement;\n\n\t\tmodal\n\t\t\t.querySelector('.feedback-modal-close')\n\t\t\t.addEventListener('click', this.closeModal);\n\t\tmodal\n\t\t\t.querySelector('.feedback-btn-cancel')\n\t\t\t.addEventListener('click', this.closeModal);\n\t\tmodal\n\t\t\t.querySelector('.feedback-modal-overlay')\n\t\t\t.addEventListener('click', (e) => {\n\t\t\t\tif (e.target === e.currentTarget) {\n\t\t\t\t\tthis.closeModal();\n\t\t\t\t}\n\t\t\t});\n\n\t\tconst form = modal.querySelector('.feedback-form');\n\t\tform.addEventListener('submit', (e) => {\n\t\t\te.preventDefault();\n\t\t\tthis.submitFeedback();\n\t\t});\n\n\t\tmodal\n\t\t\t.querySelector('input[name=\"title\"]')\n\t\t\t.addEventListener('input', (e) => {\n\t\t\t\tthis.state.title = e.target.value;\n\t\t\t});\n\n\t\tmodal\n\t\t\t.querySelector('textarea[name=\"content\"]')\n\t\t\t.addEventListener('input', (e) => {\n\t\t\t\tthis.state.content = e.target.value;\n\t\t\t});\n\t}\n\n\t_updateSubmitButton() {\n\t\tif (this.modalElement) {\n\t\t\tconst submitBtn = this.modalElement.querySelector('.feedback-btn-submit');\n\t\t\tif (submitBtn) {\n\t\t\t\tsubmitBtn.textContent = this.state.isSubmitting\n\t\t\t\t\t? 'Sending...'\n\t\t\t\t\t: 'Send Feedback';\n\t\t\t\tsubmitBtn.disabled = this.state.isSubmitting;\n\t\t\t}\n\t\t}\n\t}\n\n\t_showError(message) {\n\t\tif (this.modalElement) {\n\t\t\tconst errorElement = this.modalElement.querySelector('.feedback-error');\n\t\t\terrorElement.textContent = message;\n\t\t\terrorElement.style.display = 'block';\n\t\t\tsetTimeout(() => {\n\t\t\t\tif (errorElement) {\n\t\t\t\t\terrorElement.style.display = 'none';\n\t\t\t\t}\n\t\t\t}, 5000);\n\t\t}\n\t}\n\n\t_showSuccessMessage() {\n\t\tconst notification = document.createElement('div');\n\t\tnotification.className = 'feedback-success-notification';\n\t\tnotification.innerHTML = `\n <div class=\"feedback-success-content\">\n <span>✓ Feedback submitted successfully!</span>\n <button class=\"feedback-success-close\">&times;</button>\n </div>\n `;\n\n\t\tdocument.body.appendChild(notification);\n\n\t\tsetTimeout(() => {\n\t\t\tif (notification.parentNode) {\n\t\t\t\tnotification.parentNode.removeChild(notification);\n\t\t\t}\n\t\t}, 3000);\n\n\t\tnotification\n\t\t\t.querySelector('.feedback-success-close')\n\t\t\t.addEventListener('click', () => {\n\t\t\t\tif (notification.parentNode) {\n\t\t\t\t\tnotification.parentNode.removeChild(notification);\n\t\t\t\t}\n\t\t\t});\n\t}\n\n\t_resetForm() {\n\t\tthis.state.title = '';\n\t\tthis.state.content = '';\n\t\tthis.state.email = '';\n\t\tthis.state.errors = {};\n\t}\n\n\t_updateTheme() {\n\t\tif (this.element) {\n\t\t\tthis.element.className = this.element.className.replace(\n\t\t\t\t/theme-\\w+/,\n\t\t\t\t`theme-${this.options.theme}`\n\t\t\t);\n\t\t}\n\t\tif (this.modalElement) {\n\t\t\tthis.modalElement.className = this.modalElement.className.replace(\n\t\t\t\t/theme-\\w+/,\n\t\t\t\t`theme-${this.options.theme}`\n\t\t\t);\n\t\t}\n\t}\n}\n","import { BaseWidget } from './BaseWidget.js';\n\nexport class ButtonWidget extends BaseWidget {\n\tconstructor(options) {\n\t\tsuper({ ...options, type: 'button' });\n\t}\n\n\t_render() {\n\t\tconst button = document.createElement('div');\n\t\tbutton.className = `feedback-widget feedback-widget-button theme-${this.options.theme} position-${this.options.position}`;\n\t\tbutton.innerHTML = `\n <button class=\"feedback-trigger-btn\" type=\"button\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path d=\"M2.003 5.884L10 9.882l7.997-3.998A2 2 0 0016 4H4a2 2 0 00-1.997 1.884z\"/>\n <path d=\"M18 8.118l-8 4-8-4V14a2 2 0 002 2h12a2 2 0 002-2V8.118z\"/>\n </svg>\n Feedback\n </button>\n `;\n\n\t\tif (this.options.customStyles) {\n\t\t\tObject.assign(button.style, this.options.customStyles);\n\t\t}\n\n\t\treturn button;\n\t}\n\n\t_attachEvents() {\n\t\tconst button = this.element.querySelector('.feedback-trigger-btn');\n\t\tbutton.addEventListener('click', this.openModal);\n\n\t\tbutton.addEventListener('mouseenter', () => {\n\t\t\tif (!this.state.isSubmitting) {\n\t\t\t\tbutton.style.transform = 'translateY(-2px)';\n\t\t\t}\n\t\t});\n\n\t\tbutton.addEventListener('mouseleave', () => {\n\t\t\tbutton.style.transform = 'translateY(0)';\n\t\t});\n\t}\n\n\tupdateText(text) {\n\t\tconst button = this.element?.querySelector('.feedback-trigger-btn');\n\t\tif (button) {\n\t\t\tconst textNode = button.childNodes[button.childNodes.length - 1];\n\t\t\tif (textNode && textNode.nodeType === Node.TEXT_NODE) {\n\t\t\t\ttextNode.textContent = text;\n\t\t\t}\n\t\t}\n\t}\n\n\tupdatePosition(position) {\n\t\tthis.options.position = position;\n\t\tif (this.element) {\n\t\t\tthis.element.className = this.element.className.replace(\n\t\t\t\t/position-\\w+-\\w+/,\n\t\t\t\t`position-${position}`\n\t\t\t);\n\t\t}\n\t}\n}\n","import { BaseWidget } from './BaseWidget.js';\n\nexport class InlineWidget extends BaseWidget {\n\tconstructor(options) {\n\t\tsuper({ ...options, type: 'inline' });\n\t}\n\n\t_render() {\n\t\tconst widget = document.createElement('div');\n\t\twidget.className = `feedback-widget feedback-widget-inline theme-${this.options.theme}`;\n\t\twidget.innerHTML = `\n <div class=\"feedback-inline-content\">\n <h3>Send us your feedback</h3>\n <form class=\"feedback-inline-form\">\n <div class=\"feedback-form-group\">\n <input \n type=\"text\" \n name=\"title\" \n placeholder=\"Title (optional)\"\n value=\"${this.state.title}\"\n />\n </div>\n <div class=\"feedback-form-group\">\n <textarea \n name=\"content\" \n placeholder=\"Your feedback...\"\n required\n >${this.state.content}</textarea>\n </div>\n <div class=\"feedback-form-group\">\n <input \n type=\"email\" \n name=\"email\" \n placeholder=\"Email (optional)\"\n value=\"${this.state.email}\"\n />\n </div>\n <button type=\"submit\" class=\"feedback-btn feedback-btn-submit\">\n Send Feedback\n </button>\n <div class=\"feedback-error\" style=\"display: none;\"></div>\n </form>\n </div>\n `;\n\n\t\tif (this.options.customStyles) {\n\t\t\tObject.assign(widget.style, this.options.customStyles);\n\t\t}\n\n\t\treturn widget;\n\t}\n\n\t_attachEvents() {\n\t\tconst form = this.element.querySelector('.feedback-inline-form');\n\n\t\tform.addEventListener('submit', (e) => {\n\t\t\te.preventDefault();\n\t\t\tthis.submitFeedback();\n\t\t});\n\n\t\tform.querySelector('input[name=\"title\"]').addEventListener('input', (e) => {\n\t\t\tthis.state.title = e.target.value;\n\t\t});\n\n\t\tform\n\t\t\t.querySelector('textarea[name=\"content\"]')\n\t\t\t.addEventListener('input', (e) => {\n\t\t\t\tthis.state.content = e.target.value;\n\t\t\t});\n\n\t\tform.querySelector('input[name=\"email\"]').addEventListener('input', (e) => {\n\t\t\tthis.state.email = e.target.value;\n\t\t});\n\t}\n\n\topenModal() {\n\t\tconst textarea = this.element.querySelector('textarea[name=\"content\"]');\n\t\tif (textarea) {\n\t\t\ttextarea.focus();\n\t\t}\n\t}\n\n\tcloseModal() {\n\t\t// Inline widget doesn't use modal\n\t}\n\n\t_showSuccessMessage() {\n\t\tconst widget = this.element.querySelector('.feedback-inline-content');\n\t\tconst originalContent = widget.innerHTML;\n\n\t\twidget.innerHTML = `\n <div class=\"feedback-success\">\n <div class=\"feedback-success-icon\">✓</div>\n <h3>Thank you!</h3>\n <p>Your feedback has been submitted successfully.</p>\n <button class=\"feedback-btn feedback-btn-reset\">Send Another</button>\n </div>\n `;\n\n\t\tconst resetBtn = widget.querySelector('.feedback-btn-reset');\n\t\tresetBtn.addEventListener('click', () => {\n\t\t\twidget.innerHTML = originalContent;\n\t\t\tthis._attachEvents();\n\t\t\tthis._resetForm();\n\t\t});\n\t}\n\n\t_showError(message) {\n\t\tconst errorElement = this.element.querySelector('.feedback-error');\n\t\tif (errorElement) {\n\t\t\terrorElement.textContent = message;\n\t\t\terrorElement.style.display = 'block';\n\n\t\t\tsetTimeout(() => {\n\t\t\t\tif (errorElement) {\n\t\t\t\t\terrorElement.style.display = 'none';\n\t\t\t\t}\n\t\t\t}, 5000);\n\t\t}\n\t}\n\n\t_updateSubmitButton() {\n\t\tconst submitBtn = this.element.querySelector('.feedback-btn-submit');\n\t\tif (submitBtn) {\n\t\t\tsubmitBtn.textContent = this.state.isSubmitting\n\t\t\t\t? 'Sending...'\n\t\t\t\t: 'Send Feedback';\n\t\t\tsubmitBtn.disabled = this.state.isSubmitting;\n\t\t}\n\t}\n\n\tupdateTitle(title) {\n\t\tconst titleElement = this.element?.querySelector('h3');\n\t\tif (titleElement) {\n\t\t\ttitleElement.textContent = title;\n\t\t}\n\t}\n\n\tsetPlaceholder(field, placeholder) {\n\t\tconst input = this.element?.querySelector(`[name=\"${field}\"]`);\n\t\tif (input) {\n\t\t\tinput.placeholder = placeholder;\n\t\t}\n\t}\n}\n","import { BaseWidget } from './BaseWidget.js';\n\nexport class TabWidget extends BaseWidget {\n\tconstructor(options) {\n\t\tsuper({ ...options, type: 'tab' });\n\t}\n\n\t_render() {\n\t\tconst tab = document.createElement('div');\n\t\ttab.className = `feedback-widget feedback-widget-tab theme-${this.options.theme} position-${this.options.position}`;\n\t\ttab.innerHTML = `\n <div class=\"feedback-tab-trigger\">\n <span class=\"feedback-tab-text\">Feedback</span>\n </div>\n `;\n\n\t\tif (this.options.customStyles) {\n\t\t\tObject.assign(tab.style, this.options.customStyles);\n\t\t}\n\n\t\treturn tab;\n\t}\n\n\t_attachEvents() {\n\t\tconst tab = this.element.querySelector('.feedback-tab-trigger');\n\t\ttab.addEventListener('click', this.openModal);\n\n\t\ttab.addEventListener('mouseenter', () => {\n\t\t\tif (!this.state.isSubmitting) {\n\t\t\t\ttab.style.transform = this._getHoverTransform();\n\t\t\t}\n\t\t});\n\n\t\ttab.addEventListener('mouseleave', () => {\n\t\t\ttab.style.transform = 'none';\n\t\t});\n\t}\n\n\t_getHoverTransform() {\n\t\tconst position = this.options.position;\n\t\tif (position.includes('right')) {\n\t\t\treturn 'translateX(-5px)';\n\t\t} else if (position.includes('left')) {\n\t\t\treturn 'translateX(5px)';\n\t\t}\n\t\treturn 'none';\n\t}\n\n\tupdateText(text) {\n\t\tconst textElement = this.element?.querySelector('.feedback-tab-text');\n\t\tif (textElement) {\n\t\t\ttextElement.textContent = text;\n\t\t}\n\t}\n\n\tupdatePosition(position) {\n\t\tthis.options.position = position;\n\t\tif (this.element) {\n\t\t\tthis.element.className = this.element.className.replace(\n\t\t\t\t/position-\\w+-\\w+/,\n\t\t\t\t`position-${position}`\n\t\t\t);\n\t\t}\n\t}\n}\n","import { SDKError } from '../utils/errors.js';\nimport { ButtonWidget } from './ButtonWidget.js';\nimport { InlineWidget } from './InlineWidget.js';\nimport { TabWidget } from './TabWidget.js';\n\nexport class WidgetFactory {\n\tstatic widgets = new Map([\n\t\t['button', ButtonWidget],\n\t\t['tab', TabWidget],\n\t\t['inline', InlineWidget],\n\t]);\n\n\tstatic register(type, WidgetClass) {\n\t\tif (typeof type !== 'string' || !type.trim()) {\n\t\t\tthrow new SDKError('Widget type must be a non-empty string');\n\t\t}\n\n\t\tif (typeof WidgetClass !== 'function') {\n\t\t\tthrow new SDKError('Widget class must be a constructor function');\n\t\t}\n\n\t\tthis.widgets.set(type, WidgetClass);\n\t}\n\n\tstatic create(type, options = {}) {\n\t\tconst WidgetClass = this.widgets.get(type);\n\n\t\tif (!WidgetClass) {\n\t\t\tconst availableTypes = Array.from(this.widgets.keys()).join(', ');\n\t\t\tthrow new SDKError(\n\t\t\t\t`Unknown widget type: ${type}. Available types: ${availableTypes}`\n\t\t\t);\n\t\t}\n\n\t\ttry {\n\t\t\treturn new WidgetClass(options);\n\t\t} catch (error) {\n\t\t\tthrow new SDKError(\n\t\t\t\t`Failed to create widget of type '${type}': ${error.message}`,\n\t\t\t\terror\n\t\t\t);\n\t\t}\n\t}\n\n\tstatic getAvailableTypes() {\n\t\treturn Array.from(this.widgets.keys());\n\t}\n\n\tstatic isTypeRegistered(type) {\n\t\treturn this.widgets.has(type);\n\t}\n\n\tstatic unregister(type) {\n\t\treturn this.widgets.delete(type);\n\t}\n\n\tstatic clear() {\n\t\tthis.widgets.clear();\n\t}\n\n\tstatic getWidgetClass(type) {\n\t\treturn this.widgets.get(type);\n\t}\n}\n","import { ConfigError, SDKError } from '../utils/errors.js';\nimport { deepMerge, generateId } from '../utils/helpers.js';\nimport { WidgetFactory } from '../widgets/WidgetFactory.js';\nimport { APIService } from './APIService.js';\nimport { EventBus } from './EventBus.js';\n\nexport class FeedbackSDK {\n\tconstructor(config = {}) {\n\t\tthis.config = this._validateAndMergeConfig(config);\n\t\tthis.initialized = false;\n\t\tthis.widgets = new Map();\n\t\tthis.eventBus = new EventBus();\n\n\t\t// Initialize API service\n\t\tthis.apiService = new APIService({\n\t\t\tapiUrl: this.config.apiUrl,\n\t\t\tworkspace: this.config.workspace,\n\t\t\tuserContext: this.config.userContext,\n\t\t});\n\n\t\tthis._bindMethods();\n\t}\n\n\tasync init() {\n\t\tif (this.initialized) {\n\t\t\treturn { alreadyInitialized: true };\n\t\t}\n\n\t\ttry {\n\t\t\t// Initialize the API service (this will handle the /widget/init call)\n\t\t\tconst initData = await this.apiService.init(this.config.userContext);\n\n\t\t\t// Merge any server-provided config with local config\n\t\t\tif (initData.config) {\n\t\t\t\tthis.config = deepMerge(this.config, initData.config);\n\t\t\t}\n\n\t\t\tthis.initialized = true;\n\t\t\tthis.eventBus.emit('sdk:initialized', {\n\t\t\t\tconfig: this.config,\n\t\t\t\tsessionToken: initData.sessionToken,\n\t\t\t});\n\n\t\t\treturn {\n\t\t\t\tinitialized: true,\n\t\t\t\tconfig: initData.config || {},\n\t\t\t\tsessionToken: initData.sessionToken,\n\t\t\t\texpiresIn: initData.expiresIn,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tthis.eventBus.emit('sdk:error', { error });\n\t\t\tthrow new SDKError(`Failed to initialize SDK: ${error.message}`, error);\n\t\t}\n\t}\n\n\tcreateWidget(type = 'button', options = {}) {\n\t\tif (!this.initialized) {\n\t\t\tthrow new SDKError(\n\t\t\t\t'SDK must be initialized before creating widgets. Call init() first.'\n\t\t\t);\n\t\t}\n\n\t\tconst widgetId = generateId('widget');\n\t\tconst widgetOptions = {\n\t\t\tid: widgetId,\n\t\t\tsdk: this,\n\t\t\tapiService: this.apiService,\n\t\t\t...this.config,\n\t\t\t...options,\n\t\t};\n\n\t\ttry {\n\t\t\tconst widget = WidgetFactory.create(type, widgetOptions);\n\t\t\tthis.widgets.set(widgetId, widget);\n\n\t\t\tthis.eventBus.emit('widget:created', { widget, type });\n\t\t\treturn widget;\n\t\t} catch (error) {\n\t\t\tthrow new SDKError(`Failed to create widget: ${error.message}`, error);\n\t\t}\n\t}\n\n\tgetWidget(id) {\n\t\treturn this.widgets.get(id);\n\t}\n\n\tgetAllWidgets() {\n\t\treturn Array.from(this.widgets.values());\n\t}\n\n\tdestroyWidget(id) {\n\t\tconst widget = this.widgets.get(id);\n\t\tif (widget) {\n\t\t\twidget.destroy();\n\t\t\tthis.widgets.delete(id);\n\t\t\tthis.eventBus.emit('widget:removed', { widgetId: id });\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tdestroyAllWidgets() {\n\t\tfor (const widget of this.widgets.values()) {\n\t\t\twidget.destroy();\n\t\t}\n\t\tthis.widgets.clear();\n\t\tthis.eventBus.emit('widgets:cleared');\n\t}\n\n\tupdateConfig(newConfig) {\n\t\tconst oldConfig = { ...this.config };\n\t\tthis.config = this._validateAndMergeConfig(newConfig, this.config);\n\n\t\t// Update all existing widgets with new config\n\t\tfor (const widget of this.widgets.values()) {\n\t\t\twidget.handleConfigUpdate(this.config);\n\t\t}\n\n\t\tthis.eventBus.emit('config:updated', {\n\t\t\toldConfig,\n\t\t\tnewConfig: this.config,\n\t\t});\n\t}\n\n\tsetUserContext(userContext) {\n\t\tthis.config.userContext = userContext;\n\t\tif (this.apiService) {\n\t\t\tthis.apiService.setUserContext(userContext);\n\t\t}\n\t\tthis.eventBus.emit('user:updated', { userContext });\n\t}\n\n\tgetUserContext() {\n\t\treturn (\n\t\t\tthis.config.userContext ||\n\t\t\t(this.apiService ? this.apiService.getUserContext() : null)\n\t\t);\n\t}\n\n\tasync reinitialize(newUserContext = null) {\n\t\t// Clear current session\n\t\tthis.apiService.clearSession();\n\t\tthis.initialized = false;\n\n\t\t// Update user context if provided\n\t\tif (newUserContext) {\n\t\t\tthis.setUserContext(newUserContext);\n\t\t}\n\n\t\t// Reinitialize\n\t\treturn this.init();\n\t}\n\n\ton(event, callback) {\n\t\tthis.eventBus.on(event, callback);\n\t\treturn this;\n\t}\n\n\toff(event, callback) {\n\t\tthis.eventBus.off(event, callback);\n\t\treturn this;\n\t}\n\n\tonce(event, callback) {\n\t\tthis.eventBus.once(event, callback);\n\t\treturn this;\n\t}\n\n\temit(event, data) {\n\t\tthis.eventBus.emit(event, data);\n\t\treturn this;\n\t}\n\n\tdestroy() {\n\t\tthis.destroyAllWidgets();\n\t\tthis.eventBus.removeAllListeners();\n\t\tthis.apiService.clearSession();\n\t\tthis.initialized = false;\n\t\tthis.eventBus.emit('sdk:destroyed');\n\t}\n\n\t_validateAndMergeConfig(newConfig, existingConfig = {}) {\n\t\tconst defaultConfig = {\n\t\t\tapiUrl: null,\n\t\t\tworkspace: null,\n\t\t\tuserContext: null,\n\t\t\tposition: 'bottom-right',\n\t\t\ttheme: 'light',\n\t\t\tboardId: 'general',\n\t\t\tautoShow: true,\n\t\t\tdebug: false,\n\t\t};\n\n\t\tconst mergedConfig = deepMerge(\n\t\t\tdeepMerge(defaultConfig, existingConfig),\n\t\t\tnewConfig\n\t\t);\n\n\t\t// Validate required config\n\t\tconst requiredFields = ['workspace'];\n\t\tconst missingFields = requiredFields.filter(\n\t\t\t(field) => !mergedConfig[field]\n\t\t);\n\n\t\tif (missingFields.length > 0) {\n\t\t\tthrow new ConfigError(\n\t\t\t\t`Missing required configuration: ${missingFields.join(', ')}`\n\t\t\t);\n\t\t}\n\n\t\t// Validate userContext structure if provided\n\t\tif (mergedConfig.userContext) {\n\t\t\tthis._validateUserContext(mergedConfig.userContext);\n\t\t}\n\n\t\treturn mergedConfig;\n\t}\n\n\t_validateUserContext(userContext) {\n\t\tif (!userContext.user_id && !userContext.email) {\n\t\t\tthrow new ConfigError(\n\t\t\t\t'User context must include at least user_id or email'\n\t\t\t);\n\t\t}\n\n\t\t// Validate structure matches expected API format\n\t\tconst validStructure = {\n\t\t\tuser_id: 'string',\n\t\t\temail: 'string',\n\t\t\tname: 'string',\n\t\t\tcustom_fields: 'object',\n\t\t\tcompany: 'object',\n\t\t};\n\n\t\tfor (const [key, expectedType] of Object.entries(validStructure)) {\n\t\t\tif (userContext[key] && typeof userContext[key] !== expectedType) {\n\t\t\t\tthrow new ConfigError(\n\t\t\t\t\t`User context field '${key}' must be of type '${expectedType}'`\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t_bindMethods() {\n\t\tthis.createWidget = this.createWidget.bind(this);\n\t\tthis.destroyWidget = this.destroyWidget.bind(this);\n\t\tthis.updateConfig = this.updateConfig.bind(this);\n\t}\n\n\t// Static helper methods\n\tstatic create(config) {\n\t\treturn new FeedbackSDK(config);\n\t}\n\n\tstatic async createAndInit(config) {\n\t\tconst sdk = new FeedbackSDK(config);\n\t\tawait sdk.init();\n\t\treturn sdk;\n\t}\n\n\t// Utility methods for external integrations\n\tstatic extractUserContextFromAuth(authData) {\n\t\t// Helper method to extract user context from common auth structures\n\t\tif (!authData) return null;\n\n\t\treturn {\n\t\t\tuser_id: authData.sub || authData.id || authData.user_id,\n\t\t\temail: authData.email,\n\t\t\tname: authData.name || authData.display_name || authData.full_name,\n\t\t\tcustom_fields: {\n\t\t\t\trole: authData.role,\n\t\t\t\tplan: authData.plan || authData.subscription?.plan,\n\t\t\t\t...(authData.custom_fields || {}),\n\t\t\t},\n\t\t\tcompany:\n\t\t\t\tauthData.company || authData.organization\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tid: authData.company?.id || authData.organization?.id,\n\t\t\t\t\t\t\tname: authData.company?.name || authData.organization?.name,\n\t\t\t\t\t\t\tmonthly_spend: authData.company?.monthly_spend,\n\t\t\t\t\t\t}\n\t\t\t\t\t: undefined,\n\t\t};\n\t}\n}\n","import { APIService } from './core/APIService.js';\nimport { EventBus } from './core/EventBus.js';\nimport { FeedbackSDK } from './core/FeedbackSDK.js';\nimport { CSS_STYLES } from './styles/styles.js';\nimport {\n\tAPIError,\n\tConfigError,\n\tSDKError,\n\tValidationError,\n\tWidgetError,\n} from './utils/errors.js';\nimport * as helpers from './utils/helpers.js';\nimport { BaseWidget } from './widgets/BaseWidget.js';\nimport { ButtonWidget } from './widgets/ButtonWidget.js';\nimport { InlineWidget } from './widgets/InlineWidget.js';\nimport { TabWidget } from './widgets/TabWidget.js';\nimport { WidgetFactory } from './widgets/WidgetFactory.js';\n\nfunction injectStyles() {\n\tconsole.log('injectStyles called');\n\tconsole.log('document exists:', typeof document !== 'undefined');\n\tconsole.log('CSS_STYLES exists:', !!CSS_STYLES);\n\n\tif (\n\t\ttypeof document !== 'undefined' &&\n\t\t!document.querySelector('#feedback-sdk-styles')\n\t) {\n\t\tconsole.log('Injecting CSS...');\n\t\tconst style = document.createElement('style');\n\t\tstyle.id = 'feedback-sdk-styles';\n\t\tstyle.textContent = CSS_STYLES;\n\t\tdocument.head.appendChild(style);\n\t\tconsole.log(\n\t\t\t'CSS injected, style element created:',\n\t\t\t!!document.querySelector('#feedback-sdk-styles')\n\t\t);\n\t} else {\n\t\tconsole.log('CSS already exists or document not ready');\n\t}\n}\n\nfunction autoInit() {\n\tif (typeof window !== 'undefined' && window.FeedbackSDKConfig) {\n\t\tinjectStyles();\n\n\t\tconst config = { ...window.FeedbackSDKConfig };\n\n\t\tif (!config.userContext) {\n\t\t\tconfig.userContext = getUserContextFromEnvironment();\n\t\t}\n\n\t\tconst sdk = new FeedbackSDK(config);\n\n\t\tsdk\n\t\t\t.init()\n\t\t\t.then((initData) => {\n\t\t\t\twindow.FeedbackSDK.instance = sdk;\n\n\t\t\t\tif (window.FeedbackSDKConfig.autoCreate) {\n\t\t\t\t\tconst widgets = Array.isArray(window.FeedbackSDKConfig.autoCreate)\n\t\t\t\t\t\t? window.FeedbackSDKConfig.autoCreate\n\t\t\t\t\t\t: [window.FeedbackSDKConfig.autoCreate];\n\n\t\t\t\t\twidgets.forEach((widgetConfig) => {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst widget = sdk.createWidget(\n\t\t\t\t\t\t\t\twidgetConfig.type || 'button',\n\t\t\t\t\t\t\t\twidgetConfig\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\twidget.mount(widgetConfig.container);\n\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\tconsole.error('[FeedbackSDK] Failed to create widget:', error);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tif (typeof CustomEvent !== 'undefined') {\n\t\t\t\t\tconst event = new CustomEvent('FeedbackSDKReady', {\n\t\t\t\t\t\tdetail: {\n\t\t\t\t\t\t\tsdk,\n\t\t\t\t\t\t\tconfig: config,\n\t\t\t\t\t\t\tinitData: initData,\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t\twindow.dispatchEvent(event);\n\t\t\t\t}\n\n\t\t\t\tconsole.log(\n\t\t\t\t\t'[FeedbackSDK] Successfully initialized with session:',\n\t\t\t\t\tinitData.sessionToken ? 'Yes' : 'No'\n\t\t\t\t);\n\t\t\t})\n\t\t\t.catch((error) => {\n\t\t\t\tconsole.error('[FeedbackSDK] Auto-initialization failed:', error);\n\n\t\t\t\tif (typeof CustomEvent !== 'undefined') {\n\t\t\t\t\tconst event = new CustomEvent('FeedbackSDKError', {\n\t\t\t\t\t\tdetail: {\n\t\t\t\t\t\t\terror,\n\t\t\t\t\t\t\tconfig: config,\n\t\t\t\t\t\t\tphase: 'initialization',\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t\twindow.dispatchEvent(event);\n\t\t\t\t}\n\t\t\t});\n\t}\n}\n\nfunction getUserContextFromEnvironment() {\n\tif (typeof window === 'undefined') return null;\n\n\tif (window.FeedbackSDKUserContext) {\n\t\treturn window.FeedbackSDKUserContext;\n\t}\n\n\tconst authSources = [\n\t\t() => window.auth0?.user,\n\t\t() => window.firebase?.auth()?.currentUser,\n\t\t() => window.amplify?.Auth?.currentAuthenticatedUser(),\n\n\t\t() => window.currentUser,\n\t\t() => window.user,\n\t\t() => window.userData,\n\n\t\t() => window.app?.user,\n\t\t() => window.store?.getState?.()?.user,\n\t\t() => window.App?.currentUser,\n\t];\n\n\tfor (const getAuth of authSources) {\n\t\ttry {\n\t\t\tconst authData = getAuth();\n\t\t\tif (authData) {\n\t\t\t\tconst userContext = FeedbackSDK.extractUserContextFromAuth(authData);\n\t\t\t\tif (userContext && (userContext.user_id || userContext.email)) {\n\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t'[FeedbackSDK] Auto-detected user context from',\n\t\t\t\t\t\tgetAuth.name || 'unknown source'\n\t\t\t\t\t);\n\t\t\t\t\treturn userContext;\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tcontinue;\n\t\t}\n\t}\n\n\ttry {\n\t\tconst storedAuth =\n\t\t\tlocalStorage.getItem('auth') ||\n\t\t\tlocalStorage.getItem('user') ||\n\t\t\tlocalStorage.getItem('session');\n\t\tif (storedAuth) {\n\t\t\tconst authData = JSON.parse(storedAuth);\n\t\t\tconst userContext = FeedbackSDK.extractUserContextFromAuth(authData);\n\t\t\tif (userContext && (userContext.user_id || userContext.email)) {\n\t\t\t\tconsole.log(\n\t\t\t\t\t'[FeedbackSDK] Auto-detected user context from localStorage'\n\t\t\t\t);\n\t\t\t\treturn userContext;\n\t\t\t}\n\t\t}\n\t} catch (error) {\n\t\t// Continue\n\t}\n\n\tconsole.warn(\n\t\t'[FeedbackSDK] No user context found. Widget initialization may require manual user context setting.'\n\t);\n\treturn null;\n}\n\nfunction handleDOMReady() {\n\tif (typeof document !== 'undefined') {\n\t\tif (document.readyState === 'loading') {\n\t\t\tdocument.addEventListener('DOMContentLoaded', autoInit);\n\t\t} else {\n\t\t\tsetTimeout(autoInit, 0);\n\t\t}\n\t}\n}\n\nconst FeedbackSDKExport = {\n\tFeedbackSDK,\n\tBaseWidget,\n\tButtonWidget,\n\tTabWidget,\n\tInlineWidget,\n\tWidgetFactory,\n\tEventBus,\n\tAPIService,\n\tSDKError,\n\tAPIError,\n\tWidgetError,\n\tConfigError,\n\tValidationError,\n\thelpers,\n\tcreate: (config) => {\n\t\tinjectStyles();\n\t\treturn new FeedbackSDK(config);\n\t},\n\tversion: '1.0.0',\n\tinstance: null,\n\n\tisReady: () => Boolean(FeedbackSDKExport.instance),\n\tgetInstance: () => FeedbackSDKExport.instance,\n\n\tsetUserContext: (userContext) => {\n\t\tif (FeedbackSDKExport.instance) {\n\t\t\tFeedbackSDKExport.instance.setUserContext(userContext);\n\t\t} else {\n\t\t\tif (typeof window !== 'undefined') {\n\t\t\t\twindow.FeedbackSDKUserContext = userContext;\n\t\t\t}\n\t\t}\n\t},\n\n\tinitWithUser: async (config, userContext) => {\n\t\tinjectStyles();\n\t\tconst fullConfig = { ...config, userContext };\n\t\tconst sdk = new FeedbackSDK(fullConfig);\n\t\tawait sdk.init();\n\n\t\tif (typeof window !== 'undefined') {\n\t\t\twindow.FeedbackSDK.instance = sdk;\n\t\t}\n\n\t\treturn sdk;\n\t},\n\n\tonReady: (callback) => {\n\t\tif (typeof window !== 'undefined') {\n\t\t\tif (FeedbackSDKExport.isReady()) {\n\t\t\t\tcallback(FeedbackSDKExport.instance);\n\t\t\t} else {\n\t\t\t\twindow.addEventListener(\n\t\t\t\t\t'FeedbackSDKReady',\n\t\t\t\t\t(event) => {\n\t\t\t\t\t\tcallback(event.detail.sdk, event.detail);\n\t\t\t\t\t},\n\t\t\t\t\t{ once: true }\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t},\n\n\tonError: (callback) => {\n\t\tif (typeof window !== 'undefined') {\n\t\t\twindow.addEventListener('FeedbackSDKError', (event) => {\n\t\t\t\tcallback(event.detail.error, event.detail);\n\t\t\t});\n\t\t}\n\t},\n\n\textractUserContext: FeedbackSDK.extractUserContextFromAuth,\n};\n\nif (typeof window !== 'undefined') {\n\twindow.FeedbackSDK = FeedbackSDKExport;\n\thandleDOMReady();\n}\n\nexport default FeedbackSDKExport;\n\nexport {\n\tAPIError,\n\tAPIService,\n\tBaseWidget,\n\tButtonWidget,\n\tConfigError,\n\tEventBus,\n\tFeedbackSDK,\n\thelpers,\n\tInlineWidget,\n\tSDKError,\n\tTabWidget,\n\tValidationError,\n\tWidgetError,\n\tWidgetFactory,\n};\n","export const CSS_STYLES = `\n.feedback-widget {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', Oxygen, Ubuntu, Cantarell, sans-serif;\n font-size: 14px;\n line-height: 1.4;\n z-index: 999999;\n box-sizing: border-box;\n}\n\n.feedback-widget *,\n.feedback-widget *::before,\n.feedback-widget *::after {\n box-sizing: border-box;\n}\n\n.feedback-widget-button {\n position: fixed;\n z-index: 999999;\n}\n\n.feedback-widget-button.position-bottom-right {\n bottom: 20px;\n right: 20px;\n}\n\n.feedback-widget-button.position-bottom-left {\n bottom: 20px;\n left: 20px;\n}\n\n.feedback-widget-button.position-top-right {\n top: 20px;\n right: 20px;\n}\n\n.feedback-widget-button.position-top-left {\n top: 20px;\n left: 20px;\n}\n\n.feedback-trigger-btn {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 12px;\n height: 44px;\n overflow: hidden;\n border-radius: 0.5rem;\n border: none;\n padding: 10px 16px;\n font-size: 14px;\n font-weight: 500;\n font-family: inherit;\n cursor: pointer;\n transition: all 0.3s duration;\n color: white;\n background: #155EEF;\n box-shadow: 0 1px 2px 0 rgba(16, 24, 40, 0.05);\n}\n\n.feedback-trigger-btn:hover:not(:disabled) {\n background: #004EEB;\n box-shadow: 0 1px 2px 0 rgba(16, 24, 40, 0.1);\n}\n\n.feedback-trigger-btn:disabled {\n opacity: 0.7;\n cursor: not-allowed;\n}\n\n.feedback-trigger-btn:focus-visible {\n outline: 2px solid #155EEF;\n outline-offset: 2px;\n}\n\n.feedback-modal {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 1000000;\n display: flex;\n align-items: center;\n justify-content: center;\n font-family: inherit;\n}\n\n.feedback-modal-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.feedback-modal-content {\n background: white;\n border-radius: 8px;\n box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n min-width: 460px;\n max-width: 500px;\n width: 100%;\n padding: 16px;\n max-height: 85vh;\n overflow-y: hidden;\n position: relative;\n}\n\n.feedback-modal.theme-dark .feedback-modal-content {\n background: #1F2937;\n color: white;\n}\n\n.feedback-modal-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px;\n border-bottom: 1px solid #D1D5DB;\n flex-shrink: 0;\n}\n\n.feedback-modal.theme-dark .feedback-modal-header {\n border-bottom-color: #374151;\n}\n\n.feedback-modal-header h3 {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n}\n\n.feedback-modal-close {\n background: none;\n border: none;\n font-size: 24px;\n cursor: pointer;\n color: #6B7280;\n padding: 0;\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.3s ease;\n}\n\n.feedback-modal-close:hover {\n color: #374151;\n}\n\n.feedback-modal-close:focus-visible {\n outline: 2px solid #155EEF;\n outline-offset: 2px;\n}\n\n.feedback-modal.theme-dark .feedback-modal-close {\n color: #9CA3AF;\n}\n\n.feedback-modal.theme-dark .feedback-modal-close:hover {\n color: #D1D5DB;\n}\n\n.feedback-form {\n padding: 16px;\n}\n\n.feedback-form-group {\n display: flex;\n flex-direction: column;\n gap: 4px;\n margin-bottom: 12px;\n}\n\n.feedback-form-group:last-child {\n margin-bottom: 0;\n}\n\n.feedback-form-group label {\n font-size: 14px;\n font-weight: 500;\n line-height: 1.25;\n color: #374151;\n}\n\n.feedback-modal.theme-dark .feedback-form-group label {\n color: #D1D5DB;\n}\n\n.feedback-form-group input {\n height: 40px;\n width: 100%;\n border-radius: 6px;\n border: 1px solid #D1D5DB;\n padding: 2px 12px;\n font-size: 14px;\n font-weight: 400;\n line-height: 1.25;\n color: #1F2937;\n font-family: inherit;\n outline: none;\n transition: all 0.2s ease;\n}\n\n.feedback-form-group input::placeholder {\n font-size: 14px;\n color: #6B7280;\n}\n\n.feedback-form-group input:focus {\n border-color: #84ADFF;\n box-shadow: 0 0 0 1px rgba(16, 24, 40, 0.05), 0 0 0 3px rgba(41, 112, 255, 0.2);\n}\n\n.feedback-form-group input:focus-visible {\n outline: none;\n}\n\n.feedback-form-group textarea {\n min-height: 100px;\n width: 100%;\n resize: both;\n border-radius: 6px;\n border: 1px solid #D1D5DB;\n padding: 2px 12px;\n font-size: 14px;\n font-weight: 400;\n line-height: 1.25;\n color: #1F2937;\n font-family: inherit;\n outline: none;\n transition: all 0.2s ease;\n}\n\n.feedback-form-group textarea::placeholder {\n font-size: 14px;\n color: #6B7280;\n}\n\n.feedback-form-group textarea:focus {\n border-color: #84ADFF;\n box-shadow: 0 0 0 1px rgba(16, 24, 40, 0.05), 0 0 0 3px rgba(41, 112, 255, 0.2);\n}\n\n.feedback-form-group textarea:focus-visible {\n outline: none;\n}\n\n.feedback-modal.theme-dark .feedback-form-group input,\n.feedback-modal.theme-dark .feedback-form-group textarea {\n background: #374151;\n border-color: #4B5563;\n color: white;\n}\n\n.feedback-btn {\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n overflow: hidden;\n border-radius: 6px;\n border: none;\n height: 40px;\n padding: 2px 16px;\n font-size: 14px;\n font-weight: 500;\n font-family: inherit;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.feedback-btn:disabled {\n opacity: 0.7;\n cursor: not-allowed;\n}\n\n.feedback-btn:focus-visible {\n outline: 2px solid #155EEF;\n outline-offset: 2px;\n}\n\n.feedback-btn-submit {\n background: #155EEF;\n color: white;\n}\n\n.feedback-btn-submit:hover:not(:disabled) {\n background: #004EEB;\n}\n\n.feedback-btn-cancel {\n background: transparent;\n color: #6B7280;\n border: 1px solid #D1D5DB;\n}\n\n.feedback-btn-cancel:hover:not(:disabled) {\n background: #F9FAFB;\n border-color: #9CA3AF;\n color: #374151;\n}\n\n.feedback-modal.theme-dark .feedback-btn-cancel {\n color: #D1D5DB;\n border-color: #4B5563;\n}\n\n.feedback-modal.theme-dark .feedback-btn-cancel:hover:not(:disabled) {\n background: #374151;\n}\n\n.feedback-form-actions {\n display: flex;\n gap: 8px;\n justify-content: flex-end;\n margin-top: 16px;\n padding-top: 4px;\n}\n\n.feedback-loading {\n width: 20px;\n height: 20px;\n border-radius: 50%;\n mask: radial-gradient(transparent 62%, white 65%);\n -webkit-mask: radial-gradient(transparent 62%, white 65%);\n animation: feedbackRotate 0.7s linear infinite;\n}\n\n.feedback-loading-white {\n background: conic-gradient(from 0deg, rgba(255, 255, 255, 0.5), white);\n}\n\n.feedback-loading-blue {\n background: conic-gradient(from 0deg, #004EEB, #eff4ff);\n}\n\n@keyframes feedbackRotate {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n}\n\n.feedback-error {\n color: #F04438;\n font-size: 14px;\n font-weight: 400;\n margin-top: 4px;\n text-transform: capitalize;\n}\n\n.feedback-form-error {\n color: #F04438;\n font-size: 14px;\n margin-top: 12px;\n padding: 8px 12px;\n background: #FEE2E2;\n border: 1px solid #FECACA;\n border-radius: 6px;\n}\n\n.feedback-modal.theme-dark .feedback-form-error {\n background: #7F1D1D;\n border-color: #991B1B;\n color: #FCA5A5;\n}\n\n.feedback-form-group.error input,\n.feedback-form-group.error textarea {\n border-color: #FDA29B;\n}\n\n.feedback-form-group.error input:focus,\n.feedback-form-group.error textarea:focus {\n border-color: #FDA29B;\n box-shadow: 0 0 0 1px rgba(16, 24, 40, 0.05), 0 0 0 4px rgba(253, 162, 155, 0.3);\n}\n\n.feedback-success-notification {\n position: fixed;\n top: 20px;\n right: 20px;\n z-index: 1000001;\n background: white;\n border: 1px solid #D1FAE5;\n border-radius: 8px;\n box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);\n animation: slideInRight 0.3s ease-out;\n}\n\n.feedback-success-content {\n display: flex;\n align-items: center;\n padding: 12px 16px;\n gap: 12px;\n}\n\n.feedback-success-content span {\n color: #059669;\n font-weight: 500;\n font-size: 14px;\n}\n\n.feedback-success-close {\n background: none;\n border: none;\n color: #6B7280;\n cursor: pointer;\n font-size: 18px;\n padding: 0;\n width: 20px;\n height: 20px;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.3s ease;\n}\n\n.feedback-success-close:hover {\n color: #374151;\n}\n\n.feedback-success-close:focus-visible {\n outline: 2px solid #155EEF;\n outline-offset: 2px;\n}\n\n@keyframes slideInRight {\n from {\n transform: translateX(100%);\n opacity: 0;\n }\n to {\n transform: translateX(0);\n opacity: 1;\n }\n}\n\n@keyframes fadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n.feedback-modal {\n animation: fadeIn 0.2s ease-out;\n}\n\n.feedback-modal-content {\n animation: slideInUp 0.3s ease-out;\n}\n\n@keyframes slideInUp {\n from {\n transform: translateY(20px);\n opacity: 0;\n }\n to {\n transform: translateY(0);\n opacity: 1;\n }\n}\n\n@media (max-width: 640px) {\n .feedback-modal {\n padding: 8px;\n }\n \n .feedback-modal-content {\n min-width: 280px;\n max-width: 100%;\n max-height: 95vh;\n }\n \n .feedback-form {\n padding: 16px;\n }\n \n .feedback-modal-header {\n padding: 16px;\n }\n \n .feedback-modal-header h3 {\n font-size: 15px;\n }\n \n .feedback-form-actions {\n flex-direction: column;\n gap: 8px;\n }\n \n .feedback-btn {\n width: 100%;\n height: 40px;\n }\n \n .feedback-widget-button {\n bottom: 16px;\n right: 16px;\n }\n \n .feedback-widget-button.position-bottom-left {\n left: 16px;\n }\n \n .feedback-trigger-btn {\n padding: 10px 16px;\n font-size: 13px;\n }\n \n .feedback-success-notification {\n top: 8px;\n right: 8px;\n left: 8px;\n max-width: none;\n }\n\n .feedback-form-group input {\n height: 40px;\n padding: 2px 12px;\n }\n \n .feedback-form-group textarea {\n min-height: 80px;\n padding: 2px 12px;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .feedback-trigger-btn,\n .feedback-btn,\n .feedback-modal,\n .feedback-modal-content,\n .feedback-success-notification,\n .feedback-loading {\n transition: none;\n animation: none;\n }\n \n .feedback-trigger-btn:hover {\n transform: none;\n }\n}\n\n@media print {\n .feedback-widget,\n .feedback-modal,\n .feedback-success-notification {\n display: none !important;\n }\n}\n`;\n"],"names":["SDKError","Error","constructor","message","cause","super","this","name","captureStackTrace","APIError","status","response","isNetworkError","isClientError","isServerError","WidgetError","widgetType","widgetId","ConfigError","configKey","ValidationError","field","value","APIService","config","workspace","sessionToken","sessionExpiry","userContext","apiUrl","baseURL","console","log","_loadStoredSession","init","isSessionValid","_getUserContextFromStorage","error","payload","user","_makeRequest","method","body","JSON","stringify","headers","session_token","Date","now","expires_in","_storeSession","expiresIn","submitFeedback","feedbackData","board","board_id","boardId","title","content","attachments","Authorization","setUserContext","localStorage","setItem","getUserContext","clearSession","removeItem","stored","getItem","parse","window","FeedbackSDKUserContext","currentUser","_mapUserData","authSources","key","sessionData","parsed","userData","id","user_id","email","warn","mapped","userId","displayName","full_name","custom_fields","company","organization","company_id","company_name","monthly_spend","spend","forEach","token","expiry","toISOString","endpoint","options","url","fetch","ok","errorMessage","responseData","json","e","text","contentType","get","includes","EventBus","events","Map","on","event","callback","has","set","push","off","callbacks","index","indexOf","splice","emit","data","once","unsubscribe","clear","getListenerCount","length","generateId","prefix","Math","random","toString","substring","deepMerge","target","source","result","hasOwnProperty","Array","isArray","isBrowser","document","func","wait","timeout","args","clearTimeout","setTimeout","ms","Promise","resolve","string","replace","bytes","i","floor","parseFloat","pow","toFixed","userAgent","navigator","platform","language","userLanguage","cookieEnabled","screenResolution","screen","width","height","windowSize","innerWidth","innerHeight","timezone","Intl","DateTimeFormat","resolvedOptions","timeZone","element","property","fallback","getComputedStyle","getPropertyValue","obj","path","defaultValue","undefined","keys","split","current","rect","getBoundingClientRect","top","left","bottom","documentElement","clientHeight","right","clientWidth","test","trim","str","div","createElement","textContent","innerHTML","scrollIntoView","behavior","block","inline","lastKey","pop","limit","lastFunc","lastRan","required","missing","join","BaseWidget","sdk","apiService","type","container","position","theme","autoShow","customStyles","modalElement","mounted","destroyed","state","isOpen","isSubmitting","errors","_bindMethods","mount","querySelector","_render","appendChild","_attachEvents","onMount","show","eventBus","widget","style","display","hide","openModal","_renderModal","closeModal","remove","_resetForm","_updateSubmitButton","_showError","_showSuccessMessage","feedback","handleConfigUpdate","newConfig","_updateTheme","destroy","onDestroy","parentNode","removeChild","bind","className","_getModalHTML","_attachModalEvents","firstInput","focus","modal","addEventListener","currentTarget","preventDefault","submitBtn","disabled","errorElement","notification","ButtonWidget","button","Object","assign","transform","updateText","textNode","childNodes","nodeType","Node","TEXT_NODE","updatePosition","InlineWidget","form","textarea","originalContent","updateTitle","titleElement","setPlaceholder","placeholder","input","TabWidget","tab","_getHoverTransform","textElement","WidgetFactory","static","register","WidgetClass","widgets","create","availableTypes","from","getAvailableTypes","isTypeRegistered","unregister","delete","getWidgetClass","FeedbackSDK","_validateAndMergeConfig","initialized","alreadyInitialized","initData","createWidget","widgetOptions","getWidget","getAllWidgets","values","destroyWidget","destroyAllWidgets","updateConfig","oldConfig","reinitialize","newUserContext","removeAllListeners","existingConfig","mergedConfig","debug","missingFields","filter","_validateUserContext","validStructure","expectedType","entries","createAndInit","extractUserContextFromAuth","authData","sub","display_name","role","plan","subscription","injectStyles","head","autoInit","FeedbackSDKConfig","auth0","firebase","auth","amplify","Auth","currentAuthenticatedUser","app","store","getState","App","getAuth","storedAuth","getUserContextFromEnvironment","then","instance","autoCreate","widgetConfig","CustomEvent","detail","dispatchEvent","catch","phase","FeedbackSDKExport","helpers","version","isReady","Boolean","getInstance","initWithUser","async","fullConfig","onReady","onError","extractUserContext","readyState"],"mappings":"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"}
1
+ {"version":3,"file":"feedback-sdk.min.js","sources":["../src/utils/errors.js","../src/core/APIService.js","../src/core/EventBus.js","../src/utils/helpers.js","../src/widgets/BaseWidget.js","../src/widgets/ButtonWidget.js","../src/widgets/InlineWidget.js","../src/widgets/TabWidget.js","../src/widgets/WidgetFactory.js","../src/core/FeedbackSDK.js","../src/index.js","../src/styles/styles.js"],"sourcesContent":["export class SDKError extends Error {\n\tconstructor(message, cause) {\n\t\tsuper(message);\n\t\tthis.name = 'SDKError';\n\t\tthis.cause = cause;\n\n\t\tif (Error.captureStackTrace) {\n\t\t\tError.captureStackTrace(this, SDKError);\n\t\t}\n\t}\n}\n\nexport class APIError extends Error {\n\tconstructor(status, message, response) {\n\t\tsuper(message);\n\t\tthis.name = 'APIError';\n\t\tthis.status = status;\n\t\tthis.response = response;\n\n\t\tif (Error.captureStackTrace) {\n\t\t\tError.captureStackTrace(this, APIError);\n\t\t}\n\t}\n\n\tisNetworkError() {\n\t\treturn this.status === 0;\n\t}\n\n\tisClientError() {\n\t\treturn this.status >= 400 && this.status < 500;\n\t}\n\n\tisServerError() {\n\t\treturn this.status >= 500 && this.status < 600;\n\t}\n}\n\nexport class WidgetError extends Error {\n\tconstructor(message, widgetType, widgetId) {\n\t\tsuper(message);\n\t\tthis.name = 'WidgetError';\n\t\tthis.widgetType = widgetType;\n\t\tthis.widgetId = widgetId;\n\n\t\tif (Error.captureStackTrace) {\n\t\t\tError.captureStackTrace(this, WidgetError);\n\t\t}\n\t}\n}\n\nexport class ConfigError extends Error {\n\tconstructor(message, configKey) {\n\t\tsuper(message);\n\t\tthis.name = 'ConfigError';\n\t\tthis.configKey = configKey;\n\n\t\tif (Error.captureStackTrace) {\n\t\t\tError.captureStackTrace(this, ConfigError);\n\t\t}\n\t}\n}\n\nexport class ValidationError extends Error {\n\tconstructor(message, field, value) {\n\t\tsuper(message);\n\t\tthis.name = 'ValidationError';\n\t\tthis.field = field;\n\t\tthis.value = value;\n\n\t\tif (Error.captureStackTrace) {\n\t\t\tError.captureStackTrace(this, ValidationError);\n\t\t}\n\t}\n}\n\nexport class ErrorHandler {\n\tconstructor(debug = false) {\n\t\tthis.debug = debug;\n\t}\n\n\thandle(error, context = '') {\n\t\tconst errorInfo = {\n\t\t\tname: error.name,\n\t\t\tmessage: error.message,\n\t\t\tcontext,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t};\n\n\t\tif (error instanceof APIError) {\n\t\t\terrorInfo.status = error.status;\n\t\t\terrorInfo.type = 'api';\n\t\t} else if (error instanceof WidgetError) {\n\t\t\terrorInfo.widgetType = error.widgetType;\n\t\t\terrorInfo.widgetId = error.widgetId;\n\t\t\terrorInfo.type = 'widget';\n\t\t} else if (error instanceof ConfigError) {\n\t\t\terrorInfo.configKey = error.configKey;\n\t\t\terrorInfo.type = 'config';\n\t\t} else if (error instanceof ValidationError) {\n\t\t\terrorInfo.field = error.field;\n\t\t\terrorInfo.value = error.value;\n\t\t\terrorInfo.type = 'validation';\n\t\t} else {\n\t\t\terrorInfo.type = 'unknown';\n\t\t}\n\n\t\tif (this.debug) {\n\t\t\tconsole.error('[FeedbackSDK Error]', errorInfo, error);\n\t\t} else {\n\t\t\tconsole.error('[FeedbackSDK Error]', error.message);\n\t\t}\n\n\t\treturn errorInfo;\n\t}\n\n\tgetUserMessage(error) {\n\t\tif (error instanceof APIError) {\n\t\t\tif (error.isNetworkError()) {\n\t\t\t\treturn 'Network error. Please check your connection and try again.';\n\t\t\t} else if (error.isClientError()) {\n\t\t\t\treturn 'Invalid request. Please check your input and try again.';\n\t\t\t} else if (error.isServerError()) {\n\t\t\t\treturn 'Server error. Please try again later.';\n\t\t\t}\n\t\t\treturn 'Failed to submit feedback. Please try again.';\n\t\t}\n\n\t\tif (error instanceof ValidationError) {\n\t\t\treturn `Please check your ${error.field}: ${error.message}`;\n\t\t}\n\n\t\tif (error instanceof ConfigError) {\n\t\t\treturn 'Configuration error. Please check your SDK setup.';\n\t\t}\n\n\t\tif (error instanceof WidgetError) {\n\t\t\treturn 'Widget error. Please try refreshing the page.';\n\t\t}\n\n\t\treturn 'An unexpected error occurred. Please try again.';\n\t}\n}\n","import { APIError } from '../utils/errors.js';\n\nexport class APIService {\n\tconstructor(config = {}) {\n\t\tthis.workspace = config.workspace;\n\t\tthis.sessionToken = null;\n\t\tthis.sessionExpiry = null;\n\t\tthis.userContext = config.userContext || null;\n\n\t\tif (config.apiUrl) {\n\t\t\tthis.baseURL = config.apiUrl;\n\t\t} else if (this.workspace) {\n\t\t\tthis.baseURL = `https://${this.workspace}.api.staging.product7.io/api/v1`;\n\t\t} else {\n\t\t\tthis.baseURL = 'https://api.staging.product7.io/api/v1';\n\t\t}\n\n\t\tthis._loadStoredSession();\n\t}\n\n\tasync init(userContext = null) {\n\t\tif (userContext) {\n\t\t\tthis.userContext = userContext;\n\t\t}\n\n\t\tif (this.isSessionValid()) {\n\t\t\treturn { sessionToken: this.sessionToken };\n\t\t}\n\n\t\tif (!this.userContext || !this.workspace) {\n\t\t\tconst error = `Missing ${!this.workspace ? 'workspace' : 'user context'} for initialization`;\n\t\t\tthrow new APIError(400, error);\n\t\t}\n\n\t\tconst payload = {\n\t\t\tworkspace: this.workspace,\n\t\t\tuser: this.userContext,\n\t\t};\n\n\t\ttry {\n\t\t\tconst response = await this._makeRequest('/widget/init', {\n\t\t\t\tmethod: 'POST',\n\t\t\t\tbody: JSON.stringify(payload),\n\t\t\t\theaders: {\n\t\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tthis.sessionToken = response.session_token;\n\t\t\tthis.sessionExpiry = new Date(Date.now() + response.expires_in * 1000);\n\t\t\tthis._storeSession();\n\n\t\t\treturn {\n\t\t\t\tsessionToken: this.sessionToken,\n\t\t\t\tconfig: response.config || {},\n\t\t\t\texpiresIn: response.expires_in,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tthrow new APIError(\n\t\t\t\terror.status || 500,\n\t\t\t\t`Failed to initialize widget: ${error.message}`,\n\t\t\t\terror.response\n\t\t\t);\n\t\t}\n\t}\n\n\tasync submitFeedback(feedbackData) {\n\t\tif (!this.isSessionValid()) {\n\t\t\tawait this.init();\n\t\t}\n\n\t\tif (!this.sessionToken) {\n\t\t\tthrow new APIError(401, 'No valid session token available');\n\t\t}\n\n\t\tconst payload = {\n\t\t\tboard: feedbackData.board_id || feedbackData.board || feedbackData.boardId,\n\t\t\ttitle: feedbackData.title,\n\t\t\tcontent: feedbackData.content,\n\t\t\tattachments: feedbackData.attachments || [],\n\t\t};\n\n\t\ttry {\n\t\t\tconst response = await this._makeRequest('/widget/feedback', {\n\t\t\t\tmethod: 'POST',\n\t\t\t\tbody: JSON.stringify(payload),\n\t\t\t\theaders: {\n\t\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t\tAuthorization: `Bearer ${this.sessionToken}`,\n\t\t\t\t},\n\t\t\t});\n\n\t\t\treturn response;\n\t\t} catch (error) {\n\t\t\tif (error.status === 401) {\n\t\t\t\tthis.sessionToken = null;\n\t\t\t\tthis.sessionExpiry = null;\n\t\t\t\tawait this.init();\n\t\t\t\treturn this.submitFeedback(feedbackData);\n\t\t\t}\n\n\t\t\tthrow new APIError(\n\t\t\t\terror.status || 500,\n\t\t\t\t`Failed to submit feedback: ${error.message}`,\n\t\t\t\terror.response\n\t\t\t);\n\t\t}\n\t}\n\n\tisSessionValid() {\n\t\treturn (\n\t\t\tthis.sessionToken && this.sessionExpiry && new Date() < this.sessionExpiry\n\t\t);\n\t}\n\n\tsetUserContext(userContext) {\n\t\tthis.userContext = userContext;\n\t\tif (typeof localStorage !== 'undefined') {\n\t\t\tlocalStorage.setItem('feedbackSDK_userContext', JSON.stringify(userContext));\n\t\t}\n\t}\n\n\tgetUserContext() {\n\t\treturn this.userContext;\n\t}\n\n\tclearSession() {\n\t\tthis.sessionToken = null;\n\t\tthis.sessionExpiry = null;\n\t\tif (typeof localStorage !== 'undefined') {\n\t\t\tlocalStorage.removeItem('feedbackSDK_session');\n\t\t\tlocalStorage.removeItem('feedbackSDK_userContext');\n\t\t}\n\t}\n\n\t_storeSession() {\n\t\tif (typeof localStorage === 'undefined') return;\n\n\t\ttry {\n\t\t\tconst sessionData = {\n\t\t\t\ttoken: this.sessionToken,\n\t\t\t\texpiry: this.sessionExpiry.toISOString(),\n\t\t\t\tworkspace: this.workspace,\n\t\t\t};\n\t\t\tlocalStorage.setItem('feedbackSDK_session', JSON.stringify(sessionData));\n\t\t} catch (error) {\n\t\t\t// Silently fail if localStorage is not available\n\t\t}\n\t}\n\n\t_loadStoredSession() {\n\t\tif (typeof localStorage === 'undefined') return false;\n\n\t\ttry {\n\t\t\tconst stored = localStorage.getItem('feedbackSDK_session');\n\t\t\tif (!stored) return false;\n\n\t\t\tconst sessionData = JSON.parse(stored);\n\t\t\tthis.sessionToken = sessionData.token;\n\t\t\tthis.sessionExpiry = new Date(sessionData.expiry);\n\n\t\t\treturn this.isSessionValid();\n\t\t} catch (error) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tasync _makeRequest(endpoint, options = {}) {\n\t\tconst url = `${this.baseURL}${endpoint}`;\n\n\t\ttry {\n\t\t\tconst response = await fetch(url, options);\n\n\t\t\tif (!response.ok) {\n\t\t\t\tlet errorMessage = `HTTP ${response.status}`;\n\t\t\t\tlet responseData = null;\n\n\t\t\t\ttry {\n\t\t\t\t\tresponseData = await response.json();\n\t\t\t\t\terrorMessage = responseData.message || responseData.error || errorMessage;\n\t\t\t\t} catch (e) {\n\t\t\t\t\terrorMessage = (await response.text()) || errorMessage;\n\t\t\t\t}\n\n\t\t\t\tthrow new APIError(response.status, errorMessage, responseData);\n\t\t\t}\n\n\t\t\tconst contentType = response.headers.get('content-type');\n\t\t\tif (contentType && contentType.includes('application/json')) {\n\t\t\t\treturn await response.json();\n\t\t\t}\n\n\t\t\treturn await response.text();\n\t\t} catch (error) {\n\t\t\tif (error instanceof APIError) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tthrow new APIError(0, error.message, null);\n\t\t}\n\t}\n}","export class EventBus {\n\tconstructor() {\n\t\tthis.events = new Map();\n\t}\n\n\ton(event, callback) {\n\t\tif (!this.events.has(event)) {\n\t\t\tthis.events.set(event, []);\n\t\t}\n\t\tthis.events.get(event).push(callback);\n\n\t\treturn () => this.off(event, callback);\n\t}\n\n\toff(event, callback) {\n\t\tconst callbacks = this.events.get(event);\n\t\tif (callbacks) {\n\t\t\tconst index = callbacks.indexOf(callback);\n\t\t\tif (index > -1) {\n\t\t\t\tcallbacks.splice(index, 1);\n\t\t\t}\n\t\t}\n\t}\n\n\temit(event, data) {\n\t\tconst callbacks = this.events.get(event);\n\t\tif (callbacks) {\n\t\t\tcallbacks.forEach((callback) => {\n\t\t\t\ttry {\n\t\t\t\t\tcallback(data);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconsole.error('[FeedbackSDK] Event callback error:', error);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\tonce(event, callback) {\n\t\tconst unsubscribe = this.on(event, (data) => {\n\t\t\tcallback(data);\n\t\t\tunsubscribe();\n\t\t});\n\t\treturn unsubscribe;\n\t}\n\n\tclear() {\n\t\tthis.events.clear();\n\t}\n\n\tgetListenerCount(event) {\n\t\tconst callbacks = this.events.get(event);\n\t\treturn callbacks ? callbacks.length : 0;\n\t}\n}\n","export function generateId(prefix = 'feedback') {\n\tconst timestamp = Date.now();\n\tconst random = Math.random().toString(36).substring(2, 9);\n\treturn `${prefix}_${timestamp}_${random}`;\n}\n\nexport function deepMerge(target, source) {\n\tconst result = { ...target };\n\n\tfor (const key in source) {\n\t\tif (source.hasOwnProperty(key)) {\n\t\t\tif (\n\t\t\t\tsource[key] &&\n\t\t\t\ttypeof source[key] === 'object' &&\n\t\t\t\t!Array.isArray(source[key])\n\t\t\t) {\n\t\t\t\tresult[key] = deepMerge(target[key] || {}, source[key]);\n\t\t\t} else {\n\t\t\t\tresult[key] = source[key];\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result;\n}\n\nexport function debounce(func, wait) {\n\tlet timeout;\n\treturn function executedFunction(...args) {\n\t\tconst later = () => {\n\t\t\tclearTimeout(timeout);\n\t\t\tfunc(...args);\n\t\t};\n\t\tclearTimeout(timeout);\n\t\ttimeout = setTimeout(later, wait);\n\t};\n}\n\nexport function throttle(func, limit) {\n\tlet lastFunc;\n\tlet lastRan;\n\treturn function (...args) {\n\t\tif (!lastRan) {\n\t\t\tfunc(...args);\n\t\t\tlastRan = Date.now();\n\t\t} else {\n\t\t\tclearTimeout(lastFunc);\n\t\t\tlastFunc = setTimeout(\n\t\t\t\t() => {\n\t\t\t\t\tif (Date.now() - lastRan >= limit) {\n\t\t\t\t\t\tfunc(...args);\n\t\t\t\t\t\tlastRan = Date.now();\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tlimit - (Date.now() - lastRan)\n\t\t\t);\n\t\t}\n\t};\n}\n\nexport function isValidEmail(email) {\n\tif (!email || typeof email !== 'string') return false;\n\n\tconst emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n\treturn emailRegex.test(email.trim());\n}\n\nexport function sanitizeHTML(str) {\n\tif (!str || typeof str !== 'string') return '';\n\n\tconst div = document.createElement('div');\n\tdiv.textContent = str;\n\treturn div.innerHTML;\n}\n\nexport function getCSSProperty(element, property, fallback = '') {\n\tif (!element || !property) return fallback;\n\n\ttry {\n\t\tconst style = window.getComputedStyle(element);\n\t\treturn style.getPropertyValue(property) || fallback;\n\t} catch (error) {\n\t\treturn fallback;\n\t}\n}\n\nexport function isInViewport(element) {\n\tif (!element) return false;\n\n\tconst rect = element.getBoundingClientRect();\n\treturn (\n\t\trect.top >= 0 &&\n\t\trect.left >= 0 &&\n\t\trect.bottom <=\n\t\t\t(window.innerHeight || document.documentElement.clientHeight) &&\n\t\trect.right <= (window.innerWidth || document.documentElement.clientWidth)\n\t);\n}\n\nexport function scrollToElement(element, options = {}) {\n\tif (!element) return;\n\n\tconst defaultOptions = {\n\t\tbehavior: 'smooth',\n\t\tblock: 'center',\n\t\tinline: 'nearest',\n\t};\n\n\telement.scrollIntoView({ ...defaultOptions, ...options });\n}\n\nexport function getBrowserInfo() {\n\tconst userAgent = navigator.userAgent;\n\tconst platform = navigator.platform;\n\n\treturn {\n\t\tuserAgent,\n\t\tplatform,\n\t\tlanguage: navigator.language || navigator.userLanguage,\n\t\tcookieEnabled: navigator.cookieEnabled,\n\t\tscreenResolution: `${screen.width}x${screen.height}`,\n\t\twindowSize: `${window.innerWidth}x${window.innerHeight}`,\n\t\ttimezone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n\t};\n}\n\nexport function formatFileSize(bytes) {\n\tif (bytes === 0) return '0 Bytes';\n\n\tconst k = 1024;\n\tconst sizes = ['Bytes', 'KB', 'MB', 'GB'];\n\tconst i = Math.floor(Math.log(bytes) / Math.log(k));\n\n\treturn parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];\n}\n\nexport function delay(ms) {\n\treturn new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport function safeJsonParse(str, fallback = null) {\n\ttry {\n\t\treturn JSON.parse(str);\n\t} catch (error) {\n\t\treturn fallback;\n\t}\n}\n\nexport function escapeRegex(string) {\n\treturn string.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nexport function getNestedProperty(obj, path, defaultValue = undefined) {\n\tif (!obj || !path) return defaultValue;\n\n\tconst keys = path.split('.');\n\tlet current = obj;\n\n\tfor (const key of keys) {\n\t\tif (current === null || current === undefined || !(key in current)) {\n\t\t\treturn defaultValue;\n\t\t}\n\t\tcurrent = current[key];\n\t}\n\n\treturn current;\n}\n\nexport function setNestedProperty(obj, path, value) {\n\tif (!obj || !path) return obj;\n\n\tconst keys = path.split('.');\n\tconst lastKey = keys.pop();\n\tlet current = obj;\n\n\tfor (const key of keys) {\n\t\tif (!(key in current) || typeof current[key] !== 'object') {\n\t\t\tcurrent[key] = {};\n\t\t}\n\t\tcurrent = current[key];\n\t}\n\n\tcurrent[lastKey] = value;\n\treturn obj;\n}\n\nexport function isBrowser() {\n\treturn typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\nexport function isMobile() {\n\tif (!isBrowser()) return false;\n\n\treturn (\n\t\t/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(\n\t\t\tnavigator.userAgent\n\t\t) || window.innerWidth <= 768\n\t);\n}\n\nexport function getCurrentTimestamp() {\n\treturn new Date().toISOString();\n}\n\nexport function validateConfig(config, required = []) {\n\tconst missing = [];\n\n\tfor (const key of required) {\n\t\tif (!config[key]) {\n\t\t\tmissing.push(key);\n\t\t}\n\t}\n\n\tif (missing.length > 0) {\n\t\tthrow new Error(`Missing required configuration: ${missing.join(', ')}`);\n\t}\n\n\treturn true;\n}\n","export class BaseWidget {\n\tconstructor(options = {}) {\n\t\tthis.id = options.id;\n\t\tthis.sdk = options.sdk;\n\t\tthis.apiService = options.apiService;\n\t\tthis.type = options.type || 'base';\n\n\t\tthis.options = {\n\t\t\tcontainer: null,\n\t\t\tposition: this.sdk.config.position,\n\t\t\ttheme: this.sdk.config.theme,\n\t\t\tboardId: this.sdk.config.boardId,\n\t\t\tautoShow: false,\n\t\t\tcustomStyles: {},\n\t\t\t...options,\n\t\t};\n\n\t\tthis.element = null;\n\t\tthis.modalElement = null;\n\t\tthis.mounted = false;\n\t\tthis.destroyed = false;\n\n\t\tthis.state = {\n\t\t\tisOpen: false,\n\t\t\tisSubmitting: false,\n\t\t\ttitle: '',\n\t\t\tcontent: '',\n\t\t\temail: '',\n\t\t\tattachments: [],\n\t\t\terrors: {},\n\t\t};\n\n\t\tthis._bindMethods();\n\t}\n\n\tmount(container) {\n\t\tif (this.mounted || this.destroyed) return this;\n\n\t\tif (typeof container === 'string') {\n\t\t\tcontainer = document.querySelector(container);\n\t\t}\n\n\t\tif (!container) {\n\t\t\tcontainer = document.body;\n\t\t}\n\n\t\tthis.container = container;\n\t\tthis.element = this._render();\n\t\tthis.container.appendChild(this.element);\n\n\t\tthis.mounted = true;\n\t\tthis._attachEvents();\n\t\tthis.onMount();\n\n\t\tif (this.options.autoShow) {\n\t\t\tthis.show();\n\t\t}\n\n\t\tthis.sdk.eventBus.emit('widget:mounted', { widget: this });\n\t\treturn this;\n\t}\n\n\tshow() {\n\t\tif (this.element) {\n\t\t\tthis.element.style.display = 'block';\n\t\t}\n\t\treturn this;\n\t}\n\n\thide() {\n\t\tif (this.element) {\n\t\t\tthis.element.style.display = 'none';\n\t\t}\n\t\treturn this;\n\t}\n\n\topenModal() {\n\t\tthis.state.isOpen = true;\n\t\tthis._renderModal();\n\t}\n\n\tcloseModal() {\n\t\tthis.state.isOpen = false;\n\t\tif (this.modalElement) {\n\t\t\tthis.modalElement.remove();\n\t\t\tthis.modalElement = null;\n\t\t}\n\t\tthis._resetForm();\n\t}\n\n\tasync submitFeedback() {\n\t\tif (this.state.isSubmitting) return;\n\n\t\ttry {\n\t\t\tthis.state.isSubmitting = true;\n\t\t\tthis._updateSubmitButton();\n\n\t\t\tconst payload = {\n\t\t\t\ttitle: this.state.title || 'Feedback',\n\t\t\t\tcontent: this.state.content,\n\t\t\t\temail: this.state.email,\n\t\t\t\tboard_id: this.options.boardId,\n\t\t\t\tattachments: this.state.attachments,\n\t\t\t};\n\n\t\t\tif (!this.state.content.trim()) {\n\t\t\t\tthis._showError('Please enter your feedback message.');\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst response = await this.apiService.submitFeedback(payload);\n\n\t\t\tthis._showSuccessMessage();\n\t\t\tthis.closeModal();\n\n\t\t\tthis.sdk.eventBus.emit('feedback:submitted', {\n\t\t\t\twidget: this,\n\t\t\t\tfeedback: response,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tthis._showError('Failed to submit feedback. Please try again.');\n\t\t\tthis.sdk.eventBus.emit('feedback:error', { widget: this, error });\n\t\t} finally {\n\t\t\tthis.state.isSubmitting = false;\n\t\t\tthis._updateSubmitButton();\n\t\t}\n\t}\n\n\thandleConfigUpdate(newConfig) {\n\t\tthis.options.theme = newConfig.theme;\n\t\tif (this.element) {\n\t\t\tthis._updateTheme();\n\t\t}\n\t}\n\n\tdestroy() {\n\t\tif (this.destroyed) return;\n\n\t\tthis.onDestroy();\n\t\tthis.closeModal();\n\n\t\tif (this.element && this.element.parentNode) {\n\t\t\tthis.element.parentNode.removeChild(this.element);\n\t\t}\n\n\t\tthis.destroyed = true;\n\t\tthis.mounted = false;\n\t\tthis.sdk.eventBus.emit('widget:destroyed', { widget: this });\n\t}\n\n\tonMount() {}\n\tonDestroy() {}\n\n\t_render() {\n\t\tthrow new Error('_render() must be implemented by concrete widget');\n\t}\n\n\t_attachEvents() {\n\t\t// Override in concrete widgets\n\t}\n\n\t_bindMethods() {\n\t\tthis.openModal = this.openModal.bind(this);\n\t\tthis.closeModal = this.closeModal.bind(this);\n\t\tthis.submitFeedback = this.submitFeedback.bind(this);\n\t}\n\n\t_renderModal() {\n\t\tif (this.modalElement) return;\n\n\t\tthis.modalElement = document.createElement('div');\n\t\tthis.modalElement.className = `feedback-modal theme-${this.options.theme}`;\n\t\tthis.modalElement.innerHTML = this._getModalHTML();\n\n\t\tdocument.body.appendChild(this.modalElement);\n\t\tthis._attachModalEvents();\n\n\t\tconst firstInput = this.modalElement.querySelector('input, textarea');\n\t\tif (firstInput) {\n\t\t\tsetTimeout(() => firstInput.focus(), 100);\n\t\t}\n\t}\n\n\t_getModalHTML() {\n\t\treturn `\n <div class=\"feedback-modal-overlay\">\n <div class=\"feedback-modal-content\">\n <div class=\"feedback-modal-header\">\n <h3>Send Feedback</h3>\n <button class=\"feedback-modal-close\" type=\"button\">&times;</button>\n </div>\n <form class=\"feedback-form\">\n <div class=\"feedback-form-group\">\n <label for=\"feedback-title-${this.id}\">Title</label>\n <input \n type=\"text\" \n id=\"feedback-title-${this.id}\" \n name=\"title\" \n placeholder=\"Brief description of your feedback\"\n value=\"${this.state.title}\"\n />\n </div>\n <div class=\"feedback-form-group\">\n <label for=\"feedback-content-${this.id}\">Message *</label>\n <textarea \n id=\"feedback-content-${this.id}\" \n name=\"content\" \n placeholder=\"Tell us more about your feedback...\"\n required\n >${this.state.content}</textarea>\n </div>\n <div class=\"feedback-form-actions\">\n <button type=\"button\" class=\"feedback-btn feedback-btn-cancel\">Cancel</button>\n <button type=\"submit\" class=\"feedback-btn feedback-btn-submit\">\n ${this.state.isSubmitting ? 'Sending...' : 'Send Feedback'}\n </button>\n </div>\n <div class=\"feedback-error\" style=\"display: none;\"></div>\n </form>\n </div>\n </div>\n `;\n\t}\n\n\t_attachModalEvents() {\n\t\tconst modal = this.modalElement;\n\n\t\tmodal\n\t\t\t.querySelector('.feedback-modal-close')\n\t\t\t.addEventListener('click', this.closeModal);\n\t\tmodal\n\t\t\t.querySelector('.feedback-btn-cancel')\n\t\t\t.addEventListener('click', this.closeModal);\n\t\tmodal\n\t\t\t.querySelector('.feedback-modal-overlay')\n\t\t\t.addEventListener('click', (e) => {\n\t\t\t\tif (e.target === e.currentTarget) {\n\t\t\t\t\tthis.closeModal();\n\t\t\t\t}\n\t\t\t});\n\n\t\tconst form = modal.querySelector('.feedback-form');\n\t\tform.addEventListener('submit', (e) => {\n\t\t\te.preventDefault();\n\t\t\tthis.submitFeedback();\n\t\t});\n\n\t\tmodal\n\t\t\t.querySelector('input[name=\"title\"]')\n\t\t\t.addEventListener('input', (e) => {\n\t\t\t\tthis.state.title = e.target.value;\n\t\t\t});\n\n\t\tmodal\n\t\t\t.querySelector('textarea[name=\"content\"]')\n\t\t\t.addEventListener('input', (e) => {\n\t\t\t\tthis.state.content = e.target.value;\n\t\t\t});\n\t}\n\n\t_updateSubmitButton() {\n\t\tif (this.modalElement) {\n\t\t\tconst submitBtn = this.modalElement.querySelector('.feedback-btn-submit');\n\t\t\tif (submitBtn) {\n\t\t\t\tsubmitBtn.textContent = this.state.isSubmitting\n\t\t\t\t\t? 'Sending...'\n\t\t\t\t\t: 'Send Feedback';\n\t\t\t\tsubmitBtn.disabled = this.state.isSubmitting;\n\t\t\t}\n\t\t}\n\t}\n\n\t_showError(message) {\n\t\tif (this.modalElement) {\n\t\t\tconst errorElement = this.modalElement.querySelector('.feedback-error');\n\t\t\terrorElement.textContent = message;\n\t\t\terrorElement.style.display = 'block';\n\t\t\tsetTimeout(() => {\n\t\t\t\tif (errorElement) {\n\t\t\t\t\terrorElement.style.display = 'none';\n\t\t\t\t}\n\t\t\t}, 5000);\n\t\t}\n\t}\n\n\t_showSuccessMessage() {\n\t\tconst notification = document.createElement('div');\n\t\tnotification.className = 'feedback-success-notification';\n\t\tnotification.innerHTML = `\n <div class=\"feedback-success-content\">\n <span>✓ Feedback submitted successfully!</span>\n <button class=\"feedback-success-close\">&times;</button>\n </div>\n `;\n\n\t\tdocument.body.appendChild(notification);\n\n\t\tsetTimeout(() => {\n\t\t\tif (notification.parentNode) {\n\t\t\t\tnotification.parentNode.removeChild(notification);\n\t\t\t}\n\t\t}, 3000);\n\n\t\tnotification\n\t\t\t.querySelector('.feedback-success-close')\n\t\t\t.addEventListener('click', () => {\n\t\t\t\tif (notification.parentNode) {\n\t\t\t\t\tnotification.parentNode.removeChild(notification);\n\t\t\t\t}\n\t\t\t});\n\t}\n\n\t_resetForm() {\n\t\tthis.state.title = '';\n\t\tthis.state.content = '';\n\t\tthis.state.email = '';\n\t\tthis.state.errors = {};\n\t}\n\n\t_updateTheme() {\n\t\tif (this.element) {\n\t\t\tthis.element.className = this.element.className.replace(\n\t\t\t\t/theme-\\w+/,\n\t\t\t\t`theme-${this.options.theme}`\n\t\t\t);\n\t\t}\n\t\tif (this.modalElement) {\n\t\t\tthis.modalElement.className = this.modalElement.className.replace(\n\t\t\t\t/theme-\\w+/,\n\t\t\t\t`theme-${this.options.theme}`\n\t\t\t);\n\t\t}\n\t}\n}\n","import { BaseWidget } from './BaseWidget.js';\n\nexport class ButtonWidget extends BaseWidget {\n\tconstructor(options) {\n\t\tsuper({ ...options, type: 'button' });\n\t}\n\n\t_render() {\n\t\tconst button = document.createElement('div');\n\t\tbutton.className = `feedback-widget feedback-widget-button theme-${this.options.theme} position-${this.options.position}`;\n\t\tbutton.innerHTML = `\n <button class=\"feedback-trigger-btn\" type=\"button\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path d=\"M2.003 5.884L10 9.882l7.997-3.998A2 2 0 0016 4H4a2 2 0 00-1.997 1.884z\"/>\n <path d=\"M18 8.118l-8 4-8-4V14a2 2 0 002 2h12a2 2 0 002-2V8.118z\"/>\n </svg>\n Feedback\n </button>\n `;\n\n\t\tif (this.options.customStyles) {\n\t\t\tObject.assign(button.style, this.options.customStyles);\n\t\t}\n\n\t\treturn button;\n\t}\n\n\t_attachEvents() {\n\t\tconst button = this.element.querySelector('.feedback-trigger-btn');\n\t\tbutton.addEventListener('click', this.openModal);\n\n\t\tbutton.addEventListener('mouseenter', () => {\n\t\t\tif (!this.state.isSubmitting) {\n\t\t\t\tbutton.style.transform = 'translateY(-2px)';\n\t\t\t}\n\t\t});\n\n\t\tbutton.addEventListener('mouseleave', () => {\n\t\t\tbutton.style.transform = 'translateY(0)';\n\t\t});\n\t}\n\n\tupdateText(text) {\n\t\tconst button = this.element?.querySelector('.feedback-trigger-btn');\n\t\tif (button) {\n\t\t\tconst textNode = button.childNodes[button.childNodes.length - 1];\n\t\t\tif (textNode && textNode.nodeType === Node.TEXT_NODE) {\n\t\t\t\ttextNode.textContent = text;\n\t\t\t}\n\t\t}\n\t}\n\n\tupdatePosition(position) {\n\t\tthis.options.position = position;\n\t\tif (this.element) {\n\t\t\tthis.element.className = this.element.className.replace(\n\t\t\t\t/position-\\w+-\\w+/,\n\t\t\t\t`position-${position}`\n\t\t\t);\n\t\t}\n\t}\n}\n","import { BaseWidget } from './BaseWidget.js';\n\nexport class InlineWidget extends BaseWidget {\n\tconstructor(options) {\n\t\tsuper({ ...options, type: 'inline' });\n\t}\n\n\t_render() {\n\t\tconst widget = document.createElement('div');\n\t\twidget.className = `feedback-widget feedback-widget-inline theme-${this.options.theme}`;\n\t\twidget.innerHTML = `\n <div class=\"feedback-inline-content\">\n <h3>Send us your feedback</h3>\n <form class=\"feedback-inline-form\">\n <div class=\"feedback-form-group\">\n <input \n type=\"text\" \n name=\"title\" \n placeholder=\"Title (optional)\"\n value=\"${this.state.title}\"\n />\n </div>\n <div class=\"feedback-form-group\">\n <textarea \n name=\"content\" \n placeholder=\"Your feedback...\"\n required\n >${this.state.content}</textarea>\n </div>\n <div class=\"feedback-form-group\">\n <input \n type=\"email\" \n name=\"email\" \n placeholder=\"Email (optional)\"\n value=\"${this.state.email}\"\n />\n </div>\n <button type=\"submit\" class=\"feedback-btn feedback-btn-submit\">\n Send Feedback\n </button>\n <div class=\"feedback-error\" style=\"display: none;\"></div>\n </form>\n </div>\n `;\n\n\t\tif (this.options.customStyles) {\n\t\t\tObject.assign(widget.style, this.options.customStyles);\n\t\t}\n\n\t\treturn widget;\n\t}\n\n\t_attachEvents() {\n\t\tconst form = this.element.querySelector('.feedback-inline-form');\n\n\t\tform.addEventListener('submit', (e) => {\n\t\t\te.preventDefault();\n\t\t\tthis.submitFeedback();\n\t\t});\n\n\t\tform.querySelector('input[name=\"title\"]').addEventListener('input', (e) => {\n\t\t\tthis.state.title = e.target.value;\n\t\t});\n\n\t\tform\n\t\t\t.querySelector('textarea[name=\"content\"]')\n\t\t\t.addEventListener('input', (e) => {\n\t\t\t\tthis.state.content = e.target.value;\n\t\t\t});\n\n\t\tform.querySelector('input[name=\"email\"]').addEventListener('input', (e) => {\n\t\t\tthis.state.email = e.target.value;\n\t\t});\n\t}\n\n\topenModal() {\n\t\tconst textarea = this.element.querySelector('textarea[name=\"content\"]');\n\t\tif (textarea) {\n\t\t\ttextarea.focus();\n\t\t}\n\t}\n\n\tcloseModal() {\n\t\t// Inline widget doesn't use modal\n\t}\n\n\t_showSuccessMessage() {\n\t\tconst widget = this.element.querySelector('.feedback-inline-content');\n\t\tconst originalContent = widget.innerHTML;\n\n\t\twidget.innerHTML = `\n <div class=\"feedback-success\">\n <div class=\"feedback-success-icon\">✓</div>\n <h3>Thank you!</h3>\n <p>Your feedback has been submitted successfully.</p>\n <button class=\"feedback-btn feedback-btn-reset\">Send Another</button>\n </div>\n `;\n\n\t\tconst resetBtn = widget.querySelector('.feedback-btn-reset');\n\t\tresetBtn.addEventListener('click', () => {\n\t\t\twidget.innerHTML = originalContent;\n\t\t\tthis._attachEvents();\n\t\t\tthis._resetForm();\n\t\t});\n\t}\n\n\t_showError(message) {\n\t\tconst errorElement = this.element.querySelector('.feedback-error');\n\t\tif (errorElement) {\n\t\t\terrorElement.textContent = message;\n\t\t\terrorElement.style.display = 'block';\n\n\t\t\tsetTimeout(() => {\n\t\t\t\tif (errorElement) {\n\t\t\t\t\terrorElement.style.display = 'none';\n\t\t\t\t}\n\t\t\t}, 5000);\n\t\t}\n\t}\n\n\t_updateSubmitButton() {\n\t\tconst submitBtn = this.element.querySelector('.feedback-btn-submit');\n\t\tif (submitBtn) {\n\t\t\tsubmitBtn.textContent = this.state.isSubmitting\n\t\t\t\t? 'Sending...'\n\t\t\t\t: 'Send Feedback';\n\t\t\tsubmitBtn.disabled = this.state.isSubmitting;\n\t\t}\n\t}\n\n\tupdateTitle(title) {\n\t\tconst titleElement = this.element?.querySelector('h3');\n\t\tif (titleElement) {\n\t\t\ttitleElement.textContent = title;\n\t\t}\n\t}\n\n\tsetPlaceholder(field, placeholder) {\n\t\tconst input = this.element?.querySelector(`[name=\"${field}\"]`);\n\t\tif (input) {\n\t\t\tinput.placeholder = placeholder;\n\t\t}\n\t}\n}\n","import { BaseWidget } from './BaseWidget.js';\n\nexport class TabWidget extends BaseWidget {\n\tconstructor(options) {\n\t\tsuper({ ...options, type: 'tab' });\n\t}\n\n\t_render() {\n\t\tconst tab = document.createElement('div');\n\t\ttab.className = `feedback-widget feedback-widget-tab theme-${this.options.theme} position-${this.options.position}`;\n\t\ttab.innerHTML = `\n <div class=\"feedback-tab-trigger\">\n <span class=\"feedback-tab-text\">Feedback</span>\n </div>\n `;\n\n\t\tif (this.options.customStyles) {\n\t\t\tObject.assign(tab.style, this.options.customStyles);\n\t\t}\n\n\t\treturn tab;\n\t}\n\n\t_attachEvents() {\n\t\tconst tab = this.element.querySelector('.feedback-tab-trigger');\n\t\ttab.addEventListener('click', this.openModal);\n\n\t\ttab.addEventListener('mouseenter', () => {\n\t\t\tif (!this.state.isSubmitting) {\n\t\t\t\ttab.style.transform = this._getHoverTransform();\n\t\t\t}\n\t\t});\n\n\t\ttab.addEventListener('mouseleave', () => {\n\t\t\ttab.style.transform = 'none';\n\t\t});\n\t}\n\n\t_getHoverTransform() {\n\t\tconst position = this.options.position;\n\t\tif (position.includes('right')) {\n\t\t\treturn 'translateX(-5px)';\n\t\t} else if (position.includes('left')) {\n\t\t\treturn 'translateX(5px)';\n\t\t}\n\t\treturn 'none';\n\t}\n\n\tupdateText(text) {\n\t\tconst textElement = this.element?.querySelector('.feedback-tab-text');\n\t\tif (textElement) {\n\t\t\ttextElement.textContent = text;\n\t\t}\n\t}\n\n\tupdatePosition(position) {\n\t\tthis.options.position = position;\n\t\tif (this.element) {\n\t\t\tthis.element.className = this.element.className.replace(\n\t\t\t\t/position-\\w+-\\w+/,\n\t\t\t\t`position-${position}`\n\t\t\t);\n\t\t}\n\t}\n}\n","import { SDKError } from '../utils/errors.js';\nimport { ButtonWidget } from './ButtonWidget.js';\nimport { InlineWidget } from './InlineWidget.js';\nimport { TabWidget } from './TabWidget.js';\n\nexport class WidgetFactory {\n\tstatic widgets = new Map([\n\t\t['button', ButtonWidget],\n\t\t['tab', TabWidget],\n\t\t['inline', InlineWidget],\n\t]);\n\n\tstatic register(type, WidgetClass) {\n\t\tif (typeof type !== 'string' || !type.trim()) {\n\t\t\tthrow new SDKError('Widget type must be a non-empty string');\n\t\t}\n\n\t\tif (typeof WidgetClass !== 'function') {\n\t\t\tthrow new SDKError('Widget class must be a constructor function');\n\t\t}\n\n\t\tthis.widgets.set(type, WidgetClass);\n\t}\n\n\tstatic create(type, options = {}) {\n\t\tconst WidgetClass = this.widgets.get(type);\n\n\t\tif (!WidgetClass) {\n\t\t\tconst availableTypes = Array.from(this.widgets.keys()).join(', ');\n\t\t\tthrow new SDKError(\n\t\t\t\t`Unknown widget type: ${type}. Available types: ${availableTypes}`\n\t\t\t);\n\t\t}\n\n\t\ttry {\n\t\t\treturn new WidgetClass(options);\n\t\t} catch (error) {\n\t\t\tthrow new SDKError(\n\t\t\t\t`Failed to create widget of type '${type}': ${error.message}`,\n\t\t\t\terror\n\t\t\t);\n\t\t}\n\t}\n\n\tstatic getAvailableTypes() {\n\t\treturn Array.from(this.widgets.keys());\n\t}\n\n\tstatic isTypeRegistered(type) {\n\t\treturn this.widgets.has(type);\n\t}\n\n\tstatic unregister(type) {\n\t\treturn this.widgets.delete(type);\n\t}\n\n\tstatic clear() {\n\t\tthis.widgets.clear();\n\t}\n\n\tstatic getWidgetClass(type) {\n\t\treturn this.widgets.get(type);\n\t}\n}\n","import { ConfigError, SDKError } from '../utils/errors.js';\nimport { deepMerge, generateId } from '../utils/helpers.js';\nimport { WidgetFactory } from '../widgets/WidgetFactory.js';\nimport { APIService } from './APIService.js';\nimport { EventBus } from './EventBus.js';\n\nexport class FeedbackSDK {\n\tconstructor(config = {}) {\n\t\tthis.config = this._validateAndMergeConfig(config);\n\t\tthis.initialized = false;\n\t\tthis.widgets = new Map();\n\t\tthis.eventBus = new EventBus();\n\n\t\tthis.apiService = new APIService({\n\t\t\tapiUrl: this.config.apiUrl,\n\t\t\tworkspace: this.config.workspace,\n\t\t\tuserContext: this.config.userContext,\n\t\t});\n\n\t\tthis._bindMethods();\n\t}\n\n\tasync init() {\n\t\tif (this.initialized) {\n\t\t\treturn { alreadyInitialized: true };\n\t\t}\n\n\t\ttry {\n\t\t\tconst initData = await this.apiService.init(this.config.userContext);\n\n\t\t\tif (initData.config) {\n\t\t\t\tthis.config = deepMerge(this.config, initData.config);\n\t\t\t}\n\n\t\t\tthis.initialized = true;\n\t\t\tthis.eventBus.emit('sdk:initialized', {\n\t\t\t\tconfig: this.config,\n\t\t\t\tsessionToken: initData.sessionToken,\n\t\t\t});\n\n\t\t\treturn {\n\t\t\t\tinitialized: true,\n\t\t\t\tconfig: initData.config || {},\n\t\t\t\tsessionToken: initData.sessionToken,\n\t\t\t\texpiresIn: initData.expiresIn,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tthis.eventBus.emit('sdk:error', { error });\n\t\t\tthrow new SDKError(`Failed to initialize SDK: ${error.message}`, error);\n\t\t}\n\t}\n\n\tcreateWidget(type = 'button', options = {}) {\n\t\tif (!this.initialized) {\n\t\t\tthrow new SDKError('SDK must be initialized before creating widgets. Call init() first.');\n\t\t}\n\n\t\tconst widgetId = generateId('widget');\n\t\tconst widgetOptions = {\n\t\t\tid: widgetId,\n\t\t\tsdk: this,\n\t\t\tapiService: this.apiService,\n\t\t\t...this.config,\n\t\t\t...options,\n\t\t};\n\n\t\ttry {\n\t\t\tconst widget = WidgetFactory.create(type, widgetOptions);\n\t\t\tthis.widgets.set(widgetId, widget);\n\t\t\tthis.eventBus.emit('widget:created', { widget, type });\n\t\t\treturn widget;\n\t\t} catch (error) {\n\t\t\tthrow new SDKError(`Failed to create widget: ${error.message}`, error);\n\t\t}\n\t}\n\n\tgetWidget(id) {\n\t\treturn this.widgets.get(id);\n\t}\n\n\tgetAllWidgets() {\n\t\treturn Array.from(this.widgets.values());\n\t}\n\n\tdestroyWidget(id) {\n\t\tconst widget = this.widgets.get(id);\n\t\tif (widget) {\n\t\t\twidget.destroy();\n\t\t\tthis.widgets.delete(id);\n\t\t\tthis.eventBus.emit('widget:removed', { widgetId: id });\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tdestroyAllWidgets() {\n\t\tfor (const widget of this.widgets.values()) {\n\t\t\twidget.destroy();\n\t\t}\n\t\tthis.widgets.clear();\n\t\tthis.eventBus.emit('widgets:cleared');\n\t}\n\n\tupdateConfig(newConfig) {\n\t\tconst oldConfig = { ...this.config };\n\t\tthis.config = this._validateAndMergeConfig(newConfig, this.config);\n\n\t\tfor (const widget of this.widgets.values()) {\n\t\t\twidget.handleConfigUpdate(this.config);\n\t\t}\n\n\t\tthis.eventBus.emit('config:updated', {\n\t\t\toldConfig,\n\t\t\tnewConfig: this.config,\n\t\t});\n\t}\n\n\tsetUserContext(userContext) {\n\t\tthis.config.userContext = userContext;\n\t\tif (this.apiService) {\n\t\t\tthis.apiService.setUserContext(userContext);\n\t\t}\n\t\tthis.eventBus.emit('user:updated', { userContext });\n\t}\n\n\tgetUserContext() {\n\t\treturn this.config.userContext || (this.apiService ? this.apiService.getUserContext() : null);\n\t}\n\n\tasync reinitialize(newUserContext = null) {\n\t\tthis.apiService.clearSession();\n\t\tthis.initialized = false;\n\n\t\tif (newUserContext) {\n\t\t\tthis.setUserContext(newUserContext);\n\t\t}\n\n\t\treturn this.init();\n\t}\n\n\ton(event, callback) {\n\t\tthis.eventBus.on(event, callback);\n\t\treturn this;\n\t}\n\n\toff(event, callback) {\n\t\tthis.eventBus.off(event, callback);\n\t\treturn this;\n\t}\n\n\tonce(event, callback) {\n\t\tthis.eventBus.once(event, callback);\n\t\treturn this;\n\t}\n\n\temit(event, data) {\n\t\tthis.eventBus.emit(event, data);\n\t\treturn this;\n\t}\n\n\tdestroy() {\n\t\tthis.destroyAllWidgets();\n\t\tthis.eventBus.removeAllListeners();\n\t\tthis.apiService.clearSession();\n\t\tthis.initialized = false;\n\t\tthis.eventBus.emit('sdk:destroyed');\n\t}\n\n\t_validateAndMergeConfig(newConfig, existingConfig = {}) {\n\t\tconst defaultConfig = {\n\t\t\tapiUrl: null,\n\t\t\tworkspace: null,\n\t\t\tuserContext: null,\n\t\t\tposition: 'bottom-right',\n\t\t\ttheme: 'light',\n\t\t\tboardId: 'general',\n\t\t\tautoShow: true,\n\t\t\tdebug: false,\n\t\t};\n\n\t\tconst mergedConfig = deepMerge(deepMerge(defaultConfig, existingConfig), newConfig);\n\n\t\tif (!mergedConfig.workspace) {\n\t\t\tthrow new ConfigError('Missing required configuration: workspace');\n\t\t}\n\n\t\tif (mergedConfig.userContext) {\n\t\t\tthis._validateUserContext(mergedConfig.userContext);\n\t\t}\n\n\t\treturn mergedConfig;\n\t}\n\n\t_validateUserContext(userContext) {\n\t\tif (!userContext.user_id && !userContext.email) {\n\t\t\tthrow new ConfigError('User context must include at least user_id or email');\n\t\t}\n\n\t\tconst validStructure = {\n\t\t\tuser_id: 'string',\n\t\t\temail: 'string',\n\t\t\tname: 'string',\n\t\t\tcustom_fields: 'object',\n\t\t\tcompany: 'object',\n\t\t};\n\n\t\tfor (const [key, expectedType] of Object.entries(validStructure)) {\n\t\t\tif (userContext[key] && typeof userContext[key] !== expectedType) {\n\t\t\t\tthrow new ConfigError(`User context field '${key}' must be of type '${expectedType}'`);\n\t\t\t}\n\t\t}\n\t}\n\n\t_bindMethods() {\n\t\tthis.createWidget = this.createWidget.bind(this);\n\t\tthis.destroyWidget = this.destroyWidget.bind(this);\n\t\tthis.updateConfig = this.updateConfig.bind(this);\n\t}\n\n\tstatic create(config) {\n\t\treturn new FeedbackSDK(config);\n\t}\n\n\tstatic async createAndInit(config) {\n\t\tconst sdk = new FeedbackSDK(config);\n\t\tawait sdk.init();\n\t\treturn sdk;\n\t}\n\n\tstatic extractUserContextFromAuth(authData) {\n\t\tif (!authData) return null;\n\n\t\treturn {\n\t\t\tuser_id: authData.sub || authData.id || authData.user_id,\n\t\t\temail: authData.email,\n\t\t\tname: authData.name || authData.display_name || authData.full_name,\n\t\t\tcustom_fields: {\n\t\t\t\trole: authData.role,\n\t\t\t\tplan: authData.plan || authData.subscription?.plan,\n\t\t\t\t...(authData.custom_fields || {}),\n\t\t\t},\n\t\t\tcompany: authData.company || authData.organization ? {\n\t\t\t\tid: authData.company?.id || authData.organization?.id,\n\t\t\t\tname: authData.company?.name || authData.organization?.name,\n\t\t\t\tmonthly_spend: authData.company?.monthly_spend,\n\t\t\t} : undefined,\n\t\t};\n\t}\n}","import { APIService } from './core/APIService.js';\nimport { EventBus } from './core/EventBus.js';\nimport { FeedbackSDK } from './core/FeedbackSDK.js';\nimport { CSS_STYLES } from './styles/styles.js';\nimport {\n\tAPIError,\n\tConfigError,\n\tSDKError,\n\tValidationError,\n\tWidgetError,\n} from './utils/errors.js';\nimport * as helpers from './utils/helpers.js';\nimport { BaseWidget } from './widgets/BaseWidget.js';\nimport { ButtonWidget } from './widgets/ButtonWidget.js';\nimport { InlineWidget } from './widgets/InlineWidget.js';\nimport { TabWidget } from './widgets/TabWidget.js';\nimport { WidgetFactory } from './widgets/WidgetFactory.js';\n\nfunction injectStyles() {\n\tif (typeof document !== 'undefined' && !document.querySelector('#feedback-sdk-styles')) {\n\t\tconst style = document.createElement('style');\n\t\tstyle.id = 'feedback-sdk-styles';\n\t\tstyle.textContent = CSS_STYLES;\n\t\tdocument.head.appendChild(style);\n\t}\n}\n\nfunction autoInit() {\n\tif (typeof window !== 'undefined' && window.FeedbackSDKConfig) {\n\t\tinjectStyles();\n\n\t\tconst config = { ...window.FeedbackSDKConfig };\n\t\tconst sdk = new FeedbackSDK(config);\n\n\t\tsdk\n\t\t\t.init()\n\t\t\t.then((initData) => {\n\t\t\t\twindow.FeedbackSDK.instance = sdk;\n\n\t\t\t\tif (window.FeedbackSDKConfig.autoCreate) {\n\t\t\t\t\tconst widgets = Array.isArray(window.FeedbackSDKConfig.autoCreate)\n\t\t\t\t\t\t? window.FeedbackSDKConfig.autoCreate\n\t\t\t\t\t\t: [window.FeedbackSDKConfig.autoCreate];\n\n\t\t\t\t\twidgets.forEach((widgetConfig) => {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst widget = sdk.createWidget(\n\t\t\t\t\t\t\t\twidgetConfig.type || 'button',\n\t\t\t\t\t\t\t\twidgetConfig\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\twidget.mount(widgetConfig.container);\n\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\tconsole.error('[FeedbackSDK] Failed to create widget:', error);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tif (typeof CustomEvent !== 'undefined') {\n\t\t\t\t\tconst event = new CustomEvent('FeedbackSDKReady', {\n\t\t\t\t\t\tdetail: { sdk, config, initData },\n\t\t\t\t\t});\n\t\t\t\t\twindow.dispatchEvent(event);\n\t\t\t\t}\n\t\t\t})\n\t\t\t.catch((error) => {\n\t\t\t\tconsole.error('[FeedbackSDK] Auto-initialization failed:', error);\n\n\t\t\t\tif (typeof CustomEvent !== 'undefined') {\n\t\t\t\t\tconst event = new CustomEvent('FeedbackSDKError', {\n\t\t\t\t\t\tdetail: { error, config, phase: 'initialization' },\n\t\t\t\t\t});\n\t\t\t\t\twindow.dispatchEvent(event);\n\t\t\t\t}\n\t\t\t});\n\t}\n}\n\nfunction handleDOMReady() {\n\tif (typeof document !== 'undefined') {\n\t\tif (document.readyState === 'loading') {\n\t\t\tdocument.addEventListener('DOMContentLoaded', autoInit);\n\t\t} else {\n\t\t\tsetTimeout(autoInit, 0);\n\t\t}\n\t}\n}\n\nconst FeedbackSDKExport = {\n\tFeedbackSDK,\n\tBaseWidget,\n\tButtonWidget,\n\tTabWidget,\n\tInlineWidget,\n\tWidgetFactory,\n\tEventBus,\n\tAPIService,\n\tSDKError,\n\tAPIError,\n\tWidgetError,\n\tConfigError,\n\tValidationError,\n\thelpers,\n\tcreate: (config) => {\n\t\tinjectStyles();\n\t\treturn new FeedbackSDK(config);\n\t},\n\tversion: '1.0.0',\n\tinstance: null,\n\n\tisReady: () => Boolean(FeedbackSDKExport.instance),\n\tgetInstance: () => FeedbackSDKExport.instance,\n\n\tsetUserContext: (userContext) => {\n\t\tif (FeedbackSDKExport.instance) {\n\t\t\tFeedbackSDKExport.instance.setUserContext(userContext);\n\t\t} else {\n\t\t\tif (typeof window !== 'undefined') {\n\t\t\t\twindow.FeedbackSDKUserContext = userContext;\n\t\t\t}\n\t\t}\n\t},\n\n\tinitWithUser: async (config, userContext) => {\n\t\tinjectStyles();\n\t\tconst fullConfig = { ...config, userContext };\n\t\tconst sdk = new FeedbackSDK(fullConfig);\n\t\tawait sdk.init();\n\n\t\tif (typeof window !== 'undefined') {\n\t\t\twindow.FeedbackSDK.instance = sdk;\n\t\t}\n\n\t\treturn sdk;\n\t},\n\n\tonReady: (callback) => {\n\t\tif (typeof window !== 'undefined') {\n\t\t\tif (FeedbackSDKExport.isReady()) {\n\t\t\t\tcallback(FeedbackSDKExport.instance);\n\t\t\t} else {\n\t\t\t\twindow.addEventListener(\n\t\t\t\t\t'FeedbackSDKReady',\n\t\t\t\t\t(event) => {\n\t\t\t\t\t\tcallback(event.detail.sdk, event.detail);\n\t\t\t\t\t},\n\t\t\t\t\t{ once: true }\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t},\n\n\tonError: (callback) => {\n\t\tif (typeof window !== 'undefined') {\n\t\t\twindow.addEventListener('FeedbackSDKError', (event) => {\n\t\t\t\tcallback(event.detail.error, event.detail);\n\t\t\t});\n\t\t}\n\t},\n\n\textractUserContext: FeedbackSDK.extractUserContextFromAuth,\n};\n\nif (typeof window !== 'undefined') {\n\twindow.FeedbackSDK = FeedbackSDKExport;\n\thandleDOMReady();\n}\n\nexport default FeedbackSDKExport;\n\nexport {\n\tAPIError,\n\tAPIService,\n\tBaseWidget,\n\tButtonWidget,\n\tConfigError,\n\tEventBus,\n\tFeedbackSDK,\n\thelpers,\n\tInlineWidget,\n\tSDKError,\n\tTabWidget,\n\tValidationError,\n\tWidgetError,\n\tWidgetFactory,\n};","export const CSS_STYLES = `\n.feedback-widget {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', Oxygen, Ubuntu, Cantarell, sans-serif;\n font-size: 14px;\n line-height: 1.4;\n z-index: 999999;\n box-sizing: border-box;\n}\n\n.feedback-widget *,\n.feedback-widget *::before,\n.feedback-widget *::after {\n box-sizing: border-box;\n}\n\n.feedback-widget-button {\n position: fixed;\n z-index: 999999;\n}\n\n.feedback-widget-button.position-bottom-right {\n bottom: 20px;\n right: 20px;\n}\n\n.feedback-widget-button.position-bottom-left {\n bottom: 20px;\n left: 20px;\n}\n\n.feedback-widget-button.position-top-right {\n top: 20px;\n right: 20px;\n}\n\n.feedback-widget-button.position-top-left {\n top: 20px;\n left: 20px;\n}\n\n.feedback-trigger-btn {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 12px;\n height: 44px;\n overflow: hidden;\n border-radius: 0.5rem;\n border: none;\n padding: 10px 16px;\n font-size: 14px;\n font-weight: 500;\n font-family: inherit;\n cursor: pointer;\n transition: all 0.3s duration;\n color: white;\n background: #155EEF;\n box-shadow: 0 1px 2px 0 rgba(16, 24, 40, 0.05);\n}\n\n.feedback-trigger-btn:hover:not(:disabled) {\n background: #004EEB;\n box-shadow: 0 1px 2px 0 rgba(16, 24, 40, 0.1);\n}\n\n.feedback-trigger-btn:disabled {\n opacity: 0.7;\n cursor: not-allowed;\n}\n\n.feedback-trigger-btn:focus-visible {\n outline: 2px solid #155EEF;\n outline-offset: 2px;\n}\n\n.feedback-modal {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 1000000;\n display: flex;\n align-items: center;\n justify-content: center;\n font-family: inherit;\n}\n\n.feedback-modal-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.feedback-modal-content {\n background: white;\n border-radius: 8px;\n box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n min-width: 460px;\n max-width: 500px;\n width: 100%;\n padding: 16px;\n max-height: 85vh;\n overflow-y: hidden;\n position: relative;\n}\n\n.feedback-modal.theme-dark .feedback-modal-content {\n background: #1F2937;\n color: white;\n}\n\n.feedback-modal-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px;\n border-bottom: 1px solid #D1D5DB;\n flex-shrink: 0;\n}\n\n.feedback-modal.theme-dark .feedback-modal-header {\n border-bottom-color: #374151;\n}\n\n.feedback-modal-header h3 {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n}\n\n.feedback-modal-close {\n background: none;\n border: none;\n font-size: 24px;\n cursor: pointer;\n color: #6B7280;\n padding: 0;\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.3s ease;\n}\n\n.feedback-modal-close:hover {\n color: #374151;\n}\n\n.feedback-modal-close:focus-visible {\n outline: 2px solid #155EEF;\n outline-offset: 2px;\n}\n\n.feedback-modal.theme-dark .feedback-modal-close {\n color: #9CA3AF;\n}\n\n.feedback-modal.theme-dark .feedback-modal-close:hover {\n color: #D1D5DB;\n}\n\n.feedback-form {\n padding: 16px;\n}\n\n.feedback-form-group {\n display: flex;\n flex-direction: column;\n gap: 4px;\n margin-bottom: 12px;\n}\n\n.feedback-form-group:last-child {\n margin-bottom: 0;\n}\n\n.feedback-form-group label {\n font-size: 14px;\n font-weight: 500;\n line-height: 1.25;\n color: #374151;\n}\n\n.feedback-modal.theme-dark .feedback-form-group label {\n color: #D1D5DB;\n}\n\n.feedback-form-group input {\n height: 40px;\n width: 100%;\n border-radius: 6px;\n border: 1px solid #D1D5DB;\n padding: 2px 12px;\n font-size: 14px;\n font-weight: 400;\n line-height: 1.25;\n color: #1F2937;\n font-family: inherit;\n outline: none;\n transition: all 0.2s ease;\n}\n\n.feedback-form-group input::placeholder {\n font-size: 14px;\n color: #6B7280;\n}\n\n.feedback-form-group input:focus {\n border-color: #84ADFF;\n box-shadow: 0 0 0 1px rgba(16, 24, 40, 0.05), 0 0 0 3px rgba(41, 112, 255, 0.2);\n}\n\n.feedback-form-group input:focus-visible {\n outline: none;\n}\n\n.feedback-form-group textarea {\n min-height: 100px;\n width: 100%;\n resize: both;\n border-radius: 6px;\n border: 1px solid #D1D5DB;\n padding: 2px 12px;\n font-size: 14px;\n font-weight: 400;\n line-height: 1.25;\n color: #1F2937;\n font-family: inherit;\n outline: none;\n transition: all 0.2s ease;\n}\n\n.feedback-form-group textarea::placeholder {\n font-size: 14px;\n color: #6B7280;\n}\n\n.feedback-form-group textarea:focus {\n border-color: #84ADFF;\n box-shadow: 0 0 0 1px rgba(16, 24, 40, 0.05), 0 0 0 3px rgba(41, 112, 255, 0.2);\n}\n\n.feedback-form-group textarea:focus-visible {\n outline: none;\n}\n\n.feedback-modal.theme-dark .feedback-form-group input,\n.feedback-modal.theme-dark .feedback-form-group textarea {\n background: #374151;\n border-color: #4B5563;\n color: white;\n}\n\n.feedback-btn {\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n overflow: hidden;\n border-radius: 6px;\n border: none;\n height: 40px;\n padding: 2px 16px;\n font-size: 14px;\n font-weight: 500;\n font-family: inherit;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.feedback-btn:disabled {\n opacity: 0.7;\n cursor: not-allowed;\n}\n\n.feedback-btn:focus-visible {\n outline: 2px solid #155EEF;\n outline-offset: 2px;\n}\n\n.feedback-btn-submit {\n background: #155EEF;\n color: white;\n}\n\n.feedback-btn-submit:hover:not(:disabled) {\n background: #004EEB;\n}\n\n.feedback-btn-cancel {\n background: transparent;\n color: #6B7280;\n border: 1px solid #D1D5DB;\n}\n\n.feedback-btn-cancel:hover:not(:disabled) {\n background: #F9FAFB;\n border-color: #9CA3AF;\n color: #374151;\n}\n\n.feedback-modal.theme-dark .feedback-btn-cancel {\n color: #D1D5DB;\n border-color: #4B5563;\n}\n\n.feedback-modal.theme-dark .feedback-btn-cancel:hover:not(:disabled) {\n background: #374151;\n}\n\n.feedback-form-actions {\n display: flex;\n gap: 8px;\n justify-content: flex-end;\n margin-top: 16px;\n padding-top: 4px;\n}\n\n.feedback-loading {\n width: 20px;\n height: 20px;\n border-radius: 50%;\n mask: radial-gradient(transparent 62%, white 65%);\n -webkit-mask: radial-gradient(transparent 62%, white 65%);\n animation: feedbackRotate 0.7s linear infinite;\n}\n\n.feedback-loading-white {\n background: conic-gradient(from 0deg, rgba(255, 255, 255, 0.5), white);\n}\n\n.feedback-loading-blue {\n background: conic-gradient(from 0deg, #004EEB, #eff4ff);\n}\n\n@keyframes feedbackRotate {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n}\n\n.feedback-error {\n color: #F04438;\n font-size: 14px;\n font-weight: 400;\n margin-top: 4px;\n text-transform: capitalize;\n}\n\n.feedback-form-error {\n color: #F04438;\n font-size: 14px;\n margin-top: 12px;\n padding: 8px 12px;\n background: #FEE2E2;\n border: 1px solid #FECACA;\n border-radius: 6px;\n}\n\n.feedback-modal.theme-dark .feedback-form-error {\n background: #7F1D1D;\n border-color: #991B1B;\n color: #FCA5A5;\n}\n\n.feedback-form-group.error input,\n.feedback-form-group.error textarea {\n border-color: #FDA29B;\n}\n\n.feedback-form-group.error input:focus,\n.feedback-form-group.error textarea:focus {\n border-color: #FDA29B;\n box-shadow: 0 0 0 1px rgba(16, 24, 40, 0.05), 0 0 0 4px rgba(253, 162, 155, 0.3);\n}\n\n.feedback-success-notification {\n position: fixed;\n top: 20px;\n right: 20px;\n z-index: 1000001;\n background: white;\n border: 1px solid #D1FAE5;\n border-radius: 8px;\n box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);\n animation: slideInRight 0.3s ease-out;\n}\n\n.feedback-success-content {\n display: flex;\n align-items: center;\n padding: 12px 16px;\n gap: 12px;\n}\n\n.feedback-success-content span {\n color: #059669;\n font-weight: 500;\n font-size: 14px;\n}\n\n.feedback-success-close {\n background: none;\n border: none;\n color: #6B7280;\n cursor: pointer;\n font-size: 18px;\n padding: 0;\n width: 20px;\n height: 20px;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.3s ease;\n}\n\n.feedback-success-close:hover {\n color: #374151;\n}\n\n.feedback-success-close:focus-visible {\n outline: 2px solid #155EEF;\n outline-offset: 2px;\n}\n\n@keyframes slideInRight {\n from {\n transform: translateX(100%);\n opacity: 0;\n }\n to {\n transform: translateX(0);\n opacity: 1;\n }\n}\n\n@keyframes fadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n.feedback-modal {\n animation: fadeIn 0.2s ease-out;\n}\n\n.feedback-modal-content {\n animation: slideInUp 0.3s ease-out;\n}\n\n@keyframes slideInUp {\n from {\n transform: translateY(20px);\n opacity: 0;\n }\n to {\n transform: translateY(0);\n opacity: 1;\n }\n}\n\n@media (max-width: 640px) {\n .feedback-modal {\n padding: 8px;\n }\n \n .feedback-modal-content {\n min-width: 280px;\n max-width: 100%;\n max-height: 95vh;\n }\n \n .feedback-form {\n padding: 16px;\n }\n \n .feedback-modal-header {\n padding: 16px;\n }\n \n .feedback-modal-header h3 {\n font-size: 15px;\n }\n \n .feedback-form-actions {\n flex-direction: column;\n gap: 8px;\n }\n \n .feedback-btn {\n width: 100%;\n height: 40px;\n }\n \n .feedback-widget-button {\n bottom: 16px;\n right: 16px;\n }\n \n .feedback-widget-button.position-bottom-left {\n left: 16px;\n }\n \n .feedback-trigger-btn {\n padding: 10px 16px;\n font-size: 13px;\n }\n \n .feedback-success-notification {\n top: 8px;\n right: 8px;\n left: 8px;\n max-width: none;\n }\n\n .feedback-form-group input {\n height: 40px;\n padding: 2px 12px;\n }\n \n .feedback-form-group textarea {\n min-height: 80px;\n padding: 2px 12px;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .feedback-trigger-btn,\n .feedback-btn,\n .feedback-modal,\n .feedback-modal-content,\n .feedback-success-notification,\n .feedback-loading {\n transition: none;\n animation: none;\n }\n \n .feedback-trigger-btn:hover {\n transform: none;\n }\n}\n\n@media print {\n .feedback-widget,\n .feedback-modal,\n .feedback-success-notification {\n display: none !important;\n }\n}\n`;\n"],"names":["SDKError","Error","constructor","message","cause","super","this","name","captureStackTrace","APIError","status","response","isNetworkError","isClientError","isServerError","WidgetError","widgetType","widgetId","ConfigError","configKey","ValidationError","field","value","APIService","config","workspace","sessionToken","sessionExpiry","userContext","apiUrl","baseURL","_loadStoredSession","init","isSessionValid","error","payload","user","_makeRequest","method","body","JSON","stringify","headers","session_token","Date","now","expires_in","_storeSession","expiresIn","submitFeedback","feedbackData","board","board_id","boardId","title","content","attachments","Authorization","setUserContext","localStorage","setItem","getUserContext","clearSession","removeItem","sessionData","token","expiry","toISOString","stored","getItem","parse","endpoint","options","url","fetch","ok","errorMessage","responseData","json","e","text","contentType","get","includes","EventBus","events","Map","on","event","callback","has","set","push","off","callbacks","index","indexOf","splice","emit","data","forEach","console","once","unsubscribe","clear","getListenerCount","length","generateId","prefix","Math","random","toString","substring","deepMerge","target","source","result","key","hasOwnProperty","Array","isArray","isBrowser","window","document","func","wait","timeout","args","clearTimeout","setTimeout","ms","Promise","resolve","string","replace","bytes","i","floor","log","parseFloat","pow","toFixed","userAgent","navigator","platform","language","userLanguage","cookieEnabled","screenResolution","screen","width","height","windowSize","innerWidth","innerHeight","timezone","Intl","DateTimeFormat","resolvedOptions","timeZone","element","property","fallback","getComputedStyle","getPropertyValue","obj","path","defaultValue","undefined","keys","split","current","rect","getBoundingClientRect","top","left","bottom","documentElement","clientHeight","right","clientWidth","test","email","trim","str","div","createElement","textContent","innerHTML","scrollIntoView","behavior","block","inline","lastKey","pop","limit","lastFunc","lastRan","required","missing","join","BaseWidget","id","sdk","apiService","type","container","position","theme","autoShow","customStyles","modalElement","mounted","destroyed","state","isOpen","isSubmitting","errors","_bindMethods","mount","querySelector","_render","appendChild","_attachEvents","onMount","show","eventBus","widget","style","display","hide","openModal","_renderModal","closeModal","remove","_resetForm","_updateSubmitButton","_showError","_showSuccessMessage","feedback","handleConfigUpdate","newConfig","_updateTheme","destroy","onDestroy","parentNode","removeChild","bind","className","_getModalHTML","_attachModalEvents","firstInput","focus","modal","addEventListener","currentTarget","preventDefault","submitBtn","disabled","errorElement","notification","ButtonWidget","button","Object","assign","transform","updateText","textNode","childNodes","nodeType","Node","TEXT_NODE","updatePosition","InlineWidget","form","textarea","originalContent","updateTitle","titleElement","setPlaceholder","placeholder","input","TabWidget","tab","_getHoverTransform","textElement","WidgetFactory","static","register","WidgetClass","widgets","create","availableTypes","from","getAvailableTypes","isTypeRegistered","unregister","delete","getWidgetClass","FeedbackSDK","_validateAndMergeConfig","initialized","alreadyInitialized","initData","createWidget","widgetOptions","getWidget","getAllWidgets","values","destroyWidget","destroyAllWidgets","updateConfig","oldConfig","reinitialize","newUserContext","removeAllListeners","existingConfig","mergedConfig","debug","_validateUserContext","user_id","validStructure","custom_fields","company","expectedType","entries","createAndInit","extractUserContextFromAuth","authData","sub","display_name","full_name","role","plan","subscription","organization","monthly_spend","injectStyles","head","autoInit","FeedbackSDKConfig","then","instance","autoCreate","widgetConfig","CustomEvent","detail","dispatchEvent","catch","phase","FeedbackSDKExport","helpers","version","isReady","Boolean","getInstance","FeedbackSDKUserContext","initWithUser","async","fullConfig","onReady","onError","extractUserContext","readyState"],"mappings":"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"}
package/package.json CHANGED
@@ -1,13 +1,15 @@
1
1
  {
2
2
  "name": "@product7/feedback-sdk",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "JavaScript SDK for integrating Product7 feedback widgets into any website",
5
5
  "main": "dist/feedback-sdk.js",
6
6
  "module": "src/index.js",
7
7
  "browser": "dist/feedback-sdk.min.js",
8
+ "types": "types/index.d.ts",
8
9
  "files": [
9
10
  "dist/",
10
11
  "src/",
12
+ "types/",
11
13
  "README.md"
12
14
  ],
13
15
  "scripts": {