@feedvalue/vue 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +248 -0
- package/dist/index.cjs +116 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +142 -0
- package/dist/index.d.ts +142 -0
- package/dist/index.js +111 -0
- package/dist/index.js.map +1 -0
- package/package.json +79 -0
package/README.md
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
# @feedvalue/vue
|
|
2
|
+
|
|
3
|
+
Vue SDK for FeedValue feedback widget. Provides Plugin and Composables for Vue 3+.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @feedvalue/vue
|
|
9
|
+
# or
|
|
10
|
+
pnpm add @feedvalue/vue
|
|
11
|
+
# or
|
|
12
|
+
yarn add @feedvalue/vue
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
### Setup with Plugin
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
// main.ts
|
|
21
|
+
import { createApp } from 'vue';
|
|
22
|
+
import { createFeedValue } from '@feedvalue/vue';
|
|
23
|
+
import App from './App.vue';
|
|
24
|
+
|
|
25
|
+
const app = createApp(App);
|
|
26
|
+
|
|
27
|
+
app.use(createFeedValue({
|
|
28
|
+
widgetId: 'your-widget-id',
|
|
29
|
+
config: {
|
|
30
|
+
theme: 'auto',
|
|
31
|
+
},
|
|
32
|
+
}));
|
|
33
|
+
|
|
34
|
+
app.mount('#app');
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Using the Composable
|
|
38
|
+
|
|
39
|
+
```vue
|
|
40
|
+
<script setup>
|
|
41
|
+
import { useFeedValue } from '@feedvalue/vue';
|
|
42
|
+
|
|
43
|
+
const { open, isReady, isOpen } = useFeedValue();
|
|
44
|
+
</script>
|
|
45
|
+
|
|
46
|
+
<template>
|
|
47
|
+
<button @click="open" :disabled="!isReady">
|
|
48
|
+
{{ isOpen ? 'Close' : 'Give Feedback' }}
|
|
49
|
+
</button>
|
|
50
|
+
</template>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Standalone Usage (No Plugin)
|
|
54
|
+
|
|
55
|
+
```vue
|
|
56
|
+
<script setup>
|
|
57
|
+
import { useFeedValue } from '@feedvalue/vue';
|
|
58
|
+
|
|
59
|
+
// Pass widgetId directly when not using plugin
|
|
60
|
+
const { open, isReady } = useFeedValue('your-widget-id');
|
|
61
|
+
</script>
|
|
62
|
+
|
|
63
|
+
<template>
|
|
64
|
+
<button @click="open" :disabled="!isReady">
|
|
65
|
+
Feedback
|
|
66
|
+
</button>
|
|
67
|
+
</template>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Programmatic Submission
|
|
71
|
+
|
|
72
|
+
```vue
|
|
73
|
+
<script setup>
|
|
74
|
+
import { ref } from 'vue';
|
|
75
|
+
import { useFeedValue } from '@feedvalue/vue';
|
|
76
|
+
|
|
77
|
+
const { submit, isSubmitting, error } = useFeedValue();
|
|
78
|
+
const message = ref('');
|
|
79
|
+
|
|
80
|
+
async function handleSubmit() {
|
|
81
|
+
try {
|
|
82
|
+
await submit({ message: message.value });
|
|
83
|
+
message.value = '';
|
|
84
|
+
console.log('Feedback submitted!');
|
|
85
|
+
} catch (err) {
|
|
86
|
+
console.error('Failed:', err);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
</script>
|
|
90
|
+
|
|
91
|
+
<template>
|
|
92
|
+
<form @submit.prevent="handleSubmit">
|
|
93
|
+
<textarea v-model="message" placeholder="Your feedback..." />
|
|
94
|
+
<button type="submit" :disabled="isSubmitting">
|
|
95
|
+
{{ isSubmitting ? 'Submitting...' : 'Submit' }}
|
|
96
|
+
</button>
|
|
97
|
+
<p v-if="error" class="error">{{ error.message }}</p>
|
|
98
|
+
</form>
|
|
99
|
+
</template>
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### User Identification
|
|
103
|
+
|
|
104
|
+
```vue
|
|
105
|
+
<script setup>
|
|
106
|
+
import { watch } from 'vue';
|
|
107
|
+
import { useFeedValue } from '@feedvalue/vue';
|
|
108
|
+
|
|
109
|
+
const props = defineProps<{ user: User | null }>();
|
|
110
|
+
const { identify, setData, reset } = useFeedValue();
|
|
111
|
+
|
|
112
|
+
watch(() => props.user, (user) => {
|
|
113
|
+
if (user) {
|
|
114
|
+
identify(user.id, {
|
|
115
|
+
name: user.name,
|
|
116
|
+
email: user.email,
|
|
117
|
+
plan: user.plan,
|
|
118
|
+
});
|
|
119
|
+
setData({ company: user.company });
|
|
120
|
+
} else {
|
|
121
|
+
reset();
|
|
122
|
+
}
|
|
123
|
+
}, { immediate: true });
|
|
124
|
+
</script>
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Options API Support
|
|
128
|
+
|
|
129
|
+
```vue
|
|
130
|
+
<script>
|
|
131
|
+
export default {
|
|
132
|
+
methods: {
|
|
133
|
+
openFeedback() {
|
|
134
|
+
// Access via global property
|
|
135
|
+
this.$feedvalue?.open();
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
</script>
|
|
140
|
+
|
|
141
|
+
<template>
|
|
142
|
+
<button @click="openFeedback">Feedback</button>
|
|
143
|
+
</template>
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## API Reference
|
|
147
|
+
|
|
148
|
+
### `createFeedValue(options)`
|
|
149
|
+
|
|
150
|
+
Creates a Vue plugin for FeedValue.
|
|
151
|
+
|
|
152
|
+
| Option | Type | Required | Description |
|
|
153
|
+
|--------|------|----------|-------------|
|
|
154
|
+
| `widgetId` | `string` | Yes | Widget ID from FeedValue dashboard |
|
|
155
|
+
| `apiBaseUrl` | `string` | No | Custom API URL (for self-hosted) |
|
|
156
|
+
| `config` | `Partial<FeedValueConfig>` | No | Configuration overrides |
|
|
157
|
+
|
|
158
|
+
### `useFeedValue(widgetId?, config?)`
|
|
159
|
+
|
|
160
|
+
Composable to access FeedValue functionality.
|
|
161
|
+
|
|
162
|
+
**Parameters:**
|
|
163
|
+
|
|
164
|
+
| Param | Type | Description |
|
|
165
|
+
|-------|------|-------------|
|
|
166
|
+
| `widgetId` | `string` | Optional widget ID (not needed if plugin is installed) |
|
|
167
|
+
| `config` | `Partial<FeedValueConfig>` | Optional config overrides |
|
|
168
|
+
|
|
169
|
+
**Returns:**
|
|
170
|
+
|
|
171
|
+
| Property | Type | Description |
|
|
172
|
+
|----------|------|-------------|
|
|
173
|
+
| `instance` | `Readonly<ShallowRef<FeedValueInstance \| null>>` | Raw instance |
|
|
174
|
+
| `isReady` | `Readonly<Ref<boolean>>` | Widget initialized |
|
|
175
|
+
| `isOpen` | `Readonly<Ref<boolean>>` | Modal is open |
|
|
176
|
+
| `isVisible` | `Readonly<Ref<boolean>>` | Trigger is visible |
|
|
177
|
+
| `error` | `Readonly<Ref<Error \| null>>` | Current error |
|
|
178
|
+
| `isSubmitting` | `Readonly<Ref<boolean>>` | Submission in progress |
|
|
179
|
+
| `open` | `() => void` | Open modal |
|
|
180
|
+
| `close` | `() => void` | Close modal |
|
|
181
|
+
| `toggle` | `() => void` | Toggle modal |
|
|
182
|
+
| `show` | `() => void` | Show trigger |
|
|
183
|
+
| `hide` | `() => void` | Hide trigger |
|
|
184
|
+
| `submit` | `(feedback) => Promise<void>` | Submit feedback |
|
|
185
|
+
| `identify` | `(userId, traits?) => void` | Identify user |
|
|
186
|
+
| `setData` | `(data) => void` | Set user data |
|
|
187
|
+
| `reset` | `() => void` | Reset user data |
|
|
188
|
+
|
|
189
|
+
### Injection Keys
|
|
190
|
+
|
|
191
|
+
For advanced usage with `inject()`:
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
import { inject } from 'vue';
|
|
195
|
+
import { FEEDVALUE_KEY, FEEDVALUE_OPTIONS_KEY } from '@feedvalue/vue';
|
|
196
|
+
|
|
197
|
+
// Get raw FeedValue instance
|
|
198
|
+
const instance = inject(FEEDVALUE_KEY);
|
|
199
|
+
|
|
200
|
+
// Get plugin options
|
|
201
|
+
const options = inject(FEEDVALUE_OPTIONS_KEY);
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## Nuxt 3 Integration
|
|
205
|
+
|
|
206
|
+
Create a plugin file:
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
// plugins/feedvalue.client.ts
|
|
210
|
+
import { createFeedValue } from '@feedvalue/vue';
|
|
211
|
+
|
|
212
|
+
export default defineNuxtPlugin((nuxtApp) => {
|
|
213
|
+
nuxtApp.vueApp.use(createFeedValue({
|
|
214
|
+
widgetId: 'your-widget-id',
|
|
215
|
+
}));
|
|
216
|
+
});
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
The `.client.ts` suffix ensures the plugin only runs on the client side.
|
|
220
|
+
|
|
221
|
+
## SSR Support
|
|
222
|
+
|
|
223
|
+
The SDK handles SSR automatically:
|
|
224
|
+
- Plugin only initializes on client side
|
|
225
|
+
- Composable returns safe defaults during SSR
|
|
226
|
+
- No hydration mismatches
|
|
227
|
+
|
|
228
|
+
```vue
|
|
229
|
+
<script setup>
|
|
230
|
+
import { useFeedValue } from '@feedvalue/vue';
|
|
231
|
+
|
|
232
|
+
const { isReady } = useFeedValue();
|
|
233
|
+
// isReady.value is false during SSR
|
|
234
|
+
</script>
|
|
235
|
+
|
|
236
|
+
<template>
|
|
237
|
+
<!-- Safe to use in SSR context -->
|
|
238
|
+
<button :disabled="!isReady">Feedback</button>
|
|
239
|
+
</template>
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## Requirements
|
|
243
|
+
|
|
244
|
+
- Vue 3.3.0 or higher
|
|
245
|
+
|
|
246
|
+
## License
|
|
247
|
+
|
|
248
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var core = require('@feedvalue/core');
|
|
4
|
+
var vue = require('vue');
|
|
5
|
+
|
|
6
|
+
// src/plugin.ts
|
|
7
|
+
var FEEDVALUE_KEY = /* @__PURE__ */ Symbol("feedvalue");
|
|
8
|
+
var FEEDVALUE_OPTIONS_KEY = /* @__PURE__ */ Symbol("feedvalue-options");
|
|
9
|
+
function createFeedValue(options) {
|
|
10
|
+
let instance = null;
|
|
11
|
+
return {
|
|
12
|
+
install(app) {
|
|
13
|
+
if (typeof window !== "undefined") {
|
|
14
|
+
instance = core.FeedValue.init({
|
|
15
|
+
widgetId: options.widgetId,
|
|
16
|
+
apiBaseUrl: options.apiBaseUrl,
|
|
17
|
+
config: options.config,
|
|
18
|
+
headless: options.headless
|
|
19
|
+
});
|
|
20
|
+
app.provide(FEEDVALUE_KEY, instance);
|
|
21
|
+
app.config.globalProperties.$feedvalue = instance;
|
|
22
|
+
}
|
|
23
|
+
app.provide(FEEDVALUE_OPTIONS_KEY, options);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function useFeedValue(widgetId, config) {
|
|
28
|
+
const injectedInstance = vue.inject(FEEDVALUE_KEY, null);
|
|
29
|
+
const injectedOptions = vue.inject(FEEDVALUE_OPTIONS_KEY, null);
|
|
30
|
+
const instance = vue.shallowRef(null);
|
|
31
|
+
const isReady = vue.ref(false);
|
|
32
|
+
const isOpen = vue.ref(false);
|
|
33
|
+
const isVisible = vue.ref(false);
|
|
34
|
+
const error = vue.ref(null);
|
|
35
|
+
const isSubmitting = vue.ref(false);
|
|
36
|
+
const isHeadless = vue.ref(false);
|
|
37
|
+
let ownsInstance = false;
|
|
38
|
+
let unsubscribe = null;
|
|
39
|
+
const syncState = () => {
|
|
40
|
+
const state = instance.value?.getSnapshot();
|
|
41
|
+
if (state) {
|
|
42
|
+
isReady.value = state.isReady;
|
|
43
|
+
isOpen.value = state.isOpen;
|
|
44
|
+
isVisible.value = state.isVisible;
|
|
45
|
+
error.value = state.error;
|
|
46
|
+
isSubmitting.value = state.isSubmitting;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
vue.onMounted(() => {
|
|
50
|
+
if (injectedInstance && !widgetId) {
|
|
51
|
+
instance.value = injectedInstance;
|
|
52
|
+
isHeadless.value = injectedInstance.isHeadless();
|
|
53
|
+
} else {
|
|
54
|
+
const effectiveWidgetId = widgetId ?? injectedOptions?.widgetId;
|
|
55
|
+
if (!effectiveWidgetId) {
|
|
56
|
+
console.error(
|
|
57
|
+
"[FeedValue] No widgetId provided. Either install the plugin with createFeedValue() or pass widgetId to useFeedValue()."
|
|
58
|
+
);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
instance.value = core.FeedValue.init({
|
|
62
|
+
widgetId: effectiveWidgetId,
|
|
63
|
+
apiBaseUrl: injectedOptions?.apiBaseUrl,
|
|
64
|
+
config: config ?? injectedOptions?.config,
|
|
65
|
+
headless: injectedOptions?.headless
|
|
66
|
+
});
|
|
67
|
+
ownsInstance = true;
|
|
68
|
+
}
|
|
69
|
+
if (instance.value) {
|
|
70
|
+
unsubscribe = instance.value.subscribe(syncState);
|
|
71
|
+
isHeadless.value = instance.value.isHeadless();
|
|
72
|
+
syncState();
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
vue.onUnmounted(() => {
|
|
76
|
+
unsubscribe?.();
|
|
77
|
+
if (ownsInstance && instance.value) {
|
|
78
|
+
instance.value.destroy();
|
|
79
|
+
}
|
|
80
|
+
instance.value = null;
|
|
81
|
+
});
|
|
82
|
+
const open = () => instance.value?.open();
|
|
83
|
+
const close = () => instance.value?.close();
|
|
84
|
+
const toggle = () => instance.value?.toggle();
|
|
85
|
+
const show = () => instance.value?.show();
|
|
86
|
+
const hide = () => instance.value?.hide();
|
|
87
|
+
const submit = (feedback) => instance.value?.submit(feedback) ?? Promise.reject(new Error("Not initialized"));
|
|
88
|
+
const identify = (userId, traits) => instance.value?.identify(userId, traits);
|
|
89
|
+
const setData = (data) => instance.value?.setData(data);
|
|
90
|
+
const reset = () => instance.value?.reset();
|
|
91
|
+
return {
|
|
92
|
+
instance: vue.readonly(instance),
|
|
93
|
+
isReady: vue.readonly(isReady),
|
|
94
|
+
isOpen: vue.readonly(isOpen),
|
|
95
|
+
isVisible: vue.readonly(isVisible),
|
|
96
|
+
error: vue.readonly(error),
|
|
97
|
+
isSubmitting: vue.readonly(isSubmitting),
|
|
98
|
+
isHeadless: vue.readonly(isHeadless),
|
|
99
|
+
open,
|
|
100
|
+
close,
|
|
101
|
+
toggle,
|
|
102
|
+
show,
|
|
103
|
+
hide,
|
|
104
|
+
submit,
|
|
105
|
+
identify,
|
|
106
|
+
setData,
|
|
107
|
+
reset
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
exports.FEEDVALUE_KEY = FEEDVALUE_KEY;
|
|
112
|
+
exports.FEEDVALUE_OPTIONS_KEY = FEEDVALUE_OPTIONS_KEY;
|
|
113
|
+
exports.createFeedValue = createFeedValue;
|
|
114
|
+
exports.useFeedValue = useFeedValue;
|
|
115
|
+
//# sourceMappingURL=index.cjs.map
|
|
116
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/plugin.ts","../src/composables.ts"],"names":["FeedValue","inject","shallowRef","ref","onMounted","onUnmounted","readonly"],"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"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { InjectionKey, App, ShallowRef, Ref } from 'vue';
|
|
2
|
+
import { FeedValueInstance, FeedValueConfig, FeedbackData, UserTraits } from '@feedvalue/core';
|
|
3
|
+
export { FeedValueConfig, FeedValueEvents, FeedValueState, FeedbackData, FeedbackMetadata, UserData, UserTraits } from '@feedvalue/core';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @feedvalue/vue - Plugin
|
|
7
|
+
*
|
|
8
|
+
* Vue plugin for FeedValue. Provides app-level configuration
|
|
9
|
+
* and automatic initialization.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Plugin options
|
|
14
|
+
*/
|
|
15
|
+
interface FeedValuePluginOptions {
|
|
16
|
+
/** Widget ID from FeedValue dashboard */
|
|
17
|
+
widgetId: string;
|
|
18
|
+
/** API base URL (for self-hosted) */
|
|
19
|
+
apiBaseUrl?: string;
|
|
20
|
+
/** Configuration overrides */
|
|
21
|
+
config?: Partial<FeedValueConfig>;
|
|
22
|
+
/**
|
|
23
|
+
* Headless mode - disables all DOM rendering.
|
|
24
|
+
* Use this when you want full control over the UI.
|
|
25
|
+
* The SDK will still fetch config and provide all API methods
|
|
26
|
+
* but won't render any trigger button or modal.
|
|
27
|
+
*
|
|
28
|
+
* @default false
|
|
29
|
+
*/
|
|
30
|
+
headless?: boolean;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Injection key for FeedValue instance
|
|
34
|
+
*/
|
|
35
|
+
declare const FEEDVALUE_KEY: InjectionKey<FeedValueInstance>;
|
|
36
|
+
/**
|
|
37
|
+
* Injection key for widget ID (used by useFeedValue when no instance is injected)
|
|
38
|
+
*/
|
|
39
|
+
declare const FEEDVALUE_OPTIONS_KEY: InjectionKey<FeedValuePluginOptions>;
|
|
40
|
+
/**
|
|
41
|
+
* Create FeedValue Vue plugin
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```ts
|
|
45
|
+
* // main.ts
|
|
46
|
+
* import { createApp } from 'vue';
|
|
47
|
+
* import { createFeedValue } from '@feedvalue/vue';
|
|
48
|
+
* import App from './App.vue';
|
|
49
|
+
*
|
|
50
|
+
* const app = createApp(App);
|
|
51
|
+
*
|
|
52
|
+
* app.use(createFeedValue({
|
|
53
|
+
* widgetId: 'your-widget-id',
|
|
54
|
+
* config: { theme: 'dark' }
|
|
55
|
+
* }));
|
|
56
|
+
*
|
|
57
|
+
* app.mount('#app');
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
declare function createFeedValue(options: FeedValuePluginOptions): {
|
|
61
|
+
install(app: App): void;
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Type augmentation for global properties
|
|
65
|
+
*/
|
|
66
|
+
declare module 'vue' {
|
|
67
|
+
interface ComponentCustomProperties {
|
|
68
|
+
$feedvalue: FeedValueInstance | undefined;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @feedvalue/vue - Composables
|
|
74
|
+
*
|
|
75
|
+
* Vue composables for FeedValue. Provides reactive state and methods.
|
|
76
|
+
*/
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Return type for useFeedValue composable
|
|
80
|
+
*/
|
|
81
|
+
interface UseFeedValueReturn {
|
|
82
|
+
/** FeedValue instance (for advanced usage) */
|
|
83
|
+
instance: Readonly<ShallowRef<FeedValueInstance | null>>;
|
|
84
|
+
/** Widget is ready */
|
|
85
|
+
isReady: Readonly<Ref<boolean>>;
|
|
86
|
+
/** Modal is open */
|
|
87
|
+
isOpen: Readonly<Ref<boolean>>;
|
|
88
|
+
/** Widget is visible */
|
|
89
|
+
isVisible: Readonly<Ref<boolean>>;
|
|
90
|
+
/** Current error */
|
|
91
|
+
error: Readonly<Ref<Error | null>>;
|
|
92
|
+
/** Submission in progress */
|
|
93
|
+
isSubmitting: Readonly<Ref<boolean>>;
|
|
94
|
+
/** Running in headless mode (no default UI rendered) */
|
|
95
|
+
isHeadless: Readonly<Ref<boolean>>;
|
|
96
|
+
/** Open the feedback modal */
|
|
97
|
+
open: () => void;
|
|
98
|
+
/** Close the feedback modal */
|
|
99
|
+
close: () => void;
|
|
100
|
+
/** Toggle the feedback modal */
|
|
101
|
+
toggle: () => void;
|
|
102
|
+
/** Show the trigger button */
|
|
103
|
+
show: () => void;
|
|
104
|
+
/** Hide the trigger button */
|
|
105
|
+
hide: () => void;
|
|
106
|
+
/** Submit feedback programmatically */
|
|
107
|
+
submit: (feedback: Partial<FeedbackData>) => Promise<void>;
|
|
108
|
+
/** Identify user */
|
|
109
|
+
identify: (userId: string, traits?: UserTraits) => void;
|
|
110
|
+
/** Set user data */
|
|
111
|
+
setData: (data: Record<string, string>) => void;
|
|
112
|
+
/** Reset user data */
|
|
113
|
+
reset: () => void;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* FeedValue composable
|
|
117
|
+
*
|
|
118
|
+
* Can be used with or without plugin. If plugin is installed, uses the
|
|
119
|
+
* provided instance. Otherwise, creates a new instance.
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* ```vue
|
|
123
|
+
* <script setup>
|
|
124
|
+
* import { useFeedValue } from '@feedvalue/vue';
|
|
125
|
+
*
|
|
126
|
+
* // With plugin installed
|
|
127
|
+
* const { open, isReady } = useFeedValue();
|
|
128
|
+
*
|
|
129
|
+
* // Or standalone with widgetId
|
|
130
|
+
* const { open, isReady } = useFeedValue('your-widget-id');
|
|
131
|
+
* </script>
|
|
132
|
+
*
|
|
133
|
+
* <template>
|
|
134
|
+
* <button @click="open" :disabled="!isReady">
|
|
135
|
+
* Give Feedback
|
|
136
|
+
* </button>
|
|
137
|
+
* </template>
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
declare function useFeedValue(widgetId?: string, config?: Partial<FeedValueConfig>): UseFeedValueReturn;
|
|
141
|
+
|
|
142
|
+
export { FEEDVALUE_KEY, FEEDVALUE_OPTIONS_KEY, type FeedValuePluginOptions, type UseFeedValueReturn, createFeedValue, useFeedValue };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { InjectionKey, App, ShallowRef, Ref } from 'vue';
|
|
2
|
+
import { FeedValueInstance, FeedValueConfig, FeedbackData, UserTraits } from '@feedvalue/core';
|
|
3
|
+
export { FeedValueConfig, FeedValueEvents, FeedValueState, FeedbackData, FeedbackMetadata, UserData, UserTraits } from '@feedvalue/core';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @feedvalue/vue - Plugin
|
|
7
|
+
*
|
|
8
|
+
* Vue plugin for FeedValue. Provides app-level configuration
|
|
9
|
+
* and automatic initialization.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Plugin options
|
|
14
|
+
*/
|
|
15
|
+
interface FeedValuePluginOptions {
|
|
16
|
+
/** Widget ID from FeedValue dashboard */
|
|
17
|
+
widgetId: string;
|
|
18
|
+
/** API base URL (for self-hosted) */
|
|
19
|
+
apiBaseUrl?: string;
|
|
20
|
+
/** Configuration overrides */
|
|
21
|
+
config?: Partial<FeedValueConfig>;
|
|
22
|
+
/**
|
|
23
|
+
* Headless mode - disables all DOM rendering.
|
|
24
|
+
* Use this when you want full control over the UI.
|
|
25
|
+
* The SDK will still fetch config and provide all API methods
|
|
26
|
+
* but won't render any trigger button or modal.
|
|
27
|
+
*
|
|
28
|
+
* @default false
|
|
29
|
+
*/
|
|
30
|
+
headless?: boolean;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Injection key for FeedValue instance
|
|
34
|
+
*/
|
|
35
|
+
declare const FEEDVALUE_KEY: InjectionKey<FeedValueInstance>;
|
|
36
|
+
/**
|
|
37
|
+
* Injection key for widget ID (used by useFeedValue when no instance is injected)
|
|
38
|
+
*/
|
|
39
|
+
declare const FEEDVALUE_OPTIONS_KEY: InjectionKey<FeedValuePluginOptions>;
|
|
40
|
+
/**
|
|
41
|
+
* Create FeedValue Vue plugin
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```ts
|
|
45
|
+
* // main.ts
|
|
46
|
+
* import { createApp } from 'vue';
|
|
47
|
+
* import { createFeedValue } from '@feedvalue/vue';
|
|
48
|
+
* import App from './App.vue';
|
|
49
|
+
*
|
|
50
|
+
* const app = createApp(App);
|
|
51
|
+
*
|
|
52
|
+
* app.use(createFeedValue({
|
|
53
|
+
* widgetId: 'your-widget-id',
|
|
54
|
+
* config: { theme: 'dark' }
|
|
55
|
+
* }));
|
|
56
|
+
*
|
|
57
|
+
* app.mount('#app');
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
declare function createFeedValue(options: FeedValuePluginOptions): {
|
|
61
|
+
install(app: App): void;
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Type augmentation for global properties
|
|
65
|
+
*/
|
|
66
|
+
declare module 'vue' {
|
|
67
|
+
interface ComponentCustomProperties {
|
|
68
|
+
$feedvalue: FeedValueInstance | undefined;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @feedvalue/vue - Composables
|
|
74
|
+
*
|
|
75
|
+
* Vue composables for FeedValue. Provides reactive state and methods.
|
|
76
|
+
*/
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Return type for useFeedValue composable
|
|
80
|
+
*/
|
|
81
|
+
interface UseFeedValueReturn {
|
|
82
|
+
/** FeedValue instance (for advanced usage) */
|
|
83
|
+
instance: Readonly<ShallowRef<FeedValueInstance | null>>;
|
|
84
|
+
/** Widget is ready */
|
|
85
|
+
isReady: Readonly<Ref<boolean>>;
|
|
86
|
+
/** Modal is open */
|
|
87
|
+
isOpen: Readonly<Ref<boolean>>;
|
|
88
|
+
/** Widget is visible */
|
|
89
|
+
isVisible: Readonly<Ref<boolean>>;
|
|
90
|
+
/** Current error */
|
|
91
|
+
error: Readonly<Ref<Error | null>>;
|
|
92
|
+
/** Submission in progress */
|
|
93
|
+
isSubmitting: Readonly<Ref<boolean>>;
|
|
94
|
+
/** Running in headless mode (no default UI rendered) */
|
|
95
|
+
isHeadless: Readonly<Ref<boolean>>;
|
|
96
|
+
/** Open the feedback modal */
|
|
97
|
+
open: () => void;
|
|
98
|
+
/** Close the feedback modal */
|
|
99
|
+
close: () => void;
|
|
100
|
+
/** Toggle the feedback modal */
|
|
101
|
+
toggle: () => void;
|
|
102
|
+
/** Show the trigger button */
|
|
103
|
+
show: () => void;
|
|
104
|
+
/** Hide the trigger button */
|
|
105
|
+
hide: () => void;
|
|
106
|
+
/** Submit feedback programmatically */
|
|
107
|
+
submit: (feedback: Partial<FeedbackData>) => Promise<void>;
|
|
108
|
+
/** Identify user */
|
|
109
|
+
identify: (userId: string, traits?: UserTraits) => void;
|
|
110
|
+
/** Set user data */
|
|
111
|
+
setData: (data: Record<string, string>) => void;
|
|
112
|
+
/** Reset user data */
|
|
113
|
+
reset: () => void;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* FeedValue composable
|
|
117
|
+
*
|
|
118
|
+
* Can be used with or without plugin. If plugin is installed, uses the
|
|
119
|
+
* provided instance. Otherwise, creates a new instance.
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* ```vue
|
|
123
|
+
* <script setup>
|
|
124
|
+
* import { useFeedValue } from '@feedvalue/vue';
|
|
125
|
+
*
|
|
126
|
+
* // With plugin installed
|
|
127
|
+
* const { open, isReady } = useFeedValue();
|
|
128
|
+
*
|
|
129
|
+
* // Or standalone with widgetId
|
|
130
|
+
* const { open, isReady } = useFeedValue('your-widget-id');
|
|
131
|
+
* </script>
|
|
132
|
+
*
|
|
133
|
+
* <template>
|
|
134
|
+
* <button @click="open" :disabled="!isReady">
|
|
135
|
+
* Give Feedback
|
|
136
|
+
* </button>
|
|
137
|
+
* </template>
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
declare function useFeedValue(widgetId?: string, config?: Partial<FeedValueConfig>): UseFeedValueReturn;
|
|
141
|
+
|
|
142
|
+
export { FEEDVALUE_KEY, FEEDVALUE_OPTIONS_KEY, type FeedValuePluginOptions, type UseFeedValueReturn, createFeedValue, useFeedValue };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { FeedValue } from '@feedvalue/core';
|
|
2
|
+
import { inject, shallowRef, ref, onMounted, onUnmounted, readonly } from 'vue';
|
|
3
|
+
|
|
4
|
+
// src/plugin.ts
|
|
5
|
+
var FEEDVALUE_KEY = /* @__PURE__ */ Symbol("feedvalue");
|
|
6
|
+
var FEEDVALUE_OPTIONS_KEY = /* @__PURE__ */ Symbol("feedvalue-options");
|
|
7
|
+
function createFeedValue(options) {
|
|
8
|
+
let instance = null;
|
|
9
|
+
return {
|
|
10
|
+
install(app) {
|
|
11
|
+
if (typeof window !== "undefined") {
|
|
12
|
+
instance = FeedValue.init({
|
|
13
|
+
widgetId: options.widgetId,
|
|
14
|
+
apiBaseUrl: options.apiBaseUrl,
|
|
15
|
+
config: options.config,
|
|
16
|
+
headless: options.headless
|
|
17
|
+
});
|
|
18
|
+
app.provide(FEEDVALUE_KEY, instance);
|
|
19
|
+
app.config.globalProperties.$feedvalue = instance;
|
|
20
|
+
}
|
|
21
|
+
app.provide(FEEDVALUE_OPTIONS_KEY, options);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function useFeedValue(widgetId, config) {
|
|
26
|
+
const injectedInstance = inject(FEEDVALUE_KEY, null);
|
|
27
|
+
const injectedOptions = inject(FEEDVALUE_OPTIONS_KEY, null);
|
|
28
|
+
const instance = shallowRef(null);
|
|
29
|
+
const isReady = ref(false);
|
|
30
|
+
const isOpen = ref(false);
|
|
31
|
+
const isVisible = ref(false);
|
|
32
|
+
const error = ref(null);
|
|
33
|
+
const isSubmitting = ref(false);
|
|
34
|
+
const isHeadless = ref(false);
|
|
35
|
+
let ownsInstance = false;
|
|
36
|
+
let unsubscribe = null;
|
|
37
|
+
const syncState = () => {
|
|
38
|
+
const state = instance.value?.getSnapshot();
|
|
39
|
+
if (state) {
|
|
40
|
+
isReady.value = state.isReady;
|
|
41
|
+
isOpen.value = state.isOpen;
|
|
42
|
+
isVisible.value = state.isVisible;
|
|
43
|
+
error.value = state.error;
|
|
44
|
+
isSubmitting.value = state.isSubmitting;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
onMounted(() => {
|
|
48
|
+
if (injectedInstance && !widgetId) {
|
|
49
|
+
instance.value = injectedInstance;
|
|
50
|
+
isHeadless.value = injectedInstance.isHeadless();
|
|
51
|
+
} else {
|
|
52
|
+
const effectiveWidgetId = widgetId ?? injectedOptions?.widgetId;
|
|
53
|
+
if (!effectiveWidgetId) {
|
|
54
|
+
console.error(
|
|
55
|
+
"[FeedValue] No widgetId provided. Either install the plugin with createFeedValue() or pass widgetId to useFeedValue()."
|
|
56
|
+
);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
instance.value = FeedValue.init({
|
|
60
|
+
widgetId: effectiveWidgetId,
|
|
61
|
+
apiBaseUrl: injectedOptions?.apiBaseUrl,
|
|
62
|
+
config: config ?? injectedOptions?.config,
|
|
63
|
+
headless: injectedOptions?.headless
|
|
64
|
+
});
|
|
65
|
+
ownsInstance = true;
|
|
66
|
+
}
|
|
67
|
+
if (instance.value) {
|
|
68
|
+
unsubscribe = instance.value.subscribe(syncState);
|
|
69
|
+
isHeadless.value = instance.value.isHeadless();
|
|
70
|
+
syncState();
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
onUnmounted(() => {
|
|
74
|
+
unsubscribe?.();
|
|
75
|
+
if (ownsInstance && instance.value) {
|
|
76
|
+
instance.value.destroy();
|
|
77
|
+
}
|
|
78
|
+
instance.value = null;
|
|
79
|
+
});
|
|
80
|
+
const open = () => instance.value?.open();
|
|
81
|
+
const close = () => instance.value?.close();
|
|
82
|
+
const toggle = () => instance.value?.toggle();
|
|
83
|
+
const show = () => instance.value?.show();
|
|
84
|
+
const hide = () => instance.value?.hide();
|
|
85
|
+
const submit = (feedback) => instance.value?.submit(feedback) ?? Promise.reject(new Error("Not initialized"));
|
|
86
|
+
const identify = (userId, traits) => instance.value?.identify(userId, traits);
|
|
87
|
+
const setData = (data) => instance.value?.setData(data);
|
|
88
|
+
const reset = () => instance.value?.reset();
|
|
89
|
+
return {
|
|
90
|
+
instance: readonly(instance),
|
|
91
|
+
isReady: readonly(isReady),
|
|
92
|
+
isOpen: readonly(isOpen),
|
|
93
|
+
isVisible: readonly(isVisible),
|
|
94
|
+
error: readonly(error),
|
|
95
|
+
isSubmitting: readonly(isSubmitting),
|
|
96
|
+
isHeadless: readonly(isHeadless),
|
|
97
|
+
open,
|
|
98
|
+
close,
|
|
99
|
+
toggle,
|
|
100
|
+
show,
|
|
101
|
+
hide,
|
|
102
|
+
submit,
|
|
103
|
+
identify,
|
|
104
|
+
setData,
|
|
105
|
+
reset
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export { FEEDVALUE_KEY, FEEDVALUE_OPTIONS_KEY, createFeedValue, useFeedValue };
|
|
110
|
+
//# sourceMappingURL=index.js.map
|
|
111
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/plugin.ts","../src/composables.ts"],"names":["FeedValue"],"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"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@feedvalue/vue",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "FeedValue Vue 3 SDK - Plugin and Composables for Vue 3+",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/index.d.cts",
|
|
17
|
+
"default": "./dist/index.cjs"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"README.md"
|
|
24
|
+
],
|
|
25
|
+
"sideEffects": false,
|
|
26
|
+
"peerDependencies": {
|
|
27
|
+
"vue": ">=3.3.0"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@feedvalue/core": "^0.1.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@vitejs/plugin-vue": "^5.2.0",
|
|
34
|
+
"@vitest/coverage-v8": "^2.1.0",
|
|
35
|
+
"@vue/test-utils": "^2.4.0",
|
|
36
|
+
"eslint": "^9.17.0",
|
|
37
|
+
"happy-dom": "^15.11.0",
|
|
38
|
+
"tsup": "^8.3.0",
|
|
39
|
+
"typescript": "^5.7.0",
|
|
40
|
+
"vitest": "^2.1.0",
|
|
41
|
+
"vue": "^3.5.0"
|
|
42
|
+
},
|
|
43
|
+
"publishConfig": {
|
|
44
|
+
"access": "public"
|
|
45
|
+
},
|
|
46
|
+
"repository": {
|
|
47
|
+
"type": "git",
|
|
48
|
+
"url": "https://github.com/sarverenterprises/feedvalue-packages.git",
|
|
49
|
+
"directory": "packages/vue"
|
|
50
|
+
},
|
|
51
|
+
"homepage": "https://feedvalue.com",
|
|
52
|
+
"bugs": {
|
|
53
|
+
"url": "https://github.com/sarverenterprises/feedvalue-packages/issues"
|
|
54
|
+
},
|
|
55
|
+
"license": "MIT",
|
|
56
|
+
"author": "Sarver Enterprises",
|
|
57
|
+
"keywords": [
|
|
58
|
+
"feedvalue",
|
|
59
|
+
"feedback",
|
|
60
|
+
"widget",
|
|
61
|
+
"vue",
|
|
62
|
+
"vue3",
|
|
63
|
+
"composable",
|
|
64
|
+
"nuxt"
|
|
65
|
+
],
|
|
66
|
+
"engines": {
|
|
67
|
+
"node": ">=18"
|
|
68
|
+
},
|
|
69
|
+
"scripts": {
|
|
70
|
+
"build": "tsup",
|
|
71
|
+
"dev": "tsup --watch",
|
|
72
|
+
"lint": "eslint src --ext .ts",
|
|
73
|
+
"test": "vitest run",
|
|
74
|
+
"test:watch": "vitest",
|
|
75
|
+
"test:coverage": "vitest run --coverage",
|
|
76
|
+
"typecheck": "tsc --noEmit",
|
|
77
|
+
"clean": "rm -rf dist"
|
|
78
|
+
}
|
|
79
|
+
}
|