beeport 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 +268 -0
- package/dist/beeport.min.js +1 -0
- package/dist/beeport.mjs +1 -0
- package/dist/context.d.ts +10 -0
- package/dist/dedup-ui.d.ts +16 -0
- package/dist/dedup.d.ts +29 -0
- package/dist/errors.d.ts +51 -0
- package/dist/form.d.ts +33 -0
- package/dist/formatter.d.ts +42 -0
- package/dist/github.d.ts +47 -0
- package/dist/index.d.ts +14 -0
- package/dist/labels.d.ts +23 -0
- package/dist/styles.d.ts +4 -0
- package/dist/submit.d.ts +66 -0
- package/dist/theme.d.ts +12 -0
- package/dist/types.d.ts +86 -0
- package/dist/widget.d.ts +30 -0
- package/package.json +54 -0
package/README.md
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
# BeePort
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/beeport)
|
|
4
|
+
[](https://www.npmjs.com/package/beeport)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
[](https://www.typescriptlang.org/)
|
|
7
|
+
|
|
8
|
+
Embeddable feedback widget that turns user feedback into **agent-ready GitHub issues**. Automatically captures 90% of technical context (browser, OS, screen, URL) so users only need to describe their intent.
|
|
9
|
+
|
|
10
|
+
## Why BeePort?
|
|
11
|
+
|
|
12
|
+
- **Zero-friction feedback**: Users describe what they want, BeePort captures the technical details
|
|
13
|
+
- **Agent-ready issues**: Structured format optimized for AI/agent consumption and automation
|
|
14
|
+
- **Tiny bundle**: ~3KB gzipped, zero dependencies
|
|
15
|
+
- **Privacy-first**: No tracking, no analytics, issues go directly to your GitHub repo
|
|
16
|
+
- **Shadow DOM isolation**: Won't break your styles or scripts
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
### Via npm/yarn/pnpm
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install beeport
|
|
24
|
+
# or
|
|
25
|
+
yarn add beeport
|
|
26
|
+
# or
|
|
27
|
+
pnpm add beeport
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Via CDN
|
|
31
|
+
|
|
32
|
+
```html
|
|
33
|
+
<!-- unpkg -->
|
|
34
|
+
<script src="https://unpkg.com/beeport@latest/dist/beeport.min.js"></script>
|
|
35
|
+
|
|
36
|
+
<!-- jsdelivr -->
|
|
37
|
+
<script src="https://cdn.jsdelivr.net/npm/beeport@latest/dist/beeport.min.js"></script>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Quick Start
|
|
41
|
+
|
|
42
|
+
### ES Modules
|
|
43
|
+
|
|
44
|
+
```javascript
|
|
45
|
+
import { init } from 'beeport';
|
|
46
|
+
|
|
47
|
+
const beeport = init({
|
|
48
|
+
repo: 'your-org/your-repo',
|
|
49
|
+
token: 'ghp_your_github_token'
|
|
50
|
+
});
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Script Tag (CDN)
|
|
54
|
+
|
|
55
|
+
```html
|
|
56
|
+
<script src="https://unpkg.com/beeport@latest/dist/beeport.min.js"></script>
|
|
57
|
+
<script>
|
|
58
|
+
const beeport = BeePort.init({
|
|
59
|
+
repo: 'your-org/your-repo',
|
|
60
|
+
token: 'ghp_your_github_token'
|
|
61
|
+
});
|
|
62
|
+
</script>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### TypeScript
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
import { init, BeePortConfig, BeePortInstance } from 'beeport';
|
|
69
|
+
|
|
70
|
+
const config: BeePortConfig = {
|
|
71
|
+
repo: 'your-org/your-repo',
|
|
72
|
+
token: 'ghp_your_github_token',
|
|
73
|
+
position: 'bottom-right',
|
|
74
|
+
theme: 'auto'
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const beeport: BeePortInstance = init(config);
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Configuration API
|
|
81
|
+
|
|
82
|
+
### `init(config)`
|
|
83
|
+
|
|
84
|
+
Initialize the BeePort widget. Returns an `BeePortInstance`.
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
interface BeePortConfig {
|
|
88
|
+
/** GitHub repository in "owner/repo" format (required) */
|
|
89
|
+
repo: string;
|
|
90
|
+
|
|
91
|
+
/** GitHub Personal Access Token with repo:write scope (required) */
|
|
92
|
+
token: string;
|
|
93
|
+
|
|
94
|
+
/** Position of the widget button */
|
|
95
|
+
position?: 'bottom-right' | 'bottom-left'; // default: 'bottom-right'
|
|
96
|
+
|
|
97
|
+
/** Widget theme */
|
|
98
|
+
theme?: 'light' | 'dark' | 'auto'; // default: 'auto'
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### `BeePortInstance` Methods
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
interface BeePortInstance {
|
|
106
|
+
/** Show the widget */
|
|
107
|
+
show(): void;
|
|
108
|
+
|
|
109
|
+
/** Hide the widget */
|
|
110
|
+
hide(): void;
|
|
111
|
+
|
|
112
|
+
/** Change the widget theme */
|
|
113
|
+
setTheme(theme: 'light' | 'dark' | 'auto'): void;
|
|
114
|
+
|
|
115
|
+
/** Destroy the widget and remove from DOM */
|
|
116
|
+
destroy(): void;
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Examples
|
|
121
|
+
|
|
122
|
+
### Basic Bug Report Widget
|
|
123
|
+
|
|
124
|
+
```javascript
|
|
125
|
+
import { init } from 'beeport';
|
|
126
|
+
|
|
127
|
+
init({
|
|
128
|
+
repo: 'acme/web-app',
|
|
129
|
+
token: 'ghp_xxxxxxxxxxxxx'
|
|
130
|
+
});
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Feature Request Widget (Left Position)
|
|
134
|
+
|
|
135
|
+
```javascript
|
|
136
|
+
import { init } from 'beeport';
|
|
137
|
+
|
|
138
|
+
const beeport = init({
|
|
139
|
+
repo: 'acme/product',
|
|
140
|
+
token: 'ghp_xxxxxxxxxxxxx',
|
|
141
|
+
position: 'bottom-left'
|
|
142
|
+
});
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Custom Theme Control
|
|
146
|
+
|
|
147
|
+
```javascript
|
|
148
|
+
import { init } from 'beeport';
|
|
149
|
+
|
|
150
|
+
const beeport = init({
|
|
151
|
+
repo: 'acme/app',
|
|
152
|
+
token: 'ghp_xxxxxxxxxxxxx',
|
|
153
|
+
theme: 'dark'
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// Later, switch to light theme
|
|
157
|
+
beeport.setTheme('light');
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Conditional Widget Display
|
|
161
|
+
|
|
162
|
+
```javascript
|
|
163
|
+
import { init } from 'beeport';
|
|
164
|
+
|
|
165
|
+
const beeport = init({
|
|
166
|
+
repo: 'acme/beta-app',
|
|
167
|
+
token: 'ghp_xxxxxxxxxxxxx'
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// Hide widget for certain users
|
|
171
|
+
if (user.isPremium) {
|
|
172
|
+
beeport.hide();
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Show it again later
|
|
176
|
+
beeport.show();
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Complete Lifecycle Management
|
|
180
|
+
|
|
181
|
+
```javascript
|
|
182
|
+
import { init } from 'beeport';
|
|
183
|
+
|
|
184
|
+
// Initialize
|
|
185
|
+
const beeport = init({
|
|
186
|
+
repo: 'acme/app',
|
|
187
|
+
token: 'ghp_xxxxxxxxxxxxx'
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
// Use the widget...
|
|
191
|
+
|
|
192
|
+
// Clean up when done (e.g., SPA route change)
|
|
193
|
+
beeport.destroy();
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## TypeScript Support
|
|
197
|
+
|
|
198
|
+
BeePort is written in TypeScript and includes full type definitions.
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
import type {
|
|
202
|
+
BeePortConfig,
|
|
203
|
+
BeePortInstance,
|
|
204
|
+
Position,
|
|
205
|
+
Theme,
|
|
206
|
+
FeedbackType,
|
|
207
|
+
BrowserContext
|
|
208
|
+
} from 'beeport';
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
All configuration options and methods are fully typed for excellent IDE autocomplete and type safety.
|
|
212
|
+
|
|
213
|
+
## Browser Support
|
|
214
|
+
|
|
215
|
+
BeePort supports all modern browsers:
|
|
216
|
+
|
|
217
|
+
- Chrome/Edge 90+
|
|
218
|
+
- Firefox 88+
|
|
219
|
+
- Safari 14+
|
|
220
|
+
- Opera 76+
|
|
221
|
+
|
|
222
|
+
**ES2020 Required**: The widget uses modern JavaScript features (optional chaining, nullish coalescing, etc.). No IE11 support.
|
|
223
|
+
|
|
224
|
+
## Bundle Size
|
|
225
|
+
|
|
226
|
+
- **Minified**: ~11KB
|
|
227
|
+
- **Gzipped**: ~3KB
|
|
228
|
+
- **Zero dependencies**
|
|
229
|
+
|
|
230
|
+
The widget uses Shadow DOM for style isolation and has no external dependencies, making it extremely lightweight and non-intrusive.
|
|
231
|
+
|
|
232
|
+
## What Gets Captured?
|
|
233
|
+
|
|
234
|
+
When a user submits feedback, BeePort automatically captures:
|
|
235
|
+
|
|
236
|
+
- Page URL
|
|
237
|
+
- Browser name and version
|
|
238
|
+
- Operating system and version
|
|
239
|
+
- Screen resolution and pixel ratio
|
|
240
|
+
- Viewport dimensions
|
|
241
|
+
- Language and timezone
|
|
242
|
+
- Timestamp (ISO 8601)
|
|
243
|
+
|
|
244
|
+
This context is formatted into a GitHub issue with structured metadata for easy parsing by AI agents or automation tools.
|
|
245
|
+
|
|
246
|
+
## Security
|
|
247
|
+
|
|
248
|
+
- **Token security**: Your GitHub token is used client-side to create issues. For production use, consider proxying requests through your backend or using a token with minimal scopes (only `public_repo` or `repo` for private repos).
|
|
249
|
+
- **No tracking**: BeePort doesn't phone home, track analytics, or send data anywhere except your specified GitHub repository.
|
|
250
|
+
- **Shadow DOM**: Isolates the widget from your page's CSS and JavaScript, preventing conflicts or security issues.
|
|
251
|
+
|
|
252
|
+
## License
|
|
253
|
+
|
|
254
|
+
MIT License - see [LICENSE](https://github.com/quququ/beeport/blob/main/LICENSE) for details.
|
|
255
|
+
|
|
256
|
+
## Contributing
|
|
257
|
+
|
|
258
|
+
We welcome contributions! Please see our [contributing guidelines](https://github.com/quququ/beeport#contributing) for details.
|
|
259
|
+
|
|
260
|
+
## Links
|
|
261
|
+
|
|
262
|
+
- [GitHub Repository](https://github.com/quququ/beeport)
|
|
263
|
+
- [Issue Tracker](https://github.com/quququ/beeport/issues)
|
|
264
|
+
- [npm Package](https://www.npmjs.com/package/beeport)
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
**Made with care for developers building better products.**
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).BeePort={})}(this,function(e){"use strict";function t(e,t){if(e.setAttribute("data-theme",t),"auto"!==t)return()=>{};if("undefined"==typeof window||!window.matchMedia)return()=>{};const n=window.matchMedia("(prefers-color-scheme: dark)"),r=()=>{};n.addEventListener("change",r);let o=!1;return()=>{o||(n.removeEventListener("change",r),o=!0)}}function n(e,t){const n=document.createElement("div");n.className="beeport-form-panel",n.style.display="none",n.setAttribute("role","dialog"),n.setAttribute("aria-modal","true");const o=document.createElement("div");o.className="beeport-form-header";const i=document.createElement("h3");i.className="beeport-form-title",i.id="beeport-form-title",i.textContent="Report to BeePort";const a=document.createElement("p");a.className="beeport-form-subtitle",a.textContent="Help us fix bugs and shape features in under a minute.",n.setAttribute("aria-labelledby","beeport-form-title");const s=document.createElement("button");s.className="beeport-form-close",s.textContent="×",s.setAttribute("aria-label","Close");const p=document.createElement("div");p.className="beeport-form-heading",p.appendChild(i),p.appendChild(a),o.appendChild(p),o.appendChild(s);const c=document.createElement("p");c.className="beeport-type-legend",c.textContent="What are you sharing?";const l=document.createElement("div");l.className="beeport-type-selector",l.setAttribute("role","tablist"),l.setAttribute("aria-label","Select feedback type");const d=r("bug","Bug report",!0),u=r("feature","Feature idea",!1);l.appendChild(d),l.appendChild(u);const b=document.createElement("div");b.className="beeport-input-wrapper";const h=document.createElement("label");h.textContent="Title",h.htmlFor="beeport-title-input",h.className="beeport-input-label";const m=document.createElement("input");m.type="text",m.id="beeport-title-input",m.className="beeport-input-title",m.placeholder="Example: Save button does nothing on Safari";const f=document.createElement("div");f.className="beeport-input-hint beeport-input-hint-title",f.textContent="Use a short summary (3+ characters).";const g=document.createElement("div");g.id="beeport-title-error",g.className="beeport-error-message",g.setAttribute("role","alert"),b.appendChild(h),b.appendChild(m),b.appendChild(f),b.appendChild(g);const x=document.createElement("div");x.className="beeport-input-wrapper";const y=document.createElement("label");y.textContent="Description",y.htmlFor="beeport-description-input",y.className="beeport-input-label";const v=document.createElement("textarea");v.id="beeport-description-input",v.className="beeport-input-description",v.placeholder="What happened? What did you expect instead? Include steps to reproduce.",v.maxLength=1e3,v.rows=5;const w=document.createElement("div");w.className="beeport-input-hint beeport-input-hint-description",w.textContent="Include context, expected result, and actual result (10+ characters).";const k=document.createElement("div");k.className="beeport-char-counter",k.textContent="0/1000 characters";const E=document.createElement("div");E.className="beeport-description-meta",E.appendChild(w),E.appendChild(k);const C=document.createElement("div");C.id="beeport-description-error",C.className="beeport-error-message",C.setAttribute("role","alert"),x.appendChild(y),x.appendChild(v),x.appendChild(E),x.appendChild(C);const S=document.createElement("div");S.className="beeport-status-message",S.setAttribute("aria-live","polite"),S.setAttribute("aria-atomic","true"),S.textContent="";const A=document.createElement("div");A.className="beeport-form-buttons";const N=document.createElement("button");N.className="beeport-cancel-button",N.textContent="Not now";const L=document.createElement("button");L.className="beeport-submit-button",L.textContent="Create Issue",A.appendChild(N),A.appendChild(L);const B=document.createElement("div");B.className="beeport-form-footer";const $=document.createElement("a");$.href="https://beeport.ai",$.target="_blank",$.rel="noopener noreferrer",$.className="beeport-footer-link";const F=document.createElement("span");F.className="beeport-footer-bee",F.textContent="🐝";const O=document.createElement("span");O.className="beeport-footer-text",O.textContent="Powered by ";const P=document.createElement("span");P.className="beeport-footer-brand",P.textContent="BeePort",$.appendChild(F),$.appendChild(O),$.appendChild(P),B.appendChild($),n.appendChild(o),n.appendChild(c),n.appendChild(l),n.appendChild(b),n.appendChild(x),n.appendChild(S),n.appendChild(A),n.appendChild(B);const z=document.createElement("style");z.textContent='\n /* Form Panel */\n .beeport-form-panel {\n position: absolute;\n bottom: 72px;\n right: 0;\n width: min(420px, calc(100vw - 24px));\n max-height: min(80vh, 680px);\n background:\n radial-gradient(circle at top left, rgba(250, 204, 21, 0.18), transparent 55%),\n var(--beeport-bg-primary);\n border: 1px solid rgba(245, 158, 11, 0.32);\n border-radius: 18px;\n box-shadow: 0 20px 44px rgba(17, 24, 39, 0.28), 0 6px 18px rgba(17, 24, 39, 0.16);\n padding: 0;\n color: var(--beeport-text-primary);\n font-family: "Avenir Next", "Trebuchet MS", "Segoe UI", sans-serif;\n overflow: hidden;\n animation: beeport-form-enter 160ms cubic-bezier(0.22, 1, 0.36, 1);\n }\n\n /* Mobile responsive */\n @media (max-width: 500px) {\n .beeport-form-panel {\n right: 8px;\n bottom: 72px;\n width: calc(100vw - 16px);\n max-height: calc(100vh - 96px);\n border-radius: 14px;\n }\n }\n\n /* Header */\n .beeport-form-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n gap: 12px;\n padding: 18px 18px 14px;\n border-bottom: 1px solid rgba(245, 158, 11, 0.2);\n background: linear-gradient(180deg, rgba(250, 204, 21, 0.15) 0%, transparent 100%);\n }\n\n .beeport-form-heading {\n min-width: 0;\n flex: 1;\n }\n\n .beeport-form-title {\n margin: 0;\n font-size: 20px;\n font-weight: 700;\n color: var(--beeport-text-primary);\n line-height: 1.2;\n }\n\n .beeport-form-subtitle {\n margin: 6px 0 0;\n font-size: 12px;\n line-height: 1.4;\n color: var(--beeport-text-secondary);\n max-width: 32ch;\n }\n\n .beeport-form-close {\n background: var(--beeport-bg-secondary);\n border: 1px solid rgba(245, 158, 11, 0.3);\n font-size: 17px;\n line-height: 1;\n color: var(--beeport-text-primary);\n cursor: pointer;\n padding: 2px;\n width: 30px;\n height: 30px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 50%;\n font-family: inherit;\n transition: all var(--beeport-transition-speed) var(--beeport-transition-easing);\n }\n\n .beeport-form-close:hover {\n border-color: #f59e0b;\n background: rgba(245, 158, 11, 0.18);\n transform: rotate(90deg);\n }\n\n .beeport-form-close:focus {\n outline: 2px solid var(--beeport-input-focus-border);\n outline-offset: 2px;\n }\n\n .beeport-form-close:focus:not(:focus-visible) {\n outline: none;\n }\n\n .beeport-form-close:focus-visible {\n outline: 2px solid var(--beeport-input-focus-border);\n outline-offset: 2px;\n }\n\n .beeport-type-legend {\n margin: 12px 18px 8px;\n color: var(--beeport-text-secondary);\n font-size: 12px;\n font-weight: 600;\n letter-spacing: 0.01em;\n }\n\n /* Type Selector */\n .beeport-type-selector {\n display: flex;\n gap: 8px;\n margin: 0 18px 14px;\n padding: 5px;\n min-height: 62px;\n border: 1px solid rgba(245, 158, 11, 0.28);\n border-radius: 12px;\n background: var(--beeport-bg-secondary);\n }\n\n .beeport-type-button {\n flex: 1;\n padding: 9px 10px;\n min-height: 52px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: none;\n border-radius: 9px;\n color: var(--beeport-text-secondary);\n font-size: 12px;\n font-weight: 700;\n font-family: inherit;\n letter-spacing: 0.01em;\n text-transform: none;\n cursor: pointer;\n transition: all var(--beeport-transition-speed) var(--beeport-transition-easing);\n }\n\n .beeport-type-button:last-child {\n border-right: 0;\n }\n\n .beeport-type-button:hover {\n background: rgba(245, 158, 11, 0.1);\n color: var(--beeport-text-primary);\n }\n\n .beeport-type-button.active {\n background: linear-gradient(135deg, #f59e0b, #facc15);\n color: #111827;\n box-shadow: 0 2px 8px rgba(245, 158, 11, 0.35);\n }\n\n .beeport-type-button:focus {\n outline: 2px solid var(--beeport-input-focus-border);\n outline-offset: -2px;\n }\n\n .beeport-type-button:focus:not(:focus-visible) {\n outline: none;\n }\n\n .beeport-type-button:focus-visible {\n outline: 2px solid var(--beeport-input-focus-border);\n outline-offset: -2px;\n }\n\n /* Input Wrapper */\n .beeport-input-wrapper {\n position: relative;\n padding: 0 18px 14px;\n border-bottom: none;\n }\n\n /* Input Label */\n .beeport-input-label {\n display: block;\n margin-bottom: 6px;\n color: var(--beeport-text-secondary);\n font-size: 11px;\n font-weight: 600;\n font-family: inherit;\n letter-spacing: 0.01em;\n }\n\n /* Input and Textarea */\n .beeport-input-title,\n .beeport-input-description {\n width: 100%;\n padding: 10px 12px;\n background: var(--beeport-input-bg);\n border: 1px solid rgba(107, 114, 128, 0.45);\n border-radius: 11px;\n color: var(--beeport-text-primary);\n font-size: 14px;\n font-family: inherit;\n transition: all var(--beeport-transition-speed) var(--beeport-transition-easing);\n box-sizing: border-box;\n }\n\n .beeport-input-title::placeholder,\n .beeport-input-description::placeholder {\n color: var(--beeport-text-secondary);\n opacity: 0.8;\n }\n\n .beeport-input-title:focus,\n .beeport-input-description:focus {\n outline: none;\n border-color: #f59e0b;\n box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.2);\n }\n\n .beeport-input-title:focus:not(:focus-visible),\n .beeport-input-description:focus:not(:focus-visible) {\n outline: none;\n }\n\n .beeport-input-title:focus-visible,\n .beeport-input-description:focus-visible {\n outline: none;\n border-color: #f59e0b;\n box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.2);\n }\n\n .beeport-input-description {\n resize: vertical;\n min-height: 108px;\n max-height: 240px;\n }\n\n /* Error state */\n .beeport-input-title.error,\n .beeport-input-description.error {\n border-color: #dc2626;\n box-shadow: 0 0 0 2px rgba(220, 38, 38, 0.16);\n }\n\n .beeport-input-hint {\n margin-top: 7px;\n font-size: 11px;\n color: var(--beeport-text-secondary);\n line-height: 1.3;\n }\n\n .beeport-error-message {\n color: #dc2626;\n font-size: 12px;\n margin-top: 6px;\n min-height: 16px;\n }\n\n /* Status Message (Live Region) */\n .beeport-status-message {\n margin: 0 18px 14px;\n padding: 8px 10px;\n border-radius: 10px;\n font-size: var(--beeport-font-size-sm);\n min-height: 0;\n }\n\n .beeport-status-message:empty {\n display: none;\n }\n\n .beeport-status-message.success {\n background-color: #d1fae5;\n color: #065f46;\n border: 1px solid #10b981;\n }\n\n .beeport-status-message.error {\n background-color: #fee2e2;\n color: #991b1b;\n border: 1px solid #dc2626;\n }\n\n .beeport-description-meta {\n margin-top: 7px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n }\n\n /* Character Counter */\n .beeport-char-counter {\n font-size: 11px;\n font-family: inherit;\n color: var(--beeport-text-secondary);\n opacity: 0.8;\n font-variant-numeric: tabular-nums;\n white-space: nowrap;\n transition: color var(--beeport-transition-speed) var(--beeport-transition-easing);\n }\n\n .beeport-char-counter.warning {\n color: #b45309;\n }\n\n .beeport-char-counter.limit {\n color: #dc2626;\n font-weight: 700;\n }\n\n /* Form Buttons */\n .beeport-form-buttons {\n display: flex;\n gap: 8px;\n justify-content: flex-end;\n padding: 0 18px 16px;\n }\n\n .beeport-cancel-button,\n .beeport-submit-button {\n padding: 10px 16px;\n border-radius: 10px;\n font-size: 12px;\n font-weight: 700;\n font-family: inherit;\n letter-spacing: 0.02em;\n text-transform: none;\n cursor: pointer;\n transition: all var(--beeport-transition-speed) var(--beeport-transition-easing);\n }\n\n .beeport-cancel-button {\n background: transparent;\n border: 1px solid rgba(107, 114, 128, 0.45);\n color: var(--beeport-text-primary);\n }\n\n .beeport-cancel-button:hover {\n background: rgba(107, 114, 128, 0.1);\n color: var(--beeport-text-primary);\n border-color: rgba(107, 114, 128, 0.8);\n }\n\n .beeport-cancel-button:focus {\n outline: 2px solid var(--beeport-input-focus-border);\n outline-offset: 2px;\n }\n\n .beeport-cancel-button:focus:not(:focus-visible) {\n outline: none;\n }\n\n .beeport-cancel-button:focus-visible {\n outline: 2px solid var(--beeport-input-focus-border);\n outline-offset: 2px;\n }\n\n .beeport-submit-button {\n background: linear-gradient(135deg, #f59e0b, #facc15);\n border: 1px solid #d97706;\n color: #ffffff;\n text-shadow: 0 1px 1px rgba(0, 0, 0, 0.32);\n box-shadow: 0 4px 12px rgba(245, 158, 11, 0.28);\n }\n\n .beeport-submit-button:hover {\n transform: translateY(-1px);\n box-shadow: 0 8px 16px rgba(245, 158, 11, 0.34);\n }\n\n .beeport-submit-button:active {\n background: #f59e0b;\n border-color: #B45309;\n box-shadow: 0 2px 8px rgba(245, 158, 11, 0.28);\n transform: translateY(0);\n }\n\n .beeport-submit-button:focus {\n outline: 2px solid var(--beeport-input-focus-border);\n outline-offset: 2px;\n }\n\n .beeport-submit-button:focus:not(:focus-visible) {\n outline: none;\n }\n\n .beeport-submit-button:focus-visible {\n outline: 2px solid var(--beeport-input-focus-border);\n outline-offset: 2px;\n }\n\n /* Footer Branding */\n .beeport-form-footer {\n padding: 10px 16px 14px;\n text-align: center;\n background: linear-gradient(180deg, transparent 0%, rgba(245, 158, 11, 0.08) 100%);\n }\n\n .beeport-footer-link {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n text-decoration: none;\n color: var(--beeport-text-secondary);\n font-size: 11px;\n font-family: inherit;\n letter-spacing: 0.02em;\n transition: color var(--beeport-transition-speed) var(--beeport-transition-easing);\n }\n\n .beeport-footer-link:hover {\n color: var(--beeport-text-primary);\n }\n\n .beeport-footer-link:hover .beeport-footer-brand {\n text-decoration: underline;\n }\n\n .beeport-footer-bee {\n font-size: 11px;\n line-height: 1;\n }\n\n .beeport-footer-text {\n opacity: 0.5;\n }\n\n .beeport-footer-brand {\n font-weight: 700;\n color: #F59E0B;\n letter-spacing: 0.02em;\n }\n\n @keyframes beeport-form-enter {\n from {\n opacity: 0;\n transform: translateY(8px) scale(0.98);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n }\n ',e.appendChild(z),e.appendChild(n);let G="bug",R=null;const T=e=>{G=e,[d,u].forEach(t=>{t.dataset.type===e?(t.classList.add("active"),t.setAttribute("aria-selected","true")):(t.classList.remove("active"),t.setAttribute("aria-selected","false"))})},j=()=>{t?.onCancel&&t.onCancel()},V=e=>{const t=e.target;"block"!==n.style.display||n.contains(t)||(n.style.display="none",I())},I=()=>{R&&(R.focus(),R=null)};return d.addEventListener("click",()=>T("bug")),u.addEventListener("click",()=>T("feature")),v.addEventListener("input",()=>{const e=v.value.length;k.textContent=`${e}/1000 characters`,k.classList.toggle("warning",e>=900&&e<1e3),k.classList.toggle("limit",e>=1e3)}),L.addEventListener("click",()=>{t?.onSubmit&&t.onSubmit()}),N.addEventListener("click",j),s.addEventListener("click",j),n.addEventListener("keydown",e=>{if("Escape"===e.key)return n.style.display="none",void I();if("Tab"===e.key){const t=(()=>{const e=n.querySelectorAll(["button:not([disabled])","input:not([disabled])","textarea:not([disabled])","select:not([disabled])",'[tabindex]:not([tabindex="-1"])'].join(","));return Array.from(e)})();if(0===t.length)return;const r=t[0],o=t[t.length-1];e.shiftKey?document.activeElement===r&&o&&(e.preventDefault(),o.focus()):document.activeElement===o&&r&&(e.preventDefault(),r.focus())}}),e.addEventListener("click",V),{show(){R=document.activeElement,n.style.display="block",m.focus()},hide(){n.style.display="none",I()},reset(){m.value="",v.value="",G="bug",T("bug"),k.textContent="0/1000 characters",k.classList.remove("warning","limit"),m.classList.remove("error"),v.classList.remove("error"),m.removeAttribute("aria-invalid"),v.removeAttribute("aria-invalid"),m.removeAttribute("aria-describedby"),v.removeAttribute("aria-describedby"),g.textContent="",C.textContent=""},destroy(){e.removeEventListener("click",V),n.remove(),z.remove()},getValues:()=>({type:G,title:m.value,description:v.value}),validate:()=>(()=>{const e={},t=m.value.trim(),n=v.value.trim();return m.classList.remove("error"),v.classList.remove("error"),m.removeAttribute("aria-invalid"),v.removeAttribute("aria-invalid"),m.removeAttribute("aria-describedby"),v.removeAttribute("aria-describedby"),g.textContent="",C.textContent="",0===t.length?e.title="Title is required":t.length<3&&(e.title="Title must be at least 3 characters"),0===n.length?e.description="Description is required":n.length<10&&(e.description="Description must be at least 10 characters"),e.title&&(m.classList.add("error"),m.setAttribute("aria-invalid","true"),m.setAttribute("aria-describedby","beeport-title-error"),g.textContent=e.title),e.description&&(v.classList.add("error"),v.setAttribute("aria-invalid","true"),v.setAttribute("aria-describedby","beeport-description-error"),C.textContent=e.description),{valid:0===Object.keys(e).length,errors:e}})()}}function r(e,t,n){const r=document.createElement("button");return r.className="beeport-type-button",r.dataset.type=e,r.textContent=t,r.setAttribute("role","tab"),r.setAttribute("aria-selected",String(n)),r.setAttribute("aria-label",{bug:"Report a bug",feature:"Request a feature",question:"Ask a question"}[e]),n&&r.classList.add("active"),r}function o(e,t){try{return e()}catch{return t}}const i=["token","key","secret","password","auth","session","api_key","access_token"];function a(e){const t=function(e){try{const t=new URL(e),n=t.searchParams;return n.forEach((e,t)=>{const r=t.toLowerCase();i.some(e=>r.includes(e))&&n.set(t,"[REDACTED]")}),decodeURIComponent(t.toString())}catch{return e}}(e.url),n=e.cookiesEnabled?"Enabled":"Disabled";return`## Environment\n- **URL**: ${t}\n- **Browser**: ${e.browser.name} ${e.browser.version}\n- **OS**: ${e.os.name} ${e.os.version}\n- **Viewport**: ${e.viewport.width}x${e.viewport.height}\n- **Screen**: ${e.screen.width}x${e.screen.height} @${e.screen.pixelRatio}x\n- **Language**: ${e.language}\n- **Cookies**: ${n}\n- **Timestamp**: ${e.timestamp}`}function s(e){if(!e||0===e.length)return"No errors captured";const t=function(e){const t=new Map;for(const n of e){const e=t.get(n.message);e?(e.count++,e.errors.push(n)):t.set(n.message,{errors:[n],count:1})}return t}(e),n=[];let r=1;return t.forEach(e=>{const t=e.errors[0];if(!t)return;const o=function(e){const t=["TypeError","ReferenceError","SyntaxError","RangeError","URIError","EvalError"];for(const n of t)if(e.startsWith(n))return n;return"Error"}(t.message),i=[`### Error ${r}`,`**Type**: ${o}`,`**Message**: ${t.message}`];if(e.count>1&&i.push(`**Occurrences**: (occurred ${e.count} times)`),t.stack){const e=function(e,t=20){const n=e.split("\n");if(n.length<=t)return e;const r=n.slice(0,t),o=n.length-t;return r.push(`... (${o} more lines)`),r.join("\n")}(t.stack);i.push(`**Stack trace**:\n\`\`\`\n${e}\n\`\`\``)}i.push(`**Timestamp**: ${t.timestamp}`),n.push(i.join("\n")),r++}),n.join("\n\n")}class p extends Error{constructor(e,t,n){super(e),this.status=t,this.response=n,this.name="GitHubError"}}class c extends p{constructor(e,t,n){super(e,t,n),this.name="GitHubAuthError"}}class l extends p{constructor(e,t,n){super(e,t,n),this.name="GitHubNotFoundError"}}class d extends p{constructor(e,t,n){super(e,t,n),this.name="GitHubValidationError"}}class u extends p{constructor(e,t,n,r){super(e,t,n),this.rateLimit=r,this.name="GitHubRateLimitError"}}class b extends p{constructor(e,t){super(e),this.cause=t,this.name="GitHubNetworkError"}}async function h(e){const{token:t,owner:n,repo:r,title:o,body:i,labels:a}=e,s=`https://api.github.com/repos/${n}/${r}/issues`,h={title:o,body:i};let m;a&&a.length>0&&(h.labels=a);try{m=await fetch(s,{method:"POST",headers:{Authorization:`Bearer ${t}`,Accept:"application/vnd.github+json","X-GitHub-Api-Version":"2022-11-28","Content-Type":"application/json"},body:JSON.stringify(h)})}catch(g){throw new b("Network request failed",g instanceof Error?g:void 0)}if(!m.ok){let e;try{e=await m.json()}catch{e={}}const t=e.message||`HTTP ${m.status}`;switch(m.status){case 401:case 403:throw new c(t,m.status,e);case 404:throw new l(t,m.status,e);case 422:throw new d(t,m.status,e);case 429:{const n={limit:parseInt(m.headers.get("X-RateLimit-Limit")||"0",10),remaining:parseInt(m.headers.get("X-RateLimit-Remaining")||"0",10),reset:parseInt(m.headers.get("X-RateLimit-Reset")||"0",10)};throw new u(t,m.status,e,n)}default:throw new p(t,m.status,e)}}const f=await m.json();return{url:f.html_url,number:f.number,id:f.id}}function m(e,t){const n=e.toLowerCase().trim(),r=t.toLowerCase().trim();if(0===n.length&&0===r.length)return 1;if(0===n.length||0===r.length)return 0;const o=function(e,t){if(0===e.length)return t.length;if(0===t.length)return e.length;const n=[];for(let r=0;r<=t.length;r++)n[r]=[r];for(let r=0;r<=e.length;r++)n[0][r]=r;for(let r=1;r<=t.length;r++)for(let o=1;o<=e.length;o++)t.charAt(r-1)===e.charAt(o-1)?n[r][o]=n[r-1][o-1]:n[r][o]=Math.min(n[r-1][o-1]+1,n[r][o-1]+1,n[r-1][o]+1);return n[t.length][e.length]}(n,r);return 1-o/Math.max(n.length,r.length)}function f(e){return e instanceof c?"Authentication failed. Check your GitHub token.":e instanceof l?"Repository not found. Check the repo setting.":e instanceof u?"Rate limit exceeded. Please try again later.":e instanceof d?"Invalid issue data. Please check your input.":e instanceof b?"Network error. Check your connection.":e instanceof Error?e.message:"An unknown error occurred."}async function g(e){const{config:t,formValues:n,errors:r}=e;try{const e={url:o(()=>window.location.href,"unknown"),viewport:o(()=>({width:window.innerWidth,height:window.innerHeight}),{width:0,height:0}),screen:o(()=>({width:window.screen.width,height:window.screen.height,pixelRatio:window.devicePixelRatio}),{width:0,height:0,pixelRatio:1}),browser:o(()=>{const e=navigator.userAgentData;if(e?.brands){const t=e.brands;for(const e of t){const t=e.brand.toLowerCase();if(t.includes("chrome")&&!t.includes("chromium"))return{name:"Chrome",version:e.version};if(t.includes("edge"))return{name:"Edge",version:e.version};if(t.includes("opera"))return{name:"Opera",version:e.version}}}return function(e){if(/Edg\//.test(e)){const t=e.match(/Edg\/([\d.]+)/);return{name:"Edge",version:t?.[1]||"unknown"}}if(/OPR\//.test(e)){const t=e.match(/OPR\/([\d.]+)/);return{name:"Opera",version:t?.[1]||"unknown"}}if(/Chrome\//.test(e)&&!/Edg\//.test(e)){const t=e.match(/Chrome\/([\d.]+)/);return{name:"Chrome",version:t?.[1]||"unknown"}}if(/Firefox\//.test(e)){const t=e.match(/Firefox\/([\d.]+)/);return{name:"Firefox",version:t?.[1]||"unknown"}}if(/Safari\//.test(e)&&!/Chrome\//.test(e)){const t=e.match(/Version\/([\d.]+)/);return{name:"Safari",version:t?.[1]||"unknown"}}return{name:"Unknown",version:"unknown"}}(navigator.userAgent)},{name:"Unknown",version:"unknown"}),os:o(()=>function(e){if(/iPhone|iPad|iPod/.test(e)){const t=e.match(/OS ([\d_]+)/);return{name:"iOS",version:t?.[1]?.replace(/_/g,".")||"unknown"}}if(/Windows NT/.test(e)){const t=e.match(/Windows NT ([\d.]+)/),n=t?.[1]||"unknown";return{name:"Windows",version:{"10.0":"10",6.3:"8.1",6.2:"8",6.1:"7"}[n]||n}}if(/Mac OS X/.test(e)){const t=e.match(/Mac OS X ([\d_]+)/);return{name:"macOS",version:t?.[1]?.replace(/_/g,".")||"unknown"}}if(/Android/.test(e)){const t=e.match(/Android ([\d.]+)/);return{name:"Android",version:t?.[1]||"unknown"}}return/Linux/.test(e)?{name:"Linux",version:"unknown"}:{name:"Unknown",version:"unknown"}}(navigator.userAgent),{name:"Unknown",version:"unknown"}),timestamp:(new Date).toISOString(),language:o(()=>navigator.language,"unknown"),cookiesEnabled:o(()=>navigator.cookieEnabled,!1),doNotTrack:o(()=>navigator.doNotTrack,null)},c=function(e,t){return`${{bug:"[Bug]",feature:"[Feature]",question:"[Question]"}[e]} ${t}`}(n.type,n.title),l=function(e){switch(e.type){case"bug":return function(e){return[`## Summary\n${e.description}`,"## Steps to Reproduce\nNot provided","## Expected Behavior\nNot provided","## Actual Behavior\nNot provided",a(e.context),`## Console Errors\n${s(e.errors)}`].join("\n\n")+"\n---\n*Generated by [BeePort](https://beeport.ai) | agent-ready*"}(e);case"feature":return function(e){return[`## Summary\n${e.description}`,"## Use Case\nNot provided","## Proposed Solution\nNot provided",a(e.context)].join("\n\n")+"\n---\n*Generated by [BeePort](https://beeport.ai) | agent-ready*"}(e);case"question":return function(e){return[`## Question\n${e.description}`,"## Context\nNot provided",a(e.context)].join("\n\n")+"\n---\n*Generated by [BeePort](https://beeport.ai) | agent-ready*"}(e);default:throw new Error(`Unknown feedback type: ${e.type}`)}}({type:n.type,title:n.title,description:n.description,context:e,errors:r}),d=["bug"===(i=n.type)?"bug":"feature"===i?"enhancement":"question","beeport","agent-ready"],{owner:u,repo:b}=function(e){const t=e.split("/");return{owner:t[0]||"",repo:t.slice(1).join("/")}}(t.repo);let f=[];try{f=await async function(e){const{token:t,owner:n,repo:r,title:o}=e;try{const e=`https://api.github.com/repos/${n}/${r}/issues?labels=beeport&state=open`,i=await fetch(e,{method:"GET",headers:{Authorization:`Bearer ${t}`,Accept:"application/vnd.github+json","X-GitHub-Api-Version":"2022-11-28"}});return i.ok?(await i.json()).map(e=>({number:e.number,title:e.title,url:e.html_url,similarity:m(o,e.title),state:e.state})).filter(e=>e.similarity>.7).sort((e,t)=>t.similarity-e.similarity).slice(0,5):(console.warn(`GitHub API error: ${i.status} ${i.statusText}`),[])}catch(i){return console.warn("Failed to search for duplicate issues:",i),[]}}({token:t.token,owner:u,repo:b,title:c})}catch(p){console.warn("Duplicate search failed, proceeding with submission:",p)}if(f.length>0)return{status:"duplicates_found",candidates:f,pendingSubmission:{title:c,body:l,labels:d,owner:u,repo:b,token:t.token}};const g=await h({token:t.token,owner:u,repo:b,title:c,body:l,labels:d});return{status:"success",issueUrl:g.url,issueNumber:g.number}}catch(p){return{status:"error",error:f(p)}}var i}const x=Object.freeze(Object.defineProperty({__proto__:null,confirmSubmit:async function(e){try{const t=await h({token:e.token,owner:e.owner,repo:e.repo,title:e.title,body:e.body,labels:e.labels});return{status:"success",issueUrl:t.url,issueNumber:t.number}}catch(t){return{status:"error",error:f(t)}}},submitFeedback:g},Symbol.toStringTag,{value:"Module"}));class y{constructor(e){this.isOpen=!1,this.themeCleanup=null,this.config=e,this.hostElement=document.createElement("div"),this.hostElement.setAttribute("data-beeport-container",""),this.shadowRoot=this.hostElement.attachShadow({mode:"open"}),this.container=document.createElement("div"),this.container.className="beeport-container",this.container.setAttribute("data-open","false"),this.applyPosition(e.position);const r=document.createElement("style");r.textContent='\n /* CSS Custom Properties (theme variables) */\n :host {\n --beeport-z-index: 999999;\n --beeport-spacing-sm: 8px;\n --beeport-spacing-md: 16px;\n --beeport-spacing-lg: 24px;\n --beeport-border-radius: 8px;\n --beeport-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n\n /* Typography */\n --beeport-font-size-sm: 12px;\n --beeport-font-size-md: 14px;\n --beeport-font-size-lg: 16px;\n --beeport-font-weight-normal: 400;\n --beeport-font-weight-medium: 500;\n --beeport-font-weight-bold: 600;\n\n /* Transitions */\n --beeport-transition-speed: 200ms;\n --beeport-transition-easing: ease-in-out;\n }\n\n /* Light theme colors */\n .beeport-container[data-theme="light"] {\n /* Base colors */\n --beeport-bg-primary: #ffffff;\n --beeport-bg-secondary: #f5f5f5;\n --beeport-text-primary: #1f2937;\n --beeport-text-secondary: #6b7280;\n --beeport-border-color: #d1d5db;\n --beeport-accent: #2563eb;\n\n /* Button states */\n --beeport-button-primary-bg: #2563eb;\n --beeport-button-primary-hover: #1d4ed8;\n --beeport-button-primary-active: #1e40af;\n --beeport-button-disabled-bg: #e5e7eb;\n --beeport-button-disabled-text: #4b5563;\n\n /* Input states */\n --beeport-input-bg: #ffffff;\n --beeport-input-border: #9ca3af;\n --beeport-input-focus-border: #2563eb;\n\n /* Status colors */\n --beeport-success: #047857;\n --beeport-error: #dc2626;\n --beeport-warning: #b45309;\n }\n\n /* Dark theme colors */\n .beeport-container[data-theme="dark"] {\n /* Base colors */\n --beeport-bg-primary: #1f2937;\n --beeport-bg-secondary: #111827;\n --beeport-text-primary: #f9fafb;\n --beeport-text-secondary: #9ca3af;\n --beeport-border-color: #6b7280;\n --beeport-accent: #60a5fa;\n\n /* Button states */\n --beeport-button-primary-bg: #2563eb;\n --beeport-button-primary-hover: #2563eb;\n --beeport-button-primary-active: #1d4ed8;\n --beeport-button-disabled-bg: #374151;\n --beeport-button-disabled-text: #d1d5db;\n\n /* Input states */\n --beeport-input-bg: #111827;\n --beeport-input-border: #6b7280;\n --beeport-input-focus-border: #60a5fa;\n\n /* Status colors */\n --beeport-success: #34d399;\n --beeport-error: #f87171;\n --beeport-warning: #fbbf24;\n }\n\n /* Auto theme - respect system preference */\n .beeport-container[data-theme="auto"] {\n /* Base colors */\n --beeport-bg-primary: #ffffff;\n --beeport-bg-secondary: #f5f5f5;\n --beeport-text-primary: #1f2937;\n --beeport-text-secondary: #6b7280;\n --beeport-border-color: #d1d5db;\n --beeport-accent: #2563eb;\n\n /* Button states */\n --beeport-button-primary-bg: #2563eb;\n --beeport-button-primary-hover: #1d4ed8;\n --beeport-button-primary-active: #1e40af;\n --beeport-button-disabled-bg: #e5e7eb;\n --beeport-button-disabled-text: #4b5563;\n\n /* Input states */\n --beeport-input-bg: #ffffff;\n --beeport-input-border: #9ca3af;\n --beeport-input-focus-border: #2563eb;\n\n /* Status colors */\n --beeport-success: #047857;\n --beeport-error: #dc2626;\n --beeport-warning: #b45309;\n }\n\n @media (prefers-color-scheme: dark) {\n .beeport-container[data-theme="auto"] {\n /* Base colors */\n --beeport-bg-primary: #1f2937;\n --beeport-bg-secondary: #111827;\n --beeport-text-primary: #f9fafb;\n --beeport-text-secondary: #9ca3af;\n --beeport-border-color: #6b7280;\n --beeport-accent: #60a5fa;\n\n /* Button states */\n --beeport-button-primary-bg: #2563eb;\n --beeport-button-primary-hover: #2563eb;\n --beeport-button-primary-active: #1d4ed8;\n --beeport-button-disabled-bg: #374151;\n --beeport-button-disabled-text: #d1d5db;\n\n /* Input states */\n --beeport-input-bg: #111827;\n --beeport-input-border: #6b7280;\n --beeport-input-focus-border: #60a5fa;\n\n /* Status colors */\n --beeport-success: #34d399;\n --beeport-error: #f87171;\n --beeport-warning: #fbbf24;\n }\n }\n\n /* Container base styles */\n .beeport-container {\n position: fixed;\n z-index: var(--beeport-z-index);\n font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;\n font-size: 14px;\n line-height: 1.5;\n box-sizing: border-box;\n }\n\n .beeport-container *,\n .beeport-container *::before,\n .beeport-container *::after {\n box-sizing: border-box;\n }\n\n /* Reset button styles for future components */\n .beeport-container button {\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n margin: 0;\n padding: 0;\n border: 0;\n background: none;\n cursor: pointer;\n }\n\n /* Feedback button - floating action button */\n .beeport-feedback-button {\n position: relative;\n width: 56px;\n height: 56px;\n border-radius: 50%;\n background: linear-gradient(135deg, #FFC107 0%, #F59E0B 50%, #D97706 100%);\n color: white;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 4px 12px rgba(245, 158, 11, 0.4);\n transition: all var(--beeport-transition-speed) var(--beeport-transition-easing);\n border: none;\n cursor: pointer;\n outline: none;\n }\n\n .beeport-feedback-button:hover {\n background: linear-gradient(135deg, #FFD54F 0%, #FFC107 50%, #F59E0B 100%);\n transform: translateY(-2px);\n box-shadow: 0 6px 20px rgba(245, 158, 11, 0.5);\n }\n\n .beeport-feedback-button:focus {\n outline: 2px solid var(--beeport-input-focus-border);\n outline-offset: 2px;\n }\n\n .beeport-feedback-button:focus:not(:focus-visible) {\n outline: none;\n }\n\n .beeport-feedback-button:focus-visible {\n outline: 2px solid var(--beeport-input-focus-border);\n outline-offset: 2px;\n }\n\n .beeport-feedback-button:active {\n background: linear-gradient(135deg, #F59E0B 0%, #D97706 50%, #B45309 100%);\n transform: translateY(0);\n }\n\n .beeport-feedback-button svg {\n width: 28px;\n height: 28px;\n pointer-events: none;\n filter: drop-shadow(0 1px 1px rgba(0,0,0,0.15));\n }\n ',this.shadowRoot.appendChild(r),this.shadowRoot.appendChild(this.container),this.feedbackButton=this.createFeedbackButton(),this.container.appendChild(this.feedbackButton),this.form=n(this.container,{onSubmit:()=>{this.handleSubmit()},onCancel:()=>{this.isOpen&&this.toggleOpen()}}),document.body.appendChild(this.hostElement),this.themeCleanup=t(this.container,e.theme)}applyPosition(e){this.container.style.position="fixed",this.container.style.bottom="20px","bottom-right"===e?this.container.style.right="20px":this.container.style.left="20px"}createFeedbackButton(){const e=document.createElement("button");return e.className="beeport-feedback-button",e.setAttribute("aria-label","Send feedback"),e.setAttribute("aria-expanded","false"),e.setAttribute("tabindex","0"),this.updateButtonIcon(e,!1),e.addEventListener("click",e=>{e.stopPropagation(),this.toggleOpen()}),e.addEventListener("keydown",e=>{"Enter"!==e.key&&" "!==e.key||(e.preventDefault(),this.toggleOpen())}),e}async handleSubmit(){if(!this.form.validate().valid)return;const e=this.form.getValues(),t=await g({config:this.config,formValues:e});if("success"===t.status)this.form.reset(),this.toggleOpen(),console.log(`[BeePort] Issue created: ${t.issueUrl}`);else if("duplicates_found"===t.status){console.log("[BeePort] Potential duplicates found, submitting anyway");const{confirmSubmit:e}=await Promise.resolve().then(()=>x),n=await e(t.pendingSubmission);"success"===n.status?(this.form.reset(),this.toggleOpen(),console.log(`[BeePort] Issue created: ${n.issueUrl}`)):"error"===n.status&&console.error(`[BeePort] Submit failed: ${n.error}`)}else"error"===t.status&&console.error(`[BeePort] Submit failed: ${t.error}`)}toggleOpen(){this.isOpen=!this.isOpen,this.container.setAttribute("data-open",String(this.isOpen)),this.feedbackButton.setAttribute("aria-expanded",String(this.isOpen)),this.updateButtonIcon(this.feedbackButton,this.isOpen),this.isOpen?this.form.show():this.form.hide();const e=new CustomEvent("beeport:toggle",{detail:{open:this.isOpen},bubbles:!0,composed:!0});this.hostElement.dispatchEvent(e)}updateButtonIcon(e,t){if(e.textContent="",t){const t=this.createSVGElement("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none"}),n=this.createSVGElement("path",{d:"M18 6L6 18M6 6L18 18",stroke:"currentColor","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round"});t.appendChild(n),e.appendChild(t)}else{const t=this.createSVGElement("svg",{width:"28",height:"28",viewBox:"0 0 28 28",fill:"none"}),n=this.createSVGElement("ellipse",{cx:"14",cy:"15",rx:"6",ry:"7.5",fill:"#FFC107",stroke:"currentColor","stroke-width":"1.5"}),r=this.createSVGElement("path",{d:"M8.5 13.5 Q14 12 19.5 13.5",stroke:"#1a1a1a","stroke-width":"1.8","stroke-linecap":"round",fill:"none"}),o=this.createSVGElement("path",{d:"M8.2 16.5 Q14 15 19.8 16.5",stroke:"#1a1a1a","stroke-width":"1.8","stroke-linecap":"round",fill:"none"}),i=this.createSVGElement("ellipse",{cx:"9.5",cy:"9",rx:"3.5",ry:"4",fill:"rgba(255,255,255,0.7)",stroke:"currentColor","stroke-width":"1",transform:"rotate(-15 9.5 9)"}),a=this.createSVGElement("ellipse",{cx:"18.5",cy:"9",rx:"3.5",ry:"4",fill:"rgba(255,255,255,0.7)",stroke:"currentColor","stroke-width":"1",transform:"rotate(15 18.5 9)"}),s=this.createSVGElement("circle",{cx:"14",cy:"7.5",r:"3",fill:"#1a1a1a"}),p=this.createSVGElement("circle",{cx:"12.8",cy:"7",r:"0.8",fill:"white"}),c=this.createSVGElement("circle",{cx:"15.2",cy:"7",r:"0.8",fill:"white"}),l=this.createSVGElement("path",{d:"M12.5 5 Q11 2.5 9.5 2",stroke:"#1a1a1a","stroke-width":"1.2","stroke-linecap":"round",fill:"none"}),d=this.createSVGElement("path",{d:"M15.5 5 Q17 2.5 18.5 2",stroke:"#1a1a1a","stroke-width":"1.2","stroke-linecap":"round",fill:"none"}),u=this.createSVGElement("circle",{cx:"9.3",cy:"1.8",r:"1",fill:"#FFC107"}),b=this.createSVGElement("circle",{cx:"18.7",cy:"1.8",r:"1",fill:"#FFC107"}),h=this.createSVGElement("path",{d:"M14 22.5 L14 24.5",stroke:"#1a1a1a","stroke-width":"1.5","stroke-linecap":"round"});t.appendChild(i),t.appendChild(a),t.appendChild(n),t.appendChild(r),t.appendChild(o),t.appendChild(s),t.appendChild(p),t.appendChild(c),t.appendChild(l),t.appendChild(d),t.appendChild(u),t.appendChild(b),t.appendChild(h),e.appendChild(t)}}createSVGElement(e,t){const n=document.createElementNS("http://www.w3.org/2000/svg",e);for(const[r,o]of Object.entries(t))n.setAttribute(r,o);return n}show(){this.hostElement.style.display=""}hide(){this.hostElement.style.display="none"}destroy(){this.form.destroy(),this.themeCleanup&&(this.themeCleanup(),this.themeCleanup=null),this.hostElement.parentNode&&this.hostElement.parentNode.removeChild(this.hostElement)}setTheme(e){this.themeCleanup&&this.themeCleanup(),this.themeCleanup=t(this.container,e)}getContainer(){return this.container}}let v=null,w=null;e.destroy=function(){v&&(v.destroy(),v=null,w=null)},e.init=function(e){if(function(e){if(!e.repo)throw new Error("repo is required");if(!e.repo.includes("/")||2!==e.repo.split("/").length)throw new Error('repo must be in format "owner/repo"');if(!e.token||""===e.token.trim())throw new Error("token is required")}(e),v&&w)return w;const t={repo:e.repo,token:e.token,position:e.position??"bottom-right",theme:e.theme??"auto"};var n;return v=new y(t),n=v,w={show:()=>n.show(),hide:()=>n.hide(),destroy:()=>{n.destroy(),v=null,w=null},setTheme:e=>n.setTheme(e)},w},Object.defineProperty(e,Symbol.toStringTag,{value:"Module"})});
|
package/dist/beeport.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function e(e,t){if(e.setAttribute("data-theme",t),"auto"!==t)return()=>{};if("undefined"==typeof window||!window.matchMedia)return()=>{};const n=window.matchMedia("(prefers-color-scheme: dark)"),r=()=>{};n.addEventListener("change",r);let o=!1;return()=>{o||(n.removeEventListener("change",r),o=!0)}}function t(e,t){const r=document.createElement("div");r.className="beeport-form-panel",r.style.display="none",r.setAttribute("role","dialog"),r.setAttribute("aria-modal","true");const o=document.createElement("div");o.className="beeport-form-header";const i=document.createElement("h3");i.className="beeport-form-title",i.id="beeport-form-title",i.textContent="Report to BeePort";const a=document.createElement("p");a.className="beeport-form-subtitle",a.textContent="Help us fix bugs and shape features in under a minute.",r.setAttribute("aria-labelledby","beeport-form-title");const s=document.createElement("button");s.className="beeport-form-close",s.textContent="×",s.setAttribute("aria-label","Close");const p=document.createElement("div");p.className="beeport-form-heading",p.appendChild(i),p.appendChild(a),o.appendChild(p),o.appendChild(s);const c=document.createElement("p");c.className="beeport-type-legend",c.textContent="What are you sharing?";const l=document.createElement("div");l.className="beeport-type-selector",l.setAttribute("role","tablist"),l.setAttribute("aria-label","Select feedback type");const d=n("bug","Bug report",!0),b=n("feature","Feature idea",!1);l.appendChild(d),l.appendChild(b);const u=document.createElement("div");u.className="beeport-input-wrapper";const h=document.createElement("label");h.textContent="Title",h.htmlFor="beeport-title-input",h.className="beeport-input-label";const m=document.createElement("input");m.type="text",m.id="beeport-title-input",m.className="beeport-input-title",m.placeholder="Example: Save button does nothing on Safari";const f=document.createElement("div");f.className="beeport-input-hint beeport-input-hint-title",f.textContent="Use a short summary (3+ characters).";const g=document.createElement("div");g.id="beeport-title-error",g.className="beeport-error-message",g.setAttribute("role","alert"),u.appendChild(h),u.appendChild(m),u.appendChild(f),u.appendChild(g);const x=document.createElement("div");x.className="beeport-input-wrapper";const v=document.createElement("label");v.textContent="Description",v.htmlFor="beeport-description-input",v.className="beeport-input-label";const y=document.createElement("textarea");y.id="beeport-description-input",y.className="beeport-input-description",y.placeholder="What happened? What did you expect instead? Include steps to reproduce.",y.maxLength=1e3,y.rows=5;const w=document.createElement("div");w.className="beeport-input-hint beeport-input-hint-description",w.textContent="Include context, expected result, and actual result (10+ characters).";const k=document.createElement("div");k.className="beeport-char-counter",k.textContent="0/1000 characters";const E=document.createElement("div");E.className="beeport-description-meta",E.appendChild(w),E.appendChild(k);const C=document.createElement("div");C.id="beeport-description-error",C.className="beeport-error-message",C.setAttribute("role","alert"),x.appendChild(v),x.appendChild(y),x.appendChild(E),x.appendChild(C);const S=document.createElement("div");S.className="beeport-status-message",S.setAttribute("aria-live","polite"),S.setAttribute("aria-atomic","true"),S.textContent="";const A=document.createElement("div");A.className="beeport-form-buttons";const N=document.createElement("button");N.className="beeport-cancel-button",N.textContent="Not now";const L=document.createElement("button");L.className="beeport-submit-button",L.textContent="Create Issue",A.appendChild(N),A.appendChild(L);const B=document.createElement("div");B.className="beeport-form-footer";const $=document.createElement("a");$.href="https://beeport.ai",$.target="_blank",$.rel="noopener noreferrer",$.className="beeport-footer-link";const F=document.createElement("span");F.className="beeport-footer-bee",F.textContent="🐝";const O=document.createElement("span");O.className="beeport-footer-text",O.textContent="Powered by ";const P=document.createElement("span");P.className="beeport-footer-brand",P.textContent="BeePort",$.appendChild(F),$.appendChild(O),$.appendChild(P),B.appendChild($),r.appendChild(o),r.appendChild(c),r.appendChild(l),r.appendChild(u),r.appendChild(x),r.appendChild(S),r.appendChild(A),r.appendChild(B);const z=document.createElement("style");z.textContent='\n /* Form Panel */\n .beeport-form-panel {\n position: absolute;\n bottom: 72px;\n right: 0;\n width: min(420px, calc(100vw - 24px));\n max-height: min(80vh, 680px);\n background:\n radial-gradient(circle at top left, rgba(250, 204, 21, 0.18), transparent 55%),\n var(--beeport-bg-primary);\n border: 1px solid rgba(245, 158, 11, 0.32);\n border-radius: 18px;\n box-shadow: 0 20px 44px rgba(17, 24, 39, 0.28), 0 6px 18px rgba(17, 24, 39, 0.16);\n padding: 0;\n color: var(--beeport-text-primary);\n font-family: "Avenir Next", "Trebuchet MS", "Segoe UI", sans-serif;\n overflow: hidden;\n animation: beeport-form-enter 160ms cubic-bezier(0.22, 1, 0.36, 1);\n }\n\n /* Mobile responsive */\n @media (max-width: 500px) {\n .beeport-form-panel {\n right: 8px;\n bottom: 72px;\n width: calc(100vw - 16px);\n max-height: calc(100vh - 96px);\n border-radius: 14px;\n }\n }\n\n /* Header */\n .beeport-form-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n gap: 12px;\n padding: 18px 18px 14px;\n border-bottom: 1px solid rgba(245, 158, 11, 0.2);\n background: linear-gradient(180deg, rgba(250, 204, 21, 0.15) 0%, transparent 100%);\n }\n\n .beeport-form-heading {\n min-width: 0;\n flex: 1;\n }\n\n .beeport-form-title {\n margin: 0;\n font-size: 20px;\n font-weight: 700;\n color: var(--beeport-text-primary);\n line-height: 1.2;\n }\n\n .beeport-form-subtitle {\n margin: 6px 0 0;\n font-size: 12px;\n line-height: 1.4;\n color: var(--beeport-text-secondary);\n max-width: 32ch;\n }\n\n .beeport-form-close {\n background: var(--beeport-bg-secondary);\n border: 1px solid rgba(245, 158, 11, 0.3);\n font-size: 17px;\n line-height: 1;\n color: var(--beeport-text-primary);\n cursor: pointer;\n padding: 2px;\n width: 30px;\n height: 30px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 50%;\n font-family: inherit;\n transition: all var(--beeport-transition-speed) var(--beeport-transition-easing);\n }\n\n .beeport-form-close:hover {\n border-color: #f59e0b;\n background: rgba(245, 158, 11, 0.18);\n transform: rotate(90deg);\n }\n\n .beeport-form-close:focus {\n outline: 2px solid var(--beeport-input-focus-border);\n outline-offset: 2px;\n }\n\n .beeport-form-close:focus:not(:focus-visible) {\n outline: none;\n }\n\n .beeport-form-close:focus-visible {\n outline: 2px solid var(--beeport-input-focus-border);\n outline-offset: 2px;\n }\n\n .beeport-type-legend {\n margin: 12px 18px 8px;\n color: var(--beeport-text-secondary);\n font-size: 12px;\n font-weight: 600;\n letter-spacing: 0.01em;\n }\n\n /* Type Selector */\n .beeport-type-selector {\n display: flex;\n gap: 8px;\n margin: 0 18px 14px;\n padding: 5px;\n min-height: 62px;\n border: 1px solid rgba(245, 158, 11, 0.28);\n border-radius: 12px;\n background: var(--beeport-bg-secondary);\n }\n\n .beeport-type-button {\n flex: 1;\n padding: 9px 10px;\n min-height: 52px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: none;\n border-radius: 9px;\n color: var(--beeport-text-secondary);\n font-size: 12px;\n font-weight: 700;\n font-family: inherit;\n letter-spacing: 0.01em;\n text-transform: none;\n cursor: pointer;\n transition: all var(--beeport-transition-speed) var(--beeport-transition-easing);\n }\n\n .beeport-type-button:last-child {\n border-right: 0;\n }\n\n .beeport-type-button:hover {\n background: rgba(245, 158, 11, 0.1);\n color: var(--beeport-text-primary);\n }\n\n .beeport-type-button.active {\n background: linear-gradient(135deg, #f59e0b, #facc15);\n color: #111827;\n box-shadow: 0 2px 8px rgba(245, 158, 11, 0.35);\n }\n\n .beeport-type-button:focus {\n outline: 2px solid var(--beeport-input-focus-border);\n outline-offset: -2px;\n }\n\n .beeport-type-button:focus:not(:focus-visible) {\n outline: none;\n }\n\n .beeport-type-button:focus-visible {\n outline: 2px solid var(--beeport-input-focus-border);\n outline-offset: -2px;\n }\n\n /* Input Wrapper */\n .beeport-input-wrapper {\n position: relative;\n padding: 0 18px 14px;\n border-bottom: none;\n }\n\n /* Input Label */\n .beeport-input-label {\n display: block;\n margin-bottom: 6px;\n color: var(--beeport-text-secondary);\n font-size: 11px;\n font-weight: 600;\n font-family: inherit;\n letter-spacing: 0.01em;\n }\n\n /* Input and Textarea */\n .beeport-input-title,\n .beeport-input-description {\n width: 100%;\n padding: 10px 12px;\n background: var(--beeport-input-bg);\n border: 1px solid rgba(107, 114, 128, 0.45);\n border-radius: 11px;\n color: var(--beeport-text-primary);\n font-size: 14px;\n font-family: inherit;\n transition: all var(--beeport-transition-speed) var(--beeport-transition-easing);\n box-sizing: border-box;\n }\n\n .beeport-input-title::placeholder,\n .beeport-input-description::placeholder {\n color: var(--beeport-text-secondary);\n opacity: 0.8;\n }\n\n .beeport-input-title:focus,\n .beeport-input-description:focus {\n outline: none;\n border-color: #f59e0b;\n box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.2);\n }\n\n .beeport-input-title:focus:not(:focus-visible),\n .beeport-input-description:focus:not(:focus-visible) {\n outline: none;\n }\n\n .beeport-input-title:focus-visible,\n .beeport-input-description:focus-visible {\n outline: none;\n border-color: #f59e0b;\n box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.2);\n }\n\n .beeport-input-description {\n resize: vertical;\n min-height: 108px;\n max-height: 240px;\n }\n\n /* Error state */\n .beeport-input-title.error,\n .beeport-input-description.error {\n border-color: #dc2626;\n box-shadow: 0 0 0 2px rgba(220, 38, 38, 0.16);\n }\n\n .beeport-input-hint {\n margin-top: 7px;\n font-size: 11px;\n color: var(--beeport-text-secondary);\n line-height: 1.3;\n }\n\n .beeport-error-message {\n color: #dc2626;\n font-size: 12px;\n margin-top: 6px;\n min-height: 16px;\n }\n\n /* Status Message (Live Region) */\n .beeport-status-message {\n margin: 0 18px 14px;\n padding: 8px 10px;\n border-radius: 10px;\n font-size: var(--beeport-font-size-sm);\n min-height: 0;\n }\n\n .beeport-status-message:empty {\n display: none;\n }\n\n .beeport-status-message.success {\n background-color: #d1fae5;\n color: #065f46;\n border: 1px solid #10b981;\n }\n\n .beeport-status-message.error {\n background-color: #fee2e2;\n color: #991b1b;\n border: 1px solid #dc2626;\n }\n\n .beeport-description-meta {\n margin-top: 7px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n }\n\n /* Character Counter */\n .beeport-char-counter {\n font-size: 11px;\n font-family: inherit;\n color: var(--beeport-text-secondary);\n opacity: 0.8;\n font-variant-numeric: tabular-nums;\n white-space: nowrap;\n transition: color var(--beeport-transition-speed) var(--beeport-transition-easing);\n }\n\n .beeport-char-counter.warning {\n color: #b45309;\n }\n\n .beeport-char-counter.limit {\n color: #dc2626;\n font-weight: 700;\n }\n\n /* Form Buttons */\n .beeport-form-buttons {\n display: flex;\n gap: 8px;\n justify-content: flex-end;\n padding: 0 18px 16px;\n }\n\n .beeport-cancel-button,\n .beeport-submit-button {\n padding: 10px 16px;\n border-radius: 10px;\n font-size: 12px;\n font-weight: 700;\n font-family: inherit;\n letter-spacing: 0.02em;\n text-transform: none;\n cursor: pointer;\n transition: all var(--beeport-transition-speed) var(--beeport-transition-easing);\n }\n\n .beeport-cancel-button {\n background: transparent;\n border: 1px solid rgba(107, 114, 128, 0.45);\n color: var(--beeport-text-primary);\n }\n\n .beeport-cancel-button:hover {\n background: rgba(107, 114, 128, 0.1);\n color: var(--beeport-text-primary);\n border-color: rgba(107, 114, 128, 0.8);\n }\n\n .beeport-cancel-button:focus {\n outline: 2px solid var(--beeport-input-focus-border);\n outline-offset: 2px;\n }\n\n .beeport-cancel-button:focus:not(:focus-visible) {\n outline: none;\n }\n\n .beeport-cancel-button:focus-visible {\n outline: 2px solid var(--beeport-input-focus-border);\n outline-offset: 2px;\n }\n\n .beeport-submit-button {\n background: linear-gradient(135deg, #f59e0b, #facc15);\n border: 1px solid #d97706;\n color: #ffffff;\n text-shadow: 0 1px 1px rgba(0, 0, 0, 0.32);\n box-shadow: 0 4px 12px rgba(245, 158, 11, 0.28);\n }\n\n .beeport-submit-button:hover {\n transform: translateY(-1px);\n box-shadow: 0 8px 16px rgba(245, 158, 11, 0.34);\n }\n\n .beeport-submit-button:active {\n background: #f59e0b;\n border-color: #B45309;\n box-shadow: 0 2px 8px rgba(245, 158, 11, 0.28);\n transform: translateY(0);\n }\n\n .beeport-submit-button:focus {\n outline: 2px solid var(--beeport-input-focus-border);\n outline-offset: 2px;\n }\n\n .beeport-submit-button:focus:not(:focus-visible) {\n outline: none;\n }\n\n .beeport-submit-button:focus-visible {\n outline: 2px solid var(--beeport-input-focus-border);\n outline-offset: 2px;\n }\n\n /* Footer Branding */\n .beeport-form-footer {\n padding: 10px 16px 14px;\n text-align: center;\n background: linear-gradient(180deg, transparent 0%, rgba(245, 158, 11, 0.08) 100%);\n }\n\n .beeport-footer-link {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n text-decoration: none;\n color: var(--beeport-text-secondary);\n font-size: 11px;\n font-family: inherit;\n letter-spacing: 0.02em;\n transition: color var(--beeport-transition-speed) var(--beeport-transition-easing);\n }\n\n .beeport-footer-link:hover {\n color: var(--beeport-text-primary);\n }\n\n .beeport-footer-link:hover .beeport-footer-brand {\n text-decoration: underline;\n }\n\n .beeport-footer-bee {\n font-size: 11px;\n line-height: 1;\n }\n\n .beeport-footer-text {\n opacity: 0.5;\n }\n\n .beeport-footer-brand {\n font-weight: 700;\n color: #F59E0B;\n letter-spacing: 0.02em;\n }\n\n @keyframes beeport-form-enter {\n from {\n opacity: 0;\n transform: translateY(8px) scale(0.98);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n }\n ',e.appendChild(z),e.appendChild(r);let G="bug",R=null;const T=e=>{G=e,[d,b].forEach(t=>{t.dataset.type===e?(t.classList.add("active"),t.setAttribute("aria-selected","true")):(t.classList.remove("active"),t.setAttribute("aria-selected","false"))})},V=()=>{t?.onCancel&&t.onCancel()},j=e=>{const t=e.target;"block"!==r.style.display||r.contains(t)||(r.style.display="none",I())},I=()=>{R&&(R.focus(),R=null)};return d.addEventListener("click",()=>T("bug")),b.addEventListener("click",()=>T("feature")),y.addEventListener("input",()=>{const e=y.value.length;k.textContent=`${e}/1000 characters`,k.classList.toggle("warning",e>=900&&e<1e3),k.classList.toggle("limit",e>=1e3)}),L.addEventListener("click",()=>{t?.onSubmit&&t.onSubmit()}),N.addEventListener("click",V),s.addEventListener("click",V),r.addEventListener("keydown",e=>{if("Escape"===e.key)return r.style.display="none",void I();if("Tab"===e.key){const t=(()=>{const e=r.querySelectorAll(["button:not([disabled])","input:not([disabled])","textarea:not([disabled])","select:not([disabled])",'[tabindex]:not([tabindex="-1"])'].join(","));return Array.from(e)})();if(0===t.length)return;const n=t[0],o=t[t.length-1];e.shiftKey?document.activeElement===n&&o&&(e.preventDefault(),o.focus()):document.activeElement===o&&n&&(e.preventDefault(),n.focus())}}),e.addEventListener("click",j),{show(){R=document.activeElement,r.style.display="block",m.focus()},hide(){r.style.display="none",I()},reset(){m.value="",y.value="",G="bug",T("bug"),k.textContent="0/1000 characters",k.classList.remove("warning","limit"),m.classList.remove("error"),y.classList.remove("error"),m.removeAttribute("aria-invalid"),y.removeAttribute("aria-invalid"),m.removeAttribute("aria-describedby"),y.removeAttribute("aria-describedby"),g.textContent="",C.textContent=""},destroy(){e.removeEventListener("click",j),r.remove(),z.remove()},getValues:()=>({type:G,title:m.value,description:y.value}),validate:()=>(()=>{const e={},t=m.value.trim(),n=y.value.trim();return m.classList.remove("error"),y.classList.remove("error"),m.removeAttribute("aria-invalid"),y.removeAttribute("aria-invalid"),m.removeAttribute("aria-describedby"),y.removeAttribute("aria-describedby"),g.textContent="",C.textContent="",0===t.length?e.title="Title is required":t.length<3&&(e.title="Title must be at least 3 characters"),0===n.length?e.description="Description is required":n.length<10&&(e.description="Description must be at least 10 characters"),e.title&&(m.classList.add("error"),m.setAttribute("aria-invalid","true"),m.setAttribute("aria-describedby","beeport-title-error"),g.textContent=e.title),e.description&&(y.classList.add("error"),y.setAttribute("aria-invalid","true"),y.setAttribute("aria-describedby","beeport-description-error"),C.textContent=e.description),{valid:0===Object.keys(e).length,errors:e}})()}}function n(e,t,n){const r=document.createElement("button");return r.className="beeport-type-button",r.dataset.type=e,r.textContent=t,r.setAttribute("role","tab"),r.setAttribute("aria-selected",String(n)),r.setAttribute("aria-label",{bug:"Report a bug",feature:"Request a feature",question:"Ask a question"}[e]),n&&r.classList.add("active"),r}function r(e,t){try{return e()}catch{return t}}const o=["token","key","secret","password","auth","session","api_key","access_token"];function i(e){const t=function(e){try{const t=new URL(e),n=t.searchParams;return n.forEach((e,t)=>{const r=t.toLowerCase();o.some(e=>r.includes(e))&&n.set(t,"[REDACTED]")}),decodeURIComponent(t.toString())}catch{return e}}(e.url),n=e.cookiesEnabled?"Enabled":"Disabled";return`## Environment\n- **URL**: ${t}\n- **Browser**: ${e.browser.name} ${e.browser.version}\n- **OS**: ${e.os.name} ${e.os.version}\n- **Viewport**: ${e.viewport.width}x${e.viewport.height}\n- **Screen**: ${e.screen.width}x${e.screen.height} @${e.screen.pixelRatio}x\n- **Language**: ${e.language}\n- **Cookies**: ${n}\n- **Timestamp**: ${e.timestamp}`}function a(e){if(!e||0===e.length)return"No errors captured";const t=function(e){const t=/* @__PURE__ */new Map;for(const n of e){const e=t.get(n.message);e?(e.count++,e.errors.push(n)):t.set(n.message,{errors:[n],count:1})}return t}(e),n=[];let r=1;return t.forEach(e=>{const t=e.errors[0];if(!t)return;const o=function(e){const t=["TypeError","ReferenceError","SyntaxError","RangeError","URIError","EvalError"];for(const n of t)if(e.startsWith(n))return n;return"Error"}(t.message),i=[`### Error ${r}`,`**Type**: ${o}`,`**Message**: ${t.message}`];if(e.count>1&&i.push(`**Occurrences**: (occurred ${e.count} times)`),t.stack){const e=function(e,t=20){const n=e.split("\n");if(n.length<=t)return e;const r=n.slice(0,t),o=n.length-t;return r.push(`... (${o} more lines)`),r.join("\n")}(t.stack);i.push(`**Stack trace**:\n\`\`\`\n${e}\n\`\`\``)}i.push(`**Timestamp**: ${t.timestamp}`),n.push(i.join("\n")),r++}),n.join("\n\n")}class s extends Error{constructor(e,t,n){super(e),this.status=t,this.response=n,this.name="GitHubError"}}class p extends s{constructor(e,t,n){super(e,t,n),this.name="GitHubAuthError"}}class c extends s{constructor(e,t,n){super(e,t,n),this.name="GitHubNotFoundError"}}class l extends s{constructor(e,t,n){super(e,t,n),this.name="GitHubValidationError"}}class d extends s{constructor(e,t,n,r){super(e,t,n),this.rateLimit=r,this.name="GitHubRateLimitError"}}class b extends s{constructor(e,t){super(e),this.cause=t,this.name="GitHubNetworkError"}}async function u(e){const{token:t,owner:n,repo:r,title:o,body:i,labels:a}=e,u=`https://api.github.com/repos/${n}/${r}/issues`,h={title:o,body:i};let m;a&&a.length>0&&(h.labels=a);try{m=await fetch(u,{method:"POST",headers:{Authorization:`Bearer ${t}`,Accept:"application/vnd.github+json","X-GitHub-Api-Version":"2022-11-28","Content-Type":"application/json"},body:JSON.stringify(h)})}catch(g){throw new b("Network request failed",g instanceof Error?g:void 0)}if(!m.ok){let e;try{e=await m.json()}catch{e={}}const t=e.message||`HTTP ${m.status}`;switch(m.status){case 401:case 403:throw new p(t,m.status,e);case 404:throw new c(t,m.status,e);case 422:throw new l(t,m.status,e);case 429:{const n={limit:parseInt(m.headers.get("X-RateLimit-Limit")||"0",10),remaining:parseInt(m.headers.get("X-RateLimit-Remaining")||"0",10),reset:parseInt(m.headers.get("X-RateLimit-Reset")||"0",10)};throw new d(t,m.status,e,n)}default:throw new s(t,m.status,e)}}const f=await m.json();return{url:f.html_url,number:f.number,id:f.id}}function h(e,t){const n=e.toLowerCase().trim(),r=t.toLowerCase().trim();if(0===n.length&&0===r.length)return 1;if(0===n.length||0===r.length)return 0;const o=function(e,t){if(0===e.length)return t.length;if(0===t.length)return e.length;const n=[];for(let r=0;r<=t.length;r++)n[r]=[r];for(let r=0;r<=e.length;r++)n[0][r]=r;for(let r=1;r<=t.length;r++)for(let o=1;o<=e.length;o++)t.charAt(r-1)===e.charAt(o-1)?n[r][o]=n[r-1][o-1]:n[r][o]=Math.min(n[r-1][o-1]+1,n[r][o-1]+1,n[r-1][o]+1);return n[t.length][e.length]}(n,r);return 1-o/Math.max(n.length,r.length)}function m(e){return e instanceof p?"Authentication failed. Check your GitHub token.":e instanceof c?"Repository not found. Check the repo setting.":e instanceof d?"Rate limit exceeded. Please try again later.":e instanceof l?"Invalid issue data. Please check your input.":e instanceof b?"Network error. Check your connection.":e instanceof Error?e.message:"An unknown error occurred."}async function f(e){const{config:t,formValues:n,errors:o}=e;try{const e={url:r(()=>window.location.href,"unknown"),viewport:r(()=>({width:window.innerWidth,height:window.innerHeight}),{width:0,height:0}),screen:r(()=>({width:window.screen.width,height:window.screen.height,pixelRatio:window.devicePixelRatio}),{width:0,height:0,pixelRatio:1}),browser:r(()=>{const e=navigator.userAgentData;if(e?.brands){const t=e.brands;for(const e of t){const t=e.brand.toLowerCase();if(t.includes("chrome")&&!t.includes("chromium"))return{name:"Chrome",version:e.version};if(t.includes("edge"))return{name:"Edge",version:e.version};if(t.includes("opera"))return{name:"Opera",version:e.version}}}return function(e){if(/Edg\//.test(e)){const t=e.match(/Edg\/([\d.]+)/);return{name:"Edge",version:t?.[1]||"unknown"}}if(/OPR\//.test(e)){const t=e.match(/OPR\/([\d.]+)/);return{name:"Opera",version:t?.[1]||"unknown"}}if(/Chrome\//.test(e)&&!/Edg\//.test(e)){const t=e.match(/Chrome\/([\d.]+)/);return{name:"Chrome",version:t?.[1]||"unknown"}}if(/Firefox\//.test(e)){const t=e.match(/Firefox\/([\d.]+)/);return{name:"Firefox",version:t?.[1]||"unknown"}}if(/Safari\//.test(e)&&!/Chrome\//.test(e)){const t=e.match(/Version\/([\d.]+)/);return{name:"Safari",version:t?.[1]||"unknown"}}return{name:"Unknown",version:"unknown"}}(navigator.userAgent)},{name:"Unknown",version:"unknown"}),os:r(()=>function(e){if(/iPhone|iPad|iPod/.test(e)){const t=e.match(/OS ([\d_]+)/);return{name:"iOS",version:t?.[1]?.replace(/_/g,".")||"unknown"}}if(/Windows NT/.test(e)){const t=e.match(/Windows NT ([\d.]+)/),n=t?.[1]||"unknown";return{name:"Windows",version:{"10.0":"10",6.3:"8.1",6.2:"8",6.1:"7"}[n]||n}}if(/Mac OS X/.test(e)){const t=e.match(/Mac OS X ([\d_]+)/);return{name:"macOS",version:t?.[1]?.replace(/_/g,".")||"unknown"}}if(/Android/.test(e)){const t=e.match(/Android ([\d.]+)/);return{name:"Android",version:t?.[1]||"unknown"}}return/Linux/.test(e)?{name:"Linux",version:"unknown"}:{name:"Unknown",version:"unknown"}}(navigator.userAgent),{name:"Unknown",version:"unknown"}),timestamp:/* @__PURE__ */(new Date).toISOString(),language:r(()=>navigator.language,"unknown"),cookiesEnabled:r(()=>navigator.cookieEnabled,!1),doNotTrack:r(()=>navigator.doNotTrack,null)},c=function(e,t){return`${{bug:"[Bug]",feature:"[Feature]",question:"[Question]"}[e]} ${t}`}(n.type,n.title),l=function(e){switch(e.type){case"bug":return function(e){return[`## Summary\n${e.description}`,"## Steps to Reproduce\nNot provided","## Expected Behavior\nNot provided","## Actual Behavior\nNot provided",i(e.context),`## Console Errors\n${a(e.errors)}`].join("\n\n")+"\n---\n*Generated by [BeePort](https://beeport.ai) | agent-ready*"}(e);case"feature":return function(e){return[`## Summary\n${e.description}`,"## Use Case\nNot provided","## Proposed Solution\nNot provided",i(e.context)].join("\n\n")+"\n---\n*Generated by [BeePort](https://beeport.ai) | agent-ready*"}(e);case"question":return function(e){return[`## Question\n${e.description}`,"## Context\nNot provided",i(e.context)].join("\n\n")+"\n---\n*Generated by [BeePort](https://beeport.ai) | agent-ready*"}(e);default:throw new Error(`Unknown feedback type: ${e.type}`)}}({type:n.type,title:n.title,description:n.description,context:e,errors:o}),d=["bug"===(s=n.type)?"bug":"feature"===s?"enhancement":"question","beeport","agent-ready"],{owner:b,repo:m}=function(e){const t=e.split("/");return{owner:t[0]||"",repo:t.slice(1).join("/")}}(t.repo);let f=[];try{f=await async function(e){const{token:t,owner:n,repo:r,title:o}=e;try{const e=`https://api.github.com/repos/${n}/${r}/issues?labels=beeport&state=open`,i=await fetch(e,{method:"GET",headers:{Authorization:`Bearer ${t}`,Accept:"application/vnd.github+json","X-GitHub-Api-Version":"2022-11-28"}});return i.ok?(await i.json()).map(e=>({number:e.number,title:e.title,url:e.html_url,similarity:h(o,e.title),state:e.state})).filter(e=>e.similarity>.7).sort((e,t)=>t.similarity-e.similarity).slice(0,5):(console.warn(`GitHub API error: ${i.status} ${i.statusText}`),[])}catch(i){return console.warn("Failed to search for duplicate issues:",i),[]}}({token:t.token,owner:b,repo:m,title:c})}catch(p){console.warn("Duplicate search failed, proceeding with submission:",p)}if(f.length>0)return{status:"duplicates_found",candidates:f,pendingSubmission:{title:c,body:l,labels:d,owner:b,repo:m,token:t.token}};const g=await u({token:t.token,owner:b,repo:m,title:c,body:l,labels:d});return{status:"success",issueUrl:g.url,issueNumber:g.number}}catch(p){return{status:"error",error:m(p)}}var s}const g=/* @__PURE__ */Object.freeze(/* @__PURE__ */Object.defineProperty({__proto__:null,confirmSubmit:async function(e){try{const t=await u({token:e.token,owner:e.owner,repo:e.repo,title:e.title,body:e.body,labels:e.labels});return{status:"success",issueUrl:t.url,issueNumber:t.number}}catch(t){return{status:"error",error:m(t)}}},submitFeedback:f},Symbol.toStringTag,{value:"Module"}));class x{constructor(n){this.isOpen=!1,this.themeCleanup=null,this.config=n,this.hostElement=document.createElement("div"),this.hostElement.setAttribute("data-beeport-container",""),this.shadowRoot=this.hostElement.attachShadow({mode:"open"}),this.container=document.createElement("div"),this.container.className="beeport-container",this.container.setAttribute("data-open","false"),this.applyPosition(n.position);const r=document.createElement("style");r.textContent='\n /* CSS Custom Properties (theme variables) */\n :host {\n --beeport-z-index: 999999;\n --beeport-spacing-sm: 8px;\n --beeport-spacing-md: 16px;\n --beeport-spacing-lg: 24px;\n --beeport-border-radius: 8px;\n --beeport-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n\n /* Typography */\n --beeport-font-size-sm: 12px;\n --beeport-font-size-md: 14px;\n --beeport-font-size-lg: 16px;\n --beeport-font-weight-normal: 400;\n --beeport-font-weight-medium: 500;\n --beeport-font-weight-bold: 600;\n\n /* Transitions */\n --beeport-transition-speed: 200ms;\n --beeport-transition-easing: ease-in-out;\n }\n\n /* Light theme colors */\n .beeport-container[data-theme="light"] {\n /* Base colors */\n --beeport-bg-primary: #ffffff;\n --beeport-bg-secondary: #f5f5f5;\n --beeport-text-primary: #1f2937;\n --beeport-text-secondary: #6b7280;\n --beeport-border-color: #d1d5db;\n --beeport-accent: #2563eb;\n\n /* Button states */\n --beeport-button-primary-bg: #2563eb;\n --beeport-button-primary-hover: #1d4ed8;\n --beeport-button-primary-active: #1e40af;\n --beeport-button-disabled-bg: #e5e7eb;\n --beeport-button-disabled-text: #4b5563;\n\n /* Input states */\n --beeport-input-bg: #ffffff;\n --beeport-input-border: #9ca3af;\n --beeport-input-focus-border: #2563eb;\n\n /* Status colors */\n --beeport-success: #047857;\n --beeport-error: #dc2626;\n --beeport-warning: #b45309;\n }\n\n /* Dark theme colors */\n .beeport-container[data-theme="dark"] {\n /* Base colors */\n --beeport-bg-primary: #1f2937;\n --beeport-bg-secondary: #111827;\n --beeport-text-primary: #f9fafb;\n --beeport-text-secondary: #9ca3af;\n --beeport-border-color: #6b7280;\n --beeport-accent: #60a5fa;\n\n /* Button states */\n --beeport-button-primary-bg: #2563eb;\n --beeport-button-primary-hover: #2563eb;\n --beeport-button-primary-active: #1d4ed8;\n --beeport-button-disabled-bg: #374151;\n --beeport-button-disabled-text: #d1d5db;\n\n /* Input states */\n --beeport-input-bg: #111827;\n --beeport-input-border: #6b7280;\n --beeport-input-focus-border: #60a5fa;\n\n /* Status colors */\n --beeport-success: #34d399;\n --beeport-error: #f87171;\n --beeport-warning: #fbbf24;\n }\n\n /* Auto theme - respect system preference */\n .beeport-container[data-theme="auto"] {\n /* Base colors */\n --beeport-bg-primary: #ffffff;\n --beeport-bg-secondary: #f5f5f5;\n --beeport-text-primary: #1f2937;\n --beeport-text-secondary: #6b7280;\n --beeport-border-color: #d1d5db;\n --beeport-accent: #2563eb;\n\n /* Button states */\n --beeport-button-primary-bg: #2563eb;\n --beeport-button-primary-hover: #1d4ed8;\n --beeport-button-primary-active: #1e40af;\n --beeport-button-disabled-bg: #e5e7eb;\n --beeport-button-disabled-text: #4b5563;\n\n /* Input states */\n --beeport-input-bg: #ffffff;\n --beeport-input-border: #9ca3af;\n --beeport-input-focus-border: #2563eb;\n\n /* Status colors */\n --beeport-success: #047857;\n --beeport-error: #dc2626;\n --beeport-warning: #b45309;\n }\n\n @media (prefers-color-scheme: dark) {\n .beeport-container[data-theme="auto"] {\n /* Base colors */\n --beeport-bg-primary: #1f2937;\n --beeport-bg-secondary: #111827;\n --beeport-text-primary: #f9fafb;\n --beeport-text-secondary: #9ca3af;\n --beeport-border-color: #6b7280;\n --beeport-accent: #60a5fa;\n\n /* Button states */\n --beeport-button-primary-bg: #2563eb;\n --beeport-button-primary-hover: #2563eb;\n --beeport-button-primary-active: #1d4ed8;\n --beeport-button-disabled-bg: #374151;\n --beeport-button-disabled-text: #d1d5db;\n\n /* Input states */\n --beeport-input-bg: #111827;\n --beeport-input-border: #6b7280;\n --beeport-input-focus-border: #60a5fa;\n\n /* Status colors */\n --beeport-success: #34d399;\n --beeport-error: #f87171;\n --beeport-warning: #fbbf24;\n }\n }\n\n /* Container base styles */\n .beeport-container {\n position: fixed;\n z-index: var(--beeport-z-index);\n font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;\n font-size: 14px;\n line-height: 1.5;\n box-sizing: border-box;\n }\n\n .beeport-container *,\n .beeport-container *::before,\n .beeport-container *::after {\n box-sizing: border-box;\n }\n\n /* Reset button styles for future components */\n .beeport-container button {\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n margin: 0;\n padding: 0;\n border: 0;\n background: none;\n cursor: pointer;\n }\n\n /* Feedback button - floating action button */\n .beeport-feedback-button {\n position: relative;\n width: 56px;\n height: 56px;\n border-radius: 50%;\n background: linear-gradient(135deg, #FFC107 0%, #F59E0B 50%, #D97706 100%);\n color: white;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 4px 12px rgba(245, 158, 11, 0.4);\n transition: all var(--beeport-transition-speed) var(--beeport-transition-easing);\n border: none;\n cursor: pointer;\n outline: none;\n }\n\n .beeport-feedback-button:hover {\n background: linear-gradient(135deg, #FFD54F 0%, #FFC107 50%, #F59E0B 100%);\n transform: translateY(-2px);\n box-shadow: 0 6px 20px rgba(245, 158, 11, 0.5);\n }\n\n .beeport-feedback-button:focus {\n outline: 2px solid var(--beeport-input-focus-border);\n outline-offset: 2px;\n }\n\n .beeport-feedback-button:focus:not(:focus-visible) {\n outline: none;\n }\n\n .beeport-feedback-button:focus-visible {\n outline: 2px solid var(--beeport-input-focus-border);\n outline-offset: 2px;\n }\n\n .beeport-feedback-button:active {\n background: linear-gradient(135deg, #F59E0B 0%, #D97706 50%, #B45309 100%);\n transform: translateY(0);\n }\n\n .beeport-feedback-button svg {\n width: 28px;\n height: 28px;\n pointer-events: none;\n filter: drop-shadow(0 1px 1px rgba(0,0,0,0.15));\n }\n ',this.shadowRoot.appendChild(r),this.shadowRoot.appendChild(this.container),this.feedbackButton=this.createFeedbackButton(),this.container.appendChild(this.feedbackButton),this.form=t(this.container,{onSubmit:()=>{this.handleSubmit()},onCancel:()=>{this.isOpen&&this.toggleOpen()}}),document.body.appendChild(this.hostElement),this.themeCleanup=e(this.container,n.theme)}applyPosition(e){this.container.style.position="fixed",this.container.style.bottom="20px","bottom-right"===e?this.container.style.right="20px":this.container.style.left="20px"}createFeedbackButton(){const e=document.createElement("button");return e.className="beeport-feedback-button",e.setAttribute("aria-label","Send feedback"),e.setAttribute("aria-expanded","false"),e.setAttribute("tabindex","0"),this.updateButtonIcon(e,!1),e.addEventListener("click",e=>{e.stopPropagation(),this.toggleOpen()}),e.addEventListener("keydown",e=>{"Enter"!==e.key&&" "!==e.key||(e.preventDefault(),this.toggleOpen())}),e}async handleSubmit(){if(!this.form.validate().valid)return;const e=this.form.getValues(),t=await f({config:this.config,formValues:e});if("success"===t.status)this.form.reset(),this.toggleOpen(),console.log(`[BeePort] Issue created: ${t.issueUrl}`);else if("duplicates_found"===t.status){console.log("[BeePort] Potential duplicates found, submitting anyway");const{confirmSubmit:e}=await Promise.resolve().then(()=>g),n=await e(t.pendingSubmission);"success"===n.status?(this.form.reset(),this.toggleOpen(),console.log(`[BeePort] Issue created: ${n.issueUrl}`)):"error"===n.status&&console.error(`[BeePort] Submit failed: ${n.error}`)}else"error"===t.status&&console.error(`[BeePort] Submit failed: ${t.error}`)}toggleOpen(){this.isOpen=!this.isOpen,this.container.setAttribute("data-open",String(this.isOpen)),this.feedbackButton.setAttribute("aria-expanded",String(this.isOpen)),this.updateButtonIcon(this.feedbackButton,this.isOpen),this.isOpen?this.form.show():this.form.hide();const e=new CustomEvent("beeport:toggle",{detail:{open:this.isOpen},bubbles:!0,composed:!0});this.hostElement.dispatchEvent(e)}updateButtonIcon(e,t){if(e.textContent="",t){const t=this.createSVGElement("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none"}),n=this.createSVGElement("path",{d:"M18 6L6 18M6 6L18 18",stroke:"currentColor","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round"});t.appendChild(n),e.appendChild(t)}else{const t=this.createSVGElement("svg",{width:"28",height:"28",viewBox:"0 0 28 28",fill:"none"}),n=this.createSVGElement("ellipse",{cx:"14",cy:"15",rx:"6",ry:"7.5",fill:"#FFC107",stroke:"currentColor","stroke-width":"1.5"}),r=this.createSVGElement("path",{d:"M8.5 13.5 Q14 12 19.5 13.5",stroke:"#1a1a1a","stroke-width":"1.8","stroke-linecap":"round",fill:"none"}),o=this.createSVGElement("path",{d:"M8.2 16.5 Q14 15 19.8 16.5",stroke:"#1a1a1a","stroke-width":"1.8","stroke-linecap":"round",fill:"none"}),i=this.createSVGElement("ellipse",{cx:"9.5",cy:"9",rx:"3.5",ry:"4",fill:"rgba(255,255,255,0.7)",stroke:"currentColor","stroke-width":"1",transform:"rotate(-15 9.5 9)"}),a=this.createSVGElement("ellipse",{cx:"18.5",cy:"9",rx:"3.5",ry:"4",fill:"rgba(255,255,255,0.7)",stroke:"currentColor","stroke-width":"1",transform:"rotate(15 18.5 9)"}),s=this.createSVGElement("circle",{cx:"14",cy:"7.5",r:"3",fill:"#1a1a1a"}),p=this.createSVGElement("circle",{cx:"12.8",cy:"7",r:"0.8",fill:"white"}),c=this.createSVGElement("circle",{cx:"15.2",cy:"7",r:"0.8",fill:"white"}),l=this.createSVGElement("path",{d:"M12.5 5 Q11 2.5 9.5 2",stroke:"#1a1a1a","stroke-width":"1.2","stroke-linecap":"round",fill:"none"}),d=this.createSVGElement("path",{d:"M15.5 5 Q17 2.5 18.5 2",stroke:"#1a1a1a","stroke-width":"1.2","stroke-linecap":"round",fill:"none"}),b=this.createSVGElement("circle",{cx:"9.3",cy:"1.8",r:"1",fill:"#FFC107"}),u=this.createSVGElement("circle",{cx:"18.7",cy:"1.8",r:"1",fill:"#FFC107"}),h=this.createSVGElement("path",{d:"M14 22.5 L14 24.5",stroke:"#1a1a1a","stroke-width":"1.5","stroke-linecap":"round"});t.appendChild(i),t.appendChild(a),t.appendChild(n),t.appendChild(r),t.appendChild(o),t.appendChild(s),t.appendChild(p),t.appendChild(c),t.appendChild(l),t.appendChild(d),t.appendChild(b),t.appendChild(u),t.appendChild(h),e.appendChild(t)}}createSVGElement(e,t){const n=document.createElementNS("http://www.w3.org/2000/svg",e);for(const[r,o]of Object.entries(t))n.setAttribute(r,o);return n}show(){this.hostElement.style.display=""}hide(){this.hostElement.style.display="none"}destroy(){this.form.destroy(),this.themeCleanup&&(this.themeCleanup(),this.themeCleanup=null),this.hostElement.parentNode&&this.hostElement.parentNode.removeChild(this.hostElement)}setTheme(t){this.themeCleanup&&this.themeCleanup(),this.themeCleanup=e(this.container,t)}getContainer(){return this.container}}let v=null,y=null;function w(e){if(function(e){if(!e.repo)throw new Error("repo is required");if(!e.repo.includes("/")||2!==e.repo.split("/").length)throw new Error('repo must be in format "owner/repo"');if(!e.token||""===e.token.trim())throw new Error("token is required")}(e),v&&y)return y;const t={repo:e.repo,token:e.token,position:e.position??"bottom-right",theme:e.theme??"auto"};var n;return v=new x(t),n=v,y={show:()=>n.show(),hide:()=>n.hide(),destroy:()=>{n.destroy(),v=null,y=null},setTheme:e=>n.setTheme(e)},y}function k(){v&&(v.destroy(),v=null,y=null)}export{k as destroy,w as init};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser context capture module
|
|
3
|
+
* Captures technical context from the browser environment
|
|
4
|
+
*/
|
|
5
|
+
import type { BrowserContext } from './types';
|
|
6
|
+
/**
|
|
7
|
+
* Capture all browser context in one call
|
|
8
|
+
* Returns comprehensive browser environment information
|
|
9
|
+
*/
|
|
10
|
+
export declare function captureBrowserContext(): BrowserContext;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Duplicate confirmation UI component
|
|
3
|
+
* Shows similar issues list with title, number, similarity badge
|
|
4
|
+
*/
|
|
5
|
+
import type { DuplicateCandidate } from './dedup';
|
|
6
|
+
export interface DuplicatePanelOptions {
|
|
7
|
+
candidates: DuplicateCandidate[];
|
|
8
|
+
onSubmitAnyway: () => void;
|
|
9
|
+
onCancel: () => void;
|
|
10
|
+
}
|
|
11
|
+
export interface DuplicatePanel {
|
|
12
|
+
show: () => void;
|
|
13
|
+
hide: () => void;
|
|
14
|
+
destroy: () => void;
|
|
15
|
+
}
|
|
16
|
+
export declare function createDuplicatePanel(shadowRoot: ShadowRoot, options: DuplicatePanelOptions): DuplicatePanel;
|
package/dist/dedup.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Duplicate issue detection with fuzzy matching
|
|
3
|
+
*/
|
|
4
|
+
export interface DedupOptions {
|
|
5
|
+
token: string;
|
|
6
|
+
owner: string;
|
|
7
|
+
repo: string;
|
|
8
|
+
title: string;
|
|
9
|
+
}
|
|
10
|
+
export interface DuplicateCandidate {
|
|
11
|
+
number: number;
|
|
12
|
+
title: string;
|
|
13
|
+
url: string;
|
|
14
|
+
similarity: number;
|
|
15
|
+
state: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Calculate the Levenshtein distance between two strings
|
|
19
|
+
* @param a First string
|
|
20
|
+
* @param b Second string
|
|
21
|
+
* @returns Number of edits required to transform a into b
|
|
22
|
+
*/
|
|
23
|
+
export declare function levenshteinDistance(a: string, b: string): number;
|
|
24
|
+
/**
|
|
25
|
+
* Search for duplicate issues using fuzzy matching
|
|
26
|
+
* @param options Search options including token, owner, repo, and title
|
|
27
|
+
* @returns Array of duplicate candidates sorted by similarity (top 5)
|
|
28
|
+
*/
|
|
29
|
+
export declare function searchDuplicates(options: DedupOptions): Promise<DuplicateCandidate[]>;
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error capture module
|
|
3
|
+
* Captures window errors and unhandled promise rejections
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Captured error information
|
|
7
|
+
*/
|
|
8
|
+
export interface CapturedError {
|
|
9
|
+
/** Error message */
|
|
10
|
+
message: string;
|
|
11
|
+
/** Stack trace (null if unavailable) */
|
|
12
|
+
stack: string | null;
|
|
13
|
+
/** Source file and line number (null if unavailable) */
|
|
14
|
+
source: string | null;
|
|
15
|
+
/** Timestamp when error was captured (ISO 8601) */
|
|
16
|
+
timestamp: string;
|
|
17
|
+
/** Type of error */
|
|
18
|
+
type: 'error' | 'unhandled-rejection';
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Handle returned by startErrorCapture
|
|
22
|
+
* Used to stop error capture
|
|
23
|
+
*/
|
|
24
|
+
export interface ErrorCaptureHandle {
|
|
25
|
+
/** Internal cleanup function */
|
|
26
|
+
_cleanup: () => void;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Safe JSON stringify that handles circular references
|
|
30
|
+
* Replaces circular references with "[Circular]"
|
|
31
|
+
*/
|
|
32
|
+
export declare function safeStringify(obj: any): string;
|
|
33
|
+
/**
|
|
34
|
+
* Start capturing errors from window.onerror and window.onunhandledrejection
|
|
35
|
+
* Returns a handle that can be used to stop capture
|
|
36
|
+
*/
|
|
37
|
+
export declare function startErrorCapture(): ErrorCaptureHandle;
|
|
38
|
+
/**
|
|
39
|
+
* Stop capturing errors
|
|
40
|
+
* Removes event listeners and restores previous handlers
|
|
41
|
+
*/
|
|
42
|
+
export declare function stopErrorCapture(handle: ErrorCaptureHandle): void;
|
|
43
|
+
/**
|
|
44
|
+
* Get recently captured errors
|
|
45
|
+
* Returns array of up to 10 most recent errors
|
|
46
|
+
*/
|
|
47
|
+
export declare function getRecentErrors(): CapturedError[];
|
|
48
|
+
/**
|
|
49
|
+
* Clear all captured errors from buffer
|
|
50
|
+
*/
|
|
51
|
+
export declare function clearErrors(): void;
|
package/dist/form.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feedback form component
|
|
3
|
+
*/
|
|
4
|
+
import type { FeedbackType } from './types';
|
|
5
|
+
export interface FormValues {
|
|
6
|
+
type: FeedbackType;
|
|
7
|
+
title: string;
|
|
8
|
+
description: string;
|
|
9
|
+
}
|
|
10
|
+
export interface FormCallbacks {
|
|
11
|
+
onSubmit?: () => void;
|
|
12
|
+
onCancel?: () => void;
|
|
13
|
+
}
|
|
14
|
+
export interface ValidationResult {
|
|
15
|
+
valid: boolean;
|
|
16
|
+
errors: Record<string, string>;
|
|
17
|
+
}
|
|
18
|
+
export interface FormComponent {
|
|
19
|
+
show(): void;
|
|
20
|
+
hide(): void;
|
|
21
|
+
reset(): void;
|
|
22
|
+
destroy(): void;
|
|
23
|
+
getValues(): FormValues;
|
|
24
|
+
validate(): ValidationResult;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Create feedback form component
|
|
28
|
+
*/
|
|
29
|
+
export declare function createForm(parent: HTMLElement | ShadowRoot, callbacks?: FormCallbacks): FormComponent;
|
|
30
|
+
/**
|
|
31
|
+
* Get form styles
|
|
32
|
+
*/
|
|
33
|
+
export declare function getFormStyles(): string;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Issue body formatter module
|
|
3
|
+
* Generates agent-ready markdown for GitHub/GitLab issues
|
|
4
|
+
*/
|
|
5
|
+
import type { BrowserContext } from './types';
|
|
6
|
+
/**
|
|
7
|
+
* Feedback type - determines issue format
|
|
8
|
+
*/
|
|
9
|
+
export type FeedbackType = 'bug' | 'feature' | 'question';
|
|
10
|
+
/**
|
|
11
|
+
* Captured error from console
|
|
12
|
+
*/
|
|
13
|
+
export interface CapturedError {
|
|
14
|
+
message: string;
|
|
15
|
+
stack?: string;
|
|
16
|
+
timestamp: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Options for formatting an issue body
|
|
20
|
+
*/
|
|
21
|
+
export interface FormatOptions {
|
|
22
|
+
type: FeedbackType;
|
|
23
|
+
title: string;
|
|
24
|
+
description: string;
|
|
25
|
+
context: BrowserContext;
|
|
26
|
+
errors?: CapturedError[];
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Sanitizes a URL by replacing sensitive query parameter values with [REDACTED]
|
|
30
|
+
* @param url - URL to sanitize
|
|
31
|
+
* @returns Sanitized URL with sensitive values redacted
|
|
32
|
+
*/
|
|
33
|
+
export declare function sanitizeUrl(url: string): string;
|
|
34
|
+
/**
|
|
35
|
+
* Builds a formatted issue title with type prefix
|
|
36
|
+
*/
|
|
37
|
+
export declare function buildIssueTitle(type: FeedbackType, title: string): string;
|
|
38
|
+
/**
|
|
39
|
+
* Builds a complete issue body in markdown format
|
|
40
|
+
* Format varies based on feedback type (bug, feature, question)
|
|
41
|
+
*/
|
|
42
|
+
export declare function buildIssueBody(options: FormatOptions): string;
|
package/dist/github.d.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub API client for creating issues
|
|
3
|
+
*/
|
|
4
|
+
export interface CreateIssueOptions {
|
|
5
|
+
token: string;
|
|
6
|
+
owner: string;
|
|
7
|
+
repo: string;
|
|
8
|
+
title: string;
|
|
9
|
+
body: string;
|
|
10
|
+
labels?: string[];
|
|
11
|
+
}
|
|
12
|
+
export interface CreateIssueResult {
|
|
13
|
+
url: string;
|
|
14
|
+
number: number;
|
|
15
|
+
id: number;
|
|
16
|
+
}
|
|
17
|
+
export declare class GitHubError extends Error {
|
|
18
|
+
status?: number | undefined;
|
|
19
|
+
response?: any | undefined;
|
|
20
|
+
constructor(message: string, status?: number | undefined, response?: any | undefined);
|
|
21
|
+
}
|
|
22
|
+
export declare class GitHubAuthError extends GitHubError {
|
|
23
|
+
constructor(message: string, status: number, response?: any);
|
|
24
|
+
}
|
|
25
|
+
export declare class GitHubNotFoundError extends GitHubError {
|
|
26
|
+
constructor(message: string, status: number, response?: any);
|
|
27
|
+
}
|
|
28
|
+
export declare class GitHubValidationError extends GitHubError {
|
|
29
|
+
constructor(message: string, status: number, response?: any);
|
|
30
|
+
}
|
|
31
|
+
export declare class GitHubRateLimitError extends GitHubError {
|
|
32
|
+
rateLimit?: {
|
|
33
|
+
limit: number;
|
|
34
|
+
remaining: number;
|
|
35
|
+
reset: number;
|
|
36
|
+
} | undefined;
|
|
37
|
+
constructor(message: string, status: number, response?: any, rateLimit?: {
|
|
38
|
+
limit: number;
|
|
39
|
+
remaining: number;
|
|
40
|
+
reset: number;
|
|
41
|
+
} | undefined);
|
|
42
|
+
}
|
|
43
|
+
export declare class GitHubNetworkError extends GitHubError {
|
|
44
|
+
cause?: Error | undefined;
|
|
45
|
+
constructor(message: string, cause?: Error | undefined);
|
|
46
|
+
}
|
|
47
|
+
export declare function createIssue(options: CreateIssueOptions): Promise<CreateIssueResult>;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BeePort Widget
|
|
3
|
+
* Embeddable feedback widget for capturing user issues
|
|
4
|
+
*/
|
|
5
|
+
import type { BeePortConfig, BeePortInstance } from './types';
|
|
6
|
+
export type { BeePortConfig, BeePortInstance, Position, Theme } from './types';
|
|
7
|
+
/**
|
|
8
|
+
* Initialize the BeePort widget
|
|
9
|
+
*/
|
|
10
|
+
export declare function init(config: BeePortConfig): BeePortInstance;
|
|
11
|
+
/**
|
|
12
|
+
* Destroy the widget
|
|
13
|
+
*/
|
|
14
|
+
export declare function destroy(): void;
|
package/dist/labels.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Label auto-assignment logic for BeePort feedback
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Type of feedback being submitted
|
|
6
|
+
*/
|
|
7
|
+
export type FeedbackType = 'bug' | 'feature' | 'question';
|
|
8
|
+
/**
|
|
9
|
+
* Get labels for a given feedback type
|
|
10
|
+
*
|
|
11
|
+
* @param type - The type of feedback (bug, feature, or question)
|
|
12
|
+
* @returns Array of labels in consistent order: type-specific, beeport, agent-ready
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* getLabelsForFeedback('bug');
|
|
17
|
+
* // => ['bug', 'beeport', 'agent-ready']
|
|
18
|
+
*
|
|
19
|
+
* getLabelsForFeedback('feature');
|
|
20
|
+
* // => ['enhancement', 'beeport', 'agent-ready']
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare function getLabelsForFeedback(type: FeedbackType): string[];
|
package/dist/styles.d.ts
ADDED
package/dist/submit.d.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Form submission orchestration module
|
|
3
|
+
* Coordinates the full flow from form data to GitHub issue creation
|
|
4
|
+
*/
|
|
5
|
+
import type { BeePortConfig } from './types';
|
|
6
|
+
import type { FormValues } from './form';
|
|
7
|
+
import { type CapturedError } from './formatter';
|
|
8
|
+
import { type DuplicateCandidate } from './dedup';
|
|
9
|
+
/**
|
|
10
|
+
* Options for submitting feedback
|
|
11
|
+
*/
|
|
12
|
+
export interface SubmitOptions {
|
|
13
|
+
config: BeePortConfig;
|
|
14
|
+
formValues: FormValues;
|
|
15
|
+
errors?: CapturedError[];
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Pending submission data for confirmation after duplicate detection
|
|
19
|
+
*/
|
|
20
|
+
export interface PendingSubmission {
|
|
21
|
+
title: string;
|
|
22
|
+
body: string;
|
|
23
|
+
labels: string[];
|
|
24
|
+
owner: string;
|
|
25
|
+
repo: string;
|
|
26
|
+
token: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Result of feedback submission
|
|
30
|
+
*/
|
|
31
|
+
export type SubmitResult = {
|
|
32
|
+
status: 'success';
|
|
33
|
+
issueUrl: string;
|
|
34
|
+
issueNumber: number;
|
|
35
|
+
} | {
|
|
36
|
+
status: 'duplicates_found';
|
|
37
|
+
candidates: DuplicateCandidate[];
|
|
38
|
+
pendingSubmission: PendingSubmission;
|
|
39
|
+
} | {
|
|
40
|
+
status: 'error';
|
|
41
|
+
error: string;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Submit feedback and create a GitHub issue
|
|
45
|
+
*
|
|
46
|
+
* Orchestrates the full submission flow:
|
|
47
|
+
* 1. Capture browser context
|
|
48
|
+
* 2. Build issue title
|
|
49
|
+
* 3. Build issue body
|
|
50
|
+
* 4. Get labels
|
|
51
|
+
* 5. Parse owner/repo
|
|
52
|
+
* 6. Search for duplicates
|
|
53
|
+
* 7. If duplicates found, return them for user confirmation
|
|
54
|
+
* 8. If no duplicates, create GitHub issue
|
|
55
|
+
*
|
|
56
|
+
* @param options - Submission options
|
|
57
|
+
* @returns Result with issue URL and number, duplicates found, or error
|
|
58
|
+
*/
|
|
59
|
+
export declare function submitFeedback(options: SubmitOptions): Promise<SubmitResult>;
|
|
60
|
+
/**
|
|
61
|
+
* Confirm submission after user has reviewed duplicate candidates
|
|
62
|
+
*
|
|
63
|
+
* @param pendingSubmission - Pre-computed submission data
|
|
64
|
+
* @returns Result with issue URL and number, or error
|
|
65
|
+
*/
|
|
66
|
+
export declare function confirmSubmit(pendingSubmission: PendingSubmission): Promise<SubmitResult>;
|
package/dist/theme.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme management system
|
|
3
|
+
* Handles theme switching and auto mode with system preference watching
|
|
4
|
+
*/
|
|
5
|
+
import type { Theme } from './types';
|
|
6
|
+
/**
|
|
7
|
+
* Apply theme to container and watch for system preference changes if auto mode
|
|
8
|
+
* @param container - The container element to apply theme to
|
|
9
|
+
* @param theme - Theme to apply ('light' | 'dark' | 'auto')
|
|
10
|
+
* @returns Cleanup function to stop watching system preference changes
|
|
11
|
+
*/
|
|
12
|
+
export declare function createThemeWatcher(container: HTMLElement, theme: Theme): () => void;
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BeePort TypeScript type definitions
|
|
3
|
+
*/
|
|
4
|
+
export type Position = 'bottom-right' | 'bottom-left';
|
|
5
|
+
export type Theme = 'light' | 'dark' | 'auto';
|
|
6
|
+
export type FeedbackType = 'bug' | 'feature' | 'question';
|
|
7
|
+
/**
|
|
8
|
+
* Configuration for initializing the BeePort widget
|
|
9
|
+
*/
|
|
10
|
+
export interface BeePortConfig {
|
|
11
|
+
/**
|
|
12
|
+
* GitHub repository in "owner/repo" format
|
|
13
|
+
*/
|
|
14
|
+
repo: string;
|
|
15
|
+
/**
|
|
16
|
+
* GitHub Personal Access Token (PAT)
|
|
17
|
+
*/
|
|
18
|
+
token: string;
|
|
19
|
+
/**
|
|
20
|
+
* Position of the widget on the page
|
|
21
|
+
* @default "bottom-right"
|
|
22
|
+
*/
|
|
23
|
+
position?: Position;
|
|
24
|
+
/**
|
|
25
|
+
* Theme for the widget
|
|
26
|
+
* @default "auto"
|
|
27
|
+
*/
|
|
28
|
+
theme?: Theme;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Instance returned by BeePort.init()
|
|
32
|
+
*/
|
|
33
|
+
export interface BeePortInstance {
|
|
34
|
+
/**
|
|
35
|
+
* Show the widget
|
|
36
|
+
*/
|
|
37
|
+
show(): void;
|
|
38
|
+
/**
|
|
39
|
+
* Hide the widget
|
|
40
|
+
*/
|
|
41
|
+
hide(): void;
|
|
42
|
+
/**
|
|
43
|
+
* Destroy the widget and remove it from DOM
|
|
44
|
+
*/
|
|
45
|
+
destroy(): void;
|
|
46
|
+
/**
|
|
47
|
+
* Change the widget theme
|
|
48
|
+
*/
|
|
49
|
+
setTheme(theme: Theme): void;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Browser context captured from the user's environment
|
|
53
|
+
*/
|
|
54
|
+
export interface BrowserContext {
|
|
55
|
+
/** Current page URL */
|
|
56
|
+
url: string;
|
|
57
|
+
/** Viewport dimensions */
|
|
58
|
+
viewport: {
|
|
59
|
+
width: number;
|
|
60
|
+
height: number;
|
|
61
|
+
};
|
|
62
|
+
/** Screen dimensions and pixel ratio */
|
|
63
|
+
screen: {
|
|
64
|
+
width: number;
|
|
65
|
+
height: number;
|
|
66
|
+
pixelRatio: number;
|
|
67
|
+
};
|
|
68
|
+
/** Browser information */
|
|
69
|
+
browser: {
|
|
70
|
+
name: string;
|
|
71
|
+
version: string;
|
|
72
|
+
};
|
|
73
|
+
/** Operating system information */
|
|
74
|
+
os: {
|
|
75
|
+
name: string;
|
|
76
|
+
version: string;
|
|
77
|
+
};
|
|
78
|
+
/** Timestamp when context was captured (ISO 8601) */
|
|
79
|
+
timestamp: string;
|
|
80
|
+
/** Browser language */
|
|
81
|
+
language: string;
|
|
82
|
+
/** Whether cookies are enabled */
|
|
83
|
+
cookiesEnabled: boolean;
|
|
84
|
+
/** Do Not Track setting */
|
|
85
|
+
doNotTrack: string | null;
|
|
86
|
+
}
|
package/dist/widget.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Widget container with Shadow DOM
|
|
3
|
+
*/
|
|
4
|
+
import type { BeePortConfig, Theme } from './types';
|
|
5
|
+
/**
|
|
6
|
+
* Widget container class
|
|
7
|
+
* Manages Shadow DOM creation, lifecycle, and visibility
|
|
8
|
+
*/
|
|
9
|
+
export declare class Widget {
|
|
10
|
+
private hostElement;
|
|
11
|
+
private shadowRoot;
|
|
12
|
+
private container;
|
|
13
|
+
private feedbackButton;
|
|
14
|
+
private isOpen;
|
|
15
|
+
private themeCleanup;
|
|
16
|
+
private form;
|
|
17
|
+
private config;
|
|
18
|
+
constructor(config: Required<BeePortConfig>);
|
|
19
|
+
private applyPosition;
|
|
20
|
+
private createFeedbackButton;
|
|
21
|
+
private handleSubmit;
|
|
22
|
+
private toggleOpen;
|
|
23
|
+
private updateButtonIcon;
|
|
24
|
+
private createSVGElement;
|
|
25
|
+
show(): void;
|
|
26
|
+
hide(): void;
|
|
27
|
+
destroy(): void;
|
|
28
|
+
setTheme(theme: Theme): void;
|
|
29
|
+
getContainer(): HTMLElement;
|
|
30
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "beeport",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Embeddable feedback widget that turns user feedback into agent-ready GitHub issues",
|
|
6
|
+
"main": "./dist/beeport.min.js",
|
|
7
|
+
"module": "./dist/beeport.mjs",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/beeport.mjs",
|
|
13
|
+
"require": "./dist/beeport.min.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"dev": "vite",
|
|
21
|
+
"typecheck": "tsc --noEmit",
|
|
22
|
+
"build": "vite build && tsc --emitDeclarationOnly --outDir dist",
|
|
23
|
+
"build:check-size": "node scripts/check-size.js",
|
|
24
|
+
"test": "vitest run",
|
|
25
|
+
"test:watch": "vitest",
|
|
26
|
+
"test:coverage": "vitest run --coverage"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"feedback",
|
|
30
|
+
"widget",
|
|
31
|
+
"github",
|
|
32
|
+
"issues",
|
|
33
|
+
"bug-report",
|
|
34
|
+
"agent-ready",
|
|
35
|
+
"shadow-dom"
|
|
36
|
+
],
|
|
37
|
+
"author": "BeePort Contributors",
|
|
38
|
+
"license": "MIT",
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "https://github.com/srstomp/beeport.git",
|
|
42
|
+
"directory": "packages/widget"
|
|
43
|
+
},
|
|
44
|
+
"bugs": {
|
|
45
|
+
"url": "https://github.com/srstomp/beeport/issues"
|
|
46
|
+
},
|
|
47
|
+
"homepage": "https://github.com/srstomp/beeport#readme",
|
|
48
|
+
"engines": {
|
|
49
|
+
"node": ">=18"
|
|
50
|
+
},
|
|
51
|
+
"publishConfig": {
|
|
52
|
+
"access": "public"
|
|
53
|
+
}
|
|
54
|
+
}
|