@uselay/sdk 0.1.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +216 -49
- package/dist/index.d.mts +21 -5
- package/dist/index.d.ts +21 -5
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/server/index.d.mts +17 -1
- package/dist/server/index.d.ts +17 -1
- package/dist/server/index.js +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +1 -1
- package/dist/server/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,112 +1,279 @@
|
|
|
1
1
|
# @uselay/sdk
|
|
2
2
|
|
|
3
|
-
The feedback layer for React. Drop
|
|
3
|
+
The feedback layer for React. Drop one component into your app and let anyone point at what's wrong and say why — no more screenshots in Slack with "the thing on the right."
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Comments are pinned to the exact DOM element, not a screenshot coordinate. Your team sees what was clicked, reads the comment, and understands the problem without a follow-up call.
|
|
6
|
+
|
|
7
|
+
## Quick start
|
|
8
|
+
|
|
9
|
+
### 1. Install
|
|
6
10
|
|
|
7
11
|
```bash
|
|
8
12
|
npm install @uselay/sdk
|
|
9
13
|
```
|
|
10
14
|
|
|
11
|
-
No CSS imports needed
|
|
15
|
+
No CSS imports needed. Styles are injected at runtime.
|
|
12
16
|
|
|
13
|
-
|
|
17
|
+
### 2. Wrap your app
|
|
14
18
|
|
|
15
19
|
```tsx
|
|
16
|
-
import { LayProvider
|
|
20
|
+
import { LayProvider } from '@uselay/sdk';
|
|
17
21
|
|
|
18
22
|
function App() {
|
|
19
23
|
return (
|
|
20
|
-
<LayProvider
|
|
21
|
-
config={{
|
|
22
|
-
projectId: 'your-project-id',
|
|
23
|
-
user: { id: 'user-1', name: 'Jane' },
|
|
24
|
-
}}
|
|
25
|
-
>
|
|
24
|
+
<LayProvider projectId="your-project-id">
|
|
26
25
|
<YourApp />
|
|
27
|
-
<LayToggle />
|
|
28
26
|
</LayProvider>
|
|
29
27
|
);
|
|
30
28
|
}
|
|
31
29
|
```
|
|
32
30
|
|
|
33
|
-
|
|
31
|
+
Get your `projectId` from the [dashboard](https://uselay.com/dashboard). The toggle button and comment UI render automatically inside the provider.
|
|
32
|
+
|
|
33
|
+
Want to identify who's commenting? Add the optional `user` prop:
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
<LayProvider
|
|
37
|
+
projectId="your-project-id"
|
|
38
|
+
user={{ id: 'user-1', name: 'Jane' }}
|
|
39
|
+
>
|
|
40
|
+
<YourApp />
|
|
41
|
+
</LayProvider>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 3. Press C
|
|
45
|
+
|
|
46
|
+
Run your app and press `C` to enter comment mode. Hover to highlight elements. Click to pin a comment.
|
|
47
|
+
|
|
48
|
+
## How it works
|
|
49
|
+
|
|
50
|
+
1. **Enter comment mode** — Press `C` or click the toggle button. Elements highlight on hover.
|
|
51
|
+
2. **Click an element** — A comment input anchors to your selection. The SDK generates a CSS selector and fingerprint to track it.
|
|
52
|
+
3. **Write your comment** — Type what you see, or tap a starter chip.
|
|
53
|
+
4. **AI enrichment runs** — Element metadata is captured and enriched with context, intent detection, and suggested actions.
|
|
54
|
+
5. **Comment appears in the dashboard** — Grouped by page and element, with the AI context card and a viewport screenshot.
|
|
55
|
+
6. **Your team understands what you mean** — The comment is attached to the element itself. Navigate, resolve, and archive from the dashboard.
|
|
34
56
|
|
|
35
57
|
## Configuration
|
|
36
58
|
|
|
37
|
-
|
|
59
|
+
All props are passed directly to `LayProvider`:
|
|
38
60
|
|
|
39
61
|
| Prop | Type | Default | Description |
|
|
40
62
|
|------|------|---------|-------------|
|
|
41
63
|
| `projectId` | `string` | *required* | Project ID from the Lay dashboard |
|
|
42
|
-
| `user` | `{ id
|
|
43
|
-
| `userHash` | `string` | — | HMAC-SHA256 hash for verified identity (
|
|
44
|
-
| `adapter` | `LayAdapter` | auto | Custom data adapter. Defaults to hosted backend. |
|
|
45
|
-
| `apiUrl` | `string` | `https://uselay.com` | API base URL override |
|
|
46
|
-
| `version` | `string` | — | Version tag. Changing this archives previous comments. |
|
|
47
|
-
| `ai` | `boolean` | `true` | Enable AI enrichment on comments |
|
|
64
|
+
| `user` | `{ id, name, avatar? }` | — | Comment author identity. Omit for anonymous. |
|
|
65
|
+
| `userHash` | `string` | — | HMAC-SHA256 hash for verified identity. Use `identifyUser()` to generate. |
|
|
48
66
|
| `mode` | `'review' \| 'support'` | dashboard setting | Override project mode |
|
|
49
67
|
| `active` | `boolean` | dashboard setting | Override active state. `false` = widget hidden. |
|
|
50
|
-
| `
|
|
68
|
+
| `ai` | `boolean` | `true` | Enable AI enrichment on comments |
|
|
51
69
|
| `screenshots` | `boolean` | `true` | Capture viewport screenshots on comment creation |
|
|
70
|
+
| `starterChips` | `StarterChip[]` | `["Visual bug", "Copy issue", "Love this"]` | Quick-feedback chips. `[]` to disable. |
|
|
71
|
+
| `version` | `string` | — | Version tag. Changing this archives previous comments. |
|
|
72
|
+
| `adapter` | `LayAdapter` | hosted | Custom data adapter. Defaults to hosted backend. |
|
|
73
|
+
| `apiUrl` | `string` | `https://uselay.com` | API base URL override |
|
|
74
|
+
|
|
75
|
+
Most projects need only `projectId`.
|
|
76
|
+
|
|
77
|
+
## Modes
|
|
78
|
+
|
|
79
|
+
**Review** — Team feedback on prototypes and staging. Comments are threaded. AI generates element descriptions and fix suggestions. Best for staging URLs, design reviews, QA passes.
|
|
80
|
+
|
|
81
|
+
```tsx
|
|
82
|
+
<LayProvider projectId="..." mode="review">
|
|
83
|
+
<StagingApp />
|
|
84
|
+
</LayProvider>
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**Support** — End-user feedback on live sites. Comments are standalone. AI detects intent (bug report, confusion, feature request, praise). Best for production apps, beta programs, user research.
|
|
88
|
+
|
|
89
|
+
```tsx
|
|
90
|
+
<LayProvider projectId="..." mode="support">
|
|
91
|
+
<ProductionApp />
|
|
92
|
+
</LayProvider>
|
|
93
|
+
```
|
|
52
94
|
|
|
53
95
|
## Identified users
|
|
54
96
|
|
|
55
|
-
|
|
97
|
+
Use `identifyUser` to verify commenter identity server-side. It returns spread-friendly props — `{ user, userHash }` for a valid user, or `{}` for null/undefined input.
|
|
56
98
|
|
|
57
99
|
```ts
|
|
58
|
-
|
|
59
|
-
import { createUserHash } from '@uselay/sdk/server';
|
|
100
|
+
import { identifyUser } from '@uselay/sdk/server';
|
|
60
101
|
|
|
61
102
|
// Set LAY_SECRET_KEY in your environment (from dashboard → project settings)
|
|
62
|
-
const
|
|
103
|
+
const identified = identifyUser(session?.user);
|
|
104
|
+
// → { user: { id, name, avatar }, userHash: '...' } or {}
|
|
63
105
|
```
|
|
64
106
|
|
|
65
|
-
|
|
107
|
+
Spread the result into the provider:
|
|
66
108
|
|
|
67
109
|
```tsx
|
|
68
|
-
<LayProvider
|
|
110
|
+
<LayProvider projectId="..." {...identifyUser(session?.user)}>
|
|
111
|
+
<YourApp />
|
|
112
|
+
</LayProvider>
|
|
69
113
|
```
|
|
70
114
|
|
|
71
|
-
|
|
115
|
+
Never expose `LAY_SECRET_KEY` to the client. `identifyUser` must run on your server.
|
|
72
116
|
|
|
73
|
-
|
|
117
|
+
## Stable anchors
|
|
118
|
+
|
|
119
|
+
Comments are pinned to DOM elements via CSS selectors. The SDK resolves elements in three layers:
|
|
120
|
+
|
|
121
|
+
1. **`data-feedback-id`** — If present, always used. Most stable. Add to elements that receive frequent feedback.
|
|
122
|
+
2. **CSS selector** — Generated from IDs, `data-testid`, semantic attributes. Skips auto-generated class names.
|
|
123
|
+
3. **Element fingerprint** — Hash of tag, text, attributes, position. Used as fallback when the selector stops matching.
|
|
74
124
|
|
|
75
125
|
```tsx
|
|
76
|
-
<
|
|
77
|
-
config={{
|
|
78
|
-
projectId: '...',
|
|
79
|
-
starterChips: [
|
|
80
|
-
{ label: 'Broken', value: 'This element is broken' },
|
|
81
|
-
{ label: 'Wrong copy' },
|
|
82
|
-
{ label: 'Looks great' },
|
|
83
|
-
],
|
|
84
|
-
}}
|
|
85
|
-
>
|
|
126
|
+
<button data-feedback-id="checkout-submit">Place Order</button>
|
|
86
127
|
```
|
|
87
128
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
Viewport screenshots are captured automatically when a comment is created. Disable with `screenshots: false`.
|
|
129
|
+
If a comment can't be resolved to any element, it appears in the Detached Comments panel in the dashboard.
|
|
91
130
|
|
|
92
131
|
## Custom adapter
|
|
93
132
|
|
|
94
133
|
Implement the `LayAdapter` interface to use your own backend:
|
|
95
134
|
|
|
96
|
-
```
|
|
97
|
-
import { LayProvider } from '@uselay/sdk';
|
|
135
|
+
```ts
|
|
98
136
|
import type { LayAdapter } from '@uselay/sdk';
|
|
99
137
|
|
|
100
138
|
const myAdapter: LayAdapter = {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
139
|
+
getConfig: async (projectId) => { /* ... */ },
|
|
140
|
+
getComments: async (projectId, urlPath, options) => { /* ... */ },
|
|
141
|
+
addComment: async (comment, options) => { /* ... */ },
|
|
142
|
+
updateComment: async (id, update, options) => { /* ... */ },
|
|
143
|
+
uploadScreenshot: async (projectId, commentId, blob, bounds, options) => { /* ... */ },
|
|
144
|
+
subscribe: (projectId, callback, options) => { /* return unsubscribe fn */ },
|
|
105
145
|
};
|
|
146
|
+
```
|
|
106
147
|
|
|
107
|
-
|
|
148
|
+
```tsx
|
|
149
|
+
<LayProvider projectId="..." adapter={myAdapter}>
|
|
150
|
+
<YourApp />
|
|
151
|
+
</LayProvider>
|
|
108
152
|
```
|
|
109
153
|
|
|
154
|
+
The SDK also exports `createMemoryAdapter()` for testing and prototyping.
|
|
155
|
+
|
|
156
|
+
## Keyboard shortcuts
|
|
157
|
+
|
|
158
|
+
| Key | Action |
|
|
159
|
+
|-----|--------|
|
|
160
|
+
| `C` | Toggle comment mode |
|
|
161
|
+
| `Escape` | Exit comment mode / dismiss input |
|
|
162
|
+
|
|
163
|
+
Shortcuts are disabled when focus is inside an input, textarea, or contenteditable element.
|
|
164
|
+
|
|
165
|
+
## Framework examples
|
|
166
|
+
|
|
167
|
+
### Next.js App Router
|
|
168
|
+
|
|
169
|
+
```tsx
|
|
170
|
+
// app/layout.tsx
|
|
171
|
+
import { identifyUser } from '@uselay/sdk/server';
|
|
172
|
+
import { LayProvider } from '@uselay/sdk';
|
|
173
|
+
|
|
174
|
+
export default async function RootLayout({ children }) {
|
|
175
|
+
const session = await auth();
|
|
176
|
+
|
|
177
|
+
return (
|
|
178
|
+
<html lang="en">
|
|
179
|
+
<body>
|
|
180
|
+
<LayProvider
|
|
181
|
+
projectId={process.env.NEXT_PUBLIC_LAY_PROJECT_ID!}
|
|
182
|
+
{...identifyUser(session?.user)}
|
|
183
|
+
>
|
|
184
|
+
{children}
|
|
185
|
+
</LayProvider>
|
|
186
|
+
</body>
|
|
187
|
+
</html>
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Next.js Pages Router
|
|
193
|
+
|
|
194
|
+
```tsx
|
|
195
|
+
// pages/_app.tsx
|
|
196
|
+
import { identifyUser } from '@uselay/sdk/server';
|
|
197
|
+
import { LayProvider } from '@uselay/sdk';
|
|
198
|
+
|
|
199
|
+
export async function getServerSideProps({ req }) {
|
|
200
|
+
const session = await getSession(req);
|
|
201
|
+
return { props: { identified: identifyUser(session?.user) } };
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export default function App({ Component, pageProps }) {
|
|
205
|
+
return (
|
|
206
|
+
<LayProvider
|
|
207
|
+
projectId={process.env.NEXT_PUBLIC_LAY_PROJECT_ID!}
|
|
208
|
+
{...pageProps.identified}
|
|
209
|
+
>
|
|
210
|
+
<Component {...pageProps} />
|
|
211
|
+
</LayProvider>
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Vite + React
|
|
217
|
+
|
|
218
|
+
```tsx
|
|
219
|
+
// src/main.tsx
|
|
220
|
+
import { LayProvider } from '@uselay/sdk';
|
|
221
|
+
import App from './App';
|
|
222
|
+
|
|
223
|
+
ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
224
|
+
<LayProvider projectId={import.meta.env.VITE_LAY_PROJECT_ID}>
|
|
225
|
+
<App />
|
|
226
|
+
</LayProvider>
|
|
227
|
+
);
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Remix
|
|
231
|
+
|
|
232
|
+
```tsx
|
|
233
|
+
// app/root.tsx
|
|
234
|
+
import { LayProvider } from '@uselay/sdk';
|
|
235
|
+
import { identifyUser } from '@uselay/sdk/server';
|
|
236
|
+
|
|
237
|
+
export async function loader({ request }) {
|
|
238
|
+
const user = await getUser(request);
|
|
239
|
+
return json({
|
|
240
|
+
layProjectId: process.env.LAY_PROJECT_ID,
|
|
241
|
+
...identifyUser(user),
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
export default function Root() {
|
|
246
|
+
const { layProjectId, user, userHash } = useLoaderData();
|
|
247
|
+
return (
|
|
248
|
+
<html lang="en">
|
|
249
|
+
<body>
|
|
250
|
+
<LayProvider projectId={layProjectId!} user={user} userHash={userHash}>
|
|
251
|
+
<Outlet />
|
|
252
|
+
</LayProvider>
|
|
253
|
+
</body>
|
|
254
|
+
</html>
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
## Troubleshooting
|
|
260
|
+
|
|
261
|
+
**Widget does not appear** — Check that `LayProvider` wraps your app with a valid `projectId`. The project must be active in the dashboard (or pass the `active` prop).
|
|
262
|
+
|
|
263
|
+
**Comments disappear after deploy** — CSS selectors changed. Add `data-feedback-id` to critical elements. Detached comments appear in the Detached Comments panel.
|
|
264
|
+
|
|
265
|
+
**AI context cards not showing** — Verify `ai` is not set to `false`. AI processing takes a few seconds after comment creation.
|
|
266
|
+
|
|
267
|
+
**`identifyUser` throws "LAY_SECRET_KEY not set"** — Set the `LAY_SECRET_KEY` environment variable on your server. Never expose it client-side.
|
|
268
|
+
|
|
269
|
+
**Widget re-renders frequently** — If you pass object props like `user` inline on every render, it creates a new reference each time. Define objects outside the component or use `useMemo`.
|
|
270
|
+
|
|
271
|
+
## Next steps
|
|
272
|
+
|
|
273
|
+
- Open the [dashboard](https://uselay.com/dashboard) and create your first project
|
|
274
|
+
- Invite your team from project settings
|
|
275
|
+
- Add `data-feedback-id` to your most important UI elements
|
|
276
|
+
|
|
110
277
|
## License
|
|
111
278
|
|
|
112
279
|
MIT
|
package/dist/index.d.mts
CHANGED
|
@@ -31,8 +31,14 @@ interface ElementMetadata {
|
|
|
31
31
|
device: string;
|
|
32
32
|
fingerprint?: ElementFingerprint;
|
|
33
33
|
}
|
|
34
|
+
interface DeveloperTriage {
|
|
35
|
+
element_summary: string;
|
|
36
|
+
whats_happening: string;
|
|
37
|
+
likely_causes: string[];
|
|
38
|
+
where_to_look: string[];
|
|
39
|
+
}
|
|
34
40
|
interface AIContextReview {
|
|
35
|
-
ai_context_version: 2 | 3;
|
|
41
|
+
ai_context_version: 2 | 3 | 4;
|
|
36
42
|
mode: 'review';
|
|
37
43
|
category: 'visual' | 'accessibility' | 'layout' | 'copy' | 'interaction';
|
|
38
44
|
/** v3: single interpretation sentence replacing suggestions + accessibility_issues */
|
|
@@ -46,12 +52,15 @@ interface AIContextReview {
|
|
|
46
52
|
enriched_at: string;
|
|
47
53
|
}
|
|
48
54
|
interface AIContextSupport {
|
|
49
|
-
ai_context_version: 2 | 3;
|
|
55
|
+
ai_context_version: 2 | 3 | 4;
|
|
50
56
|
mode: 'support';
|
|
51
57
|
intent: 'confusion' | 'bug_report' | 'feature_request' | 'complaint' | 'question' | 'praise' | 'other';
|
|
52
58
|
urgency: 'low' | 'medium' | 'high';
|
|
53
59
|
summary: string;
|
|
54
|
-
|
|
60
|
+
/** v4: developer triage for bug_report/confusion intents */
|
|
61
|
+
developer_triage?: DeveloperTriage | null;
|
|
62
|
+
/** @deprecated v3 only — removed in v4 */
|
|
63
|
+
suggested_response?: string;
|
|
55
64
|
/** @deprecated v2 only — removed in v3 */
|
|
56
65
|
confidence?: number;
|
|
57
66
|
enriched_at: string;
|
|
@@ -115,6 +124,8 @@ interface LayAdapter {
|
|
|
115
124
|
|
|
116
125
|
/** Project mode: review (team feedback) or support (end-user help) */
|
|
117
126
|
type ProjectMode = 'review' | 'support';
|
|
127
|
+
/** SDK connection status after attempting to validate the projectId */
|
|
128
|
+
type ProjectStatus = 'loading' | 'valid' | 'not_found' | 'inactive';
|
|
118
129
|
/** Starter chip for the Two-Speed Composer */
|
|
119
130
|
interface StarterChip {
|
|
120
131
|
/** Display label on the chip */
|
|
@@ -175,14 +186,19 @@ interface LayContextValue {
|
|
|
175
186
|
dispatch: React.Dispatch<LayAction>;
|
|
176
187
|
portalRoot: HTMLDivElement | null;
|
|
177
188
|
mode: ProjectMode;
|
|
189
|
+
projectStatus: ProjectStatus;
|
|
178
190
|
remoteConfigLoaded: boolean;
|
|
179
191
|
detachedDomPaths: Set<string>;
|
|
180
192
|
setDetachedDomPaths: React.Dispatch<React.SetStateAction<Set<string>>>;
|
|
193
|
+
/** Ref-stable callback for when the current user submits a comment. */
|
|
194
|
+
onCommentAddedRef: React.RefObject<((comment: Comment) => void) | undefined>;
|
|
181
195
|
}
|
|
182
196
|
interface LayProviderProps extends LayConfig {
|
|
183
197
|
children: ReactNode;
|
|
198
|
+
/** Callback invoked when the current user successfully submits a comment. */
|
|
199
|
+
onCommentAdded?: (comment: Comment) => void;
|
|
184
200
|
}
|
|
185
|
-
declare function LayProvider({ children, projectId, user, userHash, adapter: customAdapter, apiUrl, version, ai, mode: modeProp, active: activeProp, starterChips, screenshots, }: LayProviderProps): react_jsx_runtime.JSX.Element;
|
|
201
|
+
declare function LayProvider({ children, projectId, user, userHash, adapter: customAdapter, apiUrl, version, ai, mode: modeProp, active: activeProp, starterChips, screenshots, onCommentAdded, }: LayProviderProps): react_jsx_runtime.JSX.Element;
|
|
186
202
|
|
|
187
203
|
declare function LayToggle(): React.ReactPortal | null;
|
|
188
204
|
|
|
@@ -490,4 +506,4 @@ interface HostedAdapterOptions {
|
|
|
490
506
|
}
|
|
491
507
|
declare function createHostedAdapter(options?: string | HostedAdapterOptions): LayAdapter;
|
|
492
508
|
|
|
493
|
-
export { type AIContext, AIContextCard, type AIContextReview, type AIContextSupport, type AdapterOptions, ArchivedThreadsPanel, type Author, type Comment, CommentActions, CommentAnchor, CommentDot, CommentDots, type CommentEvent, type CommentEventType, type CommentGroup, CommentItem, CommentLayer, type CommentStatus, CommentThread, type CommentUpdate, DetachedCommentsPanel, type ElementBounds, type ElementFingerprint, ElementHighlighter, type ElementMetadata, type LayAdapter, type LayConfig, type LayContextValue, LayProvider, LayToggle, type NewComment, type ProjectMode, type RemoteConfig, ReplyInput, type ResolveMethod, type ResolveResult, type StarterChip, type ThreadGroup, type ThreadItem, type Unsubscribe, captureElementMetadata, computeContrastRatio, createHostedAdapter, createMemoryAdapter, findByFingerprint, formatRelativeTime, generateDomPath, generateFingerprint, getGuestAuthor, isAIContextReview, isAIContextSupport, isCommentable, isGeneratedClassName, parseUserAgent, persistGuestName, resolveAuthor, resolveEffectiveBackground, resolveElement, saveGuestAuthor, scoreFingerprintMatch, summarizeDomPath, useCommentMode, useComments, useElementSelector, useLayContext };
|
|
509
|
+
export { type AIContext, AIContextCard, type AIContextReview, type AIContextSupport, type AdapterOptions, ArchivedThreadsPanel, type Author, type Comment, CommentActions, CommentAnchor, CommentDot, CommentDots, type CommentEvent, type CommentEventType, type CommentGroup, CommentItem, CommentLayer, type CommentStatus, CommentThread, type CommentUpdate, DetachedCommentsPanel, type ElementBounds, type ElementFingerprint, ElementHighlighter, type ElementMetadata, type LayAdapter, type LayConfig, type LayContextValue, LayProvider, LayToggle, type NewComment, type ProjectMode, type ProjectStatus, type RemoteConfig, ReplyInput, type ResolveMethod, type ResolveResult, type StarterChip, type ThreadGroup, type ThreadItem, type Unsubscribe, captureElementMetadata, computeContrastRatio, createHostedAdapter, createMemoryAdapter, findByFingerprint, formatRelativeTime, generateDomPath, generateFingerprint, getGuestAuthor, isAIContextReview, isAIContextSupport, isCommentable, isGeneratedClassName, parseUserAgent, persistGuestName, resolveAuthor, resolveEffectiveBackground, resolveElement, saveGuestAuthor, scoreFingerprintMatch, summarizeDomPath, useCommentMode, useComments, useElementSelector, useLayContext };
|
package/dist/index.d.ts
CHANGED
|
@@ -31,8 +31,14 @@ interface ElementMetadata {
|
|
|
31
31
|
device: string;
|
|
32
32
|
fingerprint?: ElementFingerprint;
|
|
33
33
|
}
|
|
34
|
+
interface DeveloperTriage {
|
|
35
|
+
element_summary: string;
|
|
36
|
+
whats_happening: string;
|
|
37
|
+
likely_causes: string[];
|
|
38
|
+
where_to_look: string[];
|
|
39
|
+
}
|
|
34
40
|
interface AIContextReview {
|
|
35
|
-
ai_context_version: 2 | 3;
|
|
41
|
+
ai_context_version: 2 | 3 | 4;
|
|
36
42
|
mode: 'review';
|
|
37
43
|
category: 'visual' | 'accessibility' | 'layout' | 'copy' | 'interaction';
|
|
38
44
|
/** v3: single interpretation sentence replacing suggestions + accessibility_issues */
|
|
@@ -46,12 +52,15 @@ interface AIContextReview {
|
|
|
46
52
|
enriched_at: string;
|
|
47
53
|
}
|
|
48
54
|
interface AIContextSupport {
|
|
49
|
-
ai_context_version: 2 | 3;
|
|
55
|
+
ai_context_version: 2 | 3 | 4;
|
|
50
56
|
mode: 'support';
|
|
51
57
|
intent: 'confusion' | 'bug_report' | 'feature_request' | 'complaint' | 'question' | 'praise' | 'other';
|
|
52
58
|
urgency: 'low' | 'medium' | 'high';
|
|
53
59
|
summary: string;
|
|
54
|
-
|
|
60
|
+
/** v4: developer triage for bug_report/confusion intents */
|
|
61
|
+
developer_triage?: DeveloperTriage | null;
|
|
62
|
+
/** @deprecated v3 only — removed in v4 */
|
|
63
|
+
suggested_response?: string;
|
|
55
64
|
/** @deprecated v2 only — removed in v3 */
|
|
56
65
|
confidence?: number;
|
|
57
66
|
enriched_at: string;
|
|
@@ -115,6 +124,8 @@ interface LayAdapter {
|
|
|
115
124
|
|
|
116
125
|
/** Project mode: review (team feedback) or support (end-user help) */
|
|
117
126
|
type ProjectMode = 'review' | 'support';
|
|
127
|
+
/** SDK connection status after attempting to validate the projectId */
|
|
128
|
+
type ProjectStatus = 'loading' | 'valid' | 'not_found' | 'inactive';
|
|
118
129
|
/** Starter chip for the Two-Speed Composer */
|
|
119
130
|
interface StarterChip {
|
|
120
131
|
/** Display label on the chip */
|
|
@@ -175,14 +186,19 @@ interface LayContextValue {
|
|
|
175
186
|
dispatch: React.Dispatch<LayAction>;
|
|
176
187
|
portalRoot: HTMLDivElement | null;
|
|
177
188
|
mode: ProjectMode;
|
|
189
|
+
projectStatus: ProjectStatus;
|
|
178
190
|
remoteConfigLoaded: boolean;
|
|
179
191
|
detachedDomPaths: Set<string>;
|
|
180
192
|
setDetachedDomPaths: React.Dispatch<React.SetStateAction<Set<string>>>;
|
|
193
|
+
/** Ref-stable callback for when the current user submits a comment. */
|
|
194
|
+
onCommentAddedRef: React.RefObject<((comment: Comment) => void) | undefined>;
|
|
181
195
|
}
|
|
182
196
|
interface LayProviderProps extends LayConfig {
|
|
183
197
|
children: ReactNode;
|
|
198
|
+
/** Callback invoked when the current user successfully submits a comment. */
|
|
199
|
+
onCommentAdded?: (comment: Comment) => void;
|
|
184
200
|
}
|
|
185
|
-
declare function LayProvider({ children, projectId, user, userHash, adapter: customAdapter, apiUrl, version, ai, mode: modeProp, active: activeProp, starterChips, screenshots, }: LayProviderProps): react_jsx_runtime.JSX.Element;
|
|
201
|
+
declare function LayProvider({ children, projectId, user, userHash, adapter: customAdapter, apiUrl, version, ai, mode: modeProp, active: activeProp, starterChips, screenshots, onCommentAdded, }: LayProviderProps): react_jsx_runtime.JSX.Element;
|
|
186
202
|
|
|
187
203
|
declare function LayToggle(): React.ReactPortal | null;
|
|
188
204
|
|
|
@@ -490,4 +506,4 @@ interface HostedAdapterOptions {
|
|
|
490
506
|
}
|
|
491
507
|
declare function createHostedAdapter(options?: string | HostedAdapterOptions): LayAdapter;
|
|
492
508
|
|
|
493
|
-
export { type AIContext, AIContextCard, type AIContextReview, type AIContextSupport, type AdapterOptions, ArchivedThreadsPanel, type Author, type Comment, CommentActions, CommentAnchor, CommentDot, CommentDots, type CommentEvent, type CommentEventType, type CommentGroup, CommentItem, CommentLayer, type CommentStatus, CommentThread, type CommentUpdate, DetachedCommentsPanel, type ElementBounds, type ElementFingerprint, ElementHighlighter, type ElementMetadata, type LayAdapter, type LayConfig, type LayContextValue, LayProvider, LayToggle, type NewComment, type ProjectMode, type RemoteConfig, ReplyInput, type ResolveMethod, type ResolveResult, type StarterChip, type ThreadGroup, type ThreadItem, type Unsubscribe, captureElementMetadata, computeContrastRatio, createHostedAdapter, createMemoryAdapter, findByFingerprint, formatRelativeTime, generateDomPath, generateFingerprint, getGuestAuthor, isAIContextReview, isAIContextSupport, isCommentable, isGeneratedClassName, parseUserAgent, persistGuestName, resolveAuthor, resolveEffectiveBackground, resolveElement, saveGuestAuthor, scoreFingerprintMatch, summarizeDomPath, useCommentMode, useComments, useElementSelector, useLayContext };
|
|
509
|
+
export { type AIContext, AIContextCard, type AIContextReview, type AIContextSupport, type AdapterOptions, ArchivedThreadsPanel, type Author, type Comment, CommentActions, CommentAnchor, CommentDot, CommentDots, type CommentEvent, type CommentEventType, type CommentGroup, CommentItem, CommentLayer, type CommentStatus, CommentThread, type CommentUpdate, DetachedCommentsPanel, type ElementBounds, type ElementFingerprint, ElementHighlighter, type ElementMetadata, type LayAdapter, type LayConfig, type LayContextValue, LayProvider, LayToggle, type NewComment, type ProjectMode, type ProjectStatus, type RemoteConfig, ReplyInput, type ResolveMethod, type ResolveResult, type StarterChip, type ThreadGroup, type ThreadItem, type Unsubscribe, captureElementMetadata, computeContrastRatio, createHostedAdapter, createMemoryAdapter, findByFingerprint, formatRelativeTime, generateDomPath, generateFingerprint, getGuestAuthor, isAIContextReview, isAIContextSupport, isCommentable, isGeneratedClassName, parseUserAgent, persistGuestName, resolveAuthor, resolveEffectiveBackground, resolveElement, saveGuestAuthor, scoreFingerprintMatch, summarizeDomPath, useCommentMode, useComments, useElementSelector, useLayContext };
|