@product7/feedback-sdk 1.0.9 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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\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}.staging.api.product7.io/api/v1`;\n\t\t} else {\n\t\t\tthis.baseURL = 'https://staging.api.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\tshowBackdrop: true,\n\t\t\tcustomStyles: {},\n\t\t\t...options,\n\t\t};\n\n\t\tthis.element = null;\n\t\tthis.panelElement = null;\n\t\tthis.backdropElement = 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\topenPanel() {\n\t\tthis.state.isOpen = true;\n\t\tthis._renderPanel();\n\t\t\n\t\trequestAnimationFrame(() => {\n\t\t\tif (this.panelElement) {\n\t\t\t\tthis.panelElement.classList.add('open');\n\t\t\t}\n\t\t\tif (this.backdropElement) {\n\t\t\t\tthis.backdropElement.classList.add('show');\n\t\t\t}\n\t\t});\n\t}\n\n\tclosePanel() {\n\t\tif (this.panelElement) {\n\t\t\tthis.panelElement.classList.remove('open');\n\t\t}\n\t\tif (this.backdropElement) {\n\t\t\tthis.backdropElement.classList.remove('show');\n\t\t}\n\n\t\tsetTimeout(() => {\n\t\t\tthis.state.isOpen = false;\n\t\t\tif (this.panelElement && this.panelElement.parentNode) {\n\t\t\t\tthis.panelElement.parentNode.removeChild(this.panelElement);\n\t\t\t\tthis.panelElement = null;\n\t\t\t}\n\t\t\tif (this.backdropElement && this.backdropElement.parentNode) {\n\t\t\t\tthis.backdropElement.parentNode.removeChild(this.backdropElement);\n\t\t\t\tthis.backdropElement = null;\n\t\t\t}\n\t\t\tthis._resetForm();\n\t\t}, 300);\n\t}\n\n\tasync submitFeedback() {\n\t\tif (this.state.isSubmitting) return;\n\n\t\tthis._hideError();\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.closePanel();\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.closePanel();\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.openPanel = this.openPanel.bind(this);\n\t\tthis.closePanel = this.closePanel.bind(this);\n\t\tthis.submitFeedback = this.submitFeedback.bind(this);\n\t}\n\n\t_renderPanel() {\n\t\tif (this.panelElement) return;\n\n\t\tif (this.options.showBackdrop) {\n\t\t\tthis.backdropElement = document.createElement('div');\n\t\t\tthis.backdropElement.className = 'feedback-panel-backdrop';\n\t\t\tdocument.body.appendChild(this.backdropElement);\n\n\t\t\tthis.backdropElement.addEventListener('click', this.closePanel);\n\t\t}\n\n\t\tthis.panelElement = document.createElement('div');\n\t\tthis.panelElement.className = `feedback-panel theme-${this.options.theme}`;\n\t\tthis.panelElement.innerHTML = this._getPanelHTML();\n\n\t\tdocument.body.appendChild(this.panelElement);\n\t\tthis._attachPanelEvents();\n\n\t\tconst firstInput = this.panelElement.querySelector('input, textarea');\n\t\tif (firstInput) {\n\t\t\tsetTimeout(() => firstInput.focus(), 350);\n\t\t}\n\t}\n\n\t_getPanelHTML() {\n\t\treturn `\n <div class=\"feedback-panel-content\">\n <div class=\"feedback-panel-header\">\n <h3>Send Feedback</h3>\n <button class=\"feedback-panel-close\" type=\"button\" aria-label=\"Close\">&times;</button>\n </div>\n <div class=\"feedback-panel-body\">\n <form class=\"feedback-form\">\n <div class=\"feedback-form-group\">\n <label for=\"feedback-title-${this.id}\">Title (optional)</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 what you think...\"\n required\n >${this.state.content}</textarea>\n </div>\n <div class=\"feedback-error\" role=\"alert\"></div>\n <div class=\"feedback-form-actions\">\n <button type=\"submit\" class=\"feedback-btn feedback-btn-submit\">\n ${this.state.isSubmitting ? 'Sending...' : 'Send Feedback'}\n </button>\n </div>\n </form>\n </div>\n </div>\n `;\n\t}\n\n\t_attachPanelEvents() {\n\t\tconst panel = this.panelElement;\n\n\t\tpanel\n\t\t\t.querySelector('.feedback-panel-close')\n\t\t\t.addEventListener('click', this.closePanel);\n\n\t\tconst form = panel.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\tpanel\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\tpanel\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\tconst handleEscape = (e) => {\n\t\t\tif (e.key === 'Escape') {\n\t\t\t\tthis.closePanel();\n\t\t\t\tdocument.removeEventListener('keydown', handleEscape);\n\t\t\t}\n\t\t};\n\t\tdocument.addEventListener('keydown', handleEscape);\n\t}\n\n\t_updateSubmitButton() {\n\t\tif (this.panelElement) {\n\t\t\tconst submitBtn = this.panelElement.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.panelElement) {\n\t\t\tconst errorElement = this.panelElement.querySelector('.feedback-error');\n\t\t\tif (errorElement) {\n\t\t\t\terrorElement.textContent = message;\n\t\t\t\terrorElement.classList.add('show');\n\t\t\t}\n\t\t}\n\t}\n\n\t_hideError() {\n\t\tif (this.panelElement) {\n\t\t\tconst errorElement = this.panelElement.querySelector('.feedback-error');\n\t\t\tif (errorElement) {\n\t\t\t\terrorElement.classList.remove('show');\n\t\t\t}\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 <div class=\"feedback-success-icon\">✓</div>\n <span>Feedback submitted successfully!</span>\n <button class=\"feedback-success-close\" aria-label=\"Close\">&times;</button>\n </div>\n `;\n\n\t\tdocument.body.appendChild(notification);\n\n\t\tconst closeBtn = notification.querySelector('.feedback-success-close');\n\t\tconst closeNotification = () => {\n\t\t\tif (notification.parentNode) {\n\t\t\t\tnotification.style.opacity = '0';\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tif (notification.parentNode) {\n\t\t\t\t\t\tnotification.parentNode.removeChild(notification);\n\t\t\t\t\t}\n\t\t\t\t}, 300);\n\t\t\t}\n\t\t};\n\n\t\tcloseBtn.addEventListener('click', closeNotification);\n\n\t\tsetTimeout(closeNotification, 4000);\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.panelElement) {\n\t\t\tthis.panelElement.className = this.panelElement.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\topenModal() {\n\t\tthis.openPanel();\n\t}\n\n\tcloseModal() {\n\t\tthis.closePanel();\n\t}\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\" aria-label=\"Send feedback\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"/>\n </svg>\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.openPanel);\n\n\t\tbutton.addEventListener('mouseenter', () => {\n\t\t\tif (!this.state.isSubmitting) {\n\t\t\t\tbutton.style.transform = 'scale(1.1)';\n\t\t\t}\n\t\t});\n\n\t\tbutton.addEventListener('mouseleave', () => {\n\t\t\tbutton.style.transform = 'scale(1)';\n\t\t});\n\t}\n\n\tupdateText(text) {\n\t\tconsole.warn('ButtonWidget: Text display is disabled for circular design');\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}","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}\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/* Circular button design */\n.feedback-trigger-btn {\n width: 56px;\n height: 56px;\n border-radius: 50%; /* Makes it circular */\n border: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n padding: 0;\n}\n\n.feedback-trigger-btn:hover {\n box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2);\n}\n\n.feedback-trigger-btn:active {\n transform: scale(0.95);\n}\n\n.feedback-trigger-btn svg {\n flex-shrink: 0;\n}\n\n/* Side Panel Styles */\n.feedback-panel {\n position: fixed;\n bottom: 80px;\n right: 24px;\n width: 420px;\n max-height: 500px;\n z-index: 1000000;\n transform: translateX(calc(100% + 24px));\n transition: transform 0.35s cubic-bezier(0.4, 0, 0.2, 1);\n font-family: inherit;\n}\n\n.feedback-panel.open {\n transform: translateX(0);\n}\n\n.feedback-panel-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.1);\n opacity: 0;\n transition: opacity 0.3s ease;\n pointer-events: none;\n z-index: 999999;\n}\n\n.feedback-panel-backdrop.show {\n opacity: 1;\n pointer-events: auto;\n}\n\n.feedback-panel-content {\n background: white;\n height: 100%;\n display: flex;\n flex-direction: column;\n border-radius: 16px;\n box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), \n 0 10px 10px -5px rgba(0, 0, 0, 0.04),\n 0 0 0 1px rgba(0, 0, 0, 0.05);\n}\n\n.feedback-panel.theme-dark .feedback-panel-content {\n background: #1F2937;\n color: white;\n}\n\n.feedback-panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 24px;\n border-bottom: 1px solid #E5E7EB;\n flex-shrink: 0;\n}\n\n.feedback-panel.theme-dark .feedback-panel-header {\n border-bottom-color: #374151;\n}\n\n.feedback-panel-header h3 {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n color: #111827;\n}\n\n.feedback-panel.theme-dark .feedback-panel-header h3 {\n color: white;\n}\n\n.feedback-panel-close {\n background: none;\n border: none;\n font-size: 24px;\n cursor: pointer;\n color: #6B7280;\n padding: 4px;\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n transition: all 0.2s ease;\n}\n\n.feedback-panel-close:hover {\n background: #F3F4F6;\n color: #111827;\n}\n\n.feedback-panel-close:focus-visible {\n outline: 2px solid #155EEF;\n outline-offset: 2px;\n}\n\n.feedback-panel.theme-dark .feedback-panel-close {\n color: #9CA3AF;\n}\n\n.feedback-panel.theme-dark .feedback-panel-close:hover {\n background: #374151;\n color: white;\n}\n\n.feedback-panel-body {\n flex: 1;\n overflow-y: auto;\n padding: 24px;\n}\n\n.feedback-form {\n display: flex;\n flex-direction: column;\n height: 100%;\n}\n\n.feedback-form-group {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-bottom: 20px;\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-panel.theme-dark .feedback-form-group label {\n color: #D1D5DB;\n}\n\n.feedback-form-group input {\n height: 44px;\n width: 100%;\n border-radius: 8px;\n border: 1px solid #D1D5DB;\n padding: 10px 14px;\n font-size: 15px;\n font-weight: 400;\n line-height: 1.5;\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: 15px;\n color: #9CA3AF;\n}\n\n.feedback-form-group input:focus {\n border-color: #155EEF;\n box-shadow: 0 0 0 3px rgba(21, 94, 239, 0.1);\n}\n\n.feedback-form-group input:focus-visible {\n outline: none;\n}\n\n.feedback-form-group textarea {\n min-height: 200px;\n width: 100%;\n resize: vertical;\n border-radius: 8px;\n border: 1px solid #D1D5DB;\n padding: 10px 14px;\n font-size: 15px;\n font-weight: 400;\n line-height: 1.5;\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: 15px;\n color: #9CA3AF;\n}\n\n.feedback-form-group textarea:focus {\n border-color: #155EEF;\n box-shadow: 0 0 0 3px rgba(21, 94, 239, 0.1);\n}\n\n.feedback-form-group textarea:focus-visible {\n outline: none;\n}\n\n.feedback-panel.theme-dark .feedback-form-group input,\n.feedback-panel.theme-dark .feedback-form-group textarea {\n background: #374151;\n border-color: #4B5563;\n color: white;\n}\n\n.feedback-panel.theme-dark .feedback-form-group input::placeholder,\n.feedback-panel.theme-dark .feedback-form-group textarea::placeholder {\n color: #6B7280;\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: 8px;\n border: none;\n height: 44px;\n padding: 10px 18px;\n font-size: 15px;\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.6;\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 width: 100%;\n}\n\n.feedback-btn-submit:hover:not(:disabled) {\n background: #1A56DB;\n}\n\n.feedback-btn-submit:active:not(:disabled) {\n background: #1E429F;\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-panel.theme-dark .feedback-btn-cancel {\n color: #D1D5DB;\n border-color: #4B5563;\n}\n\n.feedback-panel.theme-dark .feedback-btn-cancel:hover:not(:disabled) {\n background: #374151;\n}\n\n.feedback-form-actions {\n display: flex;\n flex-direction: column;\n gap: 12px;\n margin-top: auto;\n padding-top: 24px;\n}\n\n.feedback-error {\n color: #DC2626;\n font-size: 14px;\n font-weight: 400;\n margin-top: 8px;\n padding: 12px;\n background: #FEE2E2;\n border: 1px solid #FECACA;\n border-radius: 8px;\n display: none;\n}\n\n.feedback-error.show {\n display: block;\n}\n\n.feedback-panel.theme-dark .feedback-error {\n background: #7F1D1D;\n border-color: #991B1B;\n color: #FCA5A5;\n}\n\n.feedback-success-notification {\n position: fixed;\n top: 24px;\n right: 24px;\n z-index: 1000002;\n background: white;\n border: 1px solid #D1FAE5;\n border-radius: 12px;\n box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);\n animation: slideInRight 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n min-width: 320px;\n}\n\n.feedback-success-content {\n display: flex;\n align-items: center;\n padding: 16px 20px;\n gap: 12px;\n}\n\n.feedback-success-icon {\n width: 20px;\n height: 20px;\n border-radius: 50%;\n background: #10B981;\n color: white;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n font-weight: 600;\n flex-shrink: 0;\n}\n\n.feedback-success-content span {\n color: #065F46;\n font-weight: 500;\n font-size: 14px;\n flex: 1;\n}\n\n.feedback-success-close {\n background: none;\n border: none;\n color: #6B7280;\n cursor: pointer;\n font-size: 20px;\n padding: 0;\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.2s ease;\n border-radius: 4px;\n flex-shrink: 0;\n}\n\n.feedback-success-close:hover {\n background: #F3F4F6;\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(400px);\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-panel-backdrop {\n animation: fadeIn 0.3s ease;\n}\n\n@media (max-width: 768px) {\n .feedback-panel {\n width: 100%;\n top: auto;\n bottom: 0;\n right: 0;\n left: 0;\n height: 85vh;\n max-height: 85vh;\n transform: translateY(100%);\n border-radius: 20px 20px 0 0;\n }\n \n .feedback-panel.open {\n transform: translateY(0);\n }\n \n .feedback-panel-content {\n border-radius: 20px 20px 0 0;\n }\n \n .feedback-panel-header {\n padding: 20px;\n position: relative;\n }\n \n .feedback-panel-header::before {\n content: '';\n position: absolute;\n top: 8px;\n left: 50%;\n transform: translateX(-50%);\n width: 40px;\n height: 4px;\n background: #D1D5DB;\n border-radius: 2px;\n }\n \n .feedback-panel.theme-dark .feedback-panel-header::before {\n background: #4B5563;\n }\n \n .feedback-panel-body {\n padding: 20px;\n }\n \n .feedback-form-group textarea {\n min-height: 150px;\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-success-notification {\n top: 16px;\n right: 16px;\n left: 16px;\n min-width: auto;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .feedback-trigger-btn,\n .feedback-btn,\n .feedback-panel,\n .feedback-panel-backdrop,\n .feedback-success-notification {\n transition: none;\n animation: none;\n }\n}\n\n@media print {\n .feedback-widget,\n .feedback-panel,\n .feedback-panel-backdrop,\n .feedback-success-notification {\n display: none !important;\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","showBackdrop","customStyles","panelElement","backdropElement","mounted","destroyed","state","isOpen","isSubmitting","errors","_bindMethods","mount","querySelector","_render","appendChild","_attachEvents","onMount","show","eventBus","widget","style","display","hide","openPanel","_renderPanel","requestAnimationFrame","classList","add","closePanel","remove","parentNode","removeChild","_resetForm","_hideError","_updateSubmitButton","_showError","_showSuccessMessage","feedback","handleConfigUpdate","newConfig","_updateTheme","destroy","onDestroy","bind","className","addEventListener","_getPanelHTML","_attachPanelEvents","firstInput","focus","panel","preventDefault","handleEscape","removeEventListener","submitBtn","disabled","errorElement","notification","closeNotification","opacity","openModal","closeModal","ButtonWidget","button","Object","assign","transform","updateText","warn","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":"kPAAO,MAAMA,UAAiBC,MAC7B,WAAAC,CAAYC,EAASC,GACpBC,MAAMF,GACNG,KAAKC,KAAO,WACZD,KAAKF,MAAQA,EAETH,MAAMO,mBACTP,MAAMO,kBAAkBF,KAAMN,EAEhC,EAGM,MAAMS,UAAiBR,MAC7B,WAAAC,CAAYQ,EAAQP,EAASQ,GAC5BN,MAAMF,GACNG,KAAKC,KAAO,WACZD,KAAKI,OAASA,EACdJ,KAAKK,SAAWA,EAEZV,MAAMO,mBACTP,MAAMO,kBAAkBF,KAAMG,EAEhC,CAEA,cAAAG,GACC,OAAuB,IAAhBN,KAAKI,MACb,CAEA,aAAAG,GACC,OAAOP,KAAKI,QAAU,KAAOJ,KAAKI,OAAS,GAC5C,CAEA,aAAAI,GACC,OAAOR,KAAKI,QAAU,KAAOJ,KAAKI,OAAS,GAC5C,EAGM,MAAMK,UAAoBd,MAChC,WAAAC,CAAYC,EAASa,EAAYC,GAChCZ,MAAMF,GACNG,KAAKC,KAAO,cACZD,KAAKU,WAAaA,EAClBV,KAAKW,SAAWA,EAEZhB,MAAMO,mBACTP,MAAMO,kBAAkBF,KAAMS,EAEhC,EAGM,MAAMG,UAAoBjB,MAChC,WAAAC,CAAYC,EAASgB,GACpBd,MAAMF,GACNG,KAAKC,KAAO,cACZD,KAAKa,UAAYA,EAEblB,MAAMO,mBACTP,MAAMO,kBAAkBF,KAAMY,EAEhC,EAGM,MAAME,UAAwBnB,MACpC,WAAAC,CAAYC,EAASkB,EAAOC,GAC3BjB,MAAMF,GACNG,KAAKC,KAAO,kBACZD,KAAKe,MAAQA,EACbf,KAAKgB,MAAQA,EAETrB,MAAMO,mBACTP,MAAMO,kBAAkBF,KAAMc,EAEhC,ECtEM,MAAMG,EACZ,WAAArB,CAAYsB,EAAS,IACpBlB,KAAKmB,UAAYD,EAAOC,UACxBnB,KAAKoB,aAAe,KACpBpB,KAAKqB,cAAgB,KACrBrB,KAAKsB,YAAcJ,EAAOI,aAAe,KAErCJ,EAAOK,OACVvB,KAAKwB,QAAUN,EAAOK,OACZvB,KAAKmB,UACfnB,KAAKwB,QAAU,WAAWxB,KAAKmB,2CAE/BnB,KAAKwB,QAAU,yCAGhBxB,KAAKyB,oBACN,CAEA,UAAMC,CAAKJ,EAAc,MAKxB,GAJIA,IACHtB,KAAKsB,YAAcA,GAGhBtB,KAAK2B,iBACR,MAAO,CAAEP,aAAcpB,KAAKoB,cAG7B,IAAKpB,KAAKsB,cAAgBtB,KAAKmB,UAAW,CACzC,MAAMS,EAAQ,WAAY5B,KAAKmB,UAA0B,eAAd,iCAC3C,MAAM,IAAIhB,EAAS,IAAKyB,EACzB,CAEA,MAAMC,EAAU,CACfV,UAAWnB,KAAKmB,UAChBW,KAAM9B,KAAKsB,aAGZ,IACC,MAAMjB,QAAiBL,KAAK+B,aAAa,eAAgB,CACxDC,OAAQ,OACRC,KAAMC,KAAKC,UAAUN,GACrBO,QAAS,CACR,eAAgB,sBAQlB,OAJApC,KAAKoB,aAAef,EAASgC,cAC7BrC,KAAKqB,cAAgB,IAAIiB,KAAKA,KAAKC,MAA8B,IAAtBlC,EAASmC,YACpDxC,KAAKyC,gBAEE,CACNrB,aAAcpB,KAAKoB,aACnBF,OAAQb,EAASa,QAAU,CAAA,EAC3BwB,UAAWrC,EAASmC,WAEtB,CAAE,MAAOZ,GACR,MAAM,IAAIzB,EACTyB,EAAMxB,QAAU,IAChB,gCAAgCwB,EAAM/B,UACtC+B,EAAMvB,SAER,CACD,CAEA,oBAAMsC,CAAeC,GAKpB,GAJK5C,KAAK2B,wBACH3B,KAAK0B,QAGP1B,KAAKoB,aACT,MAAM,IAAIjB,EAAS,IAAK,oCAGzB,MAAM0B,EAAU,CACfgB,MAAOD,EAAaE,UAAYF,EAAaC,OAASD,EAAaG,QACnEC,MAAOJ,EAAaI,MACpBC,QAASL,EAAaK,QACtBC,YAAaN,EAAaM,aAAe,IAG1C,IAUC,aATuBlD,KAAK+B,aAAa,mBAAoB,CAC5DC,OAAQ,OACRC,KAAMC,KAAKC,UAAUN,GACrBO,QAAS,CACR,eAAgB,mBAChBe,cAAe,UAAUnD,KAAKoB,iBAKjC,CAAE,MAAOQ,GACR,GAAqB,MAAjBA,EAAMxB,OAIT,OAHAJ,KAAKoB,aAAe,KACpBpB,KAAKqB,cAAgB,WACfrB,KAAK0B,OACJ1B,KAAK2C,eAAeC,GAG5B,MAAM,IAAIzC,EACTyB,EAAMxB,QAAU,IAChB,8BAA8BwB,EAAM/B,UACpC+B,EAAMvB,SAER,CACD,CAEA,cAAAsB,GACC,OACC3B,KAAKoB,cAAgBpB,KAAKqB,eAAiB,IAAIiB,KAAStC,KAAKqB,aAE/D,CAEA,cAAA+B,CAAe9B,GACdtB,KAAKsB,YAAcA,EACS,oBAAjB+B,cACVA,aAAaC,QAAQ,0BAA2BpB,KAAKC,UAAUb,GAEjE,CAEA,cAAAiC,GACC,OAAOvD,KAAKsB,WACb,CAEA,YAAAkC,GACCxD,KAAKoB,aAAe,KACpBpB,KAAKqB,cAAgB,KACO,oBAAjBgC,eACVA,aAAaI,WAAW,uBACxBJ,aAAaI,WAAW,2BAE1B,CAEA,aAAAhB,GACC,GAA4B,oBAAjBY,aAEX,IACC,MAAMK,EAAc,CACnBC,MAAO3D,KAAKoB,aACZwC,OAAQ5D,KAAKqB,cAAcwC,cAC3B1C,UAAWnB,KAAKmB,WAEjBkC,aAAaC,QAAQ,sBAAuBpB,KAAKC,UAAUuB,GAC5D,CAAE,MAAO9B,GAET,CACD,CAEA,kBAAAH,GACC,GAA4B,oBAAjB4B,aAA8B,OAAO,EAEhD,IACC,MAAMS,EAAST,aAAaU,QAAQ,uBACpC,IAAKD,EAAQ,OAAO,EAEpB,MAAMJ,EAAcxB,KAAK8B,MAAMF,GAI/B,OAHA9D,KAAKoB,aAAesC,EAAYC,MAChC3D,KAAKqB,cAAgB,IAAIiB,KAAKoB,EAAYE,QAEnC5D,KAAK2B,gBACb,CAAE,MAAOC,GACR,OAAO,CACR,CACD,CAEA,kBAAMG,CAAakC,EAAUC,EAAU,IACtC,MAAMC,EAAM,GAAGnE,KAAKwB,UAAUyC,IAE9B,IACC,MAAM5D,QAAiB+D,MAAMD,EAAKD,GAElC,IAAK7D,EAASgE,GAAI,CACjB,IAAIC,EAAe,QAAQjE,EAASD,SAChCmE,EAAe,KAEnB,IACCA,QAAqBlE,EAASmE,OAC9BF,EAAeC,EAAa1E,SAAW0E,EAAa3C,OAAS0C,CAC9D,CAAE,MAAOG,GACRH,QAAsBjE,EAASqE,QAAWJ,CAC3C,CAEA,MAAM,IAAInE,EAASE,EAASD,OAAQkE,EAAcC,EACnD,CAEA,MAAMI,EAActE,EAAS+B,QAAQwC,IAAI,gBACzC,OAAID,GAAeA,EAAYE,SAAS,0BAC1BxE,EAASmE,aAGVnE,EAASqE,MACvB,CAAE,MAAO9C,GACR,GAAIA,aAAiBzB,EACpB,MAAMyB,EAEP,MAAM,IAAIzB,EAAS,EAAGyB,EAAM/B,QAAS,KACtC,CACD,ECvMM,MAAMiF,EACZ,WAAAlF,GACCI,KAAK+E,OAAS,IAAIC,GACnB,CAEA,EAAAC,CAAGC,EAAOC,GAMT,OALKnF,KAAK+E,OAAOK,IAAIF,IACpBlF,KAAK+E,OAAOM,IAAIH,EAAO,IAExBlF,KAAK+E,OAAOH,IAAIM,GAAOI,KAAKH,GAErB,IAAMnF,KAAKuF,IAAIL,EAAOC,EAC9B,CAEA,GAAAI,CAAIL,EAAOC,GACV,MAAMK,EAAYxF,KAAK+E,OAAOH,IAAIM,GAClC,GAAIM,EAAW,CACd,MAAMC,EAAQD,EAAUE,QAAQP,GAC5BM,GAAQ,GACXD,EAAUG,OAAOF,EAAO,EAE1B,CACD,CAEA,IAAAG,CAAKV,EAAOW,GACX,MAAML,EAAYxF,KAAK+E,OAAOH,IAAIM,GAC9BM,GACHA,EAAUM,QAASX,IAClB,IACCA,EAASU,EACV,CAAE,MAAOjE,GACRmE,QAAQnE,MAAM,sCAAuCA,EACtD,GAGH,CAEA,IAAAoE,CAAKd,EAAOC,GACX,MAAMc,EAAcjG,KAAKiF,GAAGC,EAAQW,IACnCV,EAASU,GACTI,MAED,OAAOA,CACR,CAEA,KAAAC,GACClG,KAAK+E,OAAOmB,OACb,CAEA,gBAAAC,CAAiBjB,GAChB,MAAMM,EAAYxF,KAAK+E,OAAOH,IAAIM,GAClC,OAAOM,EAAYA,EAAUY,OAAS,CACvC,ECpDM,SAASC,EAAWC,EAAS,YAGnC,MAAO,GAAGA,KAFQhE,KAAKC,SACRgE,KAAKC,SAASC,SAAS,IAAIC,UAAU,EAAG,IAExD,CAEO,SAASC,EAAUC,EAAQC,GACjC,MAAMC,EAAS,IAAKF,GAEpB,IAAK,MAAMG,KAAOF,EACbA,EAAOG,eAAeD,KAExBF,EAAOE,IACgB,iBAAhBF,EAAOE,KACbE,MAAMC,QAAQL,EAAOE,IAEtBD,EAAOC,GAAOJ,EAAUC,EAAOG,IAAQ,CAAA,EAAIF,EAAOE,IAElDD,EAAOC,GAAOF,EAAOE,IAKxB,OAAOD,CACR,CAkKO,SAASK,IACf,MAAyB,oBAAXC,QAA8C,oBAAbC,QAChD,8CAlKO,SAAkBC,EAAMC,GAC9B,IAAIC,EACJ,OAAO,YAA6BC,GAKnCC,aAAaF,GACbA,EAAUG,WALI,KACbD,aAAaF,GACbF,KAAQG,IAGmBF,EAC7B,CACD,oBAoGO,SAAeK,GACrB,OAAO,IAAIC,QAASC,GAAYH,WAAWG,EAASF,GACrD,cAUO,SAAqBG,GAC3B,OAAOA,EAAOC,QAAQ,sBAAuB,OAC9C,iBAxBO,SAAwBC,GAC9B,GAAc,IAAVA,EAAa,MAAO,UAExB,MAEMC,EAAI3B,KAAK4B,MAAM5B,KAAK6B,IAAIH,GAAS1B,KAAK6B,IAFlC,OAIV,OAAOC,YAAYJ,EAAQ1B,KAAK+B,IAJtB,KAI6BJ,IAAIK,QAAQ,IAAM,IAH3C,CAAC,QAAS,KAAM,KAAM,MAGiCL,EACtE,8BAvBO,WAIN,MAAO,CACNM,UAJiBC,UAAUD,UAK3BE,SAJgBD,UAAUC,SAK1BC,SAAUF,UAAUE,UAAYF,UAAUG,aAC1CC,cAAeJ,UAAUI,cACzBC,iBAAkB,GAAGC,OAAOC,SAASD,OAAOE,SAC5CC,WAAY,GAAG9B,OAAO+B,cAAc/B,OAAOgC,cAC3CC,SAAUC,KAAKC,iBAAiBC,kBAAkBC,SAEpD,iBAjDO,SAAwBC,EAASC,EAAUC,EAAW,IAC5D,IAAKF,IAAYC,EAAU,OAAOC,EAElC,IAEC,OADcxC,OAAOyC,iBAAiBH,GACzBI,iBAAiBH,IAAaC,CAC5C,CAAE,MAAOhI,GACR,OAAOgI,CACR,CACD,sBAoHO,WACN,OAAO,IAAItH,MAAOuB,aACnB,oBAlDO,SAA2BkG,EAAKC,EAAMC,OAAeC,GAC3D,IAAKH,IAAQC,EAAM,OAAOC,EAE1B,MAAME,EAAOH,EAAKI,MAAM,KACxB,IAAIC,EAAUN,EAEd,IAAK,MAAMhD,KAAOoD,EAAM,CACvB,GAAIE,WAA+CtD,KAAOsD,GACzD,OAAOJ,EAERI,EAAUA,EAAQtD,EACnB,CAEA,OAAOsD,CACR,2BAhFO,SAAsBX,GAC5B,IAAKA,EAAS,OAAO,EAErB,MAAMY,EAAOZ,EAAQa,wBACrB,OACCD,EAAKE,KAAO,GACZF,EAAKG,MAAQ,GACbH,EAAKI,SACHtD,OAAOgC,aAAe/B,SAASsD,gBAAgBC,eACjDN,EAAKO,QAAUzD,OAAO+B,YAAc9B,SAASsD,gBAAgBG,YAE/D,WA6FO,WACN,QAAK3D,MAGJ,iEAAiE4D,KAChEtC,UAAUD,YACNpB,OAAO+B,YAAc,IAE5B,eA1IO,SAAsB6B,GAC5B,SAAKA,GAA0B,iBAAVA,IAEF,6BACDD,KAAKC,EAAMC,OAC9B,gBA2EO,SAAuBC,EAAKtB,EAAW,MAC7C,IACC,OAAO1H,KAAK8B,MAAMkH,EACnB,CAAE,MAAOtJ,GACR,OAAOgI,CACR,CACD,eA/EO,SAAsBsB,GAC5B,IAAKA,GAAsB,iBAARA,EAAkB,MAAO,GAE5C,MAAMC,EAAM9D,SAAS+D,cAAc,OAEnC,OADAD,EAAIE,YAAcH,EACXC,EAAIG,SACZ,kBA0BO,SAAyB5B,EAASxF,EAAU,IAClD,IAAKwF,EAAS,OAQdA,EAAQ6B,eAAe,CALtBC,SAAU,SACVC,MAAO,SACPC,OAAQ,aAGsCxH,GAChD,oBA2DO,SAA2B6F,EAAKC,EAAMhJ,GAC5C,IAAK+I,IAAQC,EAAM,OAAOD,EAE1B,MAAMI,EAAOH,EAAKI,MAAM,KAClBuB,EAAUxB,EAAKyB,MACrB,IAAIvB,EAAUN,EAEd,IAAK,MAAMhD,KAAOoD,EACXpD,KAAOsD,GAAoC,iBAAjBA,EAAQtD,KACvCsD,EAAQtD,GAAO,CAAA,GAEhBsD,EAAUA,EAAQtD,GAInB,OADAsD,EAAQsB,GAAW3K,EACZ+I,CACR,WAlJO,SAAkBzC,EAAMuE,GAC9B,IAAIC,EACAC,EACJ,OAAO,YAAatE,GACdsE,GAIJrE,aAAaoE,GACbA,EAAWnE,WACV,KACKrF,KAAKC,MAAQwJ,GAAWF,IAC3BvE,KAAQG,GACRsE,EAAUzJ,KAAKC,QAGjBsJ,GAASvJ,KAAKC,MAAQwJ,MAXvBzE,KAAQG,GACRsE,EAAUzJ,KAAKC,MAajB,CACD,iBAkJO,SAAwBrB,EAAQ8K,EAAW,IACjD,MAAMC,EAAU,GAEhB,IAAK,MAAMlF,KAAOiF,EACZ9K,EAAO6F,IACXkF,EAAQ3G,KAAKyB,GAIf,GAAIkF,EAAQ7F,OAAS,EACpB,MAAM,IAAIzG,MAAM,mCAAmCsM,EAAQC,KAAK,SAGjE,OAAO,CACR,IC1NO,MAAMC,EACZ,WAAAvM,CAAYsE,EAAU,IACrBlE,KAAKoM,GAAKlI,EAAQkI,GAClBpM,KAAKqM,IAAMnI,EAAQmI,IACnBrM,KAAKsM,WAAapI,EAAQoI,WAC1BtM,KAAKuM,KAAOrI,EAAQqI,MAAQ,OAE5BvM,KAAKkE,QAAU,CACdsI,UAAW,KACXC,SAAUzM,KAAKqM,IAAInL,OAAOuL,SAC1BC,MAAO1M,KAAKqM,IAAInL,OAAOwL,MACvB3J,QAAS/C,KAAKqM,IAAInL,OAAO6B,QACzB4J,UAAU,EACVC,cAAc,EACdC,aAAc,CAAA,KACX3I,GAGJlE,KAAK0J,QAAU,KACf1J,KAAK8M,aAAe,KACpB9M,KAAK+M,gBAAkB,KACvB/M,KAAKgN,SAAU,EACfhN,KAAKiN,WAAY,EAEjBjN,KAAKkN,MAAQ,CACZC,QAAQ,EACRC,cAAc,EACdpK,MAAO,GACPC,QAAS,GACT+H,MAAO,GACP9H,YAAa,GACbmK,OAAQ,CAAA,GAGTrN,KAAKsN,cACN,CAEA,KAAAC,CAAMf,GACL,OAAIxM,KAAKgN,SAAWhN,KAAKiN,YAEA,iBAAdT,IACVA,EAAYnF,SAASmG,cAAchB,IAG/BA,IACJA,EAAYnF,SAASpF,MAGtBjC,KAAKwM,UAAYA,EACjBxM,KAAK0J,QAAU1J,KAAKyN,UACpBzN,KAAKwM,UAAUkB,YAAY1N,KAAK0J,SAEhC1J,KAAKgN,SAAU,EACfhN,KAAK2N,gBACL3N,KAAK4N,UAED5N,KAAKkE,QAAQyI,UAChB3M,KAAK6N,OAGN7N,KAAKqM,IAAIyB,SAASlI,KAAK,iBAAkB,CAAEmI,OAAQ/N,QAtBRA,IAwB5C,CAEA,IAAA6N,GAIC,OAHI7N,KAAK0J,UACR1J,KAAK0J,QAAQsE,MAAMC,QAAU,SAEvBjO,IACR,CAEA,IAAAkO,GAIC,OAHIlO,KAAK0J,UACR1J,KAAK0J,QAAQsE,MAAMC,QAAU,QAEvBjO,IACR,CAEA,SAAAmO,GACCnO,KAAKkN,MAAMC,QAAS,EACpBnN,KAAKoO,eAELC,sBAAsB,KACjBrO,KAAK8M,cACR9M,KAAK8M,aAAawB,UAAUC,IAAI,QAE7BvO,KAAK+M,iBACR/M,KAAK+M,gBAAgBuB,UAAUC,IAAI,SAGtC,CAEA,UAAAC,GACKxO,KAAK8M,cACR9M,KAAK8M,aAAawB,UAAUG,OAAO,QAEhCzO,KAAK+M,iBACR/M,KAAK+M,gBAAgBuB,UAAUG,OAAO,QAGvC9G,WAAW,KACV3H,KAAKkN,MAAMC,QAAS,EAChBnN,KAAK8M,cAAgB9M,KAAK8M,aAAa4B,aAC1C1O,KAAK8M,aAAa4B,WAAWC,YAAY3O,KAAK8M,cAC9C9M,KAAK8M,aAAe,MAEjB9M,KAAK+M,iBAAmB/M,KAAK+M,gBAAgB2B,aAChD1O,KAAK+M,gBAAgB2B,WAAWC,YAAY3O,KAAK+M,iBACjD/M,KAAK+M,gBAAkB,MAExB/M,KAAK4O,cACH,IACJ,CAEA,oBAAMjM,GACL,IAAI3C,KAAKkN,MAAME,aAAf,CAEApN,KAAK6O,aAEL,IACC7O,KAAKkN,MAAME,cAAe,EAC1BpN,KAAK8O,sBAEL,MAAMjN,EAAU,CACfmB,MAAOhD,KAAKkN,MAAMlK,OAAS,WAC3BC,QAASjD,KAAKkN,MAAMjK,QACpB+H,MAAOhL,KAAKkN,MAAMlC,MAClBlI,SAAU9C,KAAKkE,QAAQnB,QACvBG,YAAalD,KAAKkN,MAAMhK,aAGzB,IAAKlD,KAAKkN,MAAMjK,QAAQgI,OAEvB,YADAjL,KAAK+O,WAAW,uCAIjB,MAAM1O,QAAiBL,KAAKsM,WAAW3J,eAAed,GAEtD7B,KAAKgP,sBACLhP,KAAKwO,aAELxO,KAAKqM,IAAIyB,SAASlI,KAAK,qBAAsB,CAC5CmI,OAAQ/N,KACRiP,SAAU5O,GAEZ,CAAE,MAAOuB,GACR5B,KAAK+O,WAAW,gDAChB/O,KAAKqM,IAAIyB,SAASlI,KAAK,iBAAkB,CAAEmI,OAAQ/N,KAAM4B,SAC1D,CAAC,QACA5B,KAAKkN,MAAME,cAAe,EAC1BpN,KAAK8O,qBACN,CApC6B,CAqC9B,CAEA,kBAAAI,CAAmBC,GAClBnP,KAAKkE,QAAQwI,MAAQyC,EAAUzC,MAC3B1M,KAAK0J,SACR1J,KAAKoP,cAEP,CAEA,OAAAC,GACKrP,KAAKiN,YAETjN,KAAKsP,YACLtP,KAAKwO,aAEDxO,KAAK0J,SAAW1J,KAAK0J,QAAQgF,YAChC1O,KAAK0J,QAAQgF,WAAWC,YAAY3O,KAAK0J,SAG1C1J,KAAKiN,WAAY,EACjBjN,KAAKgN,SAAU,EACfhN,KAAKqM,IAAIyB,SAASlI,KAAK,mBAAoB,CAAEmI,OAAQ/N,OACtD,CAEA,OAAA4N,GAAW,CACX,SAAA0B,GAAa,CAEb,OAAA7B,GACC,MAAM,IAAI9N,MAAM,mDACjB,CAEA,aAAAgO,GAEA,CAEA,YAAAL,GACCtN,KAAKmO,UAAYnO,KAAKmO,UAAUoB,KAAKvP,MACrCA,KAAKwO,WAAaxO,KAAKwO,WAAWe,KAAKvP,MACvCA,KAAK2C,eAAiB3C,KAAK2C,eAAe4M,KAAKvP,KAChD,CAEA,YAAAoO,GACC,GAAIpO,KAAK8M,aAAc,OAEnB9M,KAAKkE,QAAQ0I,eAChB5M,KAAK+M,gBAAkB1F,SAAS+D,cAAc,OAC9CpL,KAAK+M,gBAAgByC,UAAY,0BACjCnI,SAASpF,KAAKyL,YAAY1N,KAAK+M,iBAE/B/M,KAAK+M,gBAAgB0C,iBAAiB,QAASzP,KAAKwO,aAGrDxO,KAAK8M,aAAezF,SAAS+D,cAAc,OAC3CpL,KAAK8M,aAAa0C,UAAY,wBAAwBxP,KAAKkE,QAAQwI,QACnE1M,KAAK8M,aAAaxB,UAAYtL,KAAK0P,gBAEnCrI,SAASpF,KAAKyL,YAAY1N,KAAK8M,cAC/B9M,KAAK2P,qBAEL,MAAMC,EAAa5P,KAAK8M,aAAaU,cAAc,mBAC/CoC,GACHjI,WAAW,IAAMiI,EAAWC,QAAS,IAEvC,CAEA,aAAAH,GACC,MAAO,6ZASkC1P,KAAKoM,yHAGXpM,KAAKoM,iIAGjBpM,KAAKkN,MAAMlK,2IAIShD,KAAKoM,yFAEXpM,KAAKoM,4IAI3BpM,KAAKkN,MAAMjK,wPAKVjD,KAAKkN,MAAME,aAAe,aAAe,qHAO1D,CAEA,kBAAAuC,GACC,MAAMG,EAAQ9P,KAAK8M,aAEnBgD,EACEtC,cAAc,yBACdiC,iBAAiB,QAASzP,KAAKwO,YAEpBsB,EAAMtC,cAAc,kBAC5BiC,iBAAiB,SAAWhL,IAChCA,EAAEsL,iBACF/P,KAAK2C,mBAGNmN,EACEtC,cAAc,uBACdiC,iBAAiB,QAAUhL,IAC3BzE,KAAKkN,MAAMlK,MAAQyB,EAAEmC,OAAO5F,QAG9B8O,EACEtC,cAAc,4BACdiC,iBAAiB,QAAUhL,IAC3BzE,KAAKkN,MAAMjK,QAAUwB,EAAEmC,OAAO5F,QAGhC,MAAMgP,EAAgBvL,IACP,WAAVA,EAAEsC,MACL/G,KAAKwO,aACLnH,SAAS4I,oBAAoB,UAAWD,KAG1C3I,SAASoI,iBAAiB,UAAWO,EACtC,CAEA,mBAAAlB,GACC,GAAI9O,KAAK8M,aAAc,CACtB,MAAMoD,EAAYlQ,KAAK8M,aAAaU,cAAc,wBAC9C0C,IACHA,EAAU7E,YAAcrL,KAAKkN,MAAME,aAChC,aACA,gBACH8C,EAAUC,SAAWnQ,KAAKkN,MAAME,aAElC,CACD,CAEA,UAAA2B,CAAWlP,GACV,GAAIG,KAAK8M,aAAc,CACtB,MAAMsD,EAAepQ,KAAK8M,aAAaU,cAAc,mBACjD4C,IACHA,EAAa/E,YAAcxL,EAC3BuQ,EAAa9B,UAAUC,IAAI,QAE7B,CACD,CAEA,UAAAM,GACC,GAAI7O,KAAK8M,aAAc,CACtB,MAAMsD,EAAepQ,KAAK8M,aAAaU,cAAc,mBACjD4C,GACHA,EAAa9B,UAAUG,OAAO,OAEhC,CACD,CAEA,mBAAAO,GACC,MAAMqB,EAAehJ,SAAS+D,cAAc,OAC5CiF,EAAab,UAAY,gCACzBa,EAAa/E,UAAY,oQAQzBjE,SAASpF,KAAKyL,YAAY2C,GAE1B,MACMC,EAAoB,KACrBD,EAAa3B,aAChB2B,EAAarC,MAAMuC,QAAU,IAC7B5I,WAAW,KACN0I,EAAa3B,YAChB2B,EAAa3B,WAAWC,YAAY0B,IAEnC,OARYA,EAAa7C,cAAc,2BAYnCiC,iBAAiB,QAASa,GAEnC3I,WAAW2I,EAAmB,IAC/B,CAEA,UAAA1B,GACC5O,KAAKkN,MAAMlK,MAAQ,GACnBhD,KAAKkN,MAAMjK,QAAU,GACrBjD,KAAKkN,MAAMlC,MAAQ,GACnBhL,KAAKkN,MAAMG,OAAS,CAAA,CACrB,CAEA,YAAA+B,GACKpP,KAAK0J,UACR1J,KAAK0J,QAAQ8F,UAAYxP,KAAK0J,QAAQ8F,UAAUxH,QAC/C,YACA,SAAShI,KAAKkE,QAAQwI,UAGpB1M,KAAK8M,eACR9M,KAAK8M,aAAa0C,UAAYxP,KAAK8M,aAAa0C,UAAUxH,QACzD,YACA,SAAShI,KAAKkE,QAAQwI,SAGzB,CAEA,SAAA8D,GACCxQ,KAAKmO,WACN,CAEA,UAAAsC,GACCzQ,KAAKwO,YACN,EC1XM,MAAMkC,UAAqBvE,EACjC,WAAAvM,CAAYsE,GACXnE,MAAM,IAAKmE,EAASqI,KAAM,UAC3B,CAEA,OAAAkB,GACC,MAAMkD,EAAStJ,SAAS+D,cAAc,OActC,OAbAuF,EAAOnB,UAAY,gDAAgDxP,KAAKkE,QAAQwI,kBAAkB1M,KAAKkE,QAAQuI,WAC/GkE,EAAOrF,UAAY,iXAQftL,KAAKkE,QAAQ2I,cAChB+D,OAAOC,OAAOF,EAAO3C,MAAOhO,KAAKkE,QAAQ2I,cAGnC8D,CACR,CAEA,aAAAhD,GACC,MAAMgD,EAAS3Q,KAAK0J,QAAQ8D,cAAc,yBAC1CmD,EAAOlB,iBAAiB,QAASzP,KAAKmO,WAEtCwC,EAAOlB,iBAAiB,aAAc,KAChCzP,KAAKkN,MAAME,eACfuD,EAAO3C,MAAM8C,UAAY,gBAI3BH,EAAOlB,iBAAiB,aAAc,KACrCkB,EAAO3C,MAAM8C,UAAY,YAE3B,CAEA,UAAAC,CAAWrM,GACVqB,QAAQiL,KAAK,6DACd,CAEA,cAAAC,CAAexE,GACdzM,KAAKkE,QAAQuI,SAAWA,EACpBzM,KAAK0J,UACR1J,KAAK0J,QAAQ8F,UAAYxP,KAAK0J,QAAQ8F,UAAUxH,QAC/C,mBACA,YAAYyE,KAGf,EClDM,MAAMyE,UAAqB/E,EACjC,WAAAvM,CAAYsE,GACXnE,MAAM,IAAKmE,EAASqI,KAAM,UAC3B,CAEA,OAAAkB,GACC,MAAMM,EAAS1G,SAAS+D,cAAc,OAyCtC,OAxCA2C,EAAOyB,UAAY,gDAAgDxP,KAAKkE,QAAQwI,QAChFqB,EAAOzC,UAAY,qUASEtL,KAAKkN,MAAMlK,oOAQnBhD,KAAKkN,MAAMjK,wOAOHjD,KAAKkN,MAAMlC,gRAW5BhL,KAAKkE,QAAQ2I,cAChB+D,OAAOC,OAAO9C,EAAOC,MAAOhO,KAAKkE,QAAQ2I,cAGnCkB,CACR,CAEA,aAAAJ,GACC,MAAMwD,EAAOnR,KAAK0J,QAAQ8D,cAAc,yBAExC2D,EAAK1B,iBAAiB,SAAWhL,IAChCA,EAAEsL,iBACF/P,KAAK2C,mBAGNwO,EAAK3D,cAAc,uBAAuBiC,iBAAiB,QAAUhL,IACpEzE,KAAKkN,MAAMlK,MAAQyB,EAAEmC,OAAO5F,QAG7BmQ,EACE3D,cAAc,4BACdiC,iBAAiB,QAAUhL,IAC3BzE,KAAKkN,MAAMjK,QAAUwB,EAAEmC,OAAO5F,QAGhCmQ,EAAK3D,cAAc,uBAAuBiC,iBAAiB,QAAUhL,IACpEzE,KAAKkN,MAAMlC,MAAQvG,EAAEmC,OAAO5F,OAE9B,CAEA,SAAAwP,GACC,MAAMY,EAAWpR,KAAK0J,QAAQ8D,cAAc,4BACxC4D,GACHA,EAASvB,OAEX,CAEA,UAAAY,GAEA,CAEA,mBAAAzB,GACC,MAAMjB,EAAS/N,KAAK0J,QAAQ8D,cAAc,4BACpC6D,EAAkBtD,EAAOzC,UAE/ByC,EAAOzC,UAAY,4RASFyC,EAAOP,cAAc,uBAC7BiC,iBAAiB,QAAS,KAClC1B,EAAOzC,UAAY+F,EACnBrR,KAAK2N,gBACL3N,KAAK4O,cAEP,CAEA,UAAAG,CAAWlP,GACV,MAAMuQ,EAAepQ,KAAK0J,QAAQ8D,cAAc,mBAC5C4C,IACHA,EAAa/E,YAAcxL,EAC3BuQ,EAAapC,MAAMC,QAAU,QAE7BtG,WAAW,KACNyI,IACHA,EAAapC,MAAMC,QAAU,SAE5B,KAEL,CAEA,mBAAAa,GACC,MAAMoB,EAAYlQ,KAAK0J,QAAQ8D,cAAc,wBACzC0C,IACHA,EAAU7E,YAAcrL,KAAKkN,MAAME,aAChC,aACA,gBACH8C,EAAUC,SAAWnQ,KAAKkN,MAAME,aAElC,CAEA,WAAAkE,CAAYtO,GACX,MAAMuO,EAAevR,KAAK0J,SAAS8D,cAAc,MAC7C+D,IACHA,EAAalG,YAAcrI,EAE7B,CAEA,cAAAwO,CAAezQ,EAAO0Q,GACrB,MAAMC,EAAQ1R,KAAK0J,SAAS8D,cAAc,UAAUzM,OAChD2Q,IACHA,EAAMD,YAAcA,EAEtB,EC7IM,MAAME,UAAkBxF,EAC9B,WAAAvM,CAAYsE,GACXnE,MAAM,IAAKmE,EAASqI,KAAM,OAC3B,CAEA,OAAAkB,GACC,MAAMmE,EAAMvK,SAAS+D,cAAc,OAYnC,OAXAwG,EAAIpC,UAAY,6CAA6CxP,KAAKkE,QAAQwI,kBAAkB1M,KAAKkE,QAAQuI,WACzGmF,EAAItG,UAAY,0HAMZtL,KAAKkE,QAAQ2I,cAChB+D,OAAOC,OAAOe,EAAI5D,MAAOhO,KAAKkE,QAAQ2I,cAGhC+E,CACR,CAEA,aAAAjE,GACC,MAAMiE,EAAM5R,KAAK0J,QAAQ8D,cAAc,yBACvCoE,EAAInC,iBAAiB,QAASzP,KAAKwQ,WAEnCoB,EAAInC,iBAAiB,aAAc,KAC7BzP,KAAKkN,MAAME,eACfwE,EAAI5D,MAAM8C,UAAY9Q,KAAK6R,wBAI7BD,EAAInC,iBAAiB,aAAc,KAClCmC,EAAI5D,MAAM8C,UAAY,QAExB,CAEA,kBAAAe,GACC,MAAMpF,EAAWzM,KAAKkE,QAAQuI,SAC9B,OAAIA,EAAS5H,SAAS,SACd,mBACG4H,EAAS5H,SAAS,QACrB,kBAED,MACR,CAEA,UAAAkM,CAAWrM,GACV,MAAMoN,EAAc9R,KAAK0J,SAAS8D,cAAc,sBAC5CsE,IACHA,EAAYzG,YAAc3G,EAE5B,CAEA,cAAAuM,CAAexE,GACdzM,KAAKkE,QAAQuI,SAAWA,EACpBzM,KAAK0J,UACR1J,KAAK0J,QAAQ8F,UAAYxP,KAAK0J,QAAQ8F,UAAUxH,QAC/C,mBACA,YAAYyE,KAGf,EC1DM,MAAMsF,EACZC,eAAiB,IAAIhN,IAAI,CACxB,CAAC,SAAU0L,GACX,CAAC,MAAOiB,GACR,CAAC,SAAUT,KAGZ,eAAOe,CAAS1F,EAAM2F,GACrB,GAAoB,iBAAT3F,IAAsBA,EAAKtB,OACrC,MAAM,IAAIvL,EAAS,0CAGpB,GAA2B,mBAAhBwS,EACV,MAAM,IAAIxS,EAAS,+CAGpBM,KAAKmS,QAAQ9M,IAAIkH,EAAM2F,EACxB,CAEA,aAAOE,CAAO7F,EAAMrI,EAAU,IAC7B,MAAMgO,EAAclS,KAAKmS,QAAQvN,IAAI2H,GAErC,IAAK2F,EAAa,CACjB,MAAMG,EAAiBpL,MAAMqL,KAAKtS,KAAKmS,QAAQhI,QAAQ+B,KAAK,MAC5D,MAAM,IAAIxM,EACT,wBAAwB6M,uBAA0B8F,IAEpD,CAEA,IACC,OAAO,IAAIH,EAAYhO,EACxB,CAAE,MAAOtC,GACR,MAAM,IAAIlC,EACT,oCAAoC6M,OAAU3K,EAAM/B,UACpD+B,EAEF,CACD,CAEA,wBAAO2Q,GACN,OAAOtL,MAAMqL,KAAKtS,KAAKmS,QAAQhI,OAChC,CAEA,uBAAOqI,CAAiBjG,GACvB,OAAOvM,KAAKmS,QAAQ/M,IAAImH,EACzB,CAEA,iBAAOkG,CAAWlG,GACjB,OAAOvM,KAAKmS,QAAQO,OAAOnG,EAC5B,CAEA,YAAOrG,GACNlG,KAAKmS,QAAQjM,OACd,CAEA,qBAAOyM,CAAepG,GACrB,OAAOvM,KAAKmS,QAAQvN,IAAI2H,EACzB,ECxDM,MAAMqG,EACZ,WAAAhT,CAAYsB,EAAS,IACpBlB,KAAKkB,OAASlB,KAAK6S,wBAAwB3R,GAC3ClB,KAAK8S,aAAc,EACnB9S,KAAKmS,QAAU,IAAInN,IACnBhF,KAAK8N,SAAW,IAAIhJ,EAEpB9E,KAAKsM,WAAa,IAAIrL,EAAW,CAChCM,OAAQvB,KAAKkB,OAAOK,OACpBJ,UAAWnB,KAAKkB,OAAOC,UACvBG,YAAatB,KAAKkB,OAAOI,cAG1BtB,KAAKsN,cACN,CAEA,UAAM5L,GACL,GAAI1B,KAAK8S,YACR,MAAO,CAAEC,oBAAoB,GAG9B,IACC,MAAMC,QAAiBhT,KAAKsM,WAAW5K,KAAK1B,KAAKkB,OAAOI,aAYxD,OAVI0R,EAAS9R,SACZlB,KAAKkB,OAASyF,EAAU3G,KAAKkB,OAAQ8R,EAAS9R,SAG/ClB,KAAK8S,aAAc,EACnB9S,KAAK8N,SAASlI,KAAK,kBAAmB,CACrC1E,OAAQlB,KAAKkB,OACbE,aAAc4R,EAAS5R,eAGjB,CACN0R,aAAa,EACb5R,OAAQ8R,EAAS9R,QAAU,CAAA,EAC3BE,aAAc4R,EAAS5R,aACvBsB,UAAWsQ,EAAStQ,UAEtB,CAAE,MAAOd,GAER,MADA5B,KAAK8N,SAASlI,KAAK,YAAa,CAAEhE,UAC5B,IAAIlC,EAAS,6BAA6BkC,EAAM/B,UAAW+B,EAClE,CACD,CAEA,YAAAqR,CAAa1G,EAAO,SAAUrI,EAAU,CAAA,GACvC,IAAKlE,KAAK8S,YACT,MAAM,IAAIpT,EAAS,uEAGpB,MAAMiB,EAAW0F,EAAW,UACtB6M,EAAgB,CACrB9G,GAAIzL,EACJ0L,IAAKrM,KACLsM,WAAYtM,KAAKsM,cACdtM,KAAKkB,UACLgD,GAGJ,IACC,MAAM6J,EAASgE,EAAcK,OAAO7F,EAAM2G,GAG1C,OAFAlT,KAAKmS,QAAQ9M,IAAI1E,EAAUoN,GAC3B/N,KAAK8N,SAASlI,KAAK,iBAAkB,CAAEmI,SAAQxB,SACxCwB,CACR,CAAE,MAAOnM,GACR,MAAM,IAAIlC,EAAS,4BAA4BkC,EAAM/B,UAAW+B,EACjE,CACD,CAEA,SAAAuR,CAAU/G,GACT,OAAOpM,KAAKmS,QAAQvN,IAAIwH,EACzB,CAEA,aAAAgH,GACC,OAAOnM,MAAMqL,KAAKtS,KAAKmS,QAAQkB,SAChC,CAEA,aAAAC,CAAclH,GACb,MAAM2B,EAAS/N,KAAKmS,QAAQvN,IAAIwH,GAChC,QAAI2B,IACHA,EAAOsB,UACPrP,KAAKmS,QAAQO,OAAOtG,GACpBpM,KAAK8N,SAASlI,KAAK,iBAAkB,CAAEjF,SAAUyL,KAC1C,EAGT,CAEA,iBAAAmH,GACC,IAAK,MAAMxF,KAAU/N,KAAKmS,QAAQkB,SACjCtF,EAAOsB,UAERrP,KAAKmS,QAAQjM,QACblG,KAAK8N,SAASlI,KAAK,kBACpB,CAEA,YAAA4N,CAAarE,GACZ,MAAMsE,EAAY,IAAKzT,KAAKkB,QAC5BlB,KAAKkB,OAASlB,KAAK6S,wBAAwB1D,EAAWnP,KAAKkB,QAE3D,IAAK,MAAM6M,KAAU/N,KAAKmS,QAAQkB,SACjCtF,EAAOmB,mBAAmBlP,KAAKkB,QAGhClB,KAAK8N,SAASlI,KAAK,iBAAkB,CACpC6N,YACAtE,UAAWnP,KAAKkB,QAElB,CAEA,cAAAkC,CAAe9B,GACdtB,KAAKkB,OAAOI,YAAcA,EACtBtB,KAAKsM,YACRtM,KAAKsM,WAAWlJ,eAAe9B,GAEhCtB,KAAK8N,SAASlI,KAAK,eAAgB,CAAEtE,eACtC,CAEA,cAAAiC,GACC,OAAOvD,KAAKkB,OAAOI,cAAgBtB,KAAKsM,WAAatM,KAAKsM,WAAW/I,iBAAmB,KACzF,CAEA,kBAAMmQ,CAAaC,EAAiB,MAQnC,OAPA3T,KAAKsM,WAAW9I,eAChBxD,KAAK8S,aAAc,EAEfa,GACH3T,KAAKoD,eAAeuQ,GAGd3T,KAAK0B,MACb,CAEA,EAAAuD,CAAGC,EAAOC,GAET,OADAnF,KAAK8N,SAAS7I,GAAGC,EAAOC,GACjBnF,IACR,CAEA,GAAAuF,CAAIL,EAAOC,GAEV,OADAnF,KAAK8N,SAASvI,IAAIL,EAAOC,GAClBnF,IACR,CAEA,IAAAgG,CAAKd,EAAOC,GAEX,OADAnF,KAAK8N,SAAS9H,KAAKd,EAAOC,GACnBnF,IACR,CAEA,IAAA4F,CAAKV,EAAOW,GAEX,OADA7F,KAAK8N,SAASlI,KAAKV,EAAOW,GACnB7F,IACR,CAEA,OAAAqP,GACCrP,KAAKuT,oBACLvT,KAAK8N,SAAS8F,qBACd5T,KAAKsM,WAAW9I,eAChBxD,KAAK8S,aAAc,EACnB9S,KAAK8N,SAASlI,KAAK,gBACpB,CAEA,uBAAAiN,CAAwB1D,EAAW0E,EAAiB,IACnD,MAWMC,EAAenN,EAAUA,EAXT,CACrBpF,OAAQ,KACRJ,UAAW,KACXG,YAAa,KACbmL,SAAU,eACVC,MAAO,QACP3J,QAAS,UACT4J,UAAU,EACVoH,OAAO,GAGgDF,GAAiB1E,GAEzE,IAAK2E,EAAa3S,UACjB,MAAM,IAAIP,EAAY,6CAOvB,OAJIkT,EAAaxS,aAChBtB,KAAKgU,qBAAqBF,EAAaxS,aAGjCwS,CACR,CAEA,oBAAAE,CAAqB1S,GACpB,IAAKA,EAAY2S,UAAY3S,EAAY0J,MACxC,MAAM,IAAIpK,EAAY,uDAGvB,MAAMsT,EAAiB,CACtBD,QAAS,SACTjJ,MAAO,SACP/K,KAAM,SACNkU,cAAe,SACfC,QAAS,UAGV,IAAK,MAAOrN,EAAKsN,KAAiBzD,OAAO0D,QAAQJ,GAChD,GAAI5S,EAAYyF,WAAezF,EAAYyF,KAASsN,EACnD,MAAM,IAAIzT,EAAY,uBAAuBmG,uBAAyBsN,KAGzE,CAEA,YAAA/G,GACCtN,KAAKiT,aAAejT,KAAKiT,aAAa1D,KAAKvP,MAC3CA,KAAKsT,cAAgBtT,KAAKsT,cAAc/D,KAAKvP,MAC7CA,KAAKwT,aAAexT,KAAKwT,aAAajE,KAAKvP,KAC5C,CAEA,aAAOoS,CAAOlR,GACb,OAAO,IAAI0R,EAAY1R,EACxB,CAEA,0BAAaqT,CAAcrT,GAC1B,MAAMmL,EAAM,IAAIuG,EAAY1R,GAE5B,aADMmL,EAAI3K,OACH2K,CACR,CAEA,iCAAOmI,CAA2BC,GACjC,OAAKA,EAEE,CACNR,QAASQ,EAASC,KAAOD,EAASrI,IAAMqI,EAASR,QACjDjJ,MAAOyJ,EAASzJ,MAChB/K,KAAMwU,EAASxU,MAAQwU,EAASE,cAAgBF,EAASG,UACzDT,cAAe,CACdU,KAAMJ,EAASI,KACfC,KAAML,EAASK,MAAQL,EAASM,cAAcD,QAC1CL,EAASN,eAAiB,IAE/BC,QAASK,EAASL,SAAWK,EAASO,aAAe,CACpD5I,GAAIqI,EAASL,SAAShI,IAAMqI,EAASO,cAAc5I,GACnDnM,KAAMwU,EAASL,SAASnU,MAAQwU,EAASO,cAAc/U,KACvDgV,cAAeR,EAASL,SAASa,oBAC9B/K,GAfiB,IAiBvB,ECrOD,SAASgL,IACR,GAAwB,oBAAb7N,WAA6BA,SAASmG,cAAc,wBAAyB,CACvF,MAAMQ,EAAQ3G,SAAS+D,cAAc,SACrC4C,EAAM5B,GAAK,sBACX4B,EAAM3C,YCtBkB,gtUDuBxBhE,SAAS8N,KAAKzH,YAAYM,EAC3B,CACD,CAEA,SAASoH,IACR,GAAsB,oBAAXhO,QAA0BA,OAAOiO,kBAAmB,CAC9DH,IAEA,MAAMhU,EAAS,IAAKkG,OAAOiO,mBACrBhJ,EAAM,IAAIuG,EAAY1R,GAE5BmL,EACE3K,OACA4T,KAAMtC,IAGN,GAFA5L,OAAOwL,YAAY2C,SAAWlJ,EAE1BjF,OAAOiO,kBAAkBG,WAAY,EACxBvO,MAAMC,QAAQE,OAAOiO,kBAAkBG,YACpDpO,OAAOiO,kBAAkBG,WACzB,CAACpO,OAAOiO,kBAAkBG,aAErB1P,QAAS2P,IAChB,IACgBpJ,EAAI4G,aAClBwC,EAAalJ,MAAQ,SACrBkJ,GAEMlI,MAAMkI,EAAajJ,UAC3B,CAAE,MAAO5K,GACRmE,QAAQnE,MAAM,yCAA0CA,EACzD,GAEF,CAEA,GAA2B,oBAAhB8T,YAA6B,CACvC,MAAMxQ,EAAQ,IAAIwQ,YAAY,mBAAoB,CACjDC,OAAQ,CAAEtJ,MAAKnL,SAAQ8R,cAExB5L,OAAOwO,cAAc1Q,EACtB,IAEA2Q,MAAOjU,IAGP,GAFAmE,QAAQnE,MAAM,4CAA6CA,GAEhC,oBAAhB8T,YAA6B,CACvC,MAAMxQ,EAAQ,IAAIwQ,YAAY,mBAAoB,CACjDC,OAAQ,CAAE/T,QAAOV,SAAQ4U,MAAO,oBAEjC1O,OAAOwO,cAAc1Q,EACtB,GAEH,CACD,CAYK,MAAC6Q,EAAoB,CACzBnD,cACAzG,aACAuE,eACAiB,YACAT,eACAa,gBACAjN,WACA7D,aACAvB,WACAS,WACAM,cACAG,cACAE,kBACAkV,UACA5D,OAASlR,IACRgU,IACO,IAAItC,EAAY1R,IAExB+U,QAAS,QACTV,SAAU,KAEVW,QAAS,IAAMC,QAAQJ,EAAkBR,UACzCa,YAAa,IAAML,EAAkBR,SAErCnS,eAAiB9B,IACZyU,EAAkBR,SACrBQ,EAAkBR,SAASnS,eAAe9B,GAEpB,oBAAX8F,SACVA,OAAOiP,uBAAyB/U,IAKnCgV,aAAcC,MAAOrV,EAAQI,KAC5B4T,IACA,MAAMsB,EAAa,IAAKtV,EAAQI,eAC1B+K,EAAM,IAAIuG,EAAY4D,GAO5B,aANMnK,EAAI3K,OAEY,oBAAX0F,SACVA,OAAOwL,YAAY2C,SAAWlJ,GAGxBA,GAGRoK,QAAUtR,IACa,oBAAXiC,SACN2O,EAAkBG,UACrB/Q,EAAS4Q,EAAkBR,UAE3BnO,OAAOqI,iBACN,mBACCvK,IACAC,EAASD,EAAMyQ,OAAOtJ,IAAKnH,EAAMyQ,SAElC,CAAE3P,MAAM,MAMZ0Q,QAAUvR,IACa,oBAAXiC,QACVA,OAAOqI,iBAAiB,mBAAqBvK,IAC5CC,EAASD,EAAMyQ,OAAO/T,MAAOsD,EAAMyQ,WAKtCgB,mBAAoB/D,EAAY4B,4BAGX,oBAAXpN,SACVA,OAAOwL,YAAcmD,EArFG,oBAAb1O,WACkB,YAAxBA,SAASuP,WACZvP,SAASoI,iBAAiB,mBAAoB2F,GAE9CzN,WAAWyN,EAAU"}
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}.staging.api.product7.io/api/v1`;\n\t\t} else {\n\t\t\tthis.baseURL = 'https://staging.api.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\tshowBackdrop: true,\n\t\t\tcustomStyles: {},\n\t\t\t...options,\n\t\t};\n\n\t\tthis.element = null;\n\t\tthis.panelElement = null;\n\t\tthis.backdropElement = 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\topenPanel() {\n\t\tthis.state.isOpen = true;\n\t\tthis._renderPanel();\n\t\t\n\t\trequestAnimationFrame(() => {\n\t\t\tif (this.panelElement) {\n\t\t\t\tthis.panelElement.classList.add('open');\n\t\t\t}\n\t\t\tif (this.backdropElement) {\n\t\t\t\tthis.backdropElement.classList.add('show');\n\t\t\t}\n\t\t});\n\t}\n\n\tclosePanel() {\n\t\tif (this.panelElement) {\n\t\t\tthis.panelElement.classList.remove('open');\n\t\t}\n\t\tif (this.backdropElement) {\n\t\t\tthis.backdropElement.classList.remove('show');\n\t\t}\n\n\t\tsetTimeout(() => {\n\t\t\tthis.state.isOpen = false;\n\t\t\tif (this.panelElement && this.panelElement.parentNode) {\n\t\t\t\tthis.panelElement.parentNode.removeChild(this.panelElement);\n\t\t\t\tthis.panelElement = null;\n\t\t\t}\n\t\t\tif (this.backdropElement && this.backdropElement.parentNode) {\n\t\t\t\tthis.backdropElement.parentNode.removeChild(this.backdropElement);\n\t\t\t\tthis.backdropElement = null;\n\t\t\t}\n\t\t\tthis._resetForm();\n\t\t}, 300);\n\t}\n\n\tasync submitFeedback() {\n\t\tif (this.state.isSubmitting) return;\n\n\t\tthis._hideError();\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.closePanel();\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.closePanel();\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.openPanel = this.openPanel.bind(this);\n\t\tthis.closePanel = this.closePanel.bind(this);\n\t\tthis.submitFeedback = this.submitFeedback.bind(this);\n\t}\n\n\t_renderPanel() {\n\t\tif (this.panelElement) return;\n\n\t\tif (this.options.showBackdrop) {\n\t\t\tthis.backdropElement = document.createElement('div');\n\t\t\tthis.backdropElement.className = 'feedback-panel-backdrop';\n\t\t\tdocument.body.appendChild(this.backdropElement);\n\n\t\t\tthis.backdropElement.addEventListener('click', this.closePanel);\n\t\t}\n\n\t\tthis.panelElement = document.createElement('div');\n\t\tthis.panelElement.className = `feedback-panel theme-${this.options.theme}`;\n\t\tthis.panelElement.innerHTML = this._getPanelHTML();\n\n\t\tdocument.body.appendChild(this.panelElement);\n\t\tthis._attachPanelEvents();\n\n\t\tconst firstInput = this.panelElement.querySelector('input, textarea');\n\t\tif (firstInput) {\n\t\t\tsetTimeout(() => firstInput.focus(), 350);\n\t\t}\n\t}\n\n\t_getPanelHTML() {\n\t\treturn `\n <div class=\"feedback-panel-content\">\n <div class=\"feedback-panel-header\">\n <h3>Send Feedback</h3>\n <button class=\"feedback-panel-close\" type=\"button\" aria-label=\"Close\">&times;</button>\n </div>\n <div class=\"feedback-panel-body\">\n <form class=\"feedback-form\">\n <div class=\"feedback-form-group\">\n <label for=\"feedback-title-${this.id}\">Title (optional)</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 what you think...\"\n required\n >${this.state.content}</textarea>\n </div>\n <div class=\"feedback-error\" role=\"alert\"></div>\n <div class=\"feedback-form-actions\">\n <button type=\"submit\" class=\"feedback-btn feedback-btn-submit\">\n ${this.state.isSubmitting ? 'Sending...' : 'Send Feedback'}\n </button>\n </div>\n </form>\n </div>\n </div>\n `;\n\t}\n\n\t_attachPanelEvents() {\n\t\tconst panel = this.panelElement;\n\n\t\tpanel\n\t\t\t.querySelector('.feedback-panel-close')\n\t\t\t.addEventListener('click', this.closePanel);\n\n\t\tconst form = panel.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\tpanel\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\tpanel\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\tconst handleEscape = (e) => {\n\t\t\tif (e.key === 'Escape') {\n\t\t\t\tthis.closePanel();\n\t\t\t\tdocument.removeEventListener('keydown', handleEscape);\n\t\t\t}\n\t\t};\n\t\tdocument.addEventListener('keydown', handleEscape);\n\t}\n\n\t_updateSubmitButton() {\n\t\tif (this.panelElement) {\n\t\t\tconst submitBtn = this.panelElement.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.panelElement) {\n\t\t\tconst errorElement = this.panelElement.querySelector('.feedback-error');\n\t\t\tif (errorElement) {\n\t\t\t\terrorElement.textContent = message;\n\t\t\t\terrorElement.classList.add('show');\n\t\t\t}\n\t\t}\n\t}\n\n\t_hideError() {\n\t\tif (this.panelElement) {\n\t\t\tconst errorElement = this.panelElement.querySelector('.feedback-error');\n\t\t\tif (errorElement) {\n\t\t\t\terrorElement.classList.remove('show');\n\t\t\t}\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 <div class=\"feedback-success-icon\">✓</div>\n <span>Feedback submitted successfully!</span>\n <button class=\"feedback-success-close\" aria-label=\"Close\">&times;</button>\n </div>\n `;\n\n\t\tdocument.body.appendChild(notification);\n\n\t\tconst closeBtn = notification.querySelector('.feedback-success-close');\n\t\tconst closeNotification = () => {\n\t\t\tif (notification.parentNode) {\n\t\t\t\tnotification.style.opacity = '0';\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tif (notification.parentNode) {\n\t\t\t\t\t\tnotification.parentNode.removeChild(notification);\n\t\t\t\t\t}\n\t\t\t\t}, 300);\n\t\t\t}\n\t\t};\n\n\t\tcloseBtn.addEventListener('click', closeNotification);\n\n\t\tsetTimeout(closeNotification, 4000);\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.panelElement) {\n\t\t\tthis.panelElement.className = this.panelElement.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\topenModal() {\n\t\tthis.openPanel();\n\t}\n\n\tcloseModal() {\n\t\tthis.closePanel();\n\t}\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\" aria-label=\"Send feedback\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"/>\n </svg>\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.openPanel);\n\n\t\tbutton.addEventListener('mouseenter', () => {\n\t\t\tif (!this.state.isSubmitting) {\n\t\t\t\tbutton.style.transform = 'scale(1.1)';\n\t\t\t}\n\t\t});\n\n\t\tbutton.addEventListener('mouseleave', () => {\n\t\t\tbutton.style.transform = 'scale(1)';\n\t\t});\n\t}\n\n\tupdateText(text) {\n\t\tconsole.warn('ButtonWidget: Text display is disabled for circular design');\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}","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}\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/* Circular button design with white bg and blue border */\n.feedback-trigger-btn {\n width: 56px;\n height: 56px;\n border-radius: 50%;\n border: 2px solid #155eff;\n background-color: #ffffff;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 4px 12px rgba(21, 94, 255, 0.15);\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n padding: 0;\n color: #155eff; /* Icon color matches border */\n}\n\n.feedback-trigger-btn:hover {\n background-color: #155eff;\n color: #ffffff;\n box-shadow: 0 6px 20px rgba(21, 94, 255, 0.3);\n}\n\n.feedback-trigger-btn:active {\n transform: scale(0.95);\n}\n\n.feedback-trigger-btn svg {\n flex-shrink: 0;\n}\n\n/* Dark theme support */\n.theme-dark .feedback-trigger-btn {\n background-color: #1a1a1a;\n border-color: #155eff;\n color: #155eff;\n}\n\n.theme-dark .feedback-trigger-btn:hover {\n background-color: #155eff;\n color: #ffffff;\n}\n\n/* Side Panel Styles */\n.feedback-panel {\n position: fixed;\n bottom: 80px;\n right: 24px;\n width: 420px;\n max-height: 500px;\n z-index: 1000000;\n transform: translateX(calc(100% + 24px));\n transition: transform 0.35s cubic-bezier(0.4, 0, 0.2, 1);\n font-family: inherit;\n}\n\n.feedback-panel.open {\n transform: translateX(0);\n}\n\n.feedback-panel-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.1);\n opacity: 0;\n transition: opacity 0.3s ease;\n pointer-events: none;\n z-index: 999999;\n}\n\n.feedback-panel-backdrop.show {\n opacity: 1;\n pointer-events: auto;\n}\n\n.feedback-panel-content {\n background: white;\n height: 100%;\n display: flex;\n flex-direction: column;\n border-radius: 16px;\n box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), \n 0 10px 10px -5px rgba(0, 0, 0, 0.04),\n 0 0 0 1px rgba(0, 0, 0, 0.05);\n}\n\n.feedback-panel.theme-dark .feedback-panel-content {\n background: #1F2937;\n color: white;\n}\n\n.feedback-panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 24px;\n border-bottom: 1px solid #E5E7EB;\n flex-shrink: 0;\n}\n\n.feedback-panel.theme-dark .feedback-panel-header {\n border-bottom-color: #374151;\n}\n\n.feedback-panel-header h3 {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n color: #111827;\n}\n\n.feedback-panel.theme-dark .feedback-panel-header h3 {\n color: white;\n}\n\n.feedback-panel-close {\n background: none;\n border: none;\n font-size: 24px;\n cursor: pointer;\n color: #6B7280;\n padding: 4px;\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n transition: all 0.2s ease;\n}\n\n.feedback-panel-close:hover {\n background: #F3F4F6;\n color: #111827;\n}\n\n.feedback-panel-close:focus-visible {\n outline: 2px solid #155EEF;\n outline-offset: 2px;\n}\n\n.feedback-panel.theme-dark .feedback-panel-close {\n color: #9CA3AF;\n}\n\n.feedback-panel.theme-dark .feedback-panel-close:hover {\n background: #374151;\n color: white;\n}\n\n.feedback-panel-body {\n flex: 1;\n overflow-y: auto;\n padding: 24px;\n}\n\n.feedback-form {\n display: flex;\n flex-direction: column;\n height: 100%;\n}\n\n.feedback-form-group {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-bottom: 20px;\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-panel.theme-dark .feedback-form-group label {\n color: #D1D5DB;\n}\n\n.feedback-form-group input {\n height: 44px;\n width: 100%;\n border-radius: 8px;\n border: 1px solid #D1D5DB;\n padding: 10px 14px;\n font-size: 15px;\n font-weight: 400;\n line-height: 1.5;\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: 15px;\n color: #9CA3AF;\n}\n\n.feedback-form-group input:focus {\n border-color: #155EEF;\n box-shadow: 0 0 0 3px rgba(21, 94, 239, 0.1);\n}\n\n.feedback-form-group input:focus-visible {\n outline: none;\n}\n\n.feedback-form-group textarea {\n min-height: 200px;\n width: 100%;\n resize: vertical;\n border-radius: 8px;\n border: 1px solid #D1D5DB;\n padding: 10px 14px;\n font-size: 15px;\n font-weight: 400;\n line-height: 1.5;\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: 15px;\n color: #9CA3AF;\n}\n\n.feedback-form-group textarea:focus {\n border-color: #155EEF;\n box-shadow: 0 0 0 3px rgba(21, 94, 239, 0.1);\n}\n\n.feedback-form-group textarea:focus-visible {\n outline: none;\n}\n\n.feedback-panel.theme-dark .feedback-form-group input,\n.feedback-panel.theme-dark .feedback-form-group textarea {\n background: #374151;\n border-color: #4B5563;\n color: white;\n}\n\n.feedback-panel.theme-dark .feedback-form-group input::placeholder,\n.feedback-panel.theme-dark .feedback-form-group textarea::placeholder {\n color: #6B7280;\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: 8px;\n border: none;\n height: 44px;\n padding: 10px 18px;\n font-size: 15px;\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.6;\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 width: 100%;\n}\n\n.feedback-btn-submit:hover:not(:disabled) {\n background: #1A56DB;\n}\n\n.feedback-btn-submit:active:not(:disabled) {\n background: #1E429F;\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-panel.theme-dark .feedback-btn-cancel {\n color: #D1D5DB;\n border-color: #4B5563;\n}\n\n.feedback-panel.theme-dark .feedback-btn-cancel:hover:not(:disabled) {\n background: #374151;\n}\n\n.feedback-form-actions {\n display: flex;\n flex-direction: column;\n gap: 12px;\n margin-top: auto;\n padding-top: 24px;\n}\n\n.feedback-error {\n color: #DC2626;\n font-size: 14px;\n font-weight: 400;\n margin-top: 8px;\n padding: 12px;\n background: #FEE2E2;\n border: 1px solid #FECACA;\n border-radius: 8px;\n display: none;\n}\n\n.feedback-error.show {\n display: block;\n}\n\n.feedback-panel.theme-dark .feedback-error {\n background: #7F1D1D;\n border-color: #991B1B;\n color: #FCA5A5;\n}\n\n.feedback-success-notification {\n position: fixed;\n top: 24px;\n right: 24px;\n z-index: 1000002;\n background: white;\n border: 1px solid #D1FAE5;\n border-radius: 12px;\n box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);\n animation: slideInRight 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n min-width: 320px;\n}\n\n.feedback-success-content {\n display: flex;\n align-items: center;\n padding: 16px 20px;\n gap: 12px;\n}\n\n.feedback-success-icon {\n width: 20px;\n height: 20px;\n border-radius: 50%;\n background: #10B981;\n color: white;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n font-weight: 600;\n flex-shrink: 0;\n}\n\n.feedback-success-content span {\n color: #065F46;\n font-weight: 500;\n font-size: 14px;\n flex: 1;\n}\n\n.feedback-success-close {\n background: none;\n border: none;\n color: #6B7280;\n cursor: pointer;\n font-size: 20px;\n padding: 0;\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.2s ease;\n border-radius: 4px;\n flex-shrink: 0;\n}\n\n.feedback-success-close:hover {\n background: #F3F4F6;\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(400px);\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-panel-backdrop {\n animation: fadeIn 0.3s ease;\n}\n\n@media (max-width: 768px) {\n .feedback-panel {\n width: 100%;\n top: auto;\n bottom: 0;\n right: 0;\n left: 0;\n height: 85vh;\n max-height: 85vh;\n transform: translateY(100%);\n border-radius: 20px 20px 0 0;\n }\n \n .feedback-panel.open {\n transform: translateY(0);\n }\n \n .feedback-panel-content {\n border-radius: 20px 20px 0 0;\n }\n \n .feedback-panel-header {\n padding: 20px;\n position: relative;\n }\n \n .feedback-panel-header::before {\n content: '';\n position: absolute;\n top: 8px;\n left: 50%;\n transform: translateX(-50%);\n width: 40px;\n height: 4px;\n background: #D1D5DB;\n border-radius: 2px;\n }\n \n .feedback-panel.theme-dark .feedback-panel-header::before {\n background: #4B5563;\n }\n \n .feedback-panel-body {\n padding: 20px;\n }\n \n .feedback-form-group textarea {\n min-height: 150px;\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-success-notification {\n top: 16px;\n right: 16px;\n left: 16px;\n min-width: auto;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .feedback-trigger-btn,\n .feedback-btn,\n .feedback-panel,\n .feedback-panel-backdrop,\n .feedback-success-notification {\n transition: none;\n animation: none;\n }\n}\n\n@media print {\n .feedback-widget,\n .feedback-panel,\n .feedback-panel-backdrop,\n .feedback-success-notification {\n display: none !important;\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","showBackdrop","customStyles","panelElement","backdropElement","mounted","destroyed","state","isOpen","isSubmitting","errors","_bindMethods","mount","querySelector","_render","appendChild","_attachEvents","onMount","show","eventBus","widget","style","display","hide","openPanel","_renderPanel","requestAnimationFrame","classList","add","closePanel","remove","parentNode","removeChild","_resetForm","_hideError","_updateSubmitButton","_showError","_showSuccessMessage","feedback","handleConfigUpdate","newConfig","_updateTheme","destroy","onDestroy","bind","className","addEventListener","_getPanelHTML","_attachPanelEvents","firstInput","focus","panel","preventDefault","handleEscape","removeEventListener","submitBtn","disabled","errorElement","notification","closeNotification","opacity","openModal","closeModal","ButtonWidget","button","Object","assign","transform","updateText","warn","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,6 +1,6 @@
1
1
  {
2
2
  "name": "@product7/feedback-sdk",
3
- "version": "1.0.9",
3
+ "version": "1.1.0",
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",
@@ -38,23 +38,27 @@ export const CSS_STYLES = `
38
38
  left: 20px;
39
39
  }
40
40
 
41
- /* Circular button design */
41
+ /* Circular button design with white bg and blue border */
42
42
  .feedback-trigger-btn {
43
43
  width: 56px;
44
44
  height: 56px;
45
- border-radius: 50%; /* Makes it circular */
46
- border: none;
45
+ border-radius: 50%;
46
+ border: 2px solid #155eff;
47
+ background-color: #ffffff;
47
48
  cursor: pointer;
48
49
  display: flex;
49
50
  align-items: center;
50
51
  justify-content: center;
51
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
52
+ box-shadow: 0 4px 12px rgba(21, 94, 255, 0.15);
52
53
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
53
54
  padding: 0;
55
+ color: #155eff; /* Icon color matches border */
54
56
  }
55
57
 
56
58
  .feedback-trigger-btn:hover {
57
- box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2);
59
+ background-color: #155eff;
60
+ color: #ffffff;
61
+ box-shadow: 0 6px 20px rgba(21, 94, 255, 0.3);
58
62
  }
59
63
 
60
64
  .feedback-trigger-btn:active {
@@ -65,6 +69,18 @@ export const CSS_STYLES = `
65
69
  flex-shrink: 0;
66
70
  }
67
71
 
72
+ /* Dark theme support */
73
+ .theme-dark .feedback-trigger-btn {
74
+ background-color: #1a1a1a;
75
+ border-color: #155eff;
76
+ color: #155eff;
77
+ }
78
+
79
+ .theme-dark .feedback-trigger-btn:hover {
80
+ background-color: #155eff;
81
+ color: #ffffff;
82
+ }
83
+
68
84
  /* Side Panel Styles */
69
85
  .feedback-panel {
70
86
  position: fixed;