instruckt 0.4.27 → 0.4.29
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 +109 -146
- package/dist/instruckt.cjs.js +108 -38
- package/dist/instruckt.cjs.js.map +1 -1
- package/dist/instruckt.d.cts +26 -1
- package/dist/instruckt.d.ts +26 -1
- package/dist/instruckt.esm.js +108 -38
- package/dist/instruckt.esm.js.map +1 -1
- package/dist/instruckt.iife.js +52 -22
- package/dist/instruckt.iife.js.map +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -10,15 +10,24 @@ Framework-agnostic JS core with adapters for Livewire, Vue, Svelte, and React.
|
|
|
10
10
|
npm install instruckt
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
## Quick Start
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
> **Pick your framework below** -- each section is self-contained.
|
|
16
|
+
|
|
17
|
+
| Framework | Setup |
|
|
18
|
+
|-----------|-------|
|
|
19
|
+
| [SPA (Vue, React, Svelte)](#spa-vue-react-svelte-with-vite) | Vite plugin only |
|
|
20
|
+
| [SvelteKit](#sveltekit) | Vite plugin + virtual import |
|
|
21
|
+
| [Nuxt](#nuxt) | Vite plugin + virtual import |
|
|
22
|
+
| [Next.js](#nextjs) | Client component |
|
|
23
|
+
| [Laravel](#laravel) | Composer package |
|
|
24
|
+
| [Astro](#astro) | Community integration |
|
|
25
|
+
|
|
26
|
+
---
|
|
18
27
|
|
|
19
|
-
|
|
28
|
+
### SPA (Vue, React, Svelte with Vite)
|
|
20
29
|
|
|
21
|
-
|
|
30
|
+
Add the Vite plugin — it handles client injection and provides a built-in dev API server. No backend required.
|
|
22
31
|
|
|
23
32
|
```js
|
|
24
33
|
// vite.config.ts
|
|
@@ -29,171 +38,59 @@ export default defineConfig({
|
|
|
29
38
|
})
|
|
30
39
|
```
|
|
31
40
|
|
|
32
|
-
That's it
|
|
33
|
-
|
|
34
|
-
### SSR Frameworks (SvelteKit, Nuxt, etc.)
|
|
35
|
-
|
|
36
|
-
For frameworks that don't use `index.html`, import the virtual module in your layout:
|
|
41
|
+
That's it. The plugin auto-injects the client via `transformIndexHtml`.
|
|
37
42
|
|
|
38
|
-
|
|
39
|
-
// SvelteKit: src/routes/+layout.svelte
|
|
40
|
-
import 'virtual:instruckt'
|
|
43
|
+
---
|
|
41
44
|
|
|
42
|
-
|
|
43
|
-
import 'virtual:instruckt'
|
|
44
|
-
```
|
|
45
|
+
### SvelteKit
|
|
45
46
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
### Laravel
|
|
49
|
-
|
|
50
|
-
The Vite plugin works alongside the Laravel package. Set `server: false` so Laravel handles the backend:
|
|
47
|
+
Two steps — add the Vite plugin, then import the virtual module in your layout:
|
|
51
48
|
|
|
52
49
|
```js
|
|
53
50
|
// vite.config.ts
|
|
54
|
-
import laravel from 'laravel-vite-plugin'
|
|
55
51
|
import instruckt from 'instruckt/vite'
|
|
56
52
|
|
|
57
53
|
export default defineConfig({
|
|
58
|
-
plugins: [
|
|
59
|
-
laravel({ input: ['resources/js/app.js'] }),
|
|
60
|
-
instruckt({
|
|
61
|
-
server: false,
|
|
62
|
-
adapters: ['livewire', 'blade'],
|
|
63
|
-
mcp: true,
|
|
64
|
-
}),
|
|
65
|
-
],
|
|
66
|
-
})
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
Then in your app entry:
|
|
70
|
-
|
|
71
|
-
```js
|
|
72
|
-
// resources/js/app.js
|
|
73
|
-
import 'virtual:instruckt'
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
### Vite Plugin Options
|
|
77
|
-
|
|
78
|
-
```js
|
|
79
|
-
instruckt({
|
|
80
|
-
// Framework adapters to activate (default: auto-detect)
|
|
81
|
-
adapters: ['svelte'],
|
|
82
|
-
|
|
83
|
-
// Theme: 'light' | 'dark' | 'auto' (default: 'auto')
|
|
84
|
-
theme: 'auto',
|
|
85
|
-
|
|
86
|
-
// Toolbar position (default: 'bottom-right')
|
|
87
|
-
position: 'bottom-right',
|
|
88
|
-
|
|
89
|
-
// Customize marker pin colors
|
|
90
|
-
colors: { default: '#6366f1', screenshot: '#22c55e', dismissed: '#71717a' },
|
|
91
|
-
|
|
92
|
-
// Customize keyboard shortcuts
|
|
93
|
-
keys: { annotate: 'a', freeze: 'f', screenshot: 'c', clearPage: 'x' },
|
|
94
|
-
|
|
95
|
-
// Storage directory for annotations + screenshots (default: '.instruckt')
|
|
96
|
-
dir: '.instruckt',
|
|
97
|
-
|
|
98
|
-
// API endpoint prefix (default: '/instruckt')
|
|
99
|
-
endpoint: '/instruckt',
|
|
100
|
-
|
|
101
|
-
// Enable built-in dev API server (default: true)
|
|
102
|
-
// Set to false when your framework provides its own backend (e.g. Laravel)
|
|
103
|
-
server: true,
|
|
104
|
-
|
|
105
|
-
// Show MCP tool instructions in clipboard markdown (default: false)
|
|
106
|
-
// Set to true when using with a backend that registers MCP tools
|
|
107
|
-
mcp: false,
|
|
54
|
+
plugins: [sveltekit(), instruckt()],
|
|
108
55
|
})
|
|
109
56
|
```
|
|
110
57
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
If you're not using Vite, you can initialize instruckt directly:
|
|
114
|
-
|
|
115
|
-
```js
|
|
116
|
-
import { Instruckt } from 'instruckt'
|
|
117
|
-
|
|
118
|
-
const instruckt = new Instruckt({
|
|
119
|
-
endpoint: '/instruckt',
|
|
120
|
-
})
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
Or with the IIFE build:
|
|
124
|
-
|
|
125
|
-
```html
|
|
126
|
-
<script src="/path/to/instruckt.iife.js"></script>
|
|
58
|
+
```svelte
|
|
59
|
+
<!-- src/routes/+layout.svelte -->
|
|
127
60
|
<script>
|
|
128
|
-
|
|
61
|
+
import 'virtual:instruckt'
|
|
129
62
|
</script>
|
|
130
63
|
```
|
|
131
64
|
|
|
132
|
-
|
|
65
|
+
The virtual module is SSR-safe — it only initializes in the browser.
|
|
133
66
|
|
|
134
|
-
|
|
67
|
+
---
|
|
135
68
|
|
|
136
|
-
|
|
137
|
-
<summary>SvelteKit</summary>
|
|
69
|
+
### Nuxt
|
|
138
70
|
|
|
139
|
-
|
|
140
|
-
<!-- src/lib/InstrucktProvider.svelte -->
|
|
141
|
-
<script>
|
|
142
|
-
import { onMount } from 'svelte';
|
|
71
|
+
Same idea — add the Vite plugin, then import the virtual module in a client plugin:
|
|
143
72
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
endpoint: '/api/annotations',
|
|
148
|
-
adapters: ['svelte'],
|
|
149
|
-
});
|
|
73
|
+
```js
|
|
74
|
+
// nuxt.config.ts — add the Vite plugin
|
|
75
|
+
import instruckt from 'instruckt/vite'
|
|
150
76
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
77
|
+
export default defineNuxtConfig({
|
|
78
|
+
vite: {
|
|
79
|
+
plugins: [instruckt()],
|
|
80
|
+
},
|
|
81
|
+
})
|
|
154
82
|
```
|
|
155
83
|
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
import { browser } from '$app/environment';
|
|
160
|
-
|
|
161
|
-
let { children } = $props();
|
|
162
|
-
</script>
|
|
163
|
-
|
|
164
|
-
{#if browser}
|
|
165
|
-
{#await import('$lib/InstrucktProvider.svelte') then { default: InstrucktProvider }}
|
|
166
|
-
<InstrucktProvider />
|
|
167
|
-
{/await}
|
|
168
|
-
{/if}
|
|
169
|
-
|
|
170
|
-
{@render children()}
|
|
84
|
+
```ts
|
|
85
|
+
// plugins/instruckt.client.ts
|
|
86
|
+
import 'virtual:instruckt'
|
|
171
87
|
```
|
|
172
88
|
|
|
173
|
-
|
|
89
|
+
---
|
|
174
90
|
|
|
175
|
-
|
|
176
|
-
<summary>Nuxt</summary>
|
|
91
|
+
### Next.js
|
|
177
92
|
|
|
178
|
-
|
|
179
|
-
<!-- plugins/instruckt.client.ts -->
|
|
180
|
-
<script>
|
|
181
|
-
// The .client.ts suffix ensures Nuxt only runs this in the browser
|
|
182
|
-
export default defineNuxtPlugin(async () => {
|
|
183
|
-
const { Instruckt } = await import('instruckt')
|
|
184
|
-
|
|
185
|
-
const instruckt = new Instruckt({
|
|
186
|
-
endpoint: '/api/annotations',
|
|
187
|
-
adapters: ['vue'],
|
|
188
|
-
})
|
|
189
|
-
})
|
|
190
|
-
</script>
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
</details>
|
|
194
|
-
|
|
195
|
-
<details>
|
|
196
|
-
<summary>Next.js (App Router)</summary>
|
|
93
|
+
Next.js doesn't use Vite, so initialize instruckt directly in a client component:
|
|
197
94
|
|
|
198
95
|
```tsx
|
|
199
96
|
// components/InstrucktProvider.tsx
|
|
@@ -235,12 +132,78 @@ export default function RootLayout({ children }) {
|
|
|
235
132
|
}
|
|
236
133
|
```
|
|
237
134
|
|
|
238
|
-
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
### Laravel
|
|
138
|
+
|
|
139
|
+
Use the **[instruckt-laravel](https://github.com/joshcirre/instruckt-laravel)** package — it provides the backend API, MCP tools, JSON file storage, and handles install/uninstall automatically:
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
composer require joshcirre/instruckt-laravel --dev
|
|
143
|
+
php artisan instruckt:install
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
The install command adds the Vite plugin to your `vite.config.js` with `server: false` (Laravel owns the backend), configures MCP for your AI agent, and adds the virtual import to your JS entry point.
|
|
147
|
+
|
|
148
|
+
```js
|
|
149
|
+
// vite.config.js (added automatically by install command)
|
|
150
|
+
import instruckt from 'instruckt/vite'
|
|
151
|
+
|
|
152
|
+
export default defineConfig({
|
|
153
|
+
plugins: [
|
|
154
|
+
laravel({ input: ['resources/js/app.js'] }),
|
|
155
|
+
instruckt({
|
|
156
|
+
server: false,
|
|
157
|
+
adapters: ['livewire', 'blade'],
|
|
158
|
+
mcp: true,
|
|
159
|
+
}),
|
|
160
|
+
],
|
|
161
|
+
})
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
---
|
|
239
165
|
|
|
240
166
|
### Astro
|
|
241
167
|
|
|
242
168
|
See **[instruckt-astro](https://github.com/sgasser/instruckt-astro)** for a community-maintained Astro integration.
|
|
243
169
|
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## Vite Plugin Options
|
|
173
|
+
|
|
174
|
+
```js
|
|
175
|
+
instruckt({
|
|
176
|
+
// Framework adapters to activate (default: auto-detect)
|
|
177
|
+
adapters: ['svelte'],
|
|
178
|
+
|
|
179
|
+
// Theme: 'light' | 'dark' | 'auto' (default: 'auto')
|
|
180
|
+
theme: 'auto',
|
|
181
|
+
|
|
182
|
+
// Toolbar position (default: 'bottom-right')
|
|
183
|
+
position: 'bottom-right',
|
|
184
|
+
|
|
185
|
+
// Customize marker pin colors
|
|
186
|
+
colors: { default: '#6366f1', screenshot: '#22c55e', dismissed: '#71717a' },
|
|
187
|
+
|
|
188
|
+
// Customize keyboard shortcuts
|
|
189
|
+
keys: { annotate: 'a', freeze: 'f', screenshot: 'c', clearPage: 'x' },
|
|
190
|
+
|
|
191
|
+
// Storage directory for annotations + screenshots (default: '.instruckt')
|
|
192
|
+
dir: '.instruckt',
|
|
193
|
+
|
|
194
|
+
// API endpoint prefix (default: '/instruckt')
|
|
195
|
+
endpoint: '/instruckt',
|
|
196
|
+
|
|
197
|
+
// Enable built-in dev API server (default: true)
|
|
198
|
+
// Set to false when your framework provides its own backend (e.g. Laravel)
|
|
199
|
+
server: true,
|
|
200
|
+
|
|
201
|
+
// Show MCP tool instructions in clipboard markdown (default: false)
|
|
202
|
+
// Set to true when using with a backend that registers MCP tools
|
|
203
|
+
mcp: false,
|
|
204
|
+
})
|
|
205
|
+
```
|
|
206
|
+
|
|
244
207
|
## How It Works
|
|
245
208
|
|
|
246
209
|
1. A floating toolbar appears in your app
|
|
@@ -355,7 +318,7 @@ The Vite plugin includes a dev API server that saves annotations and screenshots
|
|
|
355
318
|
|
|
356
319
|
### Laravel
|
|
357
320
|
|
|
358
|
-
**[instruckt-laravel](https://github.com/joshcirre/instruckt-laravel)** — Laravel package with JSON file storage, MCP tools, Blade component, and API routes.
|
|
321
|
+
**[instruckt-laravel](https://github.com/joshcirre/instruckt-laravel)** — Laravel package with JSON file storage, MCP tools, Blade component, and API routes. Includes `artisan instruckt:install` which auto-configures the Vite plugin, MCP, and agent skills.
|
|
359
322
|
|
|
360
323
|
### Custom Backend
|
|
361
324
|
|
package/dist/instruckt.cjs.js
CHANGED
|
@@ -549,7 +549,7 @@ var ICONS = {
|
|
|
549
549
|
logo: `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4 12.5-12.5z"/></svg>`
|
|
550
550
|
};
|
|
551
551
|
var Toolbar = class {
|
|
552
|
-
constructor(position, callbacks, keys) {
|
|
552
|
+
constructor(position, callbacks, keys, tools) {
|
|
553
553
|
this.position = position;
|
|
554
554
|
this.callbacks = callbacks;
|
|
555
555
|
this.fabBadge = null;
|
|
@@ -560,9 +560,15 @@ var Toolbar = class {
|
|
|
560
560
|
this.dragging = false;
|
|
561
561
|
this.dragOffset = { x: 0, y: 0 };
|
|
562
562
|
this.keys = keys != null ? keys : {};
|
|
563
|
+
this.tools = tools != null ? tools : {};
|
|
563
564
|
this.build();
|
|
564
565
|
this.setupDrag();
|
|
565
566
|
}
|
|
567
|
+
/** Whether a built-in tool should be shown (default true if not specified). */
|
|
568
|
+
show(id) {
|
|
569
|
+
const v = this.tools[id];
|
|
570
|
+
return v !== false;
|
|
571
|
+
}
|
|
566
572
|
build() {
|
|
567
573
|
var _a2, _b, _c, _d, _e;
|
|
568
574
|
this.host = document.createElement("div");
|
|
@@ -621,17 +627,18 @@ var Toolbar = class {
|
|
|
621
627
|
d.className = "divider";
|
|
622
628
|
return d;
|
|
623
629
|
};
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
);
|
|
630
|
+
const toAppend = [];
|
|
631
|
+
const add = (el) => {
|
|
632
|
+
if (toAppend.length > 0) toAppend.push(mkDiv());
|
|
633
|
+
toAppend.push(el);
|
|
634
|
+
};
|
|
635
|
+
if (this.show("annotate")) add(this.annotateBtn);
|
|
636
|
+
if (this.show("screenshot")) add(screenshotBtn);
|
|
637
|
+
if (this.show("freeze")) add(this.freezeBtn);
|
|
638
|
+
if (this.show("copy")) add(this.copyBtn);
|
|
639
|
+
if (this.show("clear_page") || this.show("clear_all")) add(clearWrap);
|
|
640
|
+
if (this.show("minimize")) add(minimizeBtn);
|
|
641
|
+
this.toolbarEl.append(...toAppend);
|
|
635
642
|
this.shadow.appendChild(this.toolbarEl);
|
|
636
643
|
this.fab = document.createElement("button");
|
|
637
644
|
this.fab.className = "fab";
|
|
@@ -2944,6 +2951,9 @@ function getPageBoundingBox(el) {
|
|
|
2944
2951
|
};
|
|
2945
2952
|
}
|
|
2946
2953
|
|
|
2954
|
+
// src/instruckt.ts
|
|
2955
|
+
var import_element_source = require("element-source");
|
|
2956
|
+
|
|
2947
2957
|
// src/adapters/livewire.ts
|
|
2948
2958
|
function isAvailable() {
|
|
2949
2959
|
return typeof window.Livewire !== "undefined";
|
|
@@ -3243,7 +3253,7 @@ var _Instruckt = class _Instruckt {
|
|
|
3243
3253
|
e.stopImmediatePropagation();
|
|
3244
3254
|
};
|
|
3245
3255
|
this.boundClick = (e) => {
|
|
3246
|
-
var _a2, _b
|
|
3256
|
+
var _a2, _b;
|
|
3247
3257
|
const target = e.target;
|
|
3248
3258
|
if (this.isInstruckt(target)) return;
|
|
3249
3259
|
e.preventDefault();
|
|
@@ -3256,23 +3266,24 @@ var _Instruckt = class _Instruckt {
|
|
|
3256
3266
|
const cssClasses = getCssClasses(target);
|
|
3257
3267
|
const nearbyText = getNearbyText(target) || void 0;
|
|
3258
3268
|
const boundingBox = getPageBoundingBox(target);
|
|
3259
|
-
|
|
3260
|
-
(_c = this.highlight) == null ? void 0 : _c.show(target);
|
|
3269
|
+
(_b = this.highlight) == null ? void 0 : _b.show(target);
|
|
3261
3270
|
this.highlightLocked = true;
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3271
|
+
this.detectFramework(target).then((framework) => {
|
|
3272
|
+
const pending = {
|
|
3273
|
+
element: target,
|
|
3274
|
+
elementPath,
|
|
3275
|
+
elementName,
|
|
3276
|
+
elementLabel,
|
|
3277
|
+
cssClasses,
|
|
3278
|
+
boundingBox,
|
|
3279
|
+
x: e.clientX,
|
|
3280
|
+
y: e.clientY,
|
|
3281
|
+
selectedText,
|
|
3282
|
+
nearbyText,
|
|
3283
|
+
framework: framework != null ? framework : void 0
|
|
3284
|
+
};
|
|
3285
|
+
this.showAnnotationPopup(pending);
|
|
3286
|
+
});
|
|
3276
3287
|
};
|
|
3277
3288
|
this.config = __spreadValues({
|
|
3278
3289
|
adapters: ["livewire", "vue", "svelte", "react", "blade"],
|
|
@@ -3305,7 +3316,7 @@ var _Instruckt = class _Instruckt {
|
|
|
3305
3316
|
onClearPage: () => this.clearPage(),
|
|
3306
3317
|
onClearAll: () => this.clearEverything(),
|
|
3307
3318
|
onMinimize: (min) => this.onMinimize(min)
|
|
3308
|
-
}, this.config.keys);
|
|
3319
|
+
}, this.config.keys, this.config.tools);
|
|
3309
3320
|
this.highlight = new ElementHighlight();
|
|
3310
3321
|
this.popup = new AnnotationPopup();
|
|
3311
3322
|
this.markers = new AnnotationMarkers((annotation) => this.onMarkerClick(annotation));
|
|
@@ -3344,7 +3355,7 @@ var _Instruckt = class _Instruckt {
|
|
|
3344
3355
|
this.isAnnotating = false;
|
|
3345
3356
|
this.isFrozen = false;
|
|
3346
3357
|
document.querySelectorAll("[data-instruckt]").forEach((el) => el.remove());
|
|
3347
|
-
this.toolbar = new Toolbar(this.config.position, this.makeToolbarCallbacks());
|
|
3358
|
+
this.toolbar = new Toolbar(this.config.position, this.makeToolbarCallbacks(), this.config.keys, this.config.tools);
|
|
3348
3359
|
if (wasMinimized) this.toolbar.minimize();
|
|
3349
3360
|
this.markers = new AnnotationMarkers((annotation) => this.onMarkerClick(annotation));
|
|
3350
3361
|
this.highlight = new ElementHighlight();
|
|
@@ -3678,7 +3689,7 @@ var _Instruckt = class _Instruckt {
|
|
|
3678
3689
|
}
|
|
3679
3690
|
// ── Region screenshot ────────────────────────────────────────
|
|
3680
3691
|
async startRegionCapture() {
|
|
3681
|
-
var _a2
|
|
3692
|
+
var _a2;
|
|
3682
3693
|
const wasAnnotating = this.isAnnotating;
|
|
3683
3694
|
if (wasAnnotating) this.setAnnotating(false);
|
|
3684
3695
|
const rect = await selectRegion();
|
|
@@ -3694,6 +3705,7 @@ var _Instruckt = class _Instruckt {
|
|
|
3694
3705
|
const centerX = rect.x + rect.width / 2;
|
|
3695
3706
|
const centerY = rect.y + rect.height / 2;
|
|
3696
3707
|
const target = (_a2 = document.elementFromPoint(centerX, centerY)) != null ? _a2 : document.body;
|
|
3708
|
+
const framework = await this.detectFramework(target);
|
|
3697
3709
|
const pending = {
|
|
3698
3710
|
element: target,
|
|
3699
3711
|
elementPath: getElementSelector(target),
|
|
@@ -3705,18 +3717,60 @@ var _Instruckt = class _Instruckt {
|
|
|
3705
3717
|
y: centerY,
|
|
3706
3718
|
nearbyText: getNearbyText(target) || void 0,
|
|
3707
3719
|
screenshot,
|
|
3708
|
-
framework:
|
|
3720
|
+
framework: framework != null ? framework : void 0
|
|
3709
3721
|
};
|
|
3710
3722
|
this.showAnnotationPopup(pending);
|
|
3711
3723
|
}
|
|
3712
3724
|
// ── Framework detection ───────────────────────────────────────
|
|
3713
|
-
|
|
3714
|
-
|
|
3725
|
+
/**
|
|
3726
|
+
* Use element-source as the primary resolver for React/Vue/Svelte,
|
|
3727
|
+
* then layer our adapters on top for props/state/framework-specific metadata.
|
|
3728
|
+
* Livewire and Blade are handled by our adapters only (element-source doesn't support them).
|
|
3729
|
+
*/
|
|
3730
|
+
async detectFramework(el) {
|
|
3731
|
+
var _a2, _b, _c, _d, _e, _f, _g;
|
|
3715
3732
|
const adapters = (_a2 = this.config.adapters) != null ? _a2 : [];
|
|
3716
3733
|
if (adapters.includes("livewire")) {
|
|
3717
3734
|
const ctx = getContext(el);
|
|
3718
3735
|
if (ctx) return ctx;
|
|
3719
3736
|
}
|
|
3737
|
+
const esAdapters = ["vue", "svelte", "react"];
|
|
3738
|
+
if (esAdapters.some((a) => adapters.includes(a))) {
|
|
3739
|
+
try {
|
|
3740
|
+
const info = await (0, import_element_source.resolveElementInfo)(el);
|
|
3741
|
+
if (info.source) {
|
|
3742
|
+
const stack = info.stack.map((f) => ({
|
|
3743
|
+
filePath: f.filePath,
|
|
3744
|
+
lineNumber: f.lineNumber,
|
|
3745
|
+
columnNumber: f.columnNumber,
|
|
3746
|
+
componentName: f.componentName
|
|
3747
|
+
}));
|
|
3748
|
+
let adapterCtx = null;
|
|
3749
|
+
if (adapters.includes("vue")) adapterCtx = getContext2(el);
|
|
3750
|
+
if (!adapterCtx && adapters.includes("svelte")) adapterCtx = getContext3(el);
|
|
3751
|
+
if (!adapterCtx && adapters.includes("react")) adapterCtx = getContext4(el);
|
|
3752
|
+
if (adapterCtx) {
|
|
3753
|
+
return __spreadProps(__spreadValues({}, adapterCtx), {
|
|
3754
|
+
component: (_b = info.componentName) != null ? _b : adapterCtx.component,
|
|
3755
|
+
source_file: info.source.filePath,
|
|
3756
|
+
source_line: (_c = info.source.lineNumber) != null ? _c : adapterCtx.source_line,
|
|
3757
|
+
source_column: (_d = info.source.columnNumber) != null ? _d : void 0,
|
|
3758
|
+
component_stack: stack.length > 0 ? stack : void 0
|
|
3759
|
+
});
|
|
3760
|
+
}
|
|
3761
|
+
return {
|
|
3762
|
+
framework: "react",
|
|
3763
|
+
// element-source defaults to React resolver
|
|
3764
|
+
component: (_e = info.componentName) != null ? _e : "Component",
|
|
3765
|
+
source_file: info.source.filePath,
|
|
3766
|
+
source_line: (_f = info.source.lineNumber) != null ? _f : void 0,
|
|
3767
|
+
source_column: (_g = info.source.columnNumber) != null ? _g : void 0,
|
|
3768
|
+
component_stack: stack.length > 0 ? stack : void 0
|
|
3769
|
+
};
|
|
3770
|
+
}
|
|
3771
|
+
} catch (e) {
|
|
3772
|
+
}
|
|
3773
|
+
}
|
|
3720
3774
|
if (adapters.includes("vue")) {
|
|
3721
3775
|
const ctx = getContext2(el);
|
|
3722
3776
|
if (ctx) return ctx;
|
|
@@ -3908,17 +3962,33 @@ No open annotations.`;
|
|
|
3908
3962
|
lines.push("");
|
|
3909
3963
|
const hPrefix = multiPage ? "###" : "##";
|
|
3910
3964
|
annotations.forEach((a, i) => {
|
|
3911
|
-
var _a2, _b, _c, _d, _e;
|
|
3965
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
3912
3966
|
const componentSuffix = ((_a2 = a.framework) == null ? void 0 : _a2.component) ? ` in \`${a.framework.component}\`` : "";
|
|
3913
3967
|
lines.push(`${hPrefix} ${i + 1}. ${a.comment}`);
|
|
3914
3968
|
lines.push(`- ID: \`${a.id}\``);
|
|
3915
3969
|
lines.push(`- Element: \`${a.element}\`${componentSuffix}`);
|
|
3916
3970
|
if ((_b = a.framework) == null ? void 0 : _b.source_file) {
|
|
3917
|
-
|
|
3971
|
+
let loc = a.framework.source_file;
|
|
3972
|
+
if (a.framework.source_line) {
|
|
3973
|
+
loc += `:${a.framework.source_line}`;
|
|
3974
|
+
if (a.framework.source_column) loc += `:${a.framework.source_column}`;
|
|
3975
|
+
}
|
|
3918
3976
|
lines.push(`- Source: \`${loc}\``);
|
|
3919
3977
|
} else if ((_d = (_c = a.framework) == null ? void 0 : _c.data) == null ? void 0 : _d.file) {
|
|
3920
3978
|
lines.push(`- File: \`${a.framework.data.file}\``);
|
|
3921
3979
|
}
|
|
3980
|
+
if (((_e = a.framework) == null ? void 0 : _e.component_stack) && a.framework.component_stack.length > 1) {
|
|
3981
|
+
lines.push(`- Component stack:`);
|
|
3982
|
+
for (const frame of a.framework.component_stack) {
|
|
3983
|
+
let frameLoc = frame.filePath;
|
|
3984
|
+
if (frame.lineNumber) {
|
|
3985
|
+
frameLoc += `:${frame.lineNumber}`;
|
|
3986
|
+
if (frame.columnNumber) frameLoc += `:${frame.columnNumber}`;
|
|
3987
|
+
}
|
|
3988
|
+
const name = frame.componentName ? `${frame.componentName} ` : "";
|
|
3989
|
+
lines.push(` - ${name}\`${frameLoc}\``);
|
|
3990
|
+
}
|
|
3991
|
+
}
|
|
3922
3992
|
if (a.cssClasses) {
|
|
3923
3993
|
lines.push(`- Classes: \`${a.cssClasses}\``);
|
|
3924
3994
|
}
|
|
@@ -3929,7 +3999,7 @@ No open annotations.`;
|
|
|
3929
3999
|
}
|
|
3930
4000
|
if (a.screenshot) {
|
|
3931
4001
|
if (!a.screenshot.startsWith("data:")) {
|
|
3932
|
-
const screenshotPath = (
|
|
4002
|
+
const screenshotPath = (_f = this.config.screenshotPath) != null ? _f : "storage/app/_instruckt/";
|
|
3933
4003
|
lines.push(`- Screenshot: \`${screenshotPath}${a.screenshot}\``);
|
|
3934
4004
|
} else {
|
|
3935
4005
|
lines.push(`- Screenshot: `);
|