@heedkit/sdk-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/LICENSE +21 -0
- package/README.md +181 -0
- package/dist/index.cjs +774 -0
- package/dist/index.d.cts +141 -0
- package/dist/index.d.ts +141 -0
- package/dist/index.js +735 -0
- package/package.json +65 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 HeedKit
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# @heedkit/sdk-react
|
|
2
|
+
|
|
3
|
+
React SDK for [HeedKit](https://heedkit.com). Drop-in feature requests, voting,
|
|
4
|
+
and comments — themed from your console.
|
|
5
|
+
|
|
6
|
+
- **Drop-in widget** — `<FeedbackButton/>` renders a floating launcher + panel.
|
|
7
|
+
- **Headless** — `useHeedKit()` gives you the client; build your own UI.
|
|
8
|
+
- **Themed remotely** — colors, radius, light/dark, tabs-vs-list, and per-kind
|
|
9
|
+
interactions are configured in the HeedKit console and applied at runtime.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm i @heedkit/sdk-react react react-dom
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
`react` and `react-dom` (both `>=17`) are **peer dependencies** — install them
|
|
18
|
+
alongside the SDK (most React apps already have them).
|
|
19
|
+
|
|
20
|
+
## Get your project key
|
|
21
|
+
|
|
22
|
+
1. Sign in to the HeedKit console at <https://heedkit.com>.
|
|
23
|
+
2. Open your project and copy its **project key** (looks like `fh_xxx`).
|
|
24
|
+
|
|
25
|
+
The key is sent client-side as the `X-Project-Key` header on every request, so
|
|
26
|
+
it's safe to embed in your front-end bundle.
|
|
27
|
+
|
|
28
|
+
## Mount the widget
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
import { HeedKitProvider, FeedbackButton } from "@heedkit/sdk-react";
|
|
32
|
+
|
|
33
|
+
export default function App() {
|
|
34
|
+
return (
|
|
35
|
+
<HeedKitProvider
|
|
36
|
+
projectKey="fh_xxx"
|
|
37
|
+
user={{ externalId: "user-123", email: "alice@example.com", name: "Alice" }}
|
|
38
|
+
>
|
|
39
|
+
<YourApp />
|
|
40
|
+
<FeedbackButton label="Feedback" />
|
|
41
|
+
</HeedKitProvider>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`FeedbackButton` mounts the floating launcher and panel — the same UI as the bare
|
|
47
|
+
JS SDK (it delegates to it). When an admin changes theme, tabs vs list, per-kind
|
|
48
|
+
interactions, or `show_counts` in the console, the widget picks it up on the next
|
|
49
|
+
mount.
|
|
50
|
+
|
|
51
|
+
## Imperative open / close
|
|
52
|
+
|
|
53
|
+
`FeedbackButton` is **self-contained**: it runs its own `init` and does **not**
|
|
54
|
+
read config from `<HeedKitProvider>`, so pass `projectKey` on every instance.
|
|
55
|
+
Forward a ref to drive it imperatively:
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
import React from "react";
|
|
59
|
+
import { FeedbackButton, type Widget } from "@heedkit/sdk-react";
|
|
60
|
+
|
|
61
|
+
function CustomTrigger() {
|
|
62
|
+
const ref = React.useRef<Widget>(null);
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<>
|
|
66
|
+
<FeedbackButton ref={ref} projectKey="fh_xxx" hideLauncher />
|
|
67
|
+
<button onClick={() => ref.current?.open()}>Open feedback</button>
|
|
68
|
+
<button onClick={() => ref.current?.close()}>Close</button>
|
|
69
|
+
</>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The ref resolves to a `Widget` exposing `open()`, `close()`, `destroy()`, and the
|
|
75
|
+
underlying `client`. If `init` fails (bad key / network), it's logged via
|
|
76
|
+
`console.warn` and `open()` becomes a no-op rather than throwing.
|
|
77
|
+
|
|
78
|
+
## Headless (no built-in UI)
|
|
79
|
+
|
|
80
|
+
`useHeedKit()` returns the ready client so you can build your own roadmap. It
|
|
81
|
+
must be called inside `<HeedKitProvider>` (it throws otherwise).
|
|
82
|
+
|
|
83
|
+
```tsx
|
|
84
|
+
import { useHeedKit, type Feature } from "@heedkit/sdk-react";
|
|
85
|
+
|
|
86
|
+
function MyRoadmap() {
|
|
87
|
+
const { client, ready, theme } = useHeedKit();
|
|
88
|
+
const [features, setFeatures] = React.useState<Feature[]>([]);
|
|
89
|
+
|
|
90
|
+
React.useEffect(() => {
|
|
91
|
+
if (ready) client.list({ sort: "top" }).then(setFeatures);
|
|
92
|
+
}, [client, ready]);
|
|
93
|
+
|
|
94
|
+
if (!ready) return null;
|
|
95
|
+
|
|
96
|
+
// Data: client.list / submit / vote / listComments / comment
|
|
97
|
+
// Config: client.getEnabledKinds() / getInteractionsFor(kind) /
|
|
98
|
+
// getKindInteractions() / getKindVisibility() / getProjectName() /
|
|
99
|
+
// getTheme() / getEndUserId()
|
|
100
|
+
return <ul>{features.map((f) => <li key={f.id}>{f.title}</li>)}</ul>;
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## SSR / Next.js (App Router)
|
|
105
|
+
|
|
106
|
+
`HeedKitProvider`, `FeedbackButton`, and `useHeedKit` use React hooks and Context,
|
|
107
|
+
so they must run in a **Client Component**. Add `"use client"` at the top of any
|
|
108
|
+
file that renders them (or wrap them in one):
|
|
109
|
+
|
|
110
|
+
```tsx
|
|
111
|
+
"use client";
|
|
112
|
+
import { HeedKitProvider, FeedbackButton } from "@heedkit/sdk-react";
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
They're safe under server rendering and streaming: the widget DOM work and
|
|
116
|
+
`client.init()` run inside `useEffect` (browser only), and the device-id helper
|
|
117
|
+
returns `null` on the server — importing the package or its types in a server
|
|
118
|
+
file won't crash. The only requirement is the Client Component boundary.
|
|
119
|
+
|
|
120
|
+
## Theming
|
|
121
|
+
|
|
122
|
+
Theme is configured in the HeedKit console (not via props) and delivered on
|
|
123
|
+
`init`. Themeable: primary color, corner radius, light / dark / `system` mode,
|
|
124
|
+
font family & size, `tabs` vs `list` grouping, and per-kind `show_counts`. Read
|
|
125
|
+
the resolved theme in headless UIs via `useHeedKit().theme` (or
|
|
126
|
+
`client.getTheme()`).
|
|
127
|
+
|
|
128
|
+
## API reference
|
|
129
|
+
|
|
130
|
+
### `<HeedKitProvider>`
|
|
131
|
+
|
|
132
|
+
| Prop | Type | Required | Notes |
|
|
133
|
+
| ------------ | ----------- | -------- | --------------------------------------- |
|
|
134
|
+
| `projectKey` | `string` | yes | Your `fh_…` key. |
|
|
135
|
+
| `apiUrl` | `string` | no | Override the API base URL. |
|
|
136
|
+
| `user` | `EndUser` | no | `{ externalId?, email?, name?, avatarUrl?, platform? }`. Omit `externalId` to use a persisted per-browser device id. |
|
|
137
|
+
|
|
138
|
+
### `useHeedKit()`
|
|
139
|
+
|
|
140
|
+
Returns `{ client: HeedKitClient, ready: boolean, theme: Theme }`. Throws if used
|
|
141
|
+
outside `<HeedKitProvider>`.
|
|
142
|
+
|
|
143
|
+
### `<FeedbackButton>`
|
|
144
|
+
|
|
145
|
+
Accepts the same config as the provider (`projectKey`, `apiUrl`, `user`) plus:
|
|
146
|
+
|
|
147
|
+
| Prop | Type | Default | Notes |
|
|
148
|
+
| -------------- | --------- | ------------ | ---------------------------------- |
|
|
149
|
+
| `label` | `string` | `"Feedback"` | Floating launcher label. |
|
|
150
|
+
| `hideLauncher` | `boolean` | `false` | Hide the launcher; drive via ref. |
|
|
151
|
+
|
|
152
|
+
Forwards a ref to a `Widget` (`open()`, `close()`, `destroy()`, `client`).
|
|
153
|
+
|
|
154
|
+
### `HeedKitClient`
|
|
155
|
+
|
|
156
|
+
| Method | Returns |
|
|
157
|
+
| --------------------------------- | ---------------------------------------- |
|
|
158
|
+
| `list(opts?)` | `Promise<Feature[]>` — `opts: { status?, kind?, sort?: "top" \| "new" }` |
|
|
159
|
+
| `submit(input)` | `Promise<Feature>` — `input: { title, description?, tag?, kind? }` |
|
|
160
|
+
| `vote(featureId)` | `Promise<{ voted: boolean; vote_count: number }>` (toggles) |
|
|
161
|
+
| `listComments(featureId)` | `Promise<Comment[]>` |
|
|
162
|
+
| `comment(featureId, body)` | `Promise<Comment>` |
|
|
163
|
+
| `getTheme()` | `Theme` |
|
|
164
|
+
| `getEnabledKinds()` | `FeatureKind[]` |
|
|
165
|
+
| `getInteractionsFor(kind)` | `Interaction[]` |
|
|
166
|
+
| `getKindInteractions()` | per-kind interaction map |
|
|
167
|
+
| `getKindVisibility()` | per-kind default visibility |
|
|
168
|
+
| `getProjectName()` | `string` |
|
|
169
|
+
| `getEndUserId()` | `string \| null` |
|
|
170
|
+
|
|
171
|
+
Methods other than `init`/getters throw if called before `init()` resolves; the
|
|
172
|
+
provider and widget call `init()` for you.
|
|
173
|
+
|
|
174
|
+
## Example
|
|
175
|
+
|
|
176
|
+
A complete Vite + React app lives in [`Example/`](./Example) — build the SDK
|
|
177
|
+
once (`npm run build`), then `cd Example && npm install && npm run dev`.
|
|
178
|
+
|
|
179
|
+
## License
|
|
180
|
+
|
|
181
|
+
MIT © HeedKit
|