@feedvalue/vue 0.1.7 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -179,6 +179,34 @@ function useReaction(widgetId) {
179
179
  const template = vue.computed(() => {
180
180
  return reactionConfig.value?.template;
181
181
  });
182
+ const styling = vue.computed(() => {
183
+ const defaultStyling = {
184
+ primaryColor: "#6366f1",
185
+ backgroundColor: "#ffffff",
186
+ textColor: "#111827",
187
+ buttonTextColor: "#4b5563",
188
+ borderColor: "#e5e7eb",
189
+ borderWidth: "1",
190
+ borderRadius: "full"
191
+ };
192
+ if (!instance.value || !isReady.value) {
193
+ return defaultStyling;
194
+ }
195
+ const widgetConfig = instance.value._widgetConfig;
196
+ if (!widgetConfig?.styling) {
197
+ return defaultStyling;
198
+ }
199
+ const widgetStyling = widgetConfig.styling;
200
+ return {
201
+ primaryColor: widgetStyling.primaryColor ?? defaultStyling.primaryColor,
202
+ backgroundColor: widgetStyling.backgroundColor ?? defaultStyling.backgroundColor,
203
+ textColor: widgetStyling.textColor ?? defaultStyling.textColor,
204
+ buttonTextColor: widgetStyling.buttonTextColor ?? defaultStyling.buttonTextColor,
205
+ borderColor: widgetStyling.borderColor ?? defaultStyling.borderColor,
206
+ borderWidth: widgetStyling.borderWidth ?? defaultStyling.borderWidth,
207
+ borderRadius: widgetStyling.borderRadius ?? defaultStyling.borderRadius
208
+ };
209
+ });
182
210
  const shouldShowFollowUp = (optionValue) => {
183
211
  if (followUpTrigger.value === "none") return false;
184
212
  if (followUpTrigger.value === "all") return true;
@@ -227,9 +255,24 @@ function useReaction(widgetId) {
227
255
  showLabels,
228
256
  buttonSize,
229
257
  followUpTrigger,
230
- shouldShowFollowUp
258
+ shouldShowFollowUp,
259
+ styling
231
260
  };
232
261
  }
262
+ var borderRadiusMap = {
263
+ full: "9999px",
264
+ lg: "12px",
265
+ md: "8px",
266
+ sm: "4px",
267
+ none: "0px"
268
+ };
269
+ var borderWidthMap = {
270
+ "0": "0px",
271
+ "1": "1px",
272
+ "2": "2px",
273
+ "3": "3px",
274
+ "4": "4px"
275
+ };
233
276
  var sizeStyles = {
234
277
  sm: {
235
278
  button: { padding: "0.375rem 0.75rem", fontSize: "0.75rem", gap: "0.375rem" },
@@ -270,11 +313,6 @@ var styles = {
270
313
  cursor: "pointer",
271
314
  transition: "background-color 0.15s, border-color 0.15s, transform 0.1s"
272
315
  },
273
- buttonActive: {
274
- backgroundColor: "#eef2ff",
275
- borderColor: "#6366f1",
276
- color: "#4f46e5"
277
- },
278
316
  buttonDisabled: {
279
317
  opacity: 0.7,
280
318
  cursor: "not-allowed"
@@ -390,7 +428,8 @@ var ReactionButtons = vue.defineComponent({
390
428
  isReady,
391
429
  showLabels,
392
430
  buttonSize,
393
- shouldShowFollowUp
431
+ shouldShowFollowUp,
432
+ styling
394
433
  } = useReaction(props.widgetId);
395
434
  const followUpText = vue.ref("");
396
435
  const getFollowUpOption = vue.computed(() => {
@@ -427,11 +466,15 @@ var ReactionButtons = vue.defineComponent({
427
466
  return null;
428
467
  }
429
468
  if (submitted.value) {
469
+ const currentStyling2 = styling.value;
430
470
  return vue.h(
431
471
  "div",
432
472
  {
433
473
  class: props.containerClass,
434
- style: styles.thankYou
474
+ style: {
475
+ ...styles.thankYou,
476
+ color: currentStyling2.primaryColor ?? "#059669"
477
+ }
435
478
  },
436
479
  [
437
480
  vue.h("span", props.thankYouMessage || "Thanks for your feedback!"),
@@ -449,12 +492,16 @@ var ReactionButtons = vue.defineComponent({
449
492
  );
450
493
  }
451
494
  const currentSizeStyles = sizeStyles[buttonSize.value] || sizeStyles.md;
495
+ const currentStyling = styling.value;
496
+ const borderRadius = borderRadiusMap[currentStyling.borderRadius ?? "full"] ?? "9999px";
497
+ const borderWidth = borderWidthMap[currentStyling.borderWidth ?? "1"] ?? "1px";
452
498
  const buttonElements = options.value.map((option) => {
499
+ const isActive = showFollowUp.value === option.value;
453
500
  const children = [
454
501
  vue.h("span", { style: { ...styles.icon, ...currentSizeStyles.icon }, "aria-hidden": "true" }, option.icon)
455
502
  ];
456
503
  if (showLabels.value) {
457
- children.push(vue.h("span", { style: currentSizeStyles.label }, option.label));
504
+ children.push(vue.h("span", { style: { ...currentSizeStyles.label, color: currentStyling.buttonTextColor ?? "#4b5563" } }, option.label));
458
505
  }
459
506
  return vue.h(
460
507
  "button",
@@ -465,11 +512,18 @@ var ReactionButtons = vue.defineComponent({
465
512
  style: {
466
513
  ...styles.button,
467
514
  ...currentSizeStyles.button,
468
- ...showFollowUp.value === option.value ? styles.buttonActive : {},
515
+ backgroundColor: currentStyling.backgroundColor ?? "#ffffff",
516
+ borderColor: isActive ? currentStyling.primaryColor ?? "#6366f1" : currentStyling.borderColor ?? "#e5e7eb",
517
+ borderWidth,
518
+ borderRadius,
519
+ color: currentStyling.buttonTextColor ?? "#4b5563",
520
+ ...isActive ? {
521
+ backgroundColor: `${currentStyling.primaryColor ?? "#6366f1"}10`
522
+ } : {},
469
523
  ...isSubmitting.value ? styles.buttonDisabled : {}
470
524
  },
471
525
  disabled: isSubmitting.value,
472
- "aria-pressed": showFollowUp.value === option.value,
526
+ "aria-pressed": isActive,
473
527
  "aria-label": option.label,
474
528
  onClick: () => handleOptionClick(option)
475
529
  },
@@ -497,13 +551,15 @@ var ReactionButtons = vue.defineComponent({
497
551
  followUpText.value = e.target.value;
498
552
  }
499
553
  }),
500
- vue.h("div", { style: styles.actions }, [
554
+ vue.h("div", { style: { ...styles.actions, justifyContent: "center" } }, [
501
555
  vue.h(
502
556
  "button",
503
557
  {
504
558
  type: "submit",
505
559
  style: {
506
560
  ...styles.submitButton,
561
+ backgroundColor: currentStyling.primaryColor ?? "#6366f1",
562
+ borderRadius,
507
563
  ...isSubmitting.value ? styles.buttonDisabled : {}
508
564
  },
509
565
  disabled: isSubmitting.value
@@ -514,7 +570,13 @@ var ReactionButtons = vue.defineComponent({
514
570
  "button",
515
571
  {
516
572
  type: "button",
517
- style: styles.cancelButton,
573
+ style: {
574
+ ...styles.cancelButton,
575
+ backgroundColor: currentStyling.backgroundColor ?? "#ffffff",
576
+ color: currentStyling.buttonTextColor ?? "#6b7280",
577
+ borderRadius,
578
+ border: `${borderWidth} solid ${currentStyling.borderColor ?? "#e5e7eb"}`
579
+ },
518
580
  disabled: isSubmitting.value,
519
581
  onClick: cancelFollowUp
520
582
  },
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/plugin.ts","../src/composables.ts","../src/use-reaction.ts","../src/ReactionButtons.ts"],"names":["FeedValue","inject","shallowRef","ref","onMounted","onUnmounted","readonly","computed","NEGATIVE_OPTIONS_MAP","defineComponent","h"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * @feedvalue/vue - Plugin\n *\n * Vue plugin for FeedValue. Provides app-level configuration\n * and automatic initialization.\n */\n\nimport type { App, InjectionKey } from 'vue';\nimport { FeedValue, type FeedValueConfig, type FeedValueInstance } from '@feedvalue/core';\n\n/**\n * Plugin options\n */\nexport interface FeedValuePluginOptions {\n /** Widget ID from FeedValue dashboard */\n widgetId: string;\n /** API base URL (for self-hosted) */\n apiBaseUrl?: string;\n /** Configuration overrides */\n config?: Partial<FeedValueConfig>;\n /**\n * Headless mode - disables all DOM rendering.\n * Use this when you want full control over the UI.\n * The SDK will still fetch config and provide all API methods\n * but won't render any trigger button or modal.\n *\n * @default false\n */\n headless?: boolean;\n}\n\n/**\n * Injection key for FeedValue instance\n */\nexport const FEEDVALUE_KEY: InjectionKey<FeedValueInstance> = Symbol('feedvalue');\n\n/**\n * Injection key for widget ID (used by useFeedValue when no instance is injected)\n */\nexport const FEEDVALUE_OPTIONS_KEY: InjectionKey<FeedValuePluginOptions> = Symbol('feedvalue-options');\n\n/**\n * Create FeedValue Vue plugin\n *\n * @example\n * ```ts\n * // main.ts\n * import { createApp } from 'vue';\n * import { createFeedValue } from '@feedvalue/vue';\n * import App from './App.vue';\n *\n * const app = createApp(App);\n *\n * app.use(createFeedValue({\n * widgetId: 'your-widget-id',\n * config: { theme: 'dark' }\n * }));\n *\n * app.mount('#app');\n * ```\n */\nexport function createFeedValue(options: FeedValuePluginOptions) {\n let instance: FeedValueInstance | null = null;\n\n return {\n install(app: App) {\n // Only initialize on client side\n if (typeof window !== 'undefined') {\n instance = FeedValue.init({\n widgetId: options.widgetId,\n apiBaseUrl: options.apiBaseUrl,\n config: options.config,\n headless: options.headless,\n });\n\n // Provide instance to all components\n app.provide(FEEDVALUE_KEY, instance);\n\n // Also provide to global properties for Options API access\n app.config.globalProperties.$feedvalue = instance;\n }\n\n // Always provide options (for SSR where we don't initialize)\n app.provide(FEEDVALUE_OPTIONS_KEY, options);\n },\n };\n}\n\n/**\n * Type augmentation for global properties\n */\ndeclare module 'vue' {\n interface ComponentCustomProperties {\n $feedvalue: FeedValueInstance | undefined;\n }\n}\n","/**\n * @feedvalue/vue - Composables\n *\n * Vue composables for FeedValue. Provides reactive state and methods.\n */\n\nimport {\n ref,\n shallowRef,\n readonly,\n onMounted,\n onUnmounted,\n inject,\n type Ref,\n type ShallowRef,\n} from 'vue';\nimport {\n FeedValue,\n type FeedValueConfig,\n type FeedValueInstance,\n type FeedbackData,\n type UserTraits,\n} from '@feedvalue/core';\nimport { FEEDVALUE_KEY, FEEDVALUE_OPTIONS_KEY } from './plugin';\n\n/**\n * Return type for useFeedValue composable\n */\nexport interface UseFeedValueReturn {\n /** FeedValue instance (for advanced usage) */\n instance: Readonly<ShallowRef<FeedValueInstance | null>>;\n /** Widget is ready */\n isReady: Readonly<Ref<boolean>>;\n /** Modal is open */\n isOpen: Readonly<Ref<boolean>>;\n /** Widget is visible */\n isVisible: Readonly<Ref<boolean>>;\n /** Current error */\n error: Readonly<Ref<Error | null>>;\n /** Submission in progress */\n isSubmitting: Readonly<Ref<boolean>>;\n /** Running in headless mode (no default UI rendered) */\n isHeadless: Readonly<Ref<boolean>>;\n /** Open the feedback modal */\n open: () => void;\n /** Close the feedback modal */\n close: () => void;\n /** Toggle the feedback modal */\n toggle: () => void;\n /** Show the trigger button */\n show: () => void;\n /** Hide the trigger button */\n hide: () => void;\n /** Submit feedback programmatically */\n submit: (feedback: Partial<FeedbackData>) => Promise<void>;\n /** Identify user */\n identify: (userId: string, traits?: UserTraits) => void;\n /** Set user data */\n setData: (data: Record<string, string>) => void;\n /** Reset user data */\n reset: () => void;\n}\n\n/**\n * FeedValue composable\n *\n * Can be used with or without plugin. If plugin is installed, uses the\n * provided instance. Otherwise, creates a new instance.\n *\n * @example\n * ```vue\n * <script setup>\n * import { useFeedValue } from '@feedvalue/vue';\n *\n * // With plugin installed\n * const { open, isReady } = useFeedValue();\n *\n * // Or standalone with widgetId\n * const { open, isReady } = useFeedValue('your-widget-id');\n * </script>\n *\n * <template>\n * <button @click=\"open\" :disabled=\"!isReady\">\n * Give Feedback\n * </button>\n * </template>\n * ```\n */\nexport function useFeedValue(\n widgetId?: string,\n config?: Partial<FeedValueConfig>\n): UseFeedValueReturn {\n // Try to inject instance from plugin\n const injectedInstance = inject(FEEDVALUE_KEY, null);\n const injectedOptions = inject(FEEDVALUE_OPTIONS_KEY, null);\n\n // Refs for reactive state\n const instance = shallowRef<FeedValueInstance | null>(null);\n const isReady = ref(false);\n const isOpen = ref(false);\n const isVisible = ref(false);\n const error = ref<Error | null>(null);\n const isSubmitting = ref(false);\n const isHeadless = ref(false);\n\n // Track if we own the instance (need to destroy on unmount)\n let ownsInstance = false;\n let unsubscribe: (() => void) | null = null;\n\n /**\n * Sync reactive state from instance\n */\n const syncState = () => {\n const state = instance.value?.getSnapshot();\n if (state) {\n isReady.value = state.isReady;\n isOpen.value = state.isOpen;\n isVisible.value = state.isVisible;\n error.value = state.error;\n isSubmitting.value = state.isSubmitting;\n }\n };\n\n onMounted(() => {\n // Use injected instance if available and no widgetId override\n if (injectedInstance && !widgetId) {\n instance.value = injectedInstance;\n isHeadless.value = injectedInstance.isHeadless();\n } else {\n // Create new instance\n const effectiveWidgetId = widgetId ?? injectedOptions?.widgetId;\n\n if (!effectiveWidgetId) {\n console.error(\n '[FeedValue] No widgetId provided. Either install the plugin with createFeedValue() ' +\n 'or pass widgetId to useFeedValue().'\n );\n return;\n }\n\n instance.value = FeedValue.init({\n widgetId: effectiveWidgetId,\n apiBaseUrl: injectedOptions?.apiBaseUrl,\n config: config ?? injectedOptions?.config,\n headless: injectedOptions?.headless,\n });\n ownsInstance = true;\n }\n\n // Subscribe to state changes\n if (instance.value) {\n unsubscribe = instance.value.subscribe(syncState);\n isHeadless.value = instance.value.isHeadless();\n syncState(); // Initial sync\n }\n });\n\n onUnmounted(() => {\n unsubscribe?.();\n if (ownsInstance && instance.value) {\n instance.value.destroy();\n }\n instance.value = null;\n });\n\n // Methods that delegate to instance\n const open = () => instance.value?.open();\n const close = () => instance.value?.close();\n const toggle = () => instance.value?.toggle();\n const show = () => instance.value?.show();\n const hide = () => instance.value?.hide();\n const submit = (feedback: Partial<FeedbackData>) =>\n instance.value?.submit(feedback) ?? Promise.reject(new Error('Not initialized'));\n const identify = (userId: string, traits?: UserTraits) =>\n instance.value?.identify(userId, traits);\n const setData = (data: Record<string, string>) => instance.value?.setData(data);\n const reset = () => instance.value?.reset();\n\n return {\n instance: readonly(instance),\n isReady: readonly(isReady),\n isOpen: readonly(isOpen),\n isVisible: readonly(isVisible),\n error: readonly(error),\n isSubmitting: readonly(isSubmitting),\n isHeadless: readonly(isHeadless),\n open,\n close,\n toggle,\n show,\n hide,\n submit,\n identify,\n setData,\n reset,\n };\n}\n","/**\n * @feedvalue/vue - useReaction Composable\n *\n * Composable for reaction widgets in Vue applications.\n * Provides a simple API for submitting reactions.\n */\n\nimport {\n ref,\n computed,\n readonly,\n onMounted,\n onUnmounted,\n inject,\n type Ref,\n type ComputedRef,\n} from 'vue';\nimport {\n FeedValue,\n NEGATIVE_OPTIONS_MAP,\n type ReactionOption,\n type FeedValueInstance,\n type ButtonSize,\n type FollowUpTrigger,\n type ReactionTemplate,\n} from '@feedvalue/core';\nimport { FEEDVALUE_KEY, FEEDVALUE_OPTIONS_KEY } from './plugin';\n\n/**\n * Return type for useReaction composable\n */\nexport interface UseReactionReturn {\n /** Available reaction options */\n options: ComputedRef<ReactionOption[] | null>;\n /** Currently submitting */\n isSubmitting: Readonly<Ref<boolean>>;\n /** Successfully submitted value (null if not yet submitted) */\n submitted: Readonly<Ref<string | null>>;\n /** Error if submission failed */\n error: Readonly<Ref<Error | null>>;\n /** Option value requiring follow-up input (null if none) */\n showFollowUp: Readonly<Ref<string | null>>;\n /** Submit a reaction */\n react: (value: string, followUp?: string) => Promise<void>;\n /** Set which option is showing follow-up input */\n setShowFollowUp: (value: string | null) => void;\n /** Clear the submitted state to allow re-submission */\n clearSubmitted: () => void;\n /** Check if widget is a reaction type */\n isReactionWidget: ComputedRef<boolean>;\n /** Widget configuration is ready */\n isReady: Readonly<Ref<boolean>>;\n /** Whether to show text labels next to icons */\n showLabels: ComputedRef<boolean>;\n /** Button size */\n buttonSize: ComputedRef<ButtonSize>;\n /** When to show follow-up input */\n followUpTrigger: ComputedRef<FollowUpTrigger>;\n /** Check if an option should show follow-up based on followUpTrigger */\n shouldShowFollowUp: (optionValue: string) => boolean;\n}\n\n/**\n * Composable for reaction widgets\n *\n * Provides reaction options, submission handling, and follow-up state management.\n * Can be used with or without the FeedValue plugin.\n *\n * @param widgetId - Optional widget ID override (uses plugin widget if not provided)\n *\n * @example\n * ```vue\n * <script setup>\n * import { useReaction } from '@feedvalue/vue';\n *\n * const {\n * options,\n * react,\n * isSubmitting,\n * submitted,\n * error,\n * showFollowUp,\n * setShowFollowUp,\n * isReady,\n * } = useReaction();\n *\n * const handleClick = (option) => {\n * if (option.showFollowUp) {\n * setShowFollowUp(option.value);\n * } else {\n * react(option.value);\n * }\n * };\n * </script>\n *\n * <template>\n * <div v-if=\"isReady && options\">\n * <div v-if=\"submitted\">Thanks for your feedback!</div>\n *\n * <template v-else>\n * <button\n * v-for=\"option in options\"\n * :key=\"option.value\"\n * @click=\"handleClick(option)\"\n * :disabled=\"isSubmitting\"\n * >\n * {{ option.icon }} {{ option.label }}\n * </button>\n *\n * <form v-if=\"showFollowUp\" @submit.prevent=\"react(showFollowUp, followUpText)\">\n * <input v-model=\"followUpText\" placeholder=\"Tell us more...\" />\n * <button type=\"submit\">Send</button>\n * </form>\n *\n * <div v-if=\"error\">Error: {{ error.message }}</div>\n * </template>\n * </div>\n * </template>\n * ```\n */\nexport function useReaction(widgetId?: string): UseReactionReturn {\n // Try to inject instance from plugin\n const injectedInstance = inject(FEEDVALUE_KEY, null);\n const injectedOptions = inject(FEEDVALUE_OPTIONS_KEY, null);\n\n // Local instance ref (may be created if no plugin or widgetId override)\n const instance = ref<FeedValueInstance | null>(null);\n const isReady = ref(false);\n\n // Local state for reaction UI\n const showFollowUp = ref<string | null>(null);\n const submitted = ref<string | null>(null);\n const isSubmitting = ref(false);\n const error = ref<Error | null>(null);\n\n // Track if we own the instance (need to destroy on unmount)\n let ownsInstance = false;\n let unsubscribe: (() => void) | null = null;\n\n /**\n * Sync ready state from instance\n */\n const syncState = () => {\n const state = instance.value?.getSnapshot();\n if (state) {\n isReady.value = state.isReady;\n }\n };\n\n onMounted(() => {\n // Use injected instance if available and no widgetId override\n if (injectedInstance && !widgetId) {\n instance.value = injectedInstance;\n } else {\n // Create new instance\n const effectiveWidgetId = widgetId ?? injectedOptions?.widgetId;\n\n if (!effectiveWidgetId) {\n console.error(\n '[FeedValue] No widgetId provided. Either install the plugin with createFeedValue() ' +\n 'or pass widgetId to useReaction().'\n );\n return;\n }\n\n instance.value = FeedValue.init({\n widgetId: effectiveWidgetId,\n apiBaseUrl: injectedOptions?.apiBaseUrl,\n config: injectedOptions?.config,\n headless: true, // Reaction widgets are always headless\n });\n ownsInstance = true;\n }\n\n // Subscribe to state changes\n if (instance.value) {\n unsubscribe = instance.value.subscribe(syncState);\n syncState(); // Initial sync\n }\n });\n\n onUnmounted(() => {\n unsubscribe?.();\n if (ownsInstance && instance.value) {\n instance.value.destroy();\n }\n instance.value = null;\n });\n\n // Computed: reaction options from instance\n const options = computed<ReactionOption[] | null>(() => {\n if (!instance.value || !isReady.value) return null;\n return instance.value.getReactionOptions();\n });\n\n // Computed: check if this is a reaction widget\n const isReactionWidget = computed(() => {\n return instance.value?.isReaction() ?? false;\n });\n\n // Computed: get config values with defaults\n const reactionConfig = computed(() => {\n if (!instance.value || !isReady.value) return null;\n // Access the widget config which includes reaction config\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (instance.value as any)._widgetConfig?.config ?? null;\n });\n\n const showLabels = computed(() => {\n return reactionConfig.value?.showLabels ?? true;\n });\n\n const buttonSize = computed<ButtonSize>(() => {\n return reactionConfig.value?.buttonSize ?? 'md';\n });\n\n const followUpTrigger = computed<FollowUpTrigger>(() => {\n return reactionConfig.value?.followUpTrigger ?? 'negative';\n });\n\n const template = computed<ReactionTemplate | undefined>(() => {\n return reactionConfig.value?.template;\n });\n\n /**\n * Check if an option should show follow-up based on followUpTrigger\n */\n const shouldShowFollowUp = (optionValue: string): boolean => {\n if (followUpTrigger.value === 'none') return false;\n if (followUpTrigger.value === 'all') return true;\n // followUpTrigger === 'negative'\n if (template.value && NEGATIVE_OPTIONS_MAP[template.value]) {\n return NEGATIVE_OPTIONS_MAP[template.value].includes(optionValue);\n }\n // For custom options, use the option's own showFollowUp setting\n const option = options.value?.find((o) => o.value === optionValue);\n return option?.showFollowUp ?? false;\n };\n\n /**\n * Submit a reaction\n */\n const react = async (value: string, followUp?: string): Promise<void> => {\n if (!instance.value) {\n throw new Error('FeedValue not initialized');\n }\n\n isSubmitting.value = true;\n error.value = null;\n\n try {\n await instance.value.react(value, followUp ? { followUp } : undefined);\n submitted.value = value;\n showFollowUp.value = null;\n } catch (err) {\n const reactionError = err instanceof Error ? err : new Error(String(err));\n error.value = reactionError;\n throw reactionError;\n } finally {\n isSubmitting.value = false;\n }\n };\n\n /**\n * Set which option is showing follow-up input\n */\n const setShowFollowUp = (value: string | null): void => {\n showFollowUp.value = value;\n };\n\n /**\n * Clear submitted state to allow re-submission\n */\n const clearSubmitted = (): void => {\n submitted.value = null;\n error.value = null;\n };\n\n return {\n options,\n isSubmitting: readonly(isSubmitting),\n submitted: readonly(submitted),\n error: readonly(error),\n showFollowUp: readonly(showFollowUp),\n react,\n setShowFollowUp,\n clearSubmitted,\n isReactionWidget,\n isReady: readonly(isReady),\n showLabels,\n buttonSize,\n followUpTrigger,\n shouldShowFollowUp,\n };\n}\n","/**\n * @feedvalue/vue - ReactionButtons Component\n *\n * Pre-built reaction buttons component for Vue applications.\n * Renders reaction options with optional follow-up input.\n */\n\nimport { defineComponent, ref, computed, h, type PropType } from 'vue';\nimport { useReaction } from './use-reaction';\nimport type { ReactionOption } from '@feedvalue/core';\n\nimport type { ButtonSize } from '@feedvalue/core';\n\n/**\n * Button size style variants\n */\nconst sizeStyles: Record<ButtonSize, { button: Record<string, string>; icon: Record<string, string>; label: Record<string, string> }> = {\n sm: {\n button: { padding: '0.375rem 0.75rem', fontSize: '0.75rem', gap: '0.375rem' },\n icon: { fontSize: '1rem' },\n label: { fontSize: '0.75rem' },\n },\n md: {\n button: { padding: '0.5rem 1rem', fontSize: '0.875rem', gap: '0.5rem' },\n icon: { fontSize: '1.125rem' },\n label: { fontSize: '0.875rem' },\n },\n lg: {\n button: { padding: '0.75rem 1.25rem', fontSize: '1rem', gap: '0.625rem' },\n icon: { fontSize: '1.5rem' },\n label: { fontSize: '1rem' },\n },\n};\n\n/**\n * Default CSS styles for the component\n */\nconst styles = {\n container: {\n display: 'flex',\n flexDirection: 'column' as const,\n gap: '0.75rem',\n fontFamily: 'system-ui, -apple-system, sans-serif',\n },\n buttonGroup: {\n display: 'flex',\n flexWrap: 'wrap' as const,\n gap: '0.5rem',\n },\n button: {\n display: 'inline-flex',\n alignItems: 'center',\n fontWeight: '500',\n color: '#374151',\n backgroundColor: '#ffffff',\n border: '1px solid #d1d5db',\n borderRadius: '9999px',\n cursor: 'pointer',\n transition: 'background-color 0.15s, border-color 0.15s, transform 0.1s',\n },\n buttonActive: {\n backgroundColor: '#eef2ff',\n borderColor: '#6366f1',\n color: '#4f46e5',\n },\n buttonDisabled: {\n opacity: 0.7,\n cursor: 'not-allowed',\n },\n icon: {},\n followUp: {\n display: 'flex',\n flexDirection: 'column' as const,\n gap: '0.5rem',\n padding: '0.75rem',\n backgroundColor: '#f9fafb',\n border: '1px solid #e5e7eb',\n borderRadius: '0.5rem',\n },\n input: {\n width: '100%',\n padding: '0.5rem 0.75rem',\n fontSize: '0.875rem',\n border: '1px solid #d1d5db',\n borderRadius: '0.375rem',\n backgroundColor: '#ffffff',\n boxSizing: 'border-box' as const,\n },\n actions: {\n display: 'flex',\n gap: '0.5rem',\n justifyContent: 'flex-end',\n },\n submitButton: {\n padding: '0.375rem 0.75rem',\n fontSize: '0.875rem',\n fontWeight: '500',\n color: '#ffffff',\n backgroundColor: '#6366f1',\n border: 'none',\n borderRadius: '0.375rem',\n cursor: 'pointer',\n },\n cancelButton: {\n padding: '0.375rem 0.75rem',\n fontSize: '0.875rem',\n color: '#6b7280',\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n },\n thankYou: {\n display: 'flex',\n alignItems: 'center',\n gap: '0.5rem',\n padding: '0.75rem 1rem',\n fontSize: '0.875rem',\n color: '#059669',\n backgroundColor: '#ecfdf5',\n border: '1px solid #a7f3d0',\n borderRadius: '0.5rem',\n },\n resetButton: {\n padding: '0.25rem 0.5rem',\n fontSize: '0.875rem',\n color: '#6b7280',\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n },\n error: {\n padding: '0.5rem 0.75rem',\n fontSize: '0.875rem',\n color: '#dc2626',\n backgroundColor: '#fef2f2',\n border: '1px solid #fecaca',\n borderRadius: '0.375rem',\n },\n};\n\n/**\n * ReactionButtons Component\n *\n * Pre-built reaction buttons with follow-up input support.\n *\n * @example\n * ```vue\n * <template>\n * <ReactionButtons widget-id=\"xxx\" @react=\"onReact\" />\n * </template>\n *\n * <script setup>\n * import { ReactionButtons } from '@feedvalue/vue';\n *\n * const onReact = (value, followUp) => {\n * console.log('Reacted:', value, followUp);\n * };\n * </script>\n * ```\n */\nexport const ReactionButtons = defineComponent({\n name: 'ReactionButtons',\n\n props: {\n /** Widget ID (optional if using FeedValue plugin) */\n widgetId: {\n type: String as PropType<string | undefined>,\n default: undefined,\n },\n /** Custom thank you message (overrides widget config) */\n thankYouMessage: {\n type: String as PropType<string | undefined>,\n default: undefined,\n },\n /** Custom class for the container */\n containerClass: {\n type: String,\n default: '',\n },\n /** Custom class for buttons */\n buttonClass: {\n type: String,\n default: '',\n },\n },\n\n emits: {\n /** Emitted when a reaction is submitted */\n react: (value: string, _followUp?: string) => typeof value === 'string',\n },\n\n setup(props, { emit }) {\n const {\n options,\n react,\n isSubmitting,\n submitted,\n error,\n showFollowUp,\n setShowFollowUp,\n clearSubmitted,\n isReady,\n showLabels,\n buttonSize,\n shouldShowFollowUp,\n } = useReaction(props.widgetId);\n\n // Local state for follow-up input\n const followUpText = ref('');\n\n // Get follow-up option\n const getFollowUpOption = computed<ReactionOption | null>(() => {\n if (!showFollowUp.value || !options.value) return null;\n return options.value.find((opt) => opt.value === showFollowUp.value) ?? null;\n });\n\n /**\n * Handle option click\n */\n const handleOptionClick = (option: ReactionOption) => {\n if (shouldShowFollowUp(option.value)) {\n setShowFollowUp(option.value);\n } else {\n submitReaction(option.value);\n }\n };\n\n /**\n * Submit reaction\n */\n const submitReaction = async (value: string, followUp?: string) => {\n try {\n await react(value, followUp);\n emit('react', value, followUp);\n } catch {\n // Error is already set in state\n }\n };\n\n /**\n * Handle follow-up form submit\n */\n const handleFollowUpSubmit = (e: Event) => {\n e.preventDefault();\n if (showFollowUp.value) {\n submitReaction(showFollowUp.value, followUpText.value || undefined);\n followUpText.value = '';\n }\n };\n\n /**\n * Cancel follow-up\n */\n const cancelFollowUp = () => {\n setShowFollowUp(null);\n followUpText.value = '';\n };\n\n return () => {\n // Don't render if not ready or no options\n if (!isReady.value || !options.value) {\n return null;\n }\n\n // Render thank you message after submission\n if (submitted.value) {\n return h(\n 'div',\n {\n class: props.containerClass,\n style: styles.thankYou,\n },\n [\n h('span', props.thankYouMessage || 'Thanks for your feedback!'),\n h(\n 'button',\n {\n type: 'button',\n style: styles.resetButton,\n onClick: clearSubmitted,\n 'aria-label': 'Submit another reaction',\n },\n '↺'\n ),\n ]\n );\n }\n\n // Build reaction buttons\n const currentSizeStyles = sizeStyles[buttonSize.value] || sizeStyles.md;\n const buttonElements = options.value.map((option) => {\n const children = [\n h('span', { style: { ...styles.icon, ...currentSizeStyles.icon }, 'aria-hidden': 'true' }, option.icon),\n ];\n if (showLabels.value) {\n children.push(h('span', { style: currentSizeStyles.label }, option.label));\n }\n\n return h(\n 'button',\n {\n key: option.value,\n type: 'button',\n class: props.buttonClass,\n style: {\n ...styles.button,\n ...currentSizeStyles.button,\n ...(showFollowUp.value === option.value ? styles.buttonActive : {}),\n ...(isSubmitting.value ? styles.buttonDisabled : {}),\n },\n disabled: isSubmitting.value,\n 'aria-pressed': showFollowUp.value === option.value,\n 'aria-label': option.label,\n onClick: () => handleOptionClick(option),\n },\n children\n );\n });\n\n // Build follow-up form if needed\n let followUpForm = null;\n const followUpOption = getFollowUpOption.value;\n if (showFollowUp.value && followUpOption) {\n followUpForm = h(\n 'form',\n {\n style: styles.followUp,\n onSubmit: handleFollowUpSubmit,\n },\n [\n h('input', {\n type: 'text',\n style: styles.input,\n value: followUpText.value,\n placeholder: followUpOption.followUpPlaceholder || 'Tell us more...',\n disabled: isSubmitting.value,\n maxlength: 500,\n onInput: (e: Event) => {\n followUpText.value = (e.target as HTMLInputElement).value;\n },\n }),\n h('div', { style: styles.actions }, [\n h(\n 'button',\n {\n type: 'submit',\n style: {\n ...styles.submitButton,\n ...(isSubmitting.value ? styles.buttonDisabled : {}),\n },\n disabled: isSubmitting.value,\n },\n isSubmitting.value ? 'Sending...' : 'Send'\n ),\n h(\n 'button',\n {\n type: 'button',\n style: styles.cancelButton,\n disabled: isSubmitting.value,\n onClick: cancelFollowUp,\n },\n 'Cancel'\n ),\n ]),\n ]\n );\n }\n\n // Build error message\n let errorElement = null;\n if (error.value) {\n errorElement = h(\n 'div',\n { style: styles.error, role: 'alert' },\n error.value.message\n );\n }\n\n // Return full component\n return h(\n 'div',\n {\n class: props.containerClass,\n style: styles.container,\n role: 'group',\n 'aria-label': 'Reaction buttons',\n },\n [\n h('div', { style: styles.buttonGroup, role: 'radiogroup' }, buttonElements),\n followUpForm,\n errorElement,\n ]\n );\n };\n },\n});\n\nexport default ReactionButtons;\n"]}
1
+ {"version":3,"sources":["../src/plugin.ts","../src/composables.ts","../src/use-reaction.ts","../src/ReactionButtons.ts"],"names":["FeedValue","inject","shallowRef","ref","onMounted","onUnmounted","readonly","computed","NEGATIVE_OPTIONS_MAP","defineComponent","currentStyling","h"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * @feedvalue/vue - Plugin\n *\n * Vue plugin for FeedValue. Provides app-level configuration\n * and automatic initialization.\n */\n\nimport type { App, InjectionKey } from 'vue';\nimport { FeedValue, type FeedValueConfig, type FeedValueInstance } from '@feedvalue/core';\n\n/**\n * Plugin options\n */\nexport interface FeedValuePluginOptions {\n /** Widget ID from FeedValue dashboard */\n widgetId: string;\n /** API base URL (for self-hosted) */\n apiBaseUrl?: string;\n /** Configuration overrides */\n config?: Partial<FeedValueConfig>;\n /**\n * Headless mode - disables all DOM rendering.\n * Use this when you want full control over the UI.\n * The SDK will still fetch config and provide all API methods\n * but won't render any trigger button or modal.\n *\n * @default false\n */\n headless?: boolean;\n}\n\n/**\n * Injection key for FeedValue instance\n */\nexport const FEEDVALUE_KEY: InjectionKey<FeedValueInstance> = Symbol('feedvalue');\n\n/**\n * Injection key for widget ID (used by useFeedValue when no instance is injected)\n */\nexport const FEEDVALUE_OPTIONS_KEY: InjectionKey<FeedValuePluginOptions> = Symbol('feedvalue-options');\n\n/**\n * Create FeedValue Vue plugin\n *\n * @example\n * ```ts\n * // main.ts\n * import { createApp } from 'vue';\n * import { createFeedValue } from '@feedvalue/vue';\n * import App from './App.vue';\n *\n * const app = createApp(App);\n *\n * app.use(createFeedValue({\n * widgetId: 'your-widget-id',\n * config: { theme: 'dark' }\n * }));\n *\n * app.mount('#app');\n * ```\n */\nexport function createFeedValue(options: FeedValuePluginOptions) {\n let instance: FeedValueInstance | null = null;\n\n return {\n install(app: App) {\n // Only initialize on client side\n if (typeof window !== 'undefined') {\n instance = FeedValue.init({\n widgetId: options.widgetId,\n apiBaseUrl: options.apiBaseUrl,\n config: options.config,\n headless: options.headless,\n });\n\n // Provide instance to all components\n app.provide(FEEDVALUE_KEY, instance);\n\n // Also provide to global properties for Options API access\n app.config.globalProperties.$feedvalue = instance;\n }\n\n // Always provide options (for SSR where we don't initialize)\n app.provide(FEEDVALUE_OPTIONS_KEY, options);\n },\n };\n}\n\n/**\n * Type augmentation for global properties\n */\ndeclare module 'vue' {\n interface ComponentCustomProperties {\n $feedvalue: FeedValueInstance | undefined;\n }\n}\n","/**\n * @feedvalue/vue - Composables\n *\n * Vue composables for FeedValue. Provides reactive state and methods.\n */\n\nimport {\n ref,\n shallowRef,\n readonly,\n onMounted,\n onUnmounted,\n inject,\n type Ref,\n type ShallowRef,\n} from 'vue';\nimport {\n FeedValue,\n type FeedValueConfig,\n type FeedValueInstance,\n type FeedbackData,\n type UserTraits,\n} from '@feedvalue/core';\nimport { FEEDVALUE_KEY, FEEDVALUE_OPTIONS_KEY } from './plugin';\n\n/**\n * Return type for useFeedValue composable\n */\nexport interface UseFeedValueReturn {\n /** FeedValue instance (for advanced usage) */\n instance: Readonly<ShallowRef<FeedValueInstance | null>>;\n /** Widget is ready */\n isReady: Readonly<Ref<boolean>>;\n /** Modal is open */\n isOpen: Readonly<Ref<boolean>>;\n /** Widget is visible */\n isVisible: Readonly<Ref<boolean>>;\n /** Current error */\n error: Readonly<Ref<Error | null>>;\n /** Submission in progress */\n isSubmitting: Readonly<Ref<boolean>>;\n /** Running in headless mode (no default UI rendered) */\n isHeadless: Readonly<Ref<boolean>>;\n /** Open the feedback modal */\n open: () => void;\n /** Close the feedback modal */\n close: () => void;\n /** Toggle the feedback modal */\n toggle: () => void;\n /** Show the trigger button */\n show: () => void;\n /** Hide the trigger button */\n hide: () => void;\n /** Submit feedback programmatically */\n submit: (feedback: Partial<FeedbackData>) => Promise<void>;\n /** Identify user */\n identify: (userId: string, traits?: UserTraits) => void;\n /** Set user data */\n setData: (data: Record<string, string>) => void;\n /** Reset user data */\n reset: () => void;\n}\n\n/**\n * FeedValue composable\n *\n * Can be used with or without plugin. If plugin is installed, uses the\n * provided instance. Otherwise, creates a new instance.\n *\n * @example\n * ```vue\n * <script setup>\n * import { useFeedValue } from '@feedvalue/vue';\n *\n * // With plugin installed\n * const { open, isReady } = useFeedValue();\n *\n * // Or standalone with widgetId\n * const { open, isReady } = useFeedValue('your-widget-id');\n * </script>\n *\n * <template>\n * <button @click=\"open\" :disabled=\"!isReady\">\n * Give Feedback\n * </button>\n * </template>\n * ```\n */\nexport function useFeedValue(\n widgetId?: string,\n config?: Partial<FeedValueConfig>\n): UseFeedValueReturn {\n // Try to inject instance from plugin\n const injectedInstance = inject(FEEDVALUE_KEY, null);\n const injectedOptions = inject(FEEDVALUE_OPTIONS_KEY, null);\n\n // Refs for reactive state\n const instance = shallowRef<FeedValueInstance | null>(null);\n const isReady = ref(false);\n const isOpen = ref(false);\n const isVisible = ref(false);\n const error = ref<Error | null>(null);\n const isSubmitting = ref(false);\n const isHeadless = ref(false);\n\n // Track if we own the instance (need to destroy on unmount)\n let ownsInstance = false;\n let unsubscribe: (() => void) | null = null;\n\n /**\n * Sync reactive state from instance\n */\n const syncState = () => {\n const state = instance.value?.getSnapshot();\n if (state) {\n isReady.value = state.isReady;\n isOpen.value = state.isOpen;\n isVisible.value = state.isVisible;\n error.value = state.error;\n isSubmitting.value = state.isSubmitting;\n }\n };\n\n onMounted(() => {\n // Use injected instance if available and no widgetId override\n if (injectedInstance && !widgetId) {\n instance.value = injectedInstance;\n isHeadless.value = injectedInstance.isHeadless();\n } else {\n // Create new instance\n const effectiveWidgetId = widgetId ?? injectedOptions?.widgetId;\n\n if (!effectiveWidgetId) {\n console.error(\n '[FeedValue] No widgetId provided. Either install the plugin with createFeedValue() ' +\n 'or pass widgetId to useFeedValue().'\n );\n return;\n }\n\n instance.value = FeedValue.init({\n widgetId: effectiveWidgetId,\n apiBaseUrl: injectedOptions?.apiBaseUrl,\n config: config ?? injectedOptions?.config,\n headless: injectedOptions?.headless,\n });\n ownsInstance = true;\n }\n\n // Subscribe to state changes\n if (instance.value) {\n unsubscribe = instance.value.subscribe(syncState);\n isHeadless.value = instance.value.isHeadless();\n syncState(); // Initial sync\n }\n });\n\n onUnmounted(() => {\n unsubscribe?.();\n if (ownsInstance && instance.value) {\n instance.value.destroy();\n }\n instance.value = null;\n });\n\n // Methods that delegate to instance\n const open = () => instance.value?.open();\n const close = () => instance.value?.close();\n const toggle = () => instance.value?.toggle();\n const show = () => instance.value?.show();\n const hide = () => instance.value?.hide();\n const submit = (feedback: Partial<FeedbackData>) =>\n instance.value?.submit(feedback) ?? Promise.reject(new Error('Not initialized'));\n const identify = (userId: string, traits?: UserTraits) =>\n instance.value?.identify(userId, traits);\n const setData = (data: Record<string, string>) => instance.value?.setData(data);\n const reset = () => instance.value?.reset();\n\n return {\n instance: readonly(instance),\n isReady: readonly(isReady),\n isOpen: readonly(isOpen),\n isVisible: readonly(isVisible),\n error: readonly(error),\n isSubmitting: readonly(isSubmitting),\n isHeadless: readonly(isHeadless),\n open,\n close,\n toggle,\n show,\n hide,\n submit,\n identify,\n setData,\n reset,\n };\n}\n","/**\n * @feedvalue/vue - useReaction Composable\n *\n * Composable for reaction widgets in Vue applications.\n * Provides a simple API for submitting reactions.\n */\n\nimport {\n ref,\n computed,\n readonly,\n onMounted,\n onUnmounted,\n inject,\n type Ref,\n type ComputedRef,\n} from 'vue';\nimport {\n FeedValue,\n NEGATIVE_OPTIONS_MAP,\n type ReactionOption,\n type FeedValueInstance,\n type ButtonSize,\n type FollowUpTrigger,\n type ReactionTemplate,\n type ReactionStyling,\n} from '@feedvalue/core';\nimport { FEEDVALUE_KEY, FEEDVALUE_OPTIONS_KEY } from './plugin';\n\n/**\n * Return type for useReaction composable\n */\nexport interface UseReactionReturn {\n /** Available reaction options */\n options: ComputedRef<ReactionOption[] | null>;\n /** Currently submitting */\n isSubmitting: Readonly<Ref<boolean>>;\n /** Successfully submitted value (null if not yet submitted) */\n submitted: Readonly<Ref<string | null>>;\n /** Error if submission failed */\n error: Readonly<Ref<Error | null>>;\n /** Option value requiring follow-up input (null if none) */\n showFollowUp: Readonly<Ref<string | null>>;\n /** Submit a reaction */\n react: (value: string, followUp?: string) => Promise<void>;\n /** Set which option is showing follow-up input */\n setShowFollowUp: (value: string | null) => void;\n /** Clear the submitted state to allow re-submission */\n clearSubmitted: () => void;\n /** Check if widget is a reaction type */\n isReactionWidget: ComputedRef<boolean>;\n /** Widget configuration is ready */\n isReady: Readonly<Ref<boolean>>;\n /** Whether to show text labels next to icons */\n showLabels: ComputedRef<boolean>;\n /** Button size */\n buttonSize: ComputedRef<ButtonSize>;\n /** When to show follow-up input */\n followUpTrigger: ComputedRef<FollowUpTrigger>;\n /** Check if an option should show follow-up based on followUpTrigger */\n shouldShowFollowUp: (optionValue: string) => boolean;\n /** Widget styling configuration */\n styling: ComputedRef<ReactionStyling>;\n}\n\n/**\n * Composable for reaction widgets\n *\n * Provides reaction options, submission handling, and follow-up state management.\n * Can be used with or without the FeedValue plugin.\n *\n * @param widgetId - Optional widget ID override (uses plugin widget if not provided)\n *\n * @example\n * ```vue\n * <script setup>\n * import { useReaction } from '@feedvalue/vue';\n *\n * const {\n * options,\n * react,\n * isSubmitting,\n * submitted,\n * error,\n * showFollowUp,\n * setShowFollowUp,\n * isReady,\n * } = useReaction();\n *\n * const handleClick = (option) => {\n * if (option.showFollowUp) {\n * setShowFollowUp(option.value);\n * } else {\n * react(option.value);\n * }\n * };\n * </script>\n *\n * <template>\n * <div v-if=\"isReady && options\">\n * <div v-if=\"submitted\">Thanks for your feedback!</div>\n *\n * <template v-else>\n * <button\n * v-for=\"option in options\"\n * :key=\"option.value\"\n * @click=\"handleClick(option)\"\n * :disabled=\"isSubmitting\"\n * >\n * {{ option.icon }} {{ option.label }}\n * </button>\n *\n * <form v-if=\"showFollowUp\" @submit.prevent=\"react(showFollowUp, followUpText)\">\n * <input v-model=\"followUpText\" placeholder=\"Tell us more...\" />\n * <button type=\"submit\">Send</button>\n * </form>\n *\n * <div v-if=\"error\">Error: {{ error.message }}</div>\n * </template>\n * </div>\n * </template>\n * ```\n */\nexport function useReaction(widgetId?: string): UseReactionReturn {\n // Try to inject instance from plugin\n const injectedInstance = inject(FEEDVALUE_KEY, null);\n const injectedOptions = inject(FEEDVALUE_OPTIONS_KEY, null);\n\n // Local instance ref (may be created if no plugin or widgetId override)\n const instance = ref<FeedValueInstance | null>(null);\n const isReady = ref(false);\n\n // Local state for reaction UI\n const showFollowUp = ref<string | null>(null);\n const submitted = ref<string | null>(null);\n const isSubmitting = ref(false);\n const error = ref<Error | null>(null);\n\n // Track if we own the instance (need to destroy on unmount)\n let ownsInstance = false;\n let unsubscribe: (() => void) | null = null;\n\n /**\n * Sync ready state from instance\n */\n const syncState = () => {\n const state = instance.value?.getSnapshot();\n if (state) {\n isReady.value = state.isReady;\n }\n };\n\n onMounted(() => {\n // Use injected instance if available and no widgetId override\n if (injectedInstance && !widgetId) {\n instance.value = injectedInstance;\n } else {\n // Create new instance\n const effectiveWidgetId = widgetId ?? injectedOptions?.widgetId;\n\n if (!effectiveWidgetId) {\n console.error(\n '[FeedValue] No widgetId provided. Either install the plugin with createFeedValue() ' +\n 'or pass widgetId to useReaction().'\n );\n return;\n }\n\n instance.value = FeedValue.init({\n widgetId: effectiveWidgetId,\n apiBaseUrl: injectedOptions?.apiBaseUrl,\n config: injectedOptions?.config,\n headless: true, // Reaction widgets are always headless\n });\n ownsInstance = true;\n }\n\n // Subscribe to state changes\n if (instance.value) {\n unsubscribe = instance.value.subscribe(syncState);\n syncState(); // Initial sync\n }\n });\n\n onUnmounted(() => {\n unsubscribe?.();\n if (ownsInstance && instance.value) {\n instance.value.destroy();\n }\n instance.value = null;\n });\n\n // Computed: reaction options from instance\n const options = computed<ReactionOption[] | null>(() => {\n if (!instance.value || !isReady.value) return null;\n return instance.value.getReactionOptions();\n });\n\n // Computed: check if this is a reaction widget\n const isReactionWidget = computed(() => {\n return instance.value?.isReaction() ?? false;\n });\n\n // Computed: get config values with defaults\n const reactionConfig = computed(() => {\n if (!instance.value || !isReady.value) return null;\n // Access the widget config which includes reaction config\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (instance.value as any)._widgetConfig?.config ?? null;\n });\n\n const showLabels = computed(() => {\n return reactionConfig.value?.showLabels ?? true;\n });\n\n const buttonSize = computed<ButtonSize>(() => {\n return reactionConfig.value?.buttonSize ?? 'md';\n });\n\n const followUpTrigger = computed<FollowUpTrigger>(() => {\n return reactionConfig.value?.followUpTrigger ?? 'negative';\n });\n\n const template = computed<ReactionTemplate | undefined>(() => {\n return reactionConfig.value?.template;\n });\n\n // Computed: widget styling configuration\n const styling = computed<ReactionStyling>(() => {\n const defaultStyling: ReactionStyling = {\n primaryColor: '#6366f1',\n backgroundColor: '#ffffff',\n textColor: '#111827',\n buttonTextColor: '#4b5563',\n borderColor: '#e5e7eb',\n borderWidth: '1',\n borderRadius: 'full',\n };\n\n if (!instance.value || !isReady.value) {\n return defaultStyling;\n }\n\n // Access the widget config styling\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const widgetConfig = (instance.value as any)._widgetConfig;\n if (!widgetConfig?.styling) {\n return defaultStyling;\n }\n\n // Cast styling to access extended properties that may be present from API\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const widgetStyling = widgetConfig.styling as any;\n return {\n primaryColor: widgetStyling.primaryColor ?? defaultStyling.primaryColor,\n backgroundColor: widgetStyling.backgroundColor ?? defaultStyling.backgroundColor,\n textColor: widgetStyling.textColor ?? defaultStyling.textColor,\n buttonTextColor: widgetStyling.buttonTextColor ?? defaultStyling.buttonTextColor,\n borderColor: widgetStyling.borderColor ?? defaultStyling.borderColor,\n borderWidth: widgetStyling.borderWidth ?? defaultStyling.borderWidth,\n borderRadius: widgetStyling.borderRadius ?? defaultStyling.borderRadius,\n };\n });\n\n /**\n * Check if an option should show follow-up based on followUpTrigger\n */\n const shouldShowFollowUp = (optionValue: string): boolean => {\n if (followUpTrigger.value === 'none') return false;\n if (followUpTrigger.value === 'all') return true;\n // followUpTrigger === 'negative'\n if (template.value && NEGATIVE_OPTIONS_MAP[template.value]) {\n return NEGATIVE_OPTIONS_MAP[template.value].includes(optionValue);\n }\n // For custom options, use the option's own showFollowUp setting\n const option = options.value?.find((o) => o.value === optionValue);\n return option?.showFollowUp ?? false;\n };\n\n /**\n * Submit a reaction\n */\n const react = async (value: string, followUp?: string): Promise<void> => {\n if (!instance.value) {\n throw new Error('FeedValue not initialized');\n }\n\n isSubmitting.value = true;\n error.value = null;\n\n try {\n await instance.value.react(value, followUp ? { followUp } : undefined);\n submitted.value = value;\n showFollowUp.value = null;\n } catch (err) {\n const reactionError = err instanceof Error ? err : new Error(String(err));\n error.value = reactionError;\n throw reactionError;\n } finally {\n isSubmitting.value = false;\n }\n };\n\n /**\n * Set which option is showing follow-up input\n */\n const setShowFollowUp = (value: string | null): void => {\n showFollowUp.value = value;\n };\n\n /**\n * Clear submitted state to allow re-submission\n */\n const clearSubmitted = (): void => {\n submitted.value = null;\n error.value = null;\n };\n\n return {\n options,\n isSubmitting: readonly(isSubmitting),\n submitted: readonly(submitted),\n error: readonly(error),\n showFollowUp: readonly(showFollowUp),\n react,\n setShowFollowUp,\n clearSubmitted,\n isReactionWidget,\n isReady: readonly(isReady),\n showLabels,\n buttonSize,\n followUpTrigger,\n shouldShowFollowUp,\n styling,\n };\n}\n","/**\n * @feedvalue/vue - ReactionButtons Component\n *\n * Pre-built reaction buttons component for Vue applications.\n * Renders reaction options with optional follow-up input.\n */\n\nimport { defineComponent, ref, computed, h, type PropType } from 'vue';\nimport { useReaction } from './use-reaction';\nimport type { ReactionOption } from '@feedvalue/core';\n\nimport type { ButtonSize, ReactionBorderRadius, ReactionBorderWidth } from '@feedvalue/core';\n\n/**\n * Border radius mapping from preset to CSS value\n */\nconst borderRadiusMap: Record<ReactionBorderRadius, string> = {\n full: '9999px',\n lg: '12px',\n md: '8px',\n sm: '4px',\n none: '0px',\n};\n\n/**\n * Border width mapping from preset to CSS value\n */\nconst borderWidthMap: Record<ReactionBorderWidth, string> = {\n '0': '0px',\n '1': '1px',\n '2': '2px',\n '3': '3px',\n '4': '4px',\n};\n\n/**\n * Button size style variants\n */\nconst sizeStyles: Record<ButtonSize, { button: Record<string, string>; icon: Record<string, string>; label: Record<string, string> }> = {\n sm: {\n button: { padding: '0.375rem 0.75rem', fontSize: '0.75rem', gap: '0.375rem' },\n icon: { fontSize: '1rem' },\n label: { fontSize: '0.75rem' },\n },\n md: {\n button: { padding: '0.5rem 1rem', fontSize: '0.875rem', gap: '0.5rem' },\n icon: { fontSize: '1.125rem' },\n label: { fontSize: '0.875rem' },\n },\n lg: {\n button: { padding: '0.75rem 1.25rem', fontSize: '1rem', gap: '0.625rem' },\n icon: { fontSize: '1.5rem' },\n label: { fontSize: '1rem' },\n },\n};\n\n/**\n * Default CSS styles for the component\n */\nconst styles = {\n container: {\n display: 'flex',\n flexDirection: 'column' as const,\n gap: '0.75rem',\n fontFamily: 'system-ui, -apple-system, sans-serif',\n },\n buttonGroup: {\n display: 'flex',\n flexWrap: 'wrap' as const,\n gap: '0.5rem',\n },\n button: {\n display: 'inline-flex',\n alignItems: 'center',\n fontWeight: '500',\n color: '#374151',\n backgroundColor: '#ffffff',\n border: '1px solid #d1d5db',\n borderRadius: '9999px',\n cursor: 'pointer',\n transition: 'background-color 0.15s, border-color 0.15s, transform 0.1s',\n },\n buttonActive: {\n backgroundColor: '#eef2ff',\n borderColor: '#6366f1',\n color: '#4f46e5',\n },\n buttonDisabled: {\n opacity: 0.7,\n cursor: 'not-allowed',\n },\n icon: {},\n followUp: {\n display: 'flex',\n flexDirection: 'column' as const,\n gap: '0.5rem',\n padding: '0.75rem',\n backgroundColor: '#f9fafb',\n border: '1px solid #e5e7eb',\n borderRadius: '0.5rem',\n },\n input: {\n width: '100%',\n padding: '0.5rem 0.75rem',\n fontSize: '0.875rem',\n border: '1px solid #d1d5db',\n borderRadius: '0.375rem',\n backgroundColor: '#ffffff',\n boxSizing: 'border-box' as const,\n },\n actions: {\n display: 'flex',\n gap: '0.5rem',\n justifyContent: 'flex-end',\n },\n submitButton: {\n padding: '0.375rem 0.75rem',\n fontSize: '0.875rem',\n fontWeight: '500',\n color: '#ffffff',\n backgroundColor: '#6366f1',\n border: 'none',\n borderRadius: '0.375rem',\n cursor: 'pointer',\n },\n cancelButton: {\n padding: '0.375rem 0.75rem',\n fontSize: '0.875rem',\n color: '#6b7280',\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n },\n thankYou: {\n display: 'flex',\n alignItems: 'center',\n gap: '0.5rem',\n padding: '0.75rem 1rem',\n fontSize: '0.875rem',\n color: '#059669',\n backgroundColor: '#ecfdf5',\n border: '1px solid #a7f3d0',\n borderRadius: '0.5rem',\n },\n resetButton: {\n padding: '0.25rem 0.5rem',\n fontSize: '0.875rem',\n color: '#6b7280',\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n },\n error: {\n padding: '0.5rem 0.75rem',\n fontSize: '0.875rem',\n color: '#dc2626',\n backgroundColor: '#fef2f2',\n border: '1px solid #fecaca',\n borderRadius: '0.375rem',\n },\n};\n\n/**\n * ReactionButtons Component\n *\n * Pre-built reaction buttons with follow-up input support.\n *\n * @example\n * ```vue\n * <template>\n * <ReactionButtons widget-id=\"xxx\" @react=\"onReact\" />\n * </template>\n *\n * <script setup>\n * import { ReactionButtons } from '@feedvalue/vue';\n *\n * const onReact = (value, followUp) => {\n * console.log('Reacted:', value, followUp);\n * };\n * </script>\n * ```\n */\nexport const ReactionButtons = defineComponent({\n name: 'ReactionButtons',\n\n props: {\n /** Widget ID (optional if using FeedValue plugin) */\n widgetId: {\n type: String as PropType<string | undefined>,\n default: undefined,\n },\n /** Custom thank you message (overrides widget config) */\n thankYouMessage: {\n type: String as PropType<string | undefined>,\n default: undefined,\n },\n /** Custom class for the container */\n containerClass: {\n type: String,\n default: '',\n },\n /** Custom class for buttons */\n buttonClass: {\n type: String,\n default: '',\n },\n },\n\n emits: {\n /** Emitted when a reaction is submitted */\n react: (value: string, _followUp?: string) => typeof value === 'string',\n },\n\n setup(props, { emit }) {\n const {\n options,\n react,\n isSubmitting,\n submitted,\n error,\n showFollowUp,\n setShowFollowUp,\n clearSubmitted,\n isReady,\n showLabels,\n buttonSize,\n shouldShowFollowUp,\n styling,\n } = useReaction(props.widgetId);\n\n // Local state for follow-up input\n const followUpText = ref('');\n\n // Get follow-up option\n const getFollowUpOption = computed<ReactionOption | null>(() => {\n if (!showFollowUp.value || !options.value) return null;\n return options.value.find((opt) => opt.value === showFollowUp.value) ?? null;\n });\n\n /**\n * Handle option click\n */\n const handleOptionClick = (option: ReactionOption) => {\n if (shouldShowFollowUp(option.value)) {\n setShowFollowUp(option.value);\n } else {\n submitReaction(option.value);\n }\n };\n\n /**\n * Submit reaction\n */\n const submitReaction = async (value: string, followUp?: string) => {\n try {\n await react(value, followUp);\n emit('react', value, followUp);\n } catch {\n // Error is already set in state\n }\n };\n\n /**\n * Handle follow-up form submit\n */\n const handleFollowUpSubmit = (e: Event) => {\n e.preventDefault();\n if (showFollowUp.value) {\n submitReaction(showFollowUp.value, followUpText.value || undefined);\n followUpText.value = '';\n }\n };\n\n /**\n * Cancel follow-up\n */\n const cancelFollowUp = () => {\n setShowFollowUp(null);\n followUpText.value = '';\n };\n\n return () => {\n // Don't render if not ready or no options\n if (!isReady.value || !options.value) {\n return null;\n }\n\n // Render thank you message after submission\n if (submitted.value) {\n const currentStyling = styling.value;\n return h(\n 'div',\n {\n class: props.containerClass,\n style: {\n ...styles.thankYou,\n color: currentStyling.primaryColor ?? '#059669',\n },\n },\n [\n h('span', props.thankYouMessage || 'Thanks for your feedback!'),\n h(\n 'button',\n {\n type: 'button',\n style: styles.resetButton,\n onClick: clearSubmitted,\n 'aria-label': 'Submit another reaction',\n },\n '↺'\n ),\n ]\n );\n }\n\n // Build reaction buttons using styling from widget config\n const currentSizeStyles = sizeStyles[buttonSize.value] || sizeStyles.md;\n const currentStyling = styling.value;\n const borderRadius = borderRadiusMap[currentStyling.borderRadius ?? 'full'] ?? '9999px';\n const borderWidth = borderWidthMap[currentStyling.borderWidth ?? '1'] ?? '1px';\n\n const buttonElements = options.value.map((option) => {\n const isActive = showFollowUp.value === option.value;\n const children = [\n h('span', { style: { ...styles.icon, ...currentSizeStyles.icon }, 'aria-hidden': 'true' }, option.icon),\n ];\n if (showLabels.value) {\n children.push(h('span', { style: { ...currentSizeStyles.label, color: currentStyling.buttonTextColor ?? '#4b5563' } }, option.label));\n }\n\n return h(\n 'button',\n {\n key: option.value,\n type: 'button',\n class: props.buttonClass,\n style: {\n ...styles.button,\n ...currentSizeStyles.button,\n backgroundColor: currentStyling.backgroundColor ?? '#ffffff',\n borderColor: isActive ? (currentStyling.primaryColor ?? '#6366f1') : (currentStyling.borderColor ?? '#e5e7eb'),\n borderWidth: borderWidth,\n borderRadius: borderRadius,\n color: currentStyling.buttonTextColor ?? '#4b5563',\n ...(isActive ? {\n backgroundColor: `${currentStyling.primaryColor ?? '#6366f1'}10`,\n } : {}),\n ...(isSubmitting.value ? styles.buttonDisabled : {}),\n },\n disabled: isSubmitting.value,\n 'aria-pressed': isActive,\n 'aria-label': option.label,\n onClick: () => handleOptionClick(option),\n },\n children\n );\n });\n\n // Build follow-up form if needed\n let followUpForm = null;\n const followUpOption = getFollowUpOption.value;\n if (showFollowUp.value && followUpOption) {\n followUpForm = h(\n 'form',\n {\n style: styles.followUp,\n onSubmit: handleFollowUpSubmit,\n },\n [\n h('input', {\n type: 'text',\n style: styles.input,\n value: followUpText.value,\n placeholder: followUpOption.followUpPlaceholder || 'Tell us more...',\n disabled: isSubmitting.value,\n maxlength: 500,\n onInput: (e: Event) => {\n followUpText.value = (e.target as HTMLInputElement).value;\n },\n }),\n h('div', { style: { ...styles.actions, justifyContent: 'center' } }, [\n h(\n 'button',\n {\n type: 'submit',\n style: {\n ...styles.submitButton,\n backgroundColor: currentStyling.primaryColor ?? '#6366f1',\n borderRadius: borderRadius,\n ...(isSubmitting.value ? styles.buttonDisabled : {}),\n },\n disabled: isSubmitting.value,\n },\n isSubmitting.value ? 'Sending...' : 'Send'\n ),\n h(\n 'button',\n {\n type: 'button',\n style: {\n ...styles.cancelButton,\n backgroundColor: currentStyling.backgroundColor ?? '#ffffff',\n color: currentStyling.buttonTextColor ?? '#6b7280',\n borderRadius: borderRadius,\n border: `${borderWidth} solid ${currentStyling.borderColor ?? '#e5e7eb'}`,\n },\n disabled: isSubmitting.value,\n onClick: cancelFollowUp,\n },\n 'Cancel'\n ),\n ]),\n ]\n );\n }\n\n // Build error message\n let errorElement = null;\n if (error.value) {\n errorElement = h(\n 'div',\n { style: styles.error, role: 'alert' },\n error.value.message\n );\n }\n\n // Return full component\n return h(\n 'div',\n {\n class: props.containerClass,\n style: styles.container,\n role: 'group',\n 'aria-label': 'Reaction buttons',\n },\n [\n h('div', { style: styles.buttonGroup, role: 'radiogroup' }, buttonElements),\n followUpForm,\n errorElement,\n ]\n );\n };\n },\n});\n\nexport default ReactionButtons;\n"]}
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as vue from 'vue';
2
2
  import { InjectionKey, App, ShallowRef, Ref, ComputedRef, PropType } from 'vue';
3
- import { FeedValueInstance, FeedValueConfig, FeedbackData, UserTraits, ReactionOption, ButtonSize, FollowUpTrigger } from '@feedvalue/core';
3
+ import { FeedValueInstance, FeedValueConfig, FeedbackData, UserTraits, ReactionOption, ButtonSize, FollowUpTrigger, ReactionStyling } from '@feedvalue/core';
4
4
  export { FeedValueConfig, FeedValueEvents, FeedValueState, FeedbackData, FeedbackMetadata, ReactionConfig, ReactionOption, ReactionState, ReactionTemplate, UserData, UserTraits } from '@feedvalue/core';
5
5
 
6
6
  /**
@@ -179,6 +179,8 @@ interface UseReactionReturn {
179
179
  followUpTrigger: ComputedRef<FollowUpTrigger>;
180
180
  /** Check if an option should show follow-up based on followUpTrigger */
181
181
  shouldShowFollowUp: (optionValue: string) => boolean;
182
+ /** Widget styling configuration */
183
+ styling: ComputedRef<ReactionStyling>;
182
184
  }
183
185
  /**
184
186
  * Composable for reaction widgets
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as vue from 'vue';
2
2
  import { InjectionKey, App, ShallowRef, Ref, ComputedRef, PropType } from 'vue';
3
- import { FeedValueInstance, FeedValueConfig, FeedbackData, UserTraits, ReactionOption, ButtonSize, FollowUpTrigger } from '@feedvalue/core';
3
+ import { FeedValueInstance, FeedValueConfig, FeedbackData, UserTraits, ReactionOption, ButtonSize, FollowUpTrigger, ReactionStyling } from '@feedvalue/core';
4
4
  export { FeedValueConfig, FeedValueEvents, FeedValueState, FeedbackData, FeedbackMetadata, ReactionConfig, ReactionOption, ReactionState, ReactionTemplate, UserData, UserTraits } from '@feedvalue/core';
5
5
 
6
6
  /**
@@ -179,6 +179,8 @@ interface UseReactionReturn {
179
179
  followUpTrigger: ComputedRef<FollowUpTrigger>;
180
180
  /** Check if an option should show follow-up based on followUpTrigger */
181
181
  shouldShowFollowUp: (optionValue: string) => boolean;
182
+ /** Widget styling configuration */
183
+ styling: ComputedRef<ReactionStyling>;
182
184
  }
183
185
  /**
184
186
  * Composable for reaction widgets
package/dist/index.js CHANGED
@@ -177,6 +177,34 @@ function useReaction(widgetId) {
177
177
  const template = computed(() => {
178
178
  return reactionConfig.value?.template;
179
179
  });
180
+ const styling = computed(() => {
181
+ const defaultStyling = {
182
+ primaryColor: "#6366f1",
183
+ backgroundColor: "#ffffff",
184
+ textColor: "#111827",
185
+ buttonTextColor: "#4b5563",
186
+ borderColor: "#e5e7eb",
187
+ borderWidth: "1",
188
+ borderRadius: "full"
189
+ };
190
+ if (!instance.value || !isReady.value) {
191
+ return defaultStyling;
192
+ }
193
+ const widgetConfig = instance.value._widgetConfig;
194
+ if (!widgetConfig?.styling) {
195
+ return defaultStyling;
196
+ }
197
+ const widgetStyling = widgetConfig.styling;
198
+ return {
199
+ primaryColor: widgetStyling.primaryColor ?? defaultStyling.primaryColor,
200
+ backgroundColor: widgetStyling.backgroundColor ?? defaultStyling.backgroundColor,
201
+ textColor: widgetStyling.textColor ?? defaultStyling.textColor,
202
+ buttonTextColor: widgetStyling.buttonTextColor ?? defaultStyling.buttonTextColor,
203
+ borderColor: widgetStyling.borderColor ?? defaultStyling.borderColor,
204
+ borderWidth: widgetStyling.borderWidth ?? defaultStyling.borderWidth,
205
+ borderRadius: widgetStyling.borderRadius ?? defaultStyling.borderRadius
206
+ };
207
+ });
180
208
  const shouldShowFollowUp = (optionValue) => {
181
209
  if (followUpTrigger.value === "none") return false;
182
210
  if (followUpTrigger.value === "all") return true;
@@ -225,9 +253,24 @@ function useReaction(widgetId) {
225
253
  showLabels,
226
254
  buttonSize,
227
255
  followUpTrigger,
228
- shouldShowFollowUp
256
+ shouldShowFollowUp,
257
+ styling
229
258
  };
230
259
  }
260
+ var borderRadiusMap = {
261
+ full: "9999px",
262
+ lg: "12px",
263
+ md: "8px",
264
+ sm: "4px",
265
+ none: "0px"
266
+ };
267
+ var borderWidthMap = {
268
+ "0": "0px",
269
+ "1": "1px",
270
+ "2": "2px",
271
+ "3": "3px",
272
+ "4": "4px"
273
+ };
231
274
  var sizeStyles = {
232
275
  sm: {
233
276
  button: { padding: "0.375rem 0.75rem", fontSize: "0.75rem", gap: "0.375rem" },
@@ -268,11 +311,6 @@ var styles = {
268
311
  cursor: "pointer",
269
312
  transition: "background-color 0.15s, border-color 0.15s, transform 0.1s"
270
313
  },
271
- buttonActive: {
272
- backgroundColor: "#eef2ff",
273
- borderColor: "#6366f1",
274
- color: "#4f46e5"
275
- },
276
314
  buttonDisabled: {
277
315
  opacity: 0.7,
278
316
  cursor: "not-allowed"
@@ -388,7 +426,8 @@ var ReactionButtons = defineComponent({
388
426
  isReady,
389
427
  showLabels,
390
428
  buttonSize,
391
- shouldShowFollowUp
429
+ shouldShowFollowUp,
430
+ styling
392
431
  } = useReaction(props.widgetId);
393
432
  const followUpText = ref("");
394
433
  const getFollowUpOption = computed(() => {
@@ -425,11 +464,15 @@ var ReactionButtons = defineComponent({
425
464
  return null;
426
465
  }
427
466
  if (submitted.value) {
467
+ const currentStyling2 = styling.value;
428
468
  return h(
429
469
  "div",
430
470
  {
431
471
  class: props.containerClass,
432
- style: styles.thankYou
472
+ style: {
473
+ ...styles.thankYou,
474
+ color: currentStyling2.primaryColor ?? "#059669"
475
+ }
433
476
  },
434
477
  [
435
478
  h("span", props.thankYouMessage || "Thanks for your feedback!"),
@@ -447,12 +490,16 @@ var ReactionButtons = defineComponent({
447
490
  );
448
491
  }
449
492
  const currentSizeStyles = sizeStyles[buttonSize.value] || sizeStyles.md;
493
+ const currentStyling = styling.value;
494
+ const borderRadius = borderRadiusMap[currentStyling.borderRadius ?? "full"] ?? "9999px";
495
+ const borderWidth = borderWidthMap[currentStyling.borderWidth ?? "1"] ?? "1px";
450
496
  const buttonElements = options.value.map((option) => {
497
+ const isActive = showFollowUp.value === option.value;
451
498
  const children = [
452
499
  h("span", { style: { ...styles.icon, ...currentSizeStyles.icon }, "aria-hidden": "true" }, option.icon)
453
500
  ];
454
501
  if (showLabels.value) {
455
- children.push(h("span", { style: currentSizeStyles.label }, option.label));
502
+ children.push(h("span", { style: { ...currentSizeStyles.label, color: currentStyling.buttonTextColor ?? "#4b5563" } }, option.label));
456
503
  }
457
504
  return h(
458
505
  "button",
@@ -463,11 +510,18 @@ var ReactionButtons = defineComponent({
463
510
  style: {
464
511
  ...styles.button,
465
512
  ...currentSizeStyles.button,
466
- ...showFollowUp.value === option.value ? styles.buttonActive : {},
513
+ backgroundColor: currentStyling.backgroundColor ?? "#ffffff",
514
+ borderColor: isActive ? currentStyling.primaryColor ?? "#6366f1" : currentStyling.borderColor ?? "#e5e7eb",
515
+ borderWidth,
516
+ borderRadius,
517
+ color: currentStyling.buttonTextColor ?? "#4b5563",
518
+ ...isActive ? {
519
+ backgroundColor: `${currentStyling.primaryColor ?? "#6366f1"}10`
520
+ } : {},
467
521
  ...isSubmitting.value ? styles.buttonDisabled : {}
468
522
  },
469
523
  disabled: isSubmitting.value,
470
- "aria-pressed": showFollowUp.value === option.value,
524
+ "aria-pressed": isActive,
471
525
  "aria-label": option.label,
472
526
  onClick: () => handleOptionClick(option)
473
527
  },
@@ -495,13 +549,15 @@ var ReactionButtons = defineComponent({
495
549
  followUpText.value = e.target.value;
496
550
  }
497
551
  }),
498
- h("div", { style: styles.actions }, [
552
+ h("div", { style: { ...styles.actions, justifyContent: "center" } }, [
499
553
  h(
500
554
  "button",
501
555
  {
502
556
  type: "submit",
503
557
  style: {
504
558
  ...styles.submitButton,
559
+ backgroundColor: currentStyling.primaryColor ?? "#6366f1",
560
+ borderRadius,
505
561
  ...isSubmitting.value ? styles.buttonDisabled : {}
506
562
  },
507
563
  disabled: isSubmitting.value
@@ -512,7 +568,13 @@ var ReactionButtons = defineComponent({
512
568
  "button",
513
569
  {
514
570
  type: "button",
515
- style: styles.cancelButton,
571
+ style: {
572
+ ...styles.cancelButton,
573
+ backgroundColor: currentStyling.backgroundColor ?? "#ffffff",
574
+ color: currentStyling.buttonTextColor ?? "#6b7280",
575
+ borderRadius,
576
+ border: `${borderWidth} solid ${currentStyling.borderColor ?? "#e5e7eb"}`
577
+ },
516
578
  disabled: isSubmitting.value,
517
579
  onClick: cancelFollowUp
518
580
  },
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/plugin.ts","../src/composables.ts","../src/use-reaction.ts","../src/ReactionButtons.ts"],"names":["FeedValue","inject","ref","onMounted","onUnmounted","readonly","computed"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @feedvalue/vue - Plugin\n *\n * Vue plugin for FeedValue. Provides app-level configuration\n * and automatic initialization.\n */\n\nimport type { App, InjectionKey } from 'vue';\nimport { FeedValue, type FeedValueConfig, type FeedValueInstance } from '@feedvalue/core';\n\n/**\n * Plugin options\n */\nexport interface FeedValuePluginOptions {\n /** Widget ID from FeedValue dashboard */\n widgetId: string;\n /** API base URL (for self-hosted) */\n apiBaseUrl?: string;\n /** Configuration overrides */\n config?: Partial<FeedValueConfig>;\n /**\n * Headless mode - disables all DOM rendering.\n * Use this when you want full control over the UI.\n * The SDK will still fetch config and provide all API methods\n * but won't render any trigger button or modal.\n *\n * @default false\n */\n headless?: boolean;\n}\n\n/**\n * Injection key for FeedValue instance\n */\nexport const FEEDVALUE_KEY: InjectionKey<FeedValueInstance> = Symbol('feedvalue');\n\n/**\n * Injection key for widget ID (used by useFeedValue when no instance is injected)\n */\nexport const FEEDVALUE_OPTIONS_KEY: InjectionKey<FeedValuePluginOptions> = Symbol('feedvalue-options');\n\n/**\n * Create FeedValue Vue plugin\n *\n * @example\n * ```ts\n * // main.ts\n * import { createApp } from 'vue';\n * import { createFeedValue } from '@feedvalue/vue';\n * import App from './App.vue';\n *\n * const app = createApp(App);\n *\n * app.use(createFeedValue({\n * widgetId: 'your-widget-id',\n * config: { theme: 'dark' }\n * }));\n *\n * app.mount('#app');\n * ```\n */\nexport function createFeedValue(options: FeedValuePluginOptions) {\n let instance: FeedValueInstance | null = null;\n\n return {\n install(app: App) {\n // Only initialize on client side\n if (typeof window !== 'undefined') {\n instance = FeedValue.init({\n widgetId: options.widgetId,\n apiBaseUrl: options.apiBaseUrl,\n config: options.config,\n headless: options.headless,\n });\n\n // Provide instance to all components\n app.provide(FEEDVALUE_KEY, instance);\n\n // Also provide to global properties for Options API access\n app.config.globalProperties.$feedvalue = instance;\n }\n\n // Always provide options (for SSR where we don't initialize)\n app.provide(FEEDVALUE_OPTIONS_KEY, options);\n },\n };\n}\n\n/**\n * Type augmentation for global properties\n */\ndeclare module 'vue' {\n interface ComponentCustomProperties {\n $feedvalue: FeedValueInstance | undefined;\n }\n}\n","/**\n * @feedvalue/vue - Composables\n *\n * Vue composables for FeedValue. Provides reactive state and methods.\n */\n\nimport {\n ref,\n shallowRef,\n readonly,\n onMounted,\n onUnmounted,\n inject,\n type Ref,\n type ShallowRef,\n} from 'vue';\nimport {\n FeedValue,\n type FeedValueConfig,\n type FeedValueInstance,\n type FeedbackData,\n type UserTraits,\n} from '@feedvalue/core';\nimport { FEEDVALUE_KEY, FEEDVALUE_OPTIONS_KEY } from './plugin';\n\n/**\n * Return type for useFeedValue composable\n */\nexport interface UseFeedValueReturn {\n /** FeedValue instance (for advanced usage) */\n instance: Readonly<ShallowRef<FeedValueInstance | null>>;\n /** Widget is ready */\n isReady: Readonly<Ref<boolean>>;\n /** Modal is open */\n isOpen: Readonly<Ref<boolean>>;\n /** Widget is visible */\n isVisible: Readonly<Ref<boolean>>;\n /** Current error */\n error: Readonly<Ref<Error | null>>;\n /** Submission in progress */\n isSubmitting: Readonly<Ref<boolean>>;\n /** Running in headless mode (no default UI rendered) */\n isHeadless: Readonly<Ref<boolean>>;\n /** Open the feedback modal */\n open: () => void;\n /** Close the feedback modal */\n close: () => void;\n /** Toggle the feedback modal */\n toggle: () => void;\n /** Show the trigger button */\n show: () => void;\n /** Hide the trigger button */\n hide: () => void;\n /** Submit feedback programmatically */\n submit: (feedback: Partial<FeedbackData>) => Promise<void>;\n /** Identify user */\n identify: (userId: string, traits?: UserTraits) => void;\n /** Set user data */\n setData: (data: Record<string, string>) => void;\n /** Reset user data */\n reset: () => void;\n}\n\n/**\n * FeedValue composable\n *\n * Can be used with or without plugin. If plugin is installed, uses the\n * provided instance. Otherwise, creates a new instance.\n *\n * @example\n * ```vue\n * <script setup>\n * import { useFeedValue } from '@feedvalue/vue';\n *\n * // With plugin installed\n * const { open, isReady } = useFeedValue();\n *\n * // Or standalone with widgetId\n * const { open, isReady } = useFeedValue('your-widget-id');\n * </script>\n *\n * <template>\n * <button @click=\"open\" :disabled=\"!isReady\">\n * Give Feedback\n * </button>\n * </template>\n * ```\n */\nexport function useFeedValue(\n widgetId?: string,\n config?: Partial<FeedValueConfig>\n): UseFeedValueReturn {\n // Try to inject instance from plugin\n const injectedInstance = inject(FEEDVALUE_KEY, null);\n const injectedOptions = inject(FEEDVALUE_OPTIONS_KEY, null);\n\n // Refs for reactive state\n const instance = shallowRef<FeedValueInstance | null>(null);\n const isReady = ref(false);\n const isOpen = ref(false);\n const isVisible = ref(false);\n const error = ref<Error | null>(null);\n const isSubmitting = ref(false);\n const isHeadless = ref(false);\n\n // Track if we own the instance (need to destroy on unmount)\n let ownsInstance = false;\n let unsubscribe: (() => void) | null = null;\n\n /**\n * Sync reactive state from instance\n */\n const syncState = () => {\n const state = instance.value?.getSnapshot();\n if (state) {\n isReady.value = state.isReady;\n isOpen.value = state.isOpen;\n isVisible.value = state.isVisible;\n error.value = state.error;\n isSubmitting.value = state.isSubmitting;\n }\n };\n\n onMounted(() => {\n // Use injected instance if available and no widgetId override\n if (injectedInstance && !widgetId) {\n instance.value = injectedInstance;\n isHeadless.value = injectedInstance.isHeadless();\n } else {\n // Create new instance\n const effectiveWidgetId = widgetId ?? injectedOptions?.widgetId;\n\n if (!effectiveWidgetId) {\n console.error(\n '[FeedValue] No widgetId provided. Either install the plugin with createFeedValue() ' +\n 'or pass widgetId to useFeedValue().'\n );\n return;\n }\n\n instance.value = FeedValue.init({\n widgetId: effectiveWidgetId,\n apiBaseUrl: injectedOptions?.apiBaseUrl,\n config: config ?? injectedOptions?.config,\n headless: injectedOptions?.headless,\n });\n ownsInstance = true;\n }\n\n // Subscribe to state changes\n if (instance.value) {\n unsubscribe = instance.value.subscribe(syncState);\n isHeadless.value = instance.value.isHeadless();\n syncState(); // Initial sync\n }\n });\n\n onUnmounted(() => {\n unsubscribe?.();\n if (ownsInstance && instance.value) {\n instance.value.destroy();\n }\n instance.value = null;\n });\n\n // Methods that delegate to instance\n const open = () => instance.value?.open();\n const close = () => instance.value?.close();\n const toggle = () => instance.value?.toggle();\n const show = () => instance.value?.show();\n const hide = () => instance.value?.hide();\n const submit = (feedback: Partial<FeedbackData>) =>\n instance.value?.submit(feedback) ?? Promise.reject(new Error('Not initialized'));\n const identify = (userId: string, traits?: UserTraits) =>\n instance.value?.identify(userId, traits);\n const setData = (data: Record<string, string>) => instance.value?.setData(data);\n const reset = () => instance.value?.reset();\n\n return {\n instance: readonly(instance),\n isReady: readonly(isReady),\n isOpen: readonly(isOpen),\n isVisible: readonly(isVisible),\n error: readonly(error),\n isSubmitting: readonly(isSubmitting),\n isHeadless: readonly(isHeadless),\n open,\n close,\n toggle,\n show,\n hide,\n submit,\n identify,\n setData,\n reset,\n };\n}\n","/**\n * @feedvalue/vue - useReaction Composable\n *\n * Composable for reaction widgets in Vue applications.\n * Provides a simple API for submitting reactions.\n */\n\nimport {\n ref,\n computed,\n readonly,\n onMounted,\n onUnmounted,\n inject,\n type Ref,\n type ComputedRef,\n} from 'vue';\nimport {\n FeedValue,\n NEGATIVE_OPTIONS_MAP,\n type ReactionOption,\n type FeedValueInstance,\n type ButtonSize,\n type FollowUpTrigger,\n type ReactionTemplate,\n} from '@feedvalue/core';\nimport { FEEDVALUE_KEY, FEEDVALUE_OPTIONS_KEY } from './plugin';\n\n/**\n * Return type for useReaction composable\n */\nexport interface UseReactionReturn {\n /** Available reaction options */\n options: ComputedRef<ReactionOption[] | null>;\n /** Currently submitting */\n isSubmitting: Readonly<Ref<boolean>>;\n /** Successfully submitted value (null if not yet submitted) */\n submitted: Readonly<Ref<string | null>>;\n /** Error if submission failed */\n error: Readonly<Ref<Error | null>>;\n /** Option value requiring follow-up input (null if none) */\n showFollowUp: Readonly<Ref<string | null>>;\n /** Submit a reaction */\n react: (value: string, followUp?: string) => Promise<void>;\n /** Set which option is showing follow-up input */\n setShowFollowUp: (value: string | null) => void;\n /** Clear the submitted state to allow re-submission */\n clearSubmitted: () => void;\n /** Check if widget is a reaction type */\n isReactionWidget: ComputedRef<boolean>;\n /** Widget configuration is ready */\n isReady: Readonly<Ref<boolean>>;\n /** Whether to show text labels next to icons */\n showLabels: ComputedRef<boolean>;\n /** Button size */\n buttonSize: ComputedRef<ButtonSize>;\n /** When to show follow-up input */\n followUpTrigger: ComputedRef<FollowUpTrigger>;\n /** Check if an option should show follow-up based on followUpTrigger */\n shouldShowFollowUp: (optionValue: string) => boolean;\n}\n\n/**\n * Composable for reaction widgets\n *\n * Provides reaction options, submission handling, and follow-up state management.\n * Can be used with or without the FeedValue plugin.\n *\n * @param widgetId - Optional widget ID override (uses plugin widget if not provided)\n *\n * @example\n * ```vue\n * <script setup>\n * import { useReaction } from '@feedvalue/vue';\n *\n * const {\n * options,\n * react,\n * isSubmitting,\n * submitted,\n * error,\n * showFollowUp,\n * setShowFollowUp,\n * isReady,\n * } = useReaction();\n *\n * const handleClick = (option) => {\n * if (option.showFollowUp) {\n * setShowFollowUp(option.value);\n * } else {\n * react(option.value);\n * }\n * };\n * </script>\n *\n * <template>\n * <div v-if=\"isReady && options\">\n * <div v-if=\"submitted\">Thanks for your feedback!</div>\n *\n * <template v-else>\n * <button\n * v-for=\"option in options\"\n * :key=\"option.value\"\n * @click=\"handleClick(option)\"\n * :disabled=\"isSubmitting\"\n * >\n * {{ option.icon }} {{ option.label }}\n * </button>\n *\n * <form v-if=\"showFollowUp\" @submit.prevent=\"react(showFollowUp, followUpText)\">\n * <input v-model=\"followUpText\" placeholder=\"Tell us more...\" />\n * <button type=\"submit\">Send</button>\n * </form>\n *\n * <div v-if=\"error\">Error: {{ error.message }}</div>\n * </template>\n * </div>\n * </template>\n * ```\n */\nexport function useReaction(widgetId?: string): UseReactionReturn {\n // Try to inject instance from plugin\n const injectedInstance = inject(FEEDVALUE_KEY, null);\n const injectedOptions = inject(FEEDVALUE_OPTIONS_KEY, null);\n\n // Local instance ref (may be created if no plugin or widgetId override)\n const instance = ref<FeedValueInstance | null>(null);\n const isReady = ref(false);\n\n // Local state for reaction UI\n const showFollowUp = ref<string | null>(null);\n const submitted = ref<string | null>(null);\n const isSubmitting = ref(false);\n const error = ref<Error | null>(null);\n\n // Track if we own the instance (need to destroy on unmount)\n let ownsInstance = false;\n let unsubscribe: (() => void) | null = null;\n\n /**\n * Sync ready state from instance\n */\n const syncState = () => {\n const state = instance.value?.getSnapshot();\n if (state) {\n isReady.value = state.isReady;\n }\n };\n\n onMounted(() => {\n // Use injected instance if available and no widgetId override\n if (injectedInstance && !widgetId) {\n instance.value = injectedInstance;\n } else {\n // Create new instance\n const effectiveWidgetId = widgetId ?? injectedOptions?.widgetId;\n\n if (!effectiveWidgetId) {\n console.error(\n '[FeedValue] No widgetId provided. Either install the plugin with createFeedValue() ' +\n 'or pass widgetId to useReaction().'\n );\n return;\n }\n\n instance.value = FeedValue.init({\n widgetId: effectiveWidgetId,\n apiBaseUrl: injectedOptions?.apiBaseUrl,\n config: injectedOptions?.config,\n headless: true, // Reaction widgets are always headless\n });\n ownsInstance = true;\n }\n\n // Subscribe to state changes\n if (instance.value) {\n unsubscribe = instance.value.subscribe(syncState);\n syncState(); // Initial sync\n }\n });\n\n onUnmounted(() => {\n unsubscribe?.();\n if (ownsInstance && instance.value) {\n instance.value.destroy();\n }\n instance.value = null;\n });\n\n // Computed: reaction options from instance\n const options = computed<ReactionOption[] | null>(() => {\n if (!instance.value || !isReady.value) return null;\n return instance.value.getReactionOptions();\n });\n\n // Computed: check if this is a reaction widget\n const isReactionWidget = computed(() => {\n return instance.value?.isReaction() ?? false;\n });\n\n // Computed: get config values with defaults\n const reactionConfig = computed(() => {\n if (!instance.value || !isReady.value) return null;\n // Access the widget config which includes reaction config\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (instance.value as any)._widgetConfig?.config ?? null;\n });\n\n const showLabels = computed(() => {\n return reactionConfig.value?.showLabels ?? true;\n });\n\n const buttonSize = computed<ButtonSize>(() => {\n return reactionConfig.value?.buttonSize ?? 'md';\n });\n\n const followUpTrigger = computed<FollowUpTrigger>(() => {\n return reactionConfig.value?.followUpTrigger ?? 'negative';\n });\n\n const template = computed<ReactionTemplate | undefined>(() => {\n return reactionConfig.value?.template;\n });\n\n /**\n * Check if an option should show follow-up based on followUpTrigger\n */\n const shouldShowFollowUp = (optionValue: string): boolean => {\n if (followUpTrigger.value === 'none') return false;\n if (followUpTrigger.value === 'all') return true;\n // followUpTrigger === 'negative'\n if (template.value && NEGATIVE_OPTIONS_MAP[template.value]) {\n return NEGATIVE_OPTIONS_MAP[template.value].includes(optionValue);\n }\n // For custom options, use the option's own showFollowUp setting\n const option = options.value?.find((o) => o.value === optionValue);\n return option?.showFollowUp ?? false;\n };\n\n /**\n * Submit a reaction\n */\n const react = async (value: string, followUp?: string): Promise<void> => {\n if (!instance.value) {\n throw new Error('FeedValue not initialized');\n }\n\n isSubmitting.value = true;\n error.value = null;\n\n try {\n await instance.value.react(value, followUp ? { followUp } : undefined);\n submitted.value = value;\n showFollowUp.value = null;\n } catch (err) {\n const reactionError = err instanceof Error ? err : new Error(String(err));\n error.value = reactionError;\n throw reactionError;\n } finally {\n isSubmitting.value = false;\n }\n };\n\n /**\n * Set which option is showing follow-up input\n */\n const setShowFollowUp = (value: string | null): void => {\n showFollowUp.value = value;\n };\n\n /**\n * Clear submitted state to allow re-submission\n */\n const clearSubmitted = (): void => {\n submitted.value = null;\n error.value = null;\n };\n\n return {\n options,\n isSubmitting: readonly(isSubmitting),\n submitted: readonly(submitted),\n error: readonly(error),\n showFollowUp: readonly(showFollowUp),\n react,\n setShowFollowUp,\n clearSubmitted,\n isReactionWidget,\n isReady: readonly(isReady),\n showLabels,\n buttonSize,\n followUpTrigger,\n shouldShowFollowUp,\n };\n}\n","/**\n * @feedvalue/vue - ReactionButtons Component\n *\n * Pre-built reaction buttons component for Vue applications.\n * Renders reaction options with optional follow-up input.\n */\n\nimport { defineComponent, ref, computed, h, type PropType } from 'vue';\nimport { useReaction } from './use-reaction';\nimport type { ReactionOption } from '@feedvalue/core';\n\nimport type { ButtonSize } from '@feedvalue/core';\n\n/**\n * Button size style variants\n */\nconst sizeStyles: Record<ButtonSize, { button: Record<string, string>; icon: Record<string, string>; label: Record<string, string> }> = {\n sm: {\n button: { padding: '0.375rem 0.75rem', fontSize: '0.75rem', gap: '0.375rem' },\n icon: { fontSize: '1rem' },\n label: { fontSize: '0.75rem' },\n },\n md: {\n button: { padding: '0.5rem 1rem', fontSize: '0.875rem', gap: '0.5rem' },\n icon: { fontSize: '1.125rem' },\n label: { fontSize: '0.875rem' },\n },\n lg: {\n button: { padding: '0.75rem 1.25rem', fontSize: '1rem', gap: '0.625rem' },\n icon: { fontSize: '1.5rem' },\n label: { fontSize: '1rem' },\n },\n};\n\n/**\n * Default CSS styles for the component\n */\nconst styles = {\n container: {\n display: 'flex',\n flexDirection: 'column' as const,\n gap: '0.75rem',\n fontFamily: 'system-ui, -apple-system, sans-serif',\n },\n buttonGroup: {\n display: 'flex',\n flexWrap: 'wrap' as const,\n gap: '0.5rem',\n },\n button: {\n display: 'inline-flex',\n alignItems: 'center',\n fontWeight: '500',\n color: '#374151',\n backgroundColor: '#ffffff',\n border: '1px solid #d1d5db',\n borderRadius: '9999px',\n cursor: 'pointer',\n transition: 'background-color 0.15s, border-color 0.15s, transform 0.1s',\n },\n buttonActive: {\n backgroundColor: '#eef2ff',\n borderColor: '#6366f1',\n color: '#4f46e5',\n },\n buttonDisabled: {\n opacity: 0.7,\n cursor: 'not-allowed',\n },\n icon: {},\n followUp: {\n display: 'flex',\n flexDirection: 'column' as const,\n gap: '0.5rem',\n padding: '0.75rem',\n backgroundColor: '#f9fafb',\n border: '1px solid #e5e7eb',\n borderRadius: '0.5rem',\n },\n input: {\n width: '100%',\n padding: '0.5rem 0.75rem',\n fontSize: '0.875rem',\n border: '1px solid #d1d5db',\n borderRadius: '0.375rem',\n backgroundColor: '#ffffff',\n boxSizing: 'border-box' as const,\n },\n actions: {\n display: 'flex',\n gap: '0.5rem',\n justifyContent: 'flex-end',\n },\n submitButton: {\n padding: '0.375rem 0.75rem',\n fontSize: '0.875rem',\n fontWeight: '500',\n color: '#ffffff',\n backgroundColor: '#6366f1',\n border: 'none',\n borderRadius: '0.375rem',\n cursor: 'pointer',\n },\n cancelButton: {\n padding: '0.375rem 0.75rem',\n fontSize: '0.875rem',\n color: '#6b7280',\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n },\n thankYou: {\n display: 'flex',\n alignItems: 'center',\n gap: '0.5rem',\n padding: '0.75rem 1rem',\n fontSize: '0.875rem',\n color: '#059669',\n backgroundColor: '#ecfdf5',\n border: '1px solid #a7f3d0',\n borderRadius: '0.5rem',\n },\n resetButton: {\n padding: '0.25rem 0.5rem',\n fontSize: '0.875rem',\n color: '#6b7280',\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n },\n error: {\n padding: '0.5rem 0.75rem',\n fontSize: '0.875rem',\n color: '#dc2626',\n backgroundColor: '#fef2f2',\n border: '1px solid #fecaca',\n borderRadius: '0.375rem',\n },\n};\n\n/**\n * ReactionButtons Component\n *\n * Pre-built reaction buttons with follow-up input support.\n *\n * @example\n * ```vue\n * <template>\n * <ReactionButtons widget-id=\"xxx\" @react=\"onReact\" />\n * </template>\n *\n * <script setup>\n * import { ReactionButtons } from '@feedvalue/vue';\n *\n * const onReact = (value, followUp) => {\n * console.log('Reacted:', value, followUp);\n * };\n * </script>\n * ```\n */\nexport const ReactionButtons = defineComponent({\n name: 'ReactionButtons',\n\n props: {\n /** Widget ID (optional if using FeedValue plugin) */\n widgetId: {\n type: String as PropType<string | undefined>,\n default: undefined,\n },\n /** Custom thank you message (overrides widget config) */\n thankYouMessage: {\n type: String as PropType<string | undefined>,\n default: undefined,\n },\n /** Custom class for the container */\n containerClass: {\n type: String,\n default: '',\n },\n /** Custom class for buttons */\n buttonClass: {\n type: String,\n default: '',\n },\n },\n\n emits: {\n /** Emitted when a reaction is submitted */\n react: (value: string, _followUp?: string) => typeof value === 'string',\n },\n\n setup(props, { emit }) {\n const {\n options,\n react,\n isSubmitting,\n submitted,\n error,\n showFollowUp,\n setShowFollowUp,\n clearSubmitted,\n isReady,\n showLabels,\n buttonSize,\n shouldShowFollowUp,\n } = useReaction(props.widgetId);\n\n // Local state for follow-up input\n const followUpText = ref('');\n\n // Get follow-up option\n const getFollowUpOption = computed<ReactionOption | null>(() => {\n if (!showFollowUp.value || !options.value) return null;\n return options.value.find((opt) => opt.value === showFollowUp.value) ?? null;\n });\n\n /**\n * Handle option click\n */\n const handleOptionClick = (option: ReactionOption) => {\n if (shouldShowFollowUp(option.value)) {\n setShowFollowUp(option.value);\n } else {\n submitReaction(option.value);\n }\n };\n\n /**\n * Submit reaction\n */\n const submitReaction = async (value: string, followUp?: string) => {\n try {\n await react(value, followUp);\n emit('react', value, followUp);\n } catch {\n // Error is already set in state\n }\n };\n\n /**\n * Handle follow-up form submit\n */\n const handleFollowUpSubmit = (e: Event) => {\n e.preventDefault();\n if (showFollowUp.value) {\n submitReaction(showFollowUp.value, followUpText.value || undefined);\n followUpText.value = '';\n }\n };\n\n /**\n * Cancel follow-up\n */\n const cancelFollowUp = () => {\n setShowFollowUp(null);\n followUpText.value = '';\n };\n\n return () => {\n // Don't render if not ready or no options\n if (!isReady.value || !options.value) {\n return null;\n }\n\n // Render thank you message after submission\n if (submitted.value) {\n return h(\n 'div',\n {\n class: props.containerClass,\n style: styles.thankYou,\n },\n [\n h('span', props.thankYouMessage || 'Thanks for your feedback!'),\n h(\n 'button',\n {\n type: 'button',\n style: styles.resetButton,\n onClick: clearSubmitted,\n 'aria-label': 'Submit another reaction',\n },\n '↺'\n ),\n ]\n );\n }\n\n // Build reaction buttons\n const currentSizeStyles = sizeStyles[buttonSize.value] || sizeStyles.md;\n const buttonElements = options.value.map((option) => {\n const children = [\n h('span', { style: { ...styles.icon, ...currentSizeStyles.icon }, 'aria-hidden': 'true' }, option.icon),\n ];\n if (showLabels.value) {\n children.push(h('span', { style: currentSizeStyles.label }, option.label));\n }\n\n return h(\n 'button',\n {\n key: option.value,\n type: 'button',\n class: props.buttonClass,\n style: {\n ...styles.button,\n ...currentSizeStyles.button,\n ...(showFollowUp.value === option.value ? styles.buttonActive : {}),\n ...(isSubmitting.value ? styles.buttonDisabled : {}),\n },\n disabled: isSubmitting.value,\n 'aria-pressed': showFollowUp.value === option.value,\n 'aria-label': option.label,\n onClick: () => handleOptionClick(option),\n },\n children\n );\n });\n\n // Build follow-up form if needed\n let followUpForm = null;\n const followUpOption = getFollowUpOption.value;\n if (showFollowUp.value && followUpOption) {\n followUpForm = h(\n 'form',\n {\n style: styles.followUp,\n onSubmit: handleFollowUpSubmit,\n },\n [\n h('input', {\n type: 'text',\n style: styles.input,\n value: followUpText.value,\n placeholder: followUpOption.followUpPlaceholder || 'Tell us more...',\n disabled: isSubmitting.value,\n maxlength: 500,\n onInput: (e: Event) => {\n followUpText.value = (e.target as HTMLInputElement).value;\n },\n }),\n h('div', { style: styles.actions }, [\n h(\n 'button',\n {\n type: 'submit',\n style: {\n ...styles.submitButton,\n ...(isSubmitting.value ? styles.buttonDisabled : {}),\n },\n disabled: isSubmitting.value,\n },\n isSubmitting.value ? 'Sending...' : 'Send'\n ),\n h(\n 'button',\n {\n type: 'button',\n style: styles.cancelButton,\n disabled: isSubmitting.value,\n onClick: cancelFollowUp,\n },\n 'Cancel'\n ),\n ]),\n ]\n );\n }\n\n // Build error message\n let errorElement = null;\n if (error.value) {\n errorElement = h(\n 'div',\n { style: styles.error, role: 'alert' },\n error.value.message\n );\n }\n\n // Return full component\n return h(\n 'div',\n {\n class: props.containerClass,\n style: styles.container,\n role: 'group',\n 'aria-label': 'Reaction buttons',\n },\n [\n h('div', { style: styles.buttonGroup, role: 'radiogroup' }, buttonElements),\n followUpForm,\n errorElement,\n ]\n );\n };\n },\n});\n\nexport default ReactionButtons;\n"]}
1
+ {"version":3,"sources":["../src/plugin.ts","../src/composables.ts","../src/use-reaction.ts","../src/ReactionButtons.ts"],"names":["FeedValue","inject","ref","onMounted","onUnmounted","readonly","computed","currentStyling"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @feedvalue/vue - Plugin\n *\n * Vue plugin for FeedValue. Provides app-level configuration\n * and automatic initialization.\n */\n\nimport type { App, InjectionKey } from 'vue';\nimport { FeedValue, type FeedValueConfig, type FeedValueInstance } from '@feedvalue/core';\n\n/**\n * Plugin options\n */\nexport interface FeedValuePluginOptions {\n /** Widget ID from FeedValue dashboard */\n widgetId: string;\n /** API base URL (for self-hosted) */\n apiBaseUrl?: string;\n /** Configuration overrides */\n config?: Partial<FeedValueConfig>;\n /**\n * Headless mode - disables all DOM rendering.\n * Use this when you want full control over the UI.\n * The SDK will still fetch config and provide all API methods\n * but won't render any trigger button or modal.\n *\n * @default false\n */\n headless?: boolean;\n}\n\n/**\n * Injection key for FeedValue instance\n */\nexport const FEEDVALUE_KEY: InjectionKey<FeedValueInstance> = Symbol('feedvalue');\n\n/**\n * Injection key for widget ID (used by useFeedValue when no instance is injected)\n */\nexport const FEEDVALUE_OPTIONS_KEY: InjectionKey<FeedValuePluginOptions> = Symbol('feedvalue-options');\n\n/**\n * Create FeedValue Vue plugin\n *\n * @example\n * ```ts\n * // main.ts\n * import { createApp } from 'vue';\n * import { createFeedValue } from '@feedvalue/vue';\n * import App from './App.vue';\n *\n * const app = createApp(App);\n *\n * app.use(createFeedValue({\n * widgetId: 'your-widget-id',\n * config: { theme: 'dark' }\n * }));\n *\n * app.mount('#app');\n * ```\n */\nexport function createFeedValue(options: FeedValuePluginOptions) {\n let instance: FeedValueInstance | null = null;\n\n return {\n install(app: App) {\n // Only initialize on client side\n if (typeof window !== 'undefined') {\n instance = FeedValue.init({\n widgetId: options.widgetId,\n apiBaseUrl: options.apiBaseUrl,\n config: options.config,\n headless: options.headless,\n });\n\n // Provide instance to all components\n app.provide(FEEDVALUE_KEY, instance);\n\n // Also provide to global properties for Options API access\n app.config.globalProperties.$feedvalue = instance;\n }\n\n // Always provide options (for SSR where we don't initialize)\n app.provide(FEEDVALUE_OPTIONS_KEY, options);\n },\n };\n}\n\n/**\n * Type augmentation for global properties\n */\ndeclare module 'vue' {\n interface ComponentCustomProperties {\n $feedvalue: FeedValueInstance | undefined;\n }\n}\n","/**\n * @feedvalue/vue - Composables\n *\n * Vue composables for FeedValue. Provides reactive state and methods.\n */\n\nimport {\n ref,\n shallowRef,\n readonly,\n onMounted,\n onUnmounted,\n inject,\n type Ref,\n type ShallowRef,\n} from 'vue';\nimport {\n FeedValue,\n type FeedValueConfig,\n type FeedValueInstance,\n type FeedbackData,\n type UserTraits,\n} from '@feedvalue/core';\nimport { FEEDVALUE_KEY, FEEDVALUE_OPTIONS_KEY } from './plugin';\n\n/**\n * Return type for useFeedValue composable\n */\nexport interface UseFeedValueReturn {\n /** FeedValue instance (for advanced usage) */\n instance: Readonly<ShallowRef<FeedValueInstance | null>>;\n /** Widget is ready */\n isReady: Readonly<Ref<boolean>>;\n /** Modal is open */\n isOpen: Readonly<Ref<boolean>>;\n /** Widget is visible */\n isVisible: Readonly<Ref<boolean>>;\n /** Current error */\n error: Readonly<Ref<Error | null>>;\n /** Submission in progress */\n isSubmitting: Readonly<Ref<boolean>>;\n /** Running in headless mode (no default UI rendered) */\n isHeadless: Readonly<Ref<boolean>>;\n /** Open the feedback modal */\n open: () => void;\n /** Close the feedback modal */\n close: () => void;\n /** Toggle the feedback modal */\n toggle: () => void;\n /** Show the trigger button */\n show: () => void;\n /** Hide the trigger button */\n hide: () => void;\n /** Submit feedback programmatically */\n submit: (feedback: Partial<FeedbackData>) => Promise<void>;\n /** Identify user */\n identify: (userId: string, traits?: UserTraits) => void;\n /** Set user data */\n setData: (data: Record<string, string>) => void;\n /** Reset user data */\n reset: () => void;\n}\n\n/**\n * FeedValue composable\n *\n * Can be used with or without plugin. If plugin is installed, uses the\n * provided instance. Otherwise, creates a new instance.\n *\n * @example\n * ```vue\n * <script setup>\n * import { useFeedValue } from '@feedvalue/vue';\n *\n * // With plugin installed\n * const { open, isReady } = useFeedValue();\n *\n * // Or standalone with widgetId\n * const { open, isReady } = useFeedValue('your-widget-id');\n * </script>\n *\n * <template>\n * <button @click=\"open\" :disabled=\"!isReady\">\n * Give Feedback\n * </button>\n * </template>\n * ```\n */\nexport function useFeedValue(\n widgetId?: string,\n config?: Partial<FeedValueConfig>\n): UseFeedValueReturn {\n // Try to inject instance from plugin\n const injectedInstance = inject(FEEDVALUE_KEY, null);\n const injectedOptions = inject(FEEDVALUE_OPTIONS_KEY, null);\n\n // Refs for reactive state\n const instance = shallowRef<FeedValueInstance | null>(null);\n const isReady = ref(false);\n const isOpen = ref(false);\n const isVisible = ref(false);\n const error = ref<Error | null>(null);\n const isSubmitting = ref(false);\n const isHeadless = ref(false);\n\n // Track if we own the instance (need to destroy on unmount)\n let ownsInstance = false;\n let unsubscribe: (() => void) | null = null;\n\n /**\n * Sync reactive state from instance\n */\n const syncState = () => {\n const state = instance.value?.getSnapshot();\n if (state) {\n isReady.value = state.isReady;\n isOpen.value = state.isOpen;\n isVisible.value = state.isVisible;\n error.value = state.error;\n isSubmitting.value = state.isSubmitting;\n }\n };\n\n onMounted(() => {\n // Use injected instance if available and no widgetId override\n if (injectedInstance && !widgetId) {\n instance.value = injectedInstance;\n isHeadless.value = injectedInstance.isHeadless();\n } else {\n // Create new instance\n const effectiveWidgetId = widgetId ?? injectedOptions?.widgetId;\n\n if (!effectiveWidgetId) {\n console.error(\n '[FeedValue] No widgetId provided. Either install the plugin with createFeedValue() ' +\n 'or pass widgetId to useFeedValue().'\n );\n return;\n }\n\n instance.value = FeedValue.init({\n widgetId: effectiveWidgetId,\n apiBaseUrl: injectedOptions?.apiBaseUrl,\n config: config ?? injectedOptions?.config,\n headless: injectedOptions?.headless,\n });\n ownsInstance = true;\n }\n\n // Subscribe to state changes\n if (instance.value) {\n unsubscribe = instance.value.subscribe(syncState);\n isHeadless.value = instance.value.isHeadless();\n syncState(); // Initial sync\n }\n });\n\n onUnmounted(() => {\n unsubscribe?.();\n if (ownsInstance && instance.value) {\n instance.value.destroy();\n }\n instance.value = null;\n });\n\n // Methods that delegate to instance\n const open = () => instance.value?.open();\n const close = () => instance.value?.close();\n const toggle = () => instance.value?.toggle();\n const show = () => instance.value?.show();\n const hide = () => instance.value?.hide();\n const submit = (feedback: Partial<FeedbackData>) =>\n instance.value?.submit(feedback) ?? Promise.reject(new Error('Not initialized'));\n const identify = (userId: string, traits?: UserTraits) =>\n instance.value?.identify(userId, traits);\n const setData = (data: Record<string, string>) => instance.value?.setData(data);\n const reset = () => instance.value?.reset();\n\n return {\n instance: readonly(instance),\n isReady: readonly(isReady),\n isOpen: readonly(isOpen),\n isVisible: readonly(isVisible),\n error: readonly(error),\n isSubmitting: readonly(isSubmitting),\n isHeadless: readonly(isHeadless),\n open,\n close,\n toggle,\n show,\n hide,\n submit,\n identify,\n setData,\n reset,\n };\n}\n","/**\n * @feedvalue/vue - useReaction Composable\n *\n * Composable for reaction widgets in Vue applications.\n * Provides a simple API for submitting reactions.\n */\n\nimport {\n ref,\n computed,\n readonly,\n onMounted,\n onUnmounted,\n inject,\n type Ref,\n type ComputedRef,\n} from 'vue';\nimport {\n FeedValue,\n NEGATIVE_OPTIONS_MAP,\n type ReactionOption,\n type FeedValueInstance,\n type ButtonSize,\n type FollowUpTrigger,\n type ReactionTemplate,\n type ReactionStyling,\n} from '@feedvalue/core';\nimport { FEEDVALUE_KEY, FEEDVALUE_OPTIONS_KEY } from './plugin';\n\n/**\n * Return type for useReaction composable\n */\nexport interface UseReactionReturn {\n /** Available reaction options */\n options: ComputedRef<ReactionOption[] | null>;\n /** Currently submitting */\n isSubmitting: Readonly<Ref<boolean>>;\n /** Successfully submitted value (null if not yet submitted) */\n submitted: Readonly<Ref<string | null>>;\n /** Error if submission failed */\n error: Readonly<Ref<Error | null>>;\n /** Option value requiring follow-up input (null if none) */\n showFollowUp: Readonly<Ref<string | null>>;\n /** Submit a reaction */\n react: (value: string, followUp?: string) => Promise<void>;\n /** Set which option is showing follow-up input */\n setShowFollowUp: (value: string | null) => void;\n /** Clear the submitted state to allow re-submission */\n clearSubmitted: () => void;\n /** Check if widget is a reaction type */\n isReactionWidget: ComputedRef<boolean>;\n /** Widget configuration is ready */\n isReady: Readonly<Ref<boolean>>;\n /** Whether to show text labels next to icons */\n showLabels: ComputedRef<boolean>;\n /** Button size */\n buttonSize: ComputedRef<ButtonSize>;\n /** When to show follow-up input */\n followUpTrigger: ComputedRef<FollowUpTrigger>;\n /** Check if an option should show follow-up based on followUpTrigger */\n shouldShowFollowUp: (optionValue: string) => boolean;\n /** Widget styling configuration */\n styling: ComputedRef<ReactionStyling>;\n}\n\n/**\n * Composable for reaction widgets\n *\n * Provides reaction options, submission handling, and follow-up state management.\n * Can be used with or without the FeedValue plugin.\n *\n * @param widgetId - Optional widget ID override (uses plugin widget if not provided)\n *\n * @example\n * ```vue\n * <script setup>\n * import { useReaction } from '@feedvalue/vue';\n *\n * const {\n * options,\n * react,\n * isSubmitting,\n * submitted,\n * error,\n * showFollowUp,\n * setShowFollowUp,\n * isReady,\n * } = useReaction();\n *\n * const handleClick = (option) => {\n * if (option.showFollowUp) {\n * setShowFollowUp(option.value);\n * } else {\n * react(option.value);\n * }\n * };\n * </script>\n *\n * <template>\n * <div v-if=\"isReady && options\">\n * <div v-if=\"submitted\">Thanks for your feedback!</div>\n *\n * <template v-else>\n * <button\n * v-for=\"option in options\"\n * :key=\"option.value\"\n * @click=\"handleClick(option)\"\n * :disabled=\"isSubmitting\"\n * >\n * {{ option.icon }} {{ option.label }}\n * </button>\n *\n * <form v-if=\"showFollowUp\" @submit.prevent=\"react(showFollowUp, followUpText)\">\n * <input v-model=\"followUpText\" placeholder=\"Tell us more...\" />\n * <button type=\"submit\">Send</button>\n * </form>\n *\n * <div v-if=\"error\">Error: {{ error.message }}</div>\n * </template>\n * </div>\n * </template>\n * ```\n */\nexport function useReaction(widgetId?: string): UseReactionReturn {\n // Try to inject instance from plugin\n const injectedInstance = inject(FEEDVALUE_KEY, null);\n const injectedOptions = inject(FEEDVALUE_OPTIONS_KEY, null);\n\n // Local instance ref (may be created if no plugin or widgetId override)\n const instance = ref<FeedValueInstance | null>(null);\n const isReady = ref(false);\n\n // Local state for reaction UI\n const showFollowUp = ref<string | null>(null);\n const submitted = ref<string | null>(null);\n const isSubmitting = ref(false);\n const error = ref<Error | null>(null);\n\n // Track if we own the instance (need to destroy on unmount)\n let ownsInstance = false;\n let unsubscribe: (() => void) | null = null;\n\n /**\n * Sync ready state from instance\n */\n const syncState = () => {\n const state = instance.value?.getSnapshot();\n if (state) {\n isReady.value = state.isReady;\n }\n };\n\n onMounted(() => {\n // Use injected instance if available and no widgetId override\n if (injectedInstance && !widgetId) {\n instance.value = injectedInstance;\n } else {\n // Create new instance\n const effectiveWidgetId = widgetId ?? injectedOptions?.widgetId;\n\n if (!effectiveWidgetId) {\n console.error(\n '[FeedValue] No widgetId provided. Either install the plugin with createFeedValue() ' +\n 'or pass widgetId to useReaction().'\n );\n return;\n }\n\n instance.value = FeedValue.init({\n widgetId: effectiveWidgetId,\n apiBaseUrl: injectedOptions?.apiBaseUrl,\n config: injectedOptions?.config,\n headless: true, // Reaction widgets are always headless\n });\n ownsInstance = true;\n }\n\n // Subscribe to state changes\n if (instance.value) {\n unsubscribe = instance.value.subscribe(syncState);\n syncState(); // Initial sync\n }\n });\n\n onUnmounted(() => {\n unsubscribe?.();\n if (ownsInstance && instance.value) {\n instance.value.destroy();\n }\n instance.value = null;\n });\n\n // Computed: reaction options from instance\n const options = computed<ReactionOption[] | null>(() => {\n if (!instance.value || !isReady.value) return null;\n return instance.value.getReactionOptions();\n });\n\n // Computed: check if this is a reaction widget\n const isReactionWidget = computed(() => {\n return instance.value?.isReaction() ?? false;\n });\n\n // Computed: get config values with defaults\n const reactionConfig = computed(() => {\n if (!instance.value || !isReady.value) return null;\n // Access the widget config which includes reaction config\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (instance.value as any)._widgetConfig?.config ?? null;\n });\n\n const showLabels = computed(() => {\n return reactionConfig.value?.showLabels ?? true;\n });\n\n const buttonSize = computed<ButtonSize>(() => {\n return reactionConfig.value?.buttonSize ?? 'md';\n });\n\n const followUpTrigger = computed<FollowUpTrigger>(() => {\n return reactionConfig.value?.followUpTrigger ?? 'negative';\n });\n\n const template = computed<ReactionTemplate | undefined>(() => {\n return reactionConfig.value?.template;\n });\n\n // Computed: widget styling configuration\n const styling = computed<ReactionStyling>(() => {\n const defaultStyling: ReactionStyling = {\n primaryColor: '#6366f1',\n backgroundColor: '#ffffff',\n textColor: '#111827',\n buttonTextColor: '#4b5563',\n borderColor: '#e5e7eb',\n borderWidth: '1',\n borderRadius: 'full',\n };\n\n if (!instance.value || !isReady.value) {\n return defaultStyling;\n }\n\n // Access the widget config styling\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const widgetConfig = (instance.value as any)._widgetConfig;\n if (!widgetConfig?.styling) {\n return defaultStyling;\n }\n\n // Cast styling to access extended properties that may be present from API\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const widgetStyling = widgetConfig.styling as any;\n return {\n primaryColor: widgetStyling.primaryColor ?? defaultStyling.primaryColor,\n backgroundColor: widgetStyling.backgroundColor ?? defaultStyling.backgroundColor,\n textColor: widgetStyling.textColor ?? defaultStyling.textColor,\n buttonTextColor: widgetStyling.buttonTextColor ?? defaultStyling.buttonTextColor,\n borderColor: widgetStyling.borderColor ?? defaultStyling.borderColor,\n borderWidth: widgetStyling.borderWidth ?? defaultStyling.borderWidth,\n borderRadius: widgetStyling.borderRadius ?? defaultStyling.borderRadius,\n };\n });\n\n /**\n * Check if an option should show follow-up based on followUpTrigger\n */\n const shouldShowFollowUp = (optionValue: string): boolean => {\n if (followUpTrigger.value === 'none') return false;\n if (followUpTrigger.value === 'all') return true;\n // followUpTrigger === 'negative'\n if (template.value && NEGATIVE_OPTIONS_MAP[template.value]) {\n return NEGATIVE_OPTIONS_MAP[template.value].includes(optionValue);\n }\n // For custom options, use the option's own showFollowUp setting\n const option = options.value?.find((o) => o.value === optionValue);\n return option?.showFollowUp ?? false;\n };\n\n /**\n * Submit a reaction\n */\n const react = async (value: string, followUp?: string): Promise<void> => {\n if (!instance.value) {\n throw new Error('FeedValue not initialized');\n }\n\n isSubmitting.value = true;\n error.value = null;\n\n try {\n await instance.value.react(value, followUp ? { followUp } : undefined);\n submitted.value = value;\n showFollowUp.value = null;\n } catch (err) {\n const reactionError = err instanceof Error ? err : new Error(String(err));\n error.value = reactionError;\n throw reactionError;\n } finally {\n isSubmitting.value = false;\n }\n };\n\n /**\n * Set which option is showing follow-up input\n */\n const setShowFollowUp = (value: string | null): void => {\n showFollowUp.value = value;\n };\n\n /**\n * Clear submitted state to allow re-submission\n */\n const clearSubmitted = (): void => {\n submitted.value = null;\n error.value = null;\n };\n\n return {\n options,\n isSubmitting: readonly(isSubmitting),\n submitted: readonly(submitted),\n error: readonly(error),\n showFollowUp: readonly(showFollowUp),\n react,\n setShowFollowUp,\n clearSubmitted,\n isReactionWidget,\n isReady: readonly(isReady),\n showLabels,\n buttonSize,\n followUpTrigger,\n shouldShowFollowUp,\n styling,\n };\n}\n","/**\n * @feedvalue/vue - ReactionButtons Component\n *\n * Pre-built reaction buttons component for Vue applications.\n * Renders reaction options with optional follow-up input.\n */\n\nimport { defineComponent, ref, computed, h, type PropType } from 'vue';\nimport { useReaction } from './use-reaction';\nimport type { ReactionOption } from '@feedvalue/core';\n\nimport type { ButtonSize, ReactionBorderRadius, ReactionBorderWidth } from '@feedvalue/core';\n\n/**\n * Border radius mapping from preset to CSS value\n */\nconst borderRadiusMap: Record<ReactionBorderRadius, string> = {\n full: '9999px',\n lg: '12px',\n md: '8px',\n sm: '4px',\n none: '0px',\n};\n\n/**\n * Border width mapping from preset to CSS value\n */\nconst borderWidthMap: Record<ReactionBorderWidth, string> = {\n '0': '0px',\n '1': '1px',\n '2': '2px',\n '3': '3px',\n '4': '4px',\n};\n\n/**\n * Button size style variants\n */\nconst sizeStyles: Record<ButtonSize, { button: Record<string, string>; icon: Record<string, string>; label: Record<string, string> }> = {\n sm: {\n button: { padding: '0.375rem 0.75rem', fontSize: '0.75rem', gap: '0.375rem' },\n icon: { fontSize: '1rem' },\n label: { fontSize: '0.75rem' },\n },\n md: {\n button: { padding: '0.5rem 1rem', fontSize: '0.875rem', gap: '0.5rem' },\n icon: { fontSize: '1.125rem' },\n label: { fontSize: '0.875rem' },\n },\n lg: {\n button: { padding: '0.75rem 1.25rem', fontSize: '1rem', gap: '0.625rem' },\n icon: { fontSize: '1.5rem' },\n label: { fontSize: '1rem' },\n },\n};\n\n/**\n * Default CSS styles for the component\n */\nconst styles = {\n container: {\n display: 'flex',\n flexDirection: 'column' as const,\n gap: '0.75rem',\n fontFamily: 'system-ui, -apple-system, sans-serif',\n },\n buttonGroup: {\n display: 'flex',\n flexWrap: 'wrap' as const,\n gap: '0.5rem',\n },\n button: {\n display: 'inline-flex',\n alignItems: 'center',\n fontWeight: '500',\n color: '#374151',\n backgroundColor: '#ffffff',\n border: '1px solid #d1d5db',\n borderRadius: '9999px',\n cursor: 'pointer',\n transition: 'background-color 0.15s, border-color 0.15s, transform 0.1s',\n },\n buttonActive: {\n backgroundColor: '#eef2ff',\n borderColor: '#6366f1',\n color: '#4f46e5',\n },\n buttonDisabled: {\n opacity: 0.7,\n cursor: 'not-allowed',\n },\n icon: {},\n followUp: {\n display: 'flex',\n flexDirection: 'column' as const,\n gap: '0.5rem',\n padding: '0.75rem',\n backgroundColor: '#f9fafb',\n border: '1px solid #e5e7eb',\n borderRadius: '0.5rem',\n },\n input: {\n width: '100%',\n padding: '0.5rem 0.75rem',\n fontSize: '0.875rem',\n border: '1px solid #d1d5db',\n borderRadius: '0.375rem',\n backgroundColor: '#ffffff',\n boxSizing: 'border-box' as const,\n },\n actions: {\n display: 'flex',\n gap: '0.5rem',\n justifyContent: 'flex-end',\n },\n submitButton: {\n padding: '0.375rem 0.75rem',\n fontSize: '0.875rem',\n fontWeight: '500',\n color: '#ffffff',\n backgroundColor: '#6366f1',\n border: 'none',\n borderRadius: '0.375rem',\n cursor: 'pointer',\n },\n cancelButton: {\n padding: '0.375rem 0.75rem',\n fontSize: '0.875rem',\n color: '#6b7280',\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n },\n thankYou: {\n display: 'flex',\n alignItems: 'center',\n gap: '0.5rem',\n padding: '0.75rem 1rem',\n fontSize: '0.875rem',\n color: '#059669',\n backgroundColor: '#ecfdf5',\n border: '1px solid #a7f3d0',\n borderRadius: '0.5rem',\n },\n resetButton: {\n padding: '0.25rem 0.5rem',\n fontSize: '0.875rem',\n color: '#6b7280',\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n },\n error: {\n padding: '0.5rem 0.75rem',\n fontSize: '0.875rem',\n color: '#dc2626',\n backgroundColor: '#fef2f2',\n border: '1px solid #fecaca',\n borderRadius: '0.375rem',\n },\n};\n\n/**\n * ReactionButtons Component\n *\n * Pre-built reaction buttons with follow-up input support.\n *\n * @example\n * ```vue\n * <template>\n * <ReactionButtons widget-id=\"xxx\" @react=\"onReact\" />\n * </template>\n *\n * <script setup>\n * import { ReactionButtons } from '@feedvalue/vue';\n *\n * const onReact = (value, followUp) => {\n * console.log('Reacted:', value, followUp);\n * };\n * </script>\n * ```\n */\nexport const ReactionButtons = defineComponent({\n name: 'ReactionButtons',\n\n props: {\n /** Widget ID (optional if using FeedValue plugin) */\n widgetId: {\n type: String as PropType<string | undefined>,\n default: undefined,\n },\n /** Custom thank you message (overrides widget config) */\n thankYouMessage: {\n type: String as PropType<string | undefined>,\n default: undefined,\n },\n /** Custom class for the container */\n containerClass: {\n type: String,\n default: '',\n },\n /** Custom class for buttons */\n buttonClass: {\n type: String,\n default: '',\n },\n },\n\n emits: {\n /** Emitted when a reaction is submitted */\n react: (value: string, _followUp?: string) => typeof value === 'string',\n },\n\n setup(props, { emit }) {\n const {\n options,\n react,\n isSubmitting,\n submitted,\n error,\n showFollowUp,\n setShowFollowUp,\n clearSubmitted,\n isReady,\n showLabels,\n buttonSize,\n shouldShowFollowUp,\n styling,\n } = useReaction(props.widgetId);\n\n // Local state for follow-up input\n const followUpText = ref('');\n\n // Get follow-up option\n const getFollowUpOption = computed<ReactionOption | null>(() => {\n if (!showFollowUp.value || !options.value) return null;\n return options.value.find((opt) => opt.value === showFollowUp.value) ?? null;\n });\n\n /**\n * Handle option click\n */\n const handleOptionClick = (option: ReactionOption) => {\n if (shouldShowFollowUp(option.value)) {\n setShowFollowUp(option.value);\n } else {\n submitReaction(option.value);\n }\n };\n\n /**\n * Submit reaction\n */\n const submitReaction = async (value: string, followUp?: string) => {\n try {\n await react(value, followUp);\n emit('react', value, followUp);\n } catch {\n // Error is already set in state\n }\n };\n\n /**\n * Handle follow-up form submit\n */\n const handleFollowUpSubmit = (e: Event) => {\n e.preventDefault();\n if (showFollowUp.value) {\n submitReaction(showFollowUp.value, followUpText.value || undefined);\n followUpText.value = '';\n }\n };\n\n /**\n * Cancel follow-up\n */\n const cancelFollowUp = () => {\n setShowFollowUp(null);\n followUpText.value = '';\n };\n\n return () => {\n // Don't render if not ready or no options\n if (!isReady.value || !options.value) {\n return null;\n }\n\n // Render thank you message after submission\n if (submitted.value) {\n const currentStyling = styling.value;\n return h(\n 'div',\n {\n class: props.containerClass,\n style: {\n ...styles.thankYou,\n color: currentStyling.primaryColor ?? '#059669',\n },\n },\n [\n h('span', props.thankYouMessage || 'Thanks for your feedback!'),\n h(\n 'button',\n {\n type: 'button',\n style: styles.resetButton,\n onClick: clearSubmitted,\n 'aria-label': 'Submit another reaction',\n },\n '↺'\n ),\n ]\n );\n }\n\n // Build reaction buttons using styling from widget config\n const currentSizeStyles = sizeStyles[buttonSize.value] || sizeStyles.md;\n const currentStyling = styling.value;\n const borderRadius = borderRadiusMap[currentStyling.borderRadius ?? 'full'] ?? '9999px';\n const borderWidth = borderWidthMap[currentStyling.borderWidth ?? '1'] ?? '1px';\n\n const buttonElements = options.value.map((option) => {\n const isActive = showFollowUp.value === option.value;\n const children = [\n h('span', { style: { ...styles.icon, ...currentSizeStyles.icon }, 'aria-hidden': 'true' }, option.icon),\n ];\n if (showLabels.value) {\n children.push(h('span', { style: { ...currentSizeStyles.label, color: currentStyling.buttonTextColor ?? '#4b5563' } }, option.label));\n }\n\n return h(\n 'button',\n {\n key: option.value,\n type: 'button',\n class: props.buttonClass,\n style: {\n ...styles.button,\n ...currentSizeStyles.button,\n backgroundColor: currentStyling.backgroundColor ?? '#ffffff',\n borderColor: isActive ? (currentStyling.primaryColor ?? '#6366f1') : (currentStyling.borderColor ?? '#e5e7eb'),\n borderWidth: borderWidth,\n borderRadius: borderRadius,\n color: currentStyling.buttonTextColor ?? '#4b5563',\n ...(isActive ? {\n backgroundColor: `${currentStyling.primaryColor ?? '#6366f1'}10`,\n } : {}),\n ...(isSubmitting.value ? styles.buttonDisabled : {}),\n },\n disabled: isSubmitting.value,\n 'aria-pressed': isActive,\n 'aria-label': option.label,\n onClick: () => handleOptionClick(option),\n },\n children\n );\n });\n\n // Build follow-up form if needed\n let followUpForm = null;\n const followUpOption = getFollowUpOption.value;\n if (showFollowUp.value && followUpOption) {\n followUpForm = h(\n 'form',\n {\n style: styles.followUp,\n onSubmit: handleFollowUpSubmit,\n },\n [\n h('input', {\n type: 'text',\n style: styles.input,\n value: followUpText.value,\n placeholder: followUpOption.followUpPlaceholder || 'Tell us more...',\n disabled: isSubmitting.value,\n maxlength: 500,\n onInput: (e: Event) => {\n followUpText.value = (e.target as HTMLInputElement).value;\n },\n }),\n h('div', { style: { ...styles.actions, justifyContent: 'center' } }, [\n h(\n 'button',\n {\n type: 'submit',\n style: {\n ...styles.submitButton,\n backgroundColor: currentStyling.primaryColor ?? '#6366f1',\n borderRadius: borderRadius,\n ...(isSubmitting.value ? styles.buttonDisabled : {}),\n },\n disabled: isSubmitting.value,\n },\n isSubmitting.value ? 'Sending...' : 'Send'\n ),\n h(\n 'button',\n {\n type: 'button',\n style: {\n ...styles.cancelButton,\n backgroundColor: currentStyling.backgroundColor ?? '#ffffff',\n color: currentStyling.buttonTextColor ?? '#6b7280',\n borderRadius: borderRadius,\n border: `${borderWidth} solid ${currentStyling.borderColor ?? '#e5e7eb'}`,\n },\n disabled: isSubmitting.value,\n onClick: cancelFollowUp,\n },\n 'Cancel'\n ),\n ]),\n ]\n );\n }\n\n // Build error message\n let errorElement = null;\n if (error.value) {\n errorElement = h(\n 'div',\n { style: styles.error, role: 'alert' },\n error.value.message\n );\n }\n\n // Return full component\n return h(\n 'div',\n {\n class: props.containerClass,\n style: styles.container,\n role: 'group',\n 'aria-label': 'Reaction buttons',\n },\n [\n h('div', { style: styles.buttonGroup, role: 'radiogroup' }, buttonElements),\n followUpForm,\n errorElement,\n ]\n );\n };\n },\n});\n\nexport default ReactionButtons;\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@feedvalue/vue",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "FeedValue Vue 3 SDK - Plugin and Composables for Vue 3+",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -27,7 +27,7 @@
27
27
  "vue": ">=3.3.0"
28
28
  },
29
29
  "dependencies": {
30
- "@feedvalue/core": "^0.1.10"
30
+ "@feedvalue/core": "^0.1.11"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@vitejs/plugin-vue": "^6.0.3",