@pollenate/react 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 +126 -0
- package/dist/index.cjs +172 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +138 -0
- package/dist/index.d.ts +138 -0
- package/dist/index.js +170 -0
- package/dist/index.js.map +1 -0
- package/package.json +64 -0
package/README.md
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# @pollenate/react
|
|
2
|
+
|
|
3
|
+
React component for the [Pollenate](https://pollenate.dev) feedback widget.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @pollenate/react
|
|
9
|
+
# or
|
|
10
|
+
pnpm add @pollenate/react
|
|
11
|
+
# or
|
|
12
|
+
yarn add @pollenate/react
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import { PollenateWidget } from '@pollenate/react';
|
|
19
|
+
|
|
20
|
+
export function App() {
|
|
21
|
+
return (
|
|
22
|
+
<PollenateWidget
|
|
23
|
+
inboxKey="YOUR_INBOX_KEY"
|
|
24
|
+
apiKey="YOUR_API_KEY"
|
|
25
|
+
type="stars"
|
|
26
|
+
theme="auto"
|
|
27
|
+
onSubmit={(event) => {
|
|
28
|
+
console.log('Feedback submitted:', event.detail);
|
|
29
|
+
}}
|
|
30
|
+
/>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Props
|
|
36
|
+
|
|
37
|
+
### Required
|
|
38
|
+
|
|
39
|
+
| Prop | Type | Description |
|
|
40
|
+
| --- | --- | --- |
|
|
41
|
+
| `inboxKey` | `string` | Your inbox key (from the Inboxes page) |
|
|
42
|
+
| `apiKey` | `string` | Your API key (must have `collect` scope) |
|
|
43
|
+
|
|
44
|
+
### Widget Behaviour
|
|
45
|
+
|
|
46
|
+
| Prop | Type | Default | Description |
|
|
47
|
+
| --- | --- | --- | --- |
|
|
48
|
+
| `type` | `'emoji' \| 'stars' \| 'thumbs' \| 'nps' \| 'csat' \| 'text'` | `'emoji'` | Widget type |
|
|
49
|
+
| `position` | `'bottom-right' \| 'bottom-left' \| 'top-right' \| 'top-left'` | `'bottom-right'` | Floating button position |
|
|
50
|
+
| `theme` | `'light' \| 'dark' \| 'auto'` | `'light'` | Color theme |
|
|
51
|
+
| `prompt` | `string` | — | Custom prompt text |
|
|
52
|
+
| `context` | `Record<string, unknown>` | — | Metadata sent with each submission |
|
|
53
|
+
| `inline` | `boolean` | `false` | Render inline instead of floating |
|
|
54
|
+
| `container` | `string` | — | CSS selector to mount into (implies inline) |
|
|
55
|
+
| `trackImpressions` | `boolean` | `true` | Track page-view impressions |
|
|
56
|
+
| `stripQueryParams` | `boolean` | `false` | Strip query params from tracked URLs |
|
|
57
|
+
| `debug` | `boolean` | `false` | Enable console logging |
|
|
58
|
+
|
|
59
|
+
### Theming
|
|
60
|
+
|
|
61
|
+
| Prop | Type | Description |
|
|
62
|
+
| --- | --- | --- |
|
|
63
|
+
| `primaryColor` | `string` | Primary / accent color (hex) |
|
|
64
|
+
| `bgColor` | `string` | Background color (hex) |
|
|
65
|
+
| `textColor` | `string` | Text color (hex) |
|
|
66
|
+
| `borderColor` | `string` | Border color (hex) |
|
|
67
|
+
| `buttonTextColor` | `string` | Button text color (hex) |
|
|
68
|
+
| `borderRadius` | `number` | Border radius in px |
|
|
69
|
+
| `fontFamily` | `string` | Font family |
|
|
70
|
+
| `triggerColor` | `string` | Trigger button background color |
|
|
71
|
+
| `triggerSize` | `number` | Trigger button size in px (default 56) |
|
|
72
|
+
| `triggerLabel` | `string` | Trigger button text / emoji |
|
|
73
|
+
| `width` | `number` | Widget panel width in px (default 320) |
|
|
74
|
+
| `buttonText` | `string` | Submit button label |
|
|
75
|
+
| `successMessage` | `string` | Post-submit message |
|
|
76
|
+
| `commentPlaceholder` | `string` | Comment textarea placeholder |
|
|
77
|
+
| `hideBranding` | `boolean` | Hide "Powered by Pollenate" |
|
|
78
|
+
| `animation` | `'slide' \| 'fade' \| 'none'` | Animation style |
|
|
79
|
+
|
|
80
|
+
### Dark-Mode Overrides
|
|
81
|
+
|
|
82
|
+
| Prop | Type | Description |
|
|
83
|
+
| --- | --- | --- |
|
|
84
|
+
| `darkPrimaryColor` | `string` | Primary color for dark theme |
|
|
85
|
+
| `darkBgColor` | `string` | Background color for dark theme |
|
|
86
|
+
| `darkTextColor` | `string` | Text color for dark theme |
|
|
87
|
+
| `darkBorderColor` | `string` | Border color for dark theme |
|
|
88
|
+
| `darkButtonTextColor` | `string` | Button text color for dark theme |
|
|
89
|
+
|
|
90
|
+
### Callbacks
|
|
91
|
+
|
|
92
|
+
| Prop | Type | Description |
|
|
93
|
+
| --- | --- | --- |
|
|
94
|
+
| `onSubmit` | `(event: PollenateSubmitEvent) => void` | Called when feedback is submitted |
|
|
95
|
+
| `onImpression` | `(event: PollenateImpressionEvent) => void` | Called on widget impression |
|
|
96
|
+
|
|
97
|
+
## Inline Example
|
|
98
|
+
|
|
99
|
+
```tsx
|
|
100
|
+
<PollenateWidget
|
|
101
|
+
inboxKey="my-inbox"
|
|
102
|
+
apiKey="pk_live_xxx"
|
|
103
|
+
type="thumbs"
|
|
104
|
+
inline
|
|
105
|
+
prompt="Was this page helpful?"
|
|
106
|
+
/>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Custom Themed Example
|
|
110
|
+
|
|
111
|
+
```tsx
|
|
112
|
+
<PollenateWidget
|
|
113
|
+
inboxKey="my-inbox"
|
|
114
|
+
apiKey="pk_live_xxx"
|
|
115
|
+
type="nps"
|
|
116
|
+
theme="auto"
|
|
117
|
+
primaryColor="#6366f1"
|
|
118
|
+
borderRadius={12}
|
|
119
|
+
buttonText="Submit Score"
|
|
120
|
+
hideBranding
|
|
121
|
+
/>
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## License
|
|
125
|
+
|
|
126
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react = require('react');
|
|
4
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
5
|
+
|
|
6
|
+
// src/PollenateWidget.tsx
|
|
7
|
+
var WIDGET_SRC = "https://pollenate.dev/widget.js";
|
|
8
|
+
function PollenateWidget(props) {
|
|
9
|
+
const {
|
|
10
|
+
// Required
|
|
11
|
+
inboxKey,
|
|
12
|
+
apiKey,
|
|
13
|
+
// Behaviour
|
|
14
|
+
type = "emoji",
|
|
15
|
+
position = "bottom-right",
|
|
16
|
+
theme = "light",
|
|
17
|
+
prompt,
|
|
18
|
+
context,
|
|
19
|
+
apiUrl,
|
|
20
|
+
inline,
|
|
21
|
+
container,
|
|
22
|
+
debug,
|
|
23
|
+
trackImpressions,
|
|
24
|
+
stripQueryParams,
|
|
25
|
+
// Theming
|
|
26
|
+
primaryColor,
|
|
27
|
+
bgColor,
|
|
28
|
+
textColor,
|
|
29
|
+
borderColor,
|
|
30
|
+
buttonTextColor,
|
|
31
|
+
borderRadius,
|
|
32
|
+
fontFamily,
|
|
33
|
+
triggerColor,
|
|
34
|
+
triggerSize,
|
|
35
|
+
triggerLabel,
|
|
36
|
+
width,
|
|
37
|
+
buttonText,
|
|
38
|
+
successMessage,
|
|
39
|
+
commentPlaceholder,
|
|
40
|
+
hideBranding,
|
|
41
|
+
animation,
|
|
42
|
+
// Dark-mode overrides
|
|
43
|
+
darkPrimaryColor,
|
|
44
|
+
darkBgColor,
|
|
45
|
+
darkTextColor,
|
|
46
|
+
darkBorderColor,
|
|
47
|
+
darkButtonTextColor,
|
|
48
|
+
// Callbacks
|
|
49
|
+
onSubmit,
|
|
50
|
+
onImpression
|
|
51
|
+
} = props;
|
|
52
|
+
const containerRef = react.useRef(null);
|
|
53
|
+
const instanceId = react.useId();
|
|
54
|
+
const containerId = `pollenate-${instanceId.replace(/:/g, "")}`;
|
|
55
|
+
const onSubmitRef = react.useRef(onSubmit);
|
|
56
|
+
const onImpressionRef = react.useRef(onImpression);
|
|
57
|
+
react.useEffect(() => {
|
|
58
|
+
onSubmitRef.current = onSubmit;
|
|
59
|
+
}, [onSubmit]);
|
|
60
|
+
react.useEffect(() => {
|
|
61
|
+
onImpressionRef.current = onImpression;
|
|
62
|
+
}, [onImpression]);
|
|
63
|
+
react.useEffect(() => {
|
|
64
|
+
const handleSubmit = (e) => {
|
|
65
|
+
onSubmitRef.current?.(e);
|
|
66
|
+
};
|
|
67
|
+
const handleImpression = (e) => {
|
|
68
|
+
onImpressionRef.current?.(e);
|
|
69
|
+
};
|
|
70
|
+
window.addEventListener("pollenate:submit", handleSubmit);
|
|
71
|
+
window.addEventListener("pollenate:impression", handleImpression);
|
|
72
|
+
return () => {
|
|
73
|
+
window.removeEventListener("pollenate:submit", handleSubmit);
|
|
74
|
+
window.removeEventListener("pollenate:impression", handleImpression);
|
|
75
|
+
};
|
|
76
|
+
}, []);
|
|
77
|
+
react.useEffect(() => {
|
|
78
|
+
const host = containerRef.current;
|
|
79
|
+
if (!host) return;
|
|
80
|
+
const script = document.createElement("script");
|
|
81
|
+
script.src = apiUrl ? `${apiUrl.replace(/\/+$/, "")}/widget.js` : WIDGET_SRC;
|
|
82
|
+
script.async = true;
|
|
83
|
+
script.setAttribute("data-inbox-key", inboxKey);
|
|
84
|
+
script.setAttribute("data-api-key", apiKey);
|
|
85
|
+
script.setAttribute("data-type", type);
|
|
86
|
+
script.setAttribute("data-theme", theme);
|
|
87
|
+
const isInline = inline || !!container;
|
|
88
|
+
if (isInline) {
|
|
89
|
+
script.setAttribute("data-inline", "true");
|
|
90
|
+
script.setAttribute(
|
|
91
|
+
"data-container",
|
|
92
|
+
container || `#${containerId}`
|
|
93
|
+
);
|
|
94
|
+
} else {
|
|
95
|
+
script.setAttribute("data-position", position);
|
|
96
|
+
}
|
|
97
|
+
if (prompt) script.setAttribute("data-prompt", prompt);
|
|
98
|
+
if (context) script.setAttribute("data-context", JSON.stringify(context));
|
|
99
|
+
if (debug) script.setAttribute("data-debug", "true");
|
|
100
|
+
if (trackImpressions === false) script.setAttribute("data-track-impressions", "false");
|
|
101
|
+
if (stripQueryParams) script.setAttribute("data-strip-query-params", "true");
|
|
102
|
+
if (primaryColor) script.setAttribute("data-primary-color", primaryColor);
|
|
103
|
+
if (bgColor) script.setAttribute("data-bg-color", bgColor);
|
|
104
|
+
if (textColor) script.setAttribute("data-text-color", textColor);
|
|
105
|
+
if (borderColor) script.setAttribute("data-border-color", borderColor);
|
|
106
|
+
if (buttonTextColor) script.setAttribute("data-button-text-color", buttonTextColor);
|
|
107
|
+
if (borderRadius !== void 0) script.setAttribute("data-border-radius", String(borderRadius));
|
|
108
|
+
if (fontFamily) script.setAttribute("data-font-family", fontFamily);
|
|
109
|
+
if (triggerColor) script.setAttribute("data-trigger-color", triggerColor);
|
|
110
|
+
if (triggerSize !== void 0) script.setAttribute("data-trigger-size", String(triggerSize));
|
|
111
|
+
if (triggerLabel) script.setAttribute("data-trigger-label", triggerLabel);
|
|
112
|
+
if (width !== void 0) script.setAttribute("data-width", String(width));
|
|
113
|
+
if (buttonText) script.setAttribute("data-button-text", buttonText);
|
|
114
|
+
if (successMessage) script.setAttribute("data-success-message", successMessage);
|
|
115
|
+
if (commentPlaceholder) script.setAttribute("data-comment-placeholder", commentPlaceholder);
|
|
116
|
+
if (hideBranding) script.setAttribute("data-hide-branding", "true");
|
|
117
|
+
if (animation) script.setAttribute("data-animation", animation);
|
|
118
|
+
if (darkPrimaryColor) script.setAttribute("data-dark-primary-color", darkPrimaryColor);
|
|
119
|
+
if (darkBgColor) script.setAttribute("data-dark-bg-color", darkBgColor);
|
|
120
|
+
if (darkTextColor) script.setAttribute("data-dark-text-color", darkTextColor);
|
|
121
|
+
if (darkBorderColor) script.setAttribute("data-dark-border-color", darkBorderColor);
|
|
122
|
+
if (darkButtonTextColor) script.setAttribute("data-dark-button-text-color", darkButtonTextColor);
|
|
123
|
+
host.appendChild(script);
|
|
124
|
+
return () => {
|
|
125
|
+
host.innerHTML = "";
|
|
126
|
+
document.querySelectorAll("[data-pollenate-widget]").forEach((el) => el.remove());
|
|
127
|
+
};
|
|
128
|
+
}, [
|
|
129
|
+
inboxKey,
|
|
130
|
+
apiKey,
|
|
131
|
+
type,
|
|
132
|
+
position,
|
|
133
|
+
theme,
|
|
134
|
+
prompt,
|
|
135
|
+
// Serialise context so the effect re-runs on deep changes
|
|
136
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
137
|
+
context ? JSON.stringify(context) : void 0,
|
|
138
|
+
apiUrl,
|
|
139
|
+
inline,
|
|
140
|
+
container,
|
|
141
|
+
debug,
|
|
142
|
+
trackImpressions,
|
|
143
|
+
stripQueryParams,
|
|
144
|
+
primaryColor,
|
|
145
|
+
bgColor,
|
|
146
|
+
textColor,
|
|
147
|
+
borderColor,
|
|
148
|
+
buttonTextColor,
|
|
149
|
+
borderRadius,
|
|
150
|
+
fontFamily,
|
|
151
|
+
triggerColor,
|
|
152
|
+
triggerSize,
|
|
153
|
+
triggerLabel,
|
|
154
|
+
width,
|
|
155
|
+
buttonText,
|
|
156
|
+
successMessage,
|
|
157
|
+
commentPlaceholder,
|
|
158
|
+
hideBranding,
|
|
159
|
+
animation,
|
|
160
|
+
darkPrimaryColor,
|
|
161
|
+
darkBgColor,
|
|
162
|
+
darkTextColor,
|
|
163
|
+
darkBorderColor,
|
|
164
|
+
darkButtonTextColor,
|
|
165
|
+
containerId
|
|
166
|
+
]);
|
|
167
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, id: containerId });
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
exports.PollenateWidget = PollenateWidget;
|
|
171
|
+
//# sourceMappingURL=index.cjs.map
|
|
172
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/PollenateWidget.tsx"],"names":["useRef","useId","useEffect","jsx"],"mappings":"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","file":"index.cjs","sourcesContent":["import { useEffect, useRef, useId } from 'react';\nimport type {\n PollenateWidgetProps,\n PollenateSubmitEvent,\n PollenateImpressionEvent,\n} from './types';\n\nconst WIDGET_SRC = 'https://pollenate.dev/widget.js';\n\n/**\n * React wrapper for the Pollenate feedback widget.\n *\n * Under the hood this injects the `widget.js` script tag with the correct\n * `data-*` attributes. When props change the old script is removed and a\n * fresh one is injected so the widget re-initialises with the new config.\n *\n * @example\n * ```tsx\n * import { PollenateWidget } from '@pollenate/react';\n *\n * export function App() {\n * return (\n * <PollenateWidget\n * inboxKey=\"my-inbox\"\n * apiKey=\"pk_live_xxx\"\n * type=\"stars\"\n * theme=\"auto\"\n * onSubmit={(e) => console.log('submitted', e.detail)}\n * />\n * );\n * }\n * ```\n */\nexport function PollenateWidget(props: PollenateWidgetProps) {\n const {\n // Required\n inboxKey,\n apiKey,\n // Behaviour\n type = 'emoji',\n position = 'bottom-right',\n theme = 'light',\n prompt,\n context,\n apiUrl,\n inline,\n container,\n debug,\n trackImpressions,\n stripQueryParams,\n // Theming\n primaryColor,\n bgColor,\n textColor,\n borderColor,\n buttonTextColor,\n borderRadius,\n fontFamily,\n triggerColor,\n triggerSize,\n triggerLabel,\n width,\n buttonText,\n successMessage,\n commentPlaceholder,\n hideBranding,\n animation,\n // Dark-mode overrides\n darkPrimaryColor,\n darkBgColor,\n darkTextColor,\n darkBorderColor,\n darkButtonTextColor,\n // Callbacks\n onSubmit,\n onImpression,\n } = props;\n\n const containerRef = useRef<HTMLDivElement>(null);\n const instanceId = useId();\n const containerId = `pollenate-${instanceId.replace(/:/g, '')}`;\n\n // Keep latest callbacks in refs so we never re-inject the script just\n // because the user created a new arrow function each render.\n const onSubmitRef = useRef(onSubmit);\n const onImpressionRef = useRef(onImpression);\n useEffect(() => { onSubmitRef.current = onSubmit; }, [onSubmit]);\n useEffect(() => { onImpressionRef.current = onImpression; }, [onImpression]);\n\n // Wire up window-level custom events → callback refs\n useEffect(() => {\n const handleSubmit = (e: Event) => {\n onSubmitRef.current?.(e as PollenateSubmitEvent);\n };\n const handleImpression = (e: Event) => {\n onImpressionRef.current?.(e as PollenateImpressionEvent);\n };\n\n window.addEventListener('pollenate:submit', handleSubmit);\n window.addEventListener('pollenate:impression', handleImpression);\n\n return () => {\n window.removeEventListener('pollenate:submit', handleSubmit);\n window.removeEventListener('pollenate:impression', handleImpression);\n };\n }, []);\n\n // Inject / re-inject the widget script whenever config props change.\n useEffect(() => {\n const host = containerRef.current;\n if (!host) return;\n\n // Build the script element with data-* attributes\n const script = document.createElement('script');\n script.src = apiUrl\n ? `${apiUrl.replace(/\\/+$/, '')}/widget.js`\n : WIDGET_SRC;\n script.async = true;\n\n // Required\n script.setAttribute('data-inbox-key', inboxKey);\n script.setAttribute('data-api-key', apiKey);\n\n // Behaviour\n script.setAttribute('data-type', type);\n script.setAttribute('data-theme', theme);\n\n // For inline mode with no explicit container, point at our wrapper div\n const isInline = inline || !!container;\n if (isInline) {\n script.setAttribute('data-inline', 'true');\n script.setAttribute(\n 'data-container',\n container || `#${containerId}`,\n );\n } else {\n script.setAttribute('data-position', position);\n }\n\n if (prompt) script.setAttribute('data-prompt', prompt);\n if (context) script.setAttribute('data-context', JSON.stringify(context));\n if (debug) script.setAttribute('data-debug', 'true');\n if (trackImpressions === false) script.setAttribute('data-track-impressions', 'false');\n if (stripQueryParams) script.setAttribute('data-strip-query-params', 'true');\n\n // Theming\n if (primaryColor) script.setAttribute('data-primary-color', primaryColor);\n if (bgColor) script.setAttribute('data-bg-color', bgColor);\n if (textColor) script.setAttribute('data-text-color', textColor);\n if (borderColor) script.setAttribute('data-border-color', borderColor);\n if (buttonTextColor) script.setAttribute('data-button-text-color', buttonTextColor);\n if (borderRadius !== undefined) script.setAttribute('data-border-radius', String(borderRadius));\n if (fontFamily) script.setAttribute('data-font-family', fontFamily);\n if (triggerColor) script.setAttribute('data-trigger-color', triggerColor);\n if (triggerSize !== undefined) script.setAttribute('data-trigger-size', String(triggerSize));\n if (triggerLabel) script.setAttribute('data-trigger-label', triggerLabel);\n if (width !== undefined) script.setAttribute('data-width', String(width));\n if (buttonText) script.setAttribute('data-button-text', buttonText);\n if (successMessage) script.setAttribute('data-success-message', successMessage);\n if (commentPlaceholder) script.setAttribute('data-comment-placeholder', commentPlaceholder);\n if (hideBranding) script.setAttribute('data-hide-branding', 'true');\n if (animation) script.setAttribute('data-animation', animation);\n\n // Dark-mode overrides\n if (darkPrimaryColor) script.setAttribute('data-dark-primary-color', darkPrimaryColor);\n if (darkBgColor) script.setAttribute('data-dark-bg-color', darkBgColor);\n if (darkTextColor) script.setAttribute('data-dark-text-color', darkTextColor);\n if (darkBorderColor) script.setAttribute('data-dark-border-color', darkBorderColor);\n if (darkButtonTextColor) script.setAttribute('data-dark-button-text-color', darkButtonTextColor);\n\n host.appendChild(script);\n\n return () => {\n // Remove the script and any DOM the widget injected inside our container\n host.innerHTML = '';\n\n // The floating widget appends elements to document.body — clean those up\n document\n .querySelectorAll('[data-pollenate-widget]')\n .forEach((el) => el.remove());\n };\n }, [\n inboxKey, apiKey, type, position, theme, prompt,\n // Serialise context so the effect re-runs on deep changes\n // eslint-disable-next-line react-hooks/exhaustive-deps\n context ? JSON.stringify(context) : undefined,\n apiUrl, inline, container, debug, trackImpressions, stripQueryParams,\n primaryColor, bgColor, textColor, borderColor, buttonTextColor,\n borderRadius, fontFamily, triggerColor, triggerSize, triggerLabel,\n width, buttonText, successMessage, commentPlaceholder, hideBranding,\n animation, darkPrimaryColor, darkBgColor, darkTextColor,\n darkBorderColor, darkButtonTextColor, containerId,\n ]);\n\n return <div ref={containerRef} id={containerId} />;\n}\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Type definitions for the @pollenate/react widget component.
|
|
5
|
+
*
|
|
6
|
+
* These map 1:1 to the data-* attributes on the vanilla widget.js script tag.
|
|
7
|
+
* See https://pollenate.dev/docs for full documentation.
|
|
8
|
+
*/
|
|
9
|
+
/** Supported widget types */
|
|
10
|
+
type WidgetType = 'emoji' | 'stars' | 'thumbs' | 'nps' | 'csat' | 'text';
|
|
11
|
+
/** Widget position (ignored when inline) */
|
|
12
|
+
type WidgetPosition = 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
|
|
13
|
+
/** Color theme */
|
|
14
|
+
type WidgetTheme = 'light' | 'dark' | 'auto';
|
|
15
|
+
/** Animation style */
|
|
16
|
+
type WidgetAnimation = 'slide' | 'fade' | 'none';
|
|
17
|
+
/** Payload emitted on pollenate:submit */
|
|
18
|
+
interface PollenateSubmitDetail {
|
|
19
|
+
id: string;
|
|
20
|
+
impressionId?: string;
|
|
21
|
+
inboxKey: string;
|
|
22
|
+
type: WidgetType;
|
|
23
|
+
score: number | null;
|
|
24
|
+
comment: string;
|
|
25
|
+
context?: Record<string, unknown>;
|
|
26
|
+
}
|
|
27
|
+
/** Payload emitted on pollenate:impression */
|
|
28
|
+
interface PollenateImpressionDetail {
|
|
29
|
+
impressionId: string;
|
|
30
|
+
context?: Record<string, unknown>;
|
|
31
|
+
}
|
|
32
|
+
/** Event payloads */
|
|
33
|
+
interface PollenateSubmitEvent extends CustomEvent<PollenateSubmitDetail> {
|
|
34
|
+
}
|
|
35
|
+
interface PollenateImpressionEvent extends CustomEvent<PollenateImpressionDetail> {
|
|
36
|
+
}
|
|
37
|
+
interface PollenateWidgetProps {
|
|
38
|
+
/** Your inbox key (from the Inboxes page) */
|
|
39
|
+
inboxKey: string;
|
|
40
|
+
/** Your API key (from the API Keys page, must have 'collect' scope) */
|
|
41
|
+
apiKey: string;
|
|
42
|
+
/** Widget type (default: 'emoji') */
|
|
43
|
+
type?: WidgetType;
|
|
44
|
+
/** Position when not inline (default: 'bottom-right') */
|
|
45
|
+
position?: WidgetPosition;
|
|
46
|
+
/** Color theme (default: 'light') */
|
|
47
|
+
theme?: WidgetTheme;
|
|
48
|
+
/** Custom prompt text shown above the rating */
|
|
49
|
+
prompt?: string;
|
|
50
|
+
/** Additional context metadata sent with each submission */
|
|
51
|
+
context?: Record<string, unknown>;
|
|
52
|
+
/** API base URL (default: 'https://api.pollenate.dev') */
|
|
53
|
+
apiUrl?: string;
|
|
54
|
+
/** Render inline instead of as a floating button */
|
|
55
|
+
inline?: boolean;
|
|
56
|
+
/** CSS selector of an existing element to mount into (implies inline) */
|
|
57
|
+
container?: string;
|
|
58
|
+
/** Enable console logging */
|
|
59
|
+
debug?: boolean;
|
|
60
|
+
/** Track page-view impressions (default: true) */
|
|
61
|
+
trackImpressions?: boolean;
|
|
62
|
+
/** Strip query parameters from tracked URLs (default: false) */
|
|
63
|
+
stripQueryParams?: boolean;
|
|
64
|
+
/** Primary / accent color (hex) */
|
|
65
|
+
primaryColor?: string;
|
|
66
|
+
/** Background color (hex) */
|
|
67
|
+
bgColor?: string;
|
|
68
|
+
/** Text color (hex) */
|
|
69
|
+
textColor?: string;
|
|
70
|
+
/** Border color (hex) */
|
|
71
|
+
borderColor?: string;
|
|
72
|
+
/** Button text / font color (hex) */
|
|
73
|
+
buttonTextColor?: string;
|
|
74
|
+
/** Border radius in px */
|
|
75
|
+
borderRadius?: number;
|
|
76
|
+
/** Custom font family */
|
|
77
|
+
fontFamily?: string;
|
|
78
|
+
/** Trigger button background color (defaults to primaryColor) */
|
|
79
|
+
triggerColor?: string;
|
|
80
|
+
/** Trigger button size in px (default: 56) */
|
|
81
|
+
triggerSize?: number;
|
|
82
|
+
/** Trigger button text / emoji */
|
|
83
|
+
triggerLabel?: string;
|
|
84
|
+
/** Widget panel width in px (default: 320) */
|
|
85
|
+
width?: number;
|
|
86
|
+
/** Submit button text (default: 'Send Feedback') */
|
|
87
|
+
buttonText?: string;
|
|
88
|
+
/** Message shown after submission */
|
|
89
|
+
successMessage?: string;
|
|
90
|
+
/** Placeholder for the comment textarea */
|
|
91
|
+
commentPlaceholder?: string;
|
|
92
|
+
/** Hide 'Powered by Pollenate' footer */
|
|
93
|
+
hideBranding?: boolean;
|
|
94
|
+
/** Animation style (default: 'slide') */
|
|
95
|
+
animation?: WidgetAnimation;
|
|
96
|
+
/** Primary color override for dark theme */
|
|
97
|
+
darkPrimaryColor?: string;
|
|
98
|
+
/** Background color override for dark theme */
|
|
99
|
+
darkBgColor?: string;
|
|
100
|
+
/** Text color override for dark theme */
|
|
101
|
+
darkTextColor?: string;
|
|
102
|
+
/** Border color override for dark theme */
|
|
103
|
+
darkBorderColor?: string;
|
|
104
|
+
/** Button text color override for dark theme */
|
|
105
|
+
darkButtonTextColor?: string;
|
|
106
|
+
/** Called when feedback is submitted */
|
|
107
|
+
onSubmit?: (event: PollenateSubmitEvent) => void;
|
|
108
|
+
/** Called when the widget registers an impression */
|
|
109
|
+
onImpression?: (event: PollenateImpressionEvent) => void;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* React wrapper for the Pollenate feedback widget.
|
|
114
|
+
*
|
|
115
|
+
* Under the hood this injects the `widget.js` script tag with the correct
|
|
116
|
+
* `data-*` attributes. When props change the old script is removed and a
|
|
117
|
+
* fresh one is injected so the widget re-initialises with the new config.
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* ```tsx
|
|
121
|
+
* import { PollenateWidget } from '@pollenate/react';
|
|
122
|
+
*
|
|
123
|
+
* export function App() {
|
|
124
|
+
* return (
|
|
125
|
+
* <PollenateWidget
|
|
126
|
+
* inboxKey="my-inbox"
|
|
127
|
+
* apiKey="pk_live_xxx"
|
|
128
|
+
* type="stars"
|
|
129
|
+
* theme="auto"
|
|
130
|
+
* onSubmit={(e) => console.log('submitted', e.detail)}
|
|
131
|
+
* />
|
|
132
|
+
* );
|
|
133
|
+
* }
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
declare function PollenateWidget(props: PollenateWidgetProps): react_jsx_runtime.JSX.Element;
|
|
137
|
+
|
|
138
|
+
export { type PollenateImpressionDetail, type PollenateImpressionEvent, type PollenateSubmitDetail, type PollenateSubmitEvent, PollenateWidget, type PollenateWidgetProps, type WidgetAnimation, type WidgetPosition, type WidgetTheme, type WidgetType };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Type definitions for the @pollenate/react widget component.
|
|
5
|
+
*
|
|
6
|
+
* These map 1:1 to the data-* attributes on the vanilla widget.js script tag.
|
|
7
|
+
* See https://pollenate.dev/docs for full documentation.
|
|
8
|
+
*/
|
|
9
|
+
/** Supported widget types */
|
|
10
|
+
type WidgetType = 'emoji' | 'stars' | 'thumbs' | 'nps' | 'csat' | 'text';
|
|
11
|
+
/** Widget position (ignored when inline) */
|
|
12
|
+
type WidgetPosition = 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
|
|
13
|
+
/** Color theme */
|
|
14
|
+
type WidgetTheme = 'light' | 'dark' | 'auto';
|
|
15
|
+
/** Animation style */
|
|
16
|
+
type WidgetAnimation = 'slide' | 'fade' | 'none';
|
|
17
|
+
/** Payload emitted on pollenate:submit */
|
|
18
|
+
interface PollenateSubmitDetail {
|
|
19
|
+
id: string;
|
|
20
|
+
impressionId?: string;
|
|
21
|
+
inboxKey: string;
|
|
22
|
+
type: WidgetType;
|
|
23
|
+
score: number | null;
|
|
24
|
+
comment: string;
|
|
25
|
+
context?: Record<string, unknown>;
|
|
26
|
+
}
|
|
27
|
+
/** Payload emitted on pollenate:impression */
|
|
28
|
+
interface PollenateImpressionDetail {
|
|
29
|
+
impressionId: string;
|
|
30
|
+
context?: Record<string, unknown>;
|
|
31
|
+
}
|
|
32
|
+
/** Event payloads */
|
|
33
|
+
interface PollenateSubmitEvent extends CustomEvent<PollenateSubmitDetail> {
|
|
34
|
+
}
|
|
35
|
+
interface PollenateImpressionEvent extends CustomEvent<PollenateImpressionDetail> {
|
|
36
|
+
}
|
|
37
|
+
interface PollenateWidgetProps {
|
|
38
|
+
/** Your inbox key (from the Inboxes page) */
|
|
39
|
+
inboxKey: string;
|
|
40
|
+
/** Your API key (from the API Keys page, must have 'collect' scope) */
|
|
41
|
+
apiKey: string;
|
|
42
|
+
/** Widget type (default: 'emoji') */
|
|
43
|
+
type?: WidgetType;
|
|
44
|
+
/** Position when not inline (default: 'bottom-right') */
|
|
45
|
+
position?: WidgetPosition;
|
|
46
|
+
/** Color theme (default: 'light') */
|
|
47
|
+
theme?: WidgetTheme;
|
|
48
|
+
/** Custom prompt text shown above the rating */
|
|
49
|
+
prompt?: string;
|
|
50
|
+
/** Additional context metadata sent with each submission */
|
|
51
|
+
context?: Record<string, unknown>;
|
|
52
|
+
/** API base URL (default: 'https://api.pollenate.dev') */
|
|
53
|
+
apiUrl?: string;
|
|
54
|
+
/** Render inline instead of as a floating button */
|
|
55
|
+
inline?: boolean;
|
|
56
|
+
/** CSS selector of an existing element to mount into (implies inline) */
|
|
57
|
+
container?: string;
|
|
58
|
+
/** Enable console logging */
|
|
59
|
+
debug?: boolean;
|
|
60
|
+
/** Track page-view impressions (default: true) */
|
|
61
|
+
trackImpressions?: boolean;
|
|
62
|
+
/** Strip query parameters from tracked URLs (default: false) */
|
|
63
|
+
stripQueryParams?: boolean;
|
|
64
|
+
/** Primary / accent color (hex) */
|
|
65
|
+
primaryColor?: string;
|
|
66
|
+
/** Background color (hex) */
|
|
67
|
+
bgColor?: string;
|
|
68
|
+
/** Text color (hex) */
|
|
69
|
+
textColor?: string;
|
|
70
|
+
/** Border color (hex) */
|
|
71
|
+
borderColor?: string;
|
|
72
|
+
/** Button text / font color (hex) */
|
|
73
|
+
buttonTextColor?: string;
|
|
74
|
+
/** Border radius in px */
|
|
75
|
+
borderRadius?: number;
|
|
76
|
+
/** Custom font family */
|
|
77
|
+
fontFamily?: string;
|
|
78
|
+
/** Trigger button background color (defaults to primaryColor) */
|
|
79
|
+
triggerColor?: string;
|
|
80
|
+
/** Trigger button size in px (default: 56) */
|
|
81
|
+
triggerSize?: number;
|
|
82
|
+
/** Trigger button text / emoji */
|
|
83
|
+
triggerLabel?: string;
|
|
84
|
+
/** Widget panel width in px (default: 320) */
|
|
85
|
+
width?: number;
|
|
86
|
+
/** Submit button text (default: 'Send Feedback') */
|
|
87
|
+
buttonText?: string;
|
|
88
|
+
/** Message shown after submission */
|
|
89
|
+
successMessage?: string;
|
|
90
|
+
/** Placeholder for the comment textarea */
|
|
91
|
+
commentPlaceholder?: string;
|
|
92
|
+
/** Hide 'Powered by Pollenate' footer */
|
|
93
|
+
hideBranding?: boolean;
|
|
94
|
+
/** Animation style (default: 'slide') */
|
|
95
|
+
animation?: WidgetAnimation;
|
|
96
|
+
/** Primary color override for dark theme */
|
|
97
|
+
darkPrimaryColor?: string;
|
|
98
|
+
/** Background color override for dark theme */
|
|
99
|
+
darkBgColor?: string;
|
|
100
|
+
/** Text color override for dark theme */
|
|
101
|
+
darkTextColor?: string;
|
|
102
|
+
/** Border color override for dark theme */
|
|
103
|
+
darkBorderColor?: string;
|
|
104
|
+
/** Button text color override for dark theme */
|
|
105
|
+
darkButtonTextColor?: string;
|
|
106
|
+
/** Called when feedback is submitted */
|
|
107
|
+
onSubmit?: (event: PollenateSubmitEvent) => void;
|
|
108
|
+
/** Called when the widget registers an impression */
|
|
109
|
+
onImpression?: (event: PollenateImpressionEvent) => void;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* React wrapper for the Pollenate feedback widget.
|
|
114
|
+
*
|
|
115
|
+
* Under the hood this injects the `widget.js` script tag with the correct
|
|
116
|
+
* `data-*` attributes. When props change the old script is removed and a
|
|
117
|
+
* fresh one is injected so the widget re-initialises with the new config.
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* ```tsx
|
|
121
|
+
* import { PollenateWidget } from '@pollenate/react';
|
|
122
|
+
*
|
|
123
|
+
* export function App() {
|
|
124
|
+
* return (
|
|
125
|
+
* <PollenateWidget
|
|
126
|
+
* inboxKey="my-inbox"
|
|
127
|
+
* apiKey="pk_live_xxx"
|
|
128
|
+
* type="stars"
|
|
129
|
+
* theme="auto"
|
|
130
|
+
* onSubmit={(e) => console.log('submitted', e.detail)}
|
|
131
|
+
* />
|
|
132
|
+
* );
|
|
133
|
+
* }
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
declare function PollenateWidget(props: PollenateWidgetProps): react_jsx_runtime.JSX.Element;
|
|
137
|
+
|
|
138
|
+
export { type PollenateImpressionDetail, type PollenateImpressionEvent, type PollenateSubmitDetail, type PollenateSubmitEvent, PollenateWidget, type PollenateWidgetProps, type WidgetAnimation, type WidgetPosition, type WidgetTheme, type WidgetType };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { useRef, useId, useEffect } from 'react';
|
|
2
|
+
import { jsx } from 'react/jsx-runtime';
|
|
3
|
+
|
|
4
|
+
// src/PollenateWidget.tsx
|
|
5
|
+
var WIDGET_SRC = "https://pollenate.dev/widget.js";
|
|
6
|
+
function PollenateWidget(props) {
|
|
7
|
+
const {
|
|
8
|
+
// Required
|
|
9
|
+
inboxKey,
|
|
10
|
+
apiKey,
|
|
11
|
+
// Behaviour
|
|
12
|
+
type = "emoji",
|
|
13
|
+
position = "bottom-right",
|
|
14
|
+
theme = "light",
|
|
15
|
+
prompt,
|
|
16
|
+
context,
|
|
17
|
+
apiUrl,
|
|
18
|
+
inline,
|
|
19
|
+
container,
|
|
20
|
+
debug,
|
|
21
|
+
trackImpressions,
|
|
22
|
+
stripQueryParams,
|
|
23
|
+
// Theming
|
|
24
|
+
primaryColor,
|
|
25
|
+
bgColor,
|
|
26
|
+
textColor,
|
|
27
|
+
borderColor,
|
|
28
|
+
buttonTextColor,
|
|
29
|
+
borderRadius,
|
|
30
|
+
fontFamily,
|
|
31
|
+
triggerColor,
|
|
32
|
+
triggerSize,
|
|
33
|
+
triggerLabel,
|
|
34
|
+
width,
|
|
35
|
+
buttonText,
|
|
36
|
+
successMessage,
|
|
37
|
+
commentPlaceholder,
|
|
38
|
+
hideBranding,
|
|
39
|
+
animation,
|
|
40
|
+
// Dark-mode overrides
|
|
41
|
+
darkPrimaryColor,
|
|
42
|
+
darkBgColor,
|
|
43
|
+
darkTextColor,
|
|
44
|
+
darkBorderColor,
|
|
45
|
+
darkButtonTextColor,
|
|
46
|
+
// Callbacks
|
|
47
|
+
onSubmit,
|
|
48
|
+
onImpression
|
|
49
|
+
} = props;
|
|
50
|
+
const containerRef = useRef(null);
|
|
51
|
+
const instanceId = useId();
|
|
52
|
+
const containerId = `pollenate-${instanceId.replace(/:/g, "")}`;
|
|
53
|
+
const onSubmitRef = useRef(onSubmit);
|
|
54
|
+
const onImpressionRef = useRef(onImpression);
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
onSubmitRef.current = onSubmit;
|
|
57
|
+
}, [onSubmit]);
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
onImpressionRef.current = onImpression;
|
|
60
|
+
}, [onImpression]);
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
const handleSubmit = (e) => {
|
|
63
|
+
onSubmitRef.current?.(e);
|
|
64
|
+
};
|
|
65
|
+
const handleImpression = (e) => {
|
|
66
|
+
onImpressionRef.current?.(e);
|
|
67
|
+
};
|
|
68
|
+
window.addEventListener("pollenate:submit", handleSubmit);
|
|
69
|
+
window.addEventListener("pollenate:impression", handleImpression);
|
|
70
|
+
return () => {
|
|
71
|
+
window.removeEventListener("pollenate:submit", handleSubmit);
|
|
72
|
+
window.removeEventListener("pollenate:impression", handleImpression);
|
|
73
|
+
};
|
|
74
|
+
}, []);
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
const host = containerRef.current;
|
|
77
|
+
if (!host) return;
|
|
78
|
+
const script = document.createElement("script");
|
|
79
|
+
script.src = apiUrl ? `${apiUrl.replace(/\/+$/, "")}/widget.js` : WIDGET_SRC;
|
|
80
|
+
script.async = true;
|
|
81
|
+
script.setAttribute("data-inbox-key", inboxKey);
|
|
82
|
+
script.setAttribute("data-api-key", apiKey);
|
|
83
|
+
script.setAttribute("data-type", type);
|
|
84
|
+
script.setAttribute("data-theme", theme);
|
|
85
|
+
const isInline = inline || !!container;
|
|
86
|
+
if (isInline) {
|
|
87
|
+
script.setAttribute("data-inline", "true");
|
|
88
|
+
script.setAttribute(
|
|
89
|
+
"data-container",
|
|
90
|
+
container || `#${containerId}`
|
|
91
|
+
);
|
|
92
|
+
} else {
|
|
93
|
+
script.setAttribute("data-position", position);
|
|
94
|
+
}
|
|
95
|
+
if (prompt) script.setAttribute("data-prompt", prompt);
|
|
96
|
+
if (context) script.setAttribute("data-context", JSON.stringify(context));
|
|
97
|
+
if (debug) script.setAttribute("data-debug", "true");
|
|
98
|
+
if (trackImpressions === false) script.setAttribute("data-track-impressions", "false");
|
|
99
|
+
if (stripQueryParams) script.setAttribute("data-strip-query-params", "true");
|
|
100
|
+
if (primaryColor) script.setAttribute("data-primary-color", primaryColor);
|
|
101
|
+
if (bgColor) script.setAttribute("data-bg-color", bgColor);
|
|
102
|
+
if (textColor) script.setAttribute("data-text-color", textColor);
|
|
103
|
+
if (borderColor) script.setAttribute("data-border-color", borderColor);
|
|
104
|
+
if (buttonTextColor) script.setAttribute("data-button-text-color", buttonTextColor);
|
|
105
|
+
if (borderRadius !== void 0) script.setAttribute("data-border-radius", String(borderRadius));
|
|
106
|
+
if (fontFamily) script.setAttribute("data-font-family", fontFamily);
|
|
107
|
+
if (triggerColor) script.setAttribute("data-trigger-color", triggerColor);
|
|
108
|
+
if (triggerSize !== void 0) script.setAttribute("data-trigger-size", String(triggerSize));
|
|
109
|
+
if (triggerLabel) script.setAttribute("data-trigger-label", triggerLabel);
|
|
110
|
+
if (width !== void 0) script.setAttribute("data-width", String(width));
|
|
111
|
+
if (buttonText) script.setAttribute("data-button-text", buttonText);
|
|
112
|
+
if (successMessage) script.setAttribute("data-success-message", successMessage);
|
|
113
|
+
if (commentPlaceholder) script.setAttribute("data-comment-placeholder", commentPlaceholder);
|
|
114
|
+
if (hideBranding) script.setAttribute("data-hide-branding", "true");
|
|
115
|
+
if (animation) script.setAttribute("data-animation", animation);
|
|
116
|
+
if (darkPrimaryColor) script.setAttribute("data-dark-primary-color", darkPrimaryColor);
|
|
117
|
+
if (darkBgColor) script.setAttribute("data-dark-bg-color", darkBgColor);
|
|
118
|
+
if (darkTextColor) script.setAttribute("data-dark-text-color", darkTextColor);
|
|
119
|
+
if (darkBorderColor) script.setAttribute("data-dark-border-color", darkBorderColor);
|
|
120
|
+
if (darkButtonTextColor) script.setAttribute("data-dark-button-text-color", darkButtonTextColor);
|
|
121
|
+
host.appendChild(script);
|
|
122
|
+
return () => {
|
|
123
|
+
host.innerHTML = "";
|
|
124
|
+
document.querySelectorAll("[data-pollenate-widget]").forEach((el) => el.remove());
|
|
125
|
+
};
|
|
126
|
+
}, [
|
|
127
|
+
inboxKey,
|
|
128
|
+
apiKey,
|
|
129
|
+
type,
|
|
130
|
+
position,
|
|
131
|
+
theme,
|
|
132
|
+
prompt,
|
|
133
|
+
// Serialise context so the effect re-runs on deep changes
|
|
134
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
135
|
+
context ? JSON.stringify(context) : void 0,
|
|
136
|
+
apiUrl,
|
|
137
|
+
inline,
|
|
138
|
+
container,
|
|
139
|
+
debug,
|
|
140
|
+
trackImpressions,
|
|
141
|
+
stripQueryParams,
|
|
142
|
+
primaryColor,
|
|
143
|
+
bgColor,
|
|
144
|
+
textColor,
|
|
145
|
+
borderColor,
|
|
146
|
+
buttonTextColor,
|
|
147
|
+
borderRadius,
|
|
148
|
+
fontFamily,
|
|
149
|
+
triggerColor,
|
|
150
|
+
triggerSize,
|
|
151
|
+
triggerLabel,
|
|
152
|
+
width,
|
|
153
|
+
buttonText,
|
|
154
|
+
successMessage,
|
|
155
|
+
commentPlaceholder,
|
|
156
|
+
hideBranding,
|
|
157
|
+
animation,
|
|
158
|
+
darkPrimaryColor,
|
|
159
|
+
darkBgColor,
|
|
160
|
+
darkTextColor,
|
|
161
|
+
darkBorderColor,
|
|
162
|
+
darkButtonTextColor,
|
|
163
|
+
containerId
|
|
164
|
+
]);
|
|
165
|
+
return /* @__PURE__ */ jsx("div", { ref: containerRef, id: containerId });
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export { PollenateWidget };
|
|
169
|
+
//# sourceMappingURL=index.js.map
|
|
170
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/PollenateWidget.tsx"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { useEffect, useRef, useId } from 'react';\nimport type {\n PollenateWidgetProps,\n PollenateSubmitEvent,\n PollenateImpressionEvent,\n} from './types';\n\nconst WIDGET_SRC = 'https://pollenate.dev/widget.js';\n\n/**\n * React wrapper for the Pollenate feedback widget.\n *\n * Under the hood this injects the `widget.js` script tag with the correct\n * `data-*` attributes. When props change the old script is removed and a\n * fresh one is injected so the widget re-initialises with the new config.\n *\n * @example\n * ```tsx\n * import { PollenateWidget } from '@pollenate/react';\n *\n * export function App() {\n * return (\n * <PollenateWidget\n * inboxKey=\"my-inbox\"\n * apiKey=\"pk_live_xxx\"\n * type=\"stars\"\n * theme=\"auto\"\n * onSubmit={(e) => console.log('submitted', e.detail)}\n * />\n * );\n * }\n * ```\n */\nexport function PollenateWidget(props: PollenateWidgetProps) {\n const {\n // Required\n inboxKey,\n apiKey,\n // Behaviour\n type = 'emoji',\n position = 'bottom-right',\n theme = 'light',\n prompt,\n context,\n apiUrl,\n inline,\n container,\n debug,\n trackImpressions,\n stripQueryParams,\n // Theming\n primaryColor,\n bgColor,\n textColor,\n borderColor,\n buttonTextColor,\n borderRadius,\n fontFamily,\n triggerColor,\n triggerSize,\n triggerLabel,\n width,\n buttonText,\n successMessage,\n commentPlaceholder,\n hideBranding,\n animation,\n // Dark-mode overrides\n darkPrimaryColor,\n darkBgColor,\n darkTextColor,\n darkBorderColor,\n darkButtonTextColor,\n // Callbacks\n onSubmit,\n onImpression,\n } = props;\n\n const containerRef = useRef<HTMLDivElement>(null);\n const instanceId = useId();\n const containerId = `pollenate-${instanceId.replace(/:/g, '')}`;\n\n // Keep latest callbacks in refs so we never re-inject the script just\n // because the user created a new arrow function each render.\n const onSubmitRef = useRef(onSubmit);\n const onImpressionRef = useRef(onImpression);\n useEffect(() => { onSubmitRef.current = onSubmit; }, [onSubmit]);\n useEffect(() => { onImpressionRef.current = onImpression; }, [onImpression]);\n\n // Wire up window-level custom events → callback refs\n useEffect(() => {\n const handleSubmit = (e: Event) => {\n onSubmitRef.current?.(e as PollenateSubmitEvent);\n };\n const handleImpression = (e: Event) => {\n onImpressionRef.current?.(e as PollenateImpressionEvent);\n };\n\n window.addEventListener('pollenate:submit', handleSubmit);\n window.addEventListener('pollenate:impression', handleImpression);\n\n return () => {\n window.removeEventListener('pollenate:submit', handleSubmit);\n window.removeEventListener('pollenate:impression', handleImpression);\n };\n }, []);\n\n // Inject / re-inject the widget script whenever config props change.\n useEffect(() => {\n const host = containerRef.current;\n if (!host) return;\n\n // Build the script element with data-* attributes\n const script = document.createElement('script');\n script.src = apiUrl\n ? `${apiUrl.replace(/\\/+$/, '')}/widget.js`\n : WIDGET_SRC;\n script.async = true;\n\n // Required\n script.setAttribute('data-inbox-key', inboxKey);\n script.setAttribute('data-api-key', apiKey);\n\n // Behaviour\n script.setAttribute('data-type', type);\n script.setAttribute('data-theme', theme);\n\n // For inline mode with no explicit container, point at our wrapper div\n const isInline = inline || !!container;\n if (isInline) {\n script.setAttribute('data-inline', 'true');\n script.setAttribute(\n 'data-container',\n container || `#${containerId}`,\n );\n } else {\n script.setAttribute('data-position', position);\n }\n\n if (prompt) script.setAttribute('data-prompt', prompt);\n if (context) script.setAttribute('data-context', JSON.stringify(context));\n if (debug) script.setAttribute('data-debug', 'true');\n if (trackImpressions === false) script.setAttribute('data-track-impressions', 'false');\n if (stripQueryParams) script.setAttribute('data-strip-query-params', 'true');\n\n // Theming\n if (primaryColor) script.setAttribute('data-primary-color', primaryColor);\n if (bgColor) script.setAttribute('data-bg-color', bgColor);\n if (textColor) script.setAttribute('data-text-color', textColor);\n if (borderColor) script.setAttribute('data-border-color', borderColor);\n if (buttonTextColor) script.setAttribute('data-button-text-color', buttonTextColor);\n if (borderRadius !== undefined) script.setAttribute('data-border-radius', String(borderRadius));\n if (fontFamily) script.setAttribute('data-font-family', fontFamily);\n if (triggerColor) script.setAttribute('data-trigger-color', triggerColor);\n if (triggerSize !== undefined) script.setAttribute('data-trigger-size', String(triggerSize));\n if (triggerLabel) script.setAttribute('data-trigger-label', triggerLabel);\n if (width !== undefined) script.setAttribute('data-width', String(width));\n if (buttonText) script.setAttribute('data-button-text', buttonText);\n if (successMessage) script.setAttribute('data-success-message', successMessage);\n if (commentPlaceholder) script.setAttribute('data-comment-placeholder', commentPlaceholder);\n if (hideBranding) script.setAttribute('data-hide-branding', 'true');\n if (animation) script.setAttribute('data-animation', animation);\n\n // Dark-mode overrides\n if (darkPrimaryColor) script.setAttribute('data-dark-primary-color', darkPrimaryColor);\n if (darkBgColor) script.setAttribute('data-dark-bg-color', darkBgColor);\n if (darkTextColor) script.setAttribute('data-dark-text-color', darkTextColor);\n if (darkBorderColor) script.setAttribute('data-dark-border-color', darkBorderColor);\n if (darkButtonTextColor) script.setAttribute('data-dark-button-text-color', darkButtonTextColor);\n\n host.appendChild(script);\n\n return () => {\n // Remove the script and any DOM the widget injected inside our container\n host.innerHTML = '';\n\n // The floating widget appends elements to document.body — clean those up\n document\n .querySelectorAll('[data-pollenate-widget]')\n .forEach((el) => el.remove());\n };\n }, [\n inboxKey, apiKey, type, position, theme, prompt,\n // Serialise context so the effect re-runs on deep changes\n // eslint-disable-next-line react-hooks/exhaustive-deps\n context ? JSON.stringify(context) : undefined,\n apiUrl, inline, container, debug, trackImpressions, stripQueryParams,\n primaryColor, bgColor, textColor, borderColor, buttonTextColor,\n borderRadius, fontFamily, triggerColor, triggerSize, triggerLabel,\n width, buttonText, successMessage, commentPlaceholder, hideBranding,\n animation, darkPrimaryColor, darkBgColor, darkTextColor,\n darkBorderColor, darkButtonTextColor, containerId,\n ]);\n\n return <div ref={containerRef} id={containerId} />;\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pollenate/react",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "React component for the Pollenate feedback widget",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.cjs",
|
|
8
|
+
"module": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"import": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"default": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"require": {
|
|
17
|
+
"types": "./dist/index.d.cts",
|
|
18
|
+
"default": "./dist/index.cjs"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"README.md"
|
|
25
|
+
],
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "tsup",
|
|
28
|
+
"dev": "tsup --watch",
|
|
29
|
+
"typecheck": "tsc --noEmit",
|
|
30
|
+
"prepublishOnly": "npm run build"
|
|
31
|
+
},
|
|
32
|
+
"peerDependencies": {
|
|
33
|
+
"react": ">=17.0.0",
|
|
34
|
+
"react-dom": ">=17.0.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/react": "^19.1.0",
|
|
38
|
+
"@types/react-dom": "^19.1.0",
|
|
39
|
+
"react": "^19.1.0",
|
|
40
|
+
"react-dom": "^19.1.0",
|
|
41
|
+
"tsup": "^8.4.0",
|
|
42
|
+
"typescript": "^5.7.0"
|
|
43
|
+
},
|
|
44
|
+
"keywords": [
|
|
45
|
+
"pollenate",
|
|
46
|
+
"feedback",
|
|
47
|
+
"widget",
|
|
48
|
+
"react",
|
|
49
|
+
"nps",
|
|
50
|
+
"csat",
|
|
51
|
+
"stars",
|
|
52
|
+
"survey",
|
|
53
|
+
"rating"
|
|
54
|
+
],
|
|
55
|
+
"repository": {
|
|
56
|
+
"type": "git",
|
|
57
|
+
"url": "https://github.com/bluehive-health/pollenate-cloud",
|
|
58
|
+
"directory": "packages/react"
|
|
59
|
+
},
|
|
60
|
+
"homepage": "https://pollenate.dev/docs",
|
|
61
|
+
"bugs": {
|
|
62
|
+
"url": "https://github.com/bluehive-health/pollenate-cloud/issues"
|
|
63
|
+
}
|
|
64
|
+
}
|