@triagly/sdk 0.1.1-beta.4 → 0.1.1-beta.5
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 +130 -24
- package/dist/api.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +81 -120
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +81 -120
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/types.d.ts +0 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/ui.d.ts.map +1 -1
- package/dist/utils.d.ts +0 -4
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.test.d.ts +2 -0
- package/dist/utils.test.d.ts.map +1 -0
- package/package.json +15 -9
package/dist/index.js
CHANGED
|
@@ -51,26 +51,23 @@
|
|
|
51
51
|
// Button orientation
|
|
52
52
|
const orientation = this.config.orientation || 'horizontal';
|
|
53
53
|
button.classList.add(`triagly-orientation-${orientation}`);
|
|
54
|
+
// Speech bubble SVG icon
|
|
55
|
+
const speechBubbleIcon = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor" class="triagly-icon"><path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2z"/></svg>`;
|
|
56
|
+
const largeIcon = `<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24" fill="currentColor" class="triagly-icon"><path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2z"/></svg>`;
|
|
54
57
|
// Handle button text based on shape
|
|
55
|
-
const fullText = this.config.buttonText || '
|
|
58
|
+
const fullText = this.config.buttonText || 'Feedback';
|
|
56
59
|
if (shape === 'circular') {
|
|
57
|
-
button.innerHTML =
|
|
60
|
+
button.innerHTML = largeIcon;
|
|
58
61
|
button.setAttribute('aria-label', fullText);
|
|
59
62
|
}
|
|
60
63
|
else if (shape === 'expandable') {
|
|
61
|
-
// Expandable starts with
|
|
62
|
-
button.innerHTML =
|
|
64
|
+
// Expandable starts with icon, expands to full text on hover
|
|
65
|
+
button.innerHTML = `<span class="triagly-btn-icon">${largeIcon}</span><span class="triagly-btn-text"> ${this.config.buttonText || 'Feedback'}</span>`;
|
|
63
66
|
button.setAttribute('aria-label', fullText);
|
|
64
|
-
// Store custom text if provided
|
|
65
|
-
if (this.config.buttonText) {
|
|
66
|
-
const textSpan = button.querySelector('.triagly-btn-text');
|
|
67
|
-
if (textSpan) {
|
|
68
|
-
textSpan.textContent = ' ' + this.config.buttonText.replace('🐛', '').trim();
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
67
|
}
|
|
72
68
|
else {
|
|
73
|
-
|
|
69
|
+
// Default: icon + text
|
|
70
|
+
button.innerHTML = `${speechBubbleIcon}<span class="triagly-btn-label">${fullText}</span>`;
|
|
74
71
|
}
|
|
75
72
|
button.onclick = () => this.toggle();
|
|
76
73
|
// Position button
|
|
@@ -136,9 +133,9 @@
|
|
|
136
133
|
this.setupKeyboardEvents();
|
|
137
134
|
// Set up focus trap
|
|
138
135
|
this.setupFocusTrap();
|
|
139
|
-
// Focus on
|
|
140
|
-
const
|
|
141
|
-
|
|
136
|
+
// Focus on description field
|
|
137
|
+
const descInput = this.container?.querySelector('#triagly-description');
|
|
138
|
+
descInput?.focus();
|
|
142
139
|
}, 0);
|
|
143
140
|
}
|
|
144
141
|
/**
|
|
@@ -183,7 +180,7 @@
|
|
|
183
180
|
overlay.className = 'triagly-overlay';
|
|
184
181
|
overlay.setAttribute('role', 'dialog');
|
|
185
182
|
overlay.setAttribute('aria-modal', 'true');
|
|
186
|
-
overlay.setAttribute('aria-
|
|
183
|
+
overlay.setAttribute('aria-label', 'Send feedback');
|
|
187
184
|
overlay.onclick = (e) => {
|
|
188
185
|
if (e.target === overlay)
|
|
189
186
|
this.close('overlay');
|
|
@@ -194,7 +191,6 @@
|
|
|
194
191
|
const header = document.createElement('div');
|
|
195
192
|
header.className = 'triagly-header';
|
|
196
193
|
header.innerHTML = `
|
|
197
|
-
<h3 id="triagly-modal-title">Send Feedback</h3>
|
|
198
194
|
<button type="button" class="triagly-close" aria-label="Close feedback form">×</button>
|
|
199
195
|
`;
|
|
200
196
|
const closeBtn = header.querySelector('.triagly-close');
|
|
@@ -203,16 +199,7 @@
|
|
|
203
199
|
form.className = 'triagly-form';
|
|
204
200
|
form.innerHTML = `
|
|
205
201
|
<div class="triagly-field">
|
|
206
|
-
<label for="triagly-
|
|
207
|
-
<input
|
|
208
|
-
type="text"
|
|
209
|
-
id="triagly-title"
|
|
210
|
-
placeholder="Brief summary of your feedback"
|
|
211
|
-
/>
|
|
212
|
-
</div>
|
|
213
|
-
|
|
214
|
-
<div class="triagly-field">
|
|
215
|
-
<label for="triagly-description">Description *</label>
|
|
202
|
+
<label for="triagly-description">What's on your mind?</label>
|
|
216
203
|
<textarea
|
|
217
204
|
id="triagly-description"
|
|
218
205
|
required
|
|
@@ -221,6 +208,15 @@
|
|
|
221
208
|
></textarea>
|
|
222
209
|
</div>
|
|
223
210
|
|
|
211
|
+
<div class="triagly-field">
|
|
212
|
+
<label for="triagly-name">Name (optional)</label>
|
|
213
|
+
<input
|
|
214
|
+
type="text"
|
|
215
|
+
id="triagly-name"
|
|
216
|
+
placeholder="Your name"
|
|
217
|
+
/>
|
|
218
|
+
</div>
|
|
219
|
+
|
|
224
220
|
<div class="triagly-field">
|
|
225
221
|
<label for="triagly-email">Email (optional)</label>
|
|
226
222
|
<input
|
|
@@ -230,13 +226,6 @@
|
|
|
230
226
|
/>
|
|
231
227
|
</div>
|
|
232
228
|
|
|
233
|
-
<div class="triagly-field triagly-checkbox">
|
|
234
|
-
<label>
|
|
235
|
-
<input type="checkbox" id="triagly-screenshot" checked />
|
|
236
|
-
<span>Include screenshot</span>
|
|
237
|
-
</label>
|
|
238
|
-
</div>
|
|
239
|
-
|
|
240
229
|
${this.config.turnstileSiteKey ? `
|
|
241
230
|
<div class="triagly-field triagly-turnstile">
|
|
242
231
|
<div class="cf-turnstile" data-sitekey="${this.config.turnstileSiteKey}" data-theme="light"></div>
|
|
@@ -260,8 +249,16 @@
|
|
|
260
249
|
e.preventDefault();
|
|
261
250
|
this.handleSubmit(form);
|
|
262
251
|
};
|
|
252
|
+
const footer = document.createElement('div');
|
|
253
|
+
footer.className = 'triagly-footer';
|
|
254
|
+
footer.innerHTML = `
|
|
255
|
+
<a href="https://triagly.com" target="_blank" rel="noopener noreferrer" class="triagly-branding">
|
|
256
|
+
Powered by <strong>Triagly</strong>
|
|
257
|
+
</a>
|
|
258
|
+
`;
|
|
263
259
|
modal.appendChild(header);
|
|
264
260
|
modal.appendChild(form);
|
|
261
|
+
modal.appendChild(footer);
|
|
265
262
|
overlay.appendChild(modal);
|
|
266
263
|
// Render Turnstile widget if available
|
|
267
264
|
if (this.config.turnstileSiteKey) {
|
|
@@ -310,10 +307,9 @@
|
|
|
310
307
|
* Handle form submission
|
|
311
308
|
*/
|
|
312
309
|
async handleSubmit(form) {
|
|
313
|
-
const titleInput = form.querySelector('#triagly-title');
|
|
314
310
|
const descInput = form.querySelector('#triagly-description');
|
|
311
|
+
const nameInput = form.querySelector('#triagly-name');
|
|
315
312
|
const emailInput = form.querySelector('#triagly-email');
|
|
316
|
-
const screenshotCheckbox = form.querySelector('#triagly-screenshot');
|
|
317
313
|
const statusDiv = form.querySelector('#triagly-status');
|
|
318
314
|
const submitBtn = form.querySelector('button[type="submit"]');
|
|
319
315
|
const turnstileContainer = form.querySelector('.cf-turnstile');
|
|
@@ -327,10 +323,9 @@
|
|
|
327
323
|
turnstileToken = turnstileContainer.getAttribute('data-turnstile-response') || undefined;
|
|
328
324
|
}
|
|
329
325
|
const data = {
|
|
330
|
-
title: titleInput.value.trim() || undefined,
|
|
331
326
|
description: descInput.value.trim(),
|
|
327
|
+
reporterName: nameInput.value.trim() || undefined,
|
|
332
328
|
reporterEmail: emailInput.value.trim() || undefined,
|
|
333
|
-
includeScreenshot: screenshotCheckbox.checked,
|
|
334
329
|
turnstileToken,
|
|
335
330
|
};
|
|
336
331
|
// Create a promise that waits for actual submission result
|
|
@@ -394,21 +389,32 @@
|
|
|
394
389
|
position: fixed;
|
|
395
390
|
z-index: 999999;
|
|
396
391
|
padding: 12px 20px;
|
|
397
|
-
background: var(--triagly-button-bg, #
|
|
392
|
+
background: var(--triagly-button-bg, #18181b);
|
|
398
393
|
color: var(--triagly-button-text, #ffffff);
|
|
399
394
|
border: none;
|
|
400
395
|
border-radius: var(--triagly-button-radius, 8px);
|
|
401
396
|
font-size: 14px;
|
|
402
397
|
font-weight: 500;
|
|
403
398
|
cursor: pointer;
|
|
404
|
-
box-shadow: var(--triagly-button-shadow, 0 4px 12px rgba(
|
|
399
|
+
box-shadow: var(--triagly-button-shadow, 0 4px 12px rgba(0, 0, 0, 0.15));
|
|
405
400
|
transition: all 0.2s;
|
|
401
|
+
display: inline-flex;
|
|
402
|
+
align-items: center;
|
|
403
|
+
gap: 8px;
|
|
406
404
|
}
|
|
407
405
|
|
|
408
406
|
.triagly-button:hover {
|
|
409
|
-
background: var(--triagly-button-bg-hover, #
|
|
407
|
+
background: var(--triagly-button-bg-hover, #27272a);
|
|
410
408
|
transform: translateY(-2px);
|
|
411
|
-
box-shadow: var(--triagly-button-shadow-hover, 0 6px 16px rgba(
|
|
409
|
+
box-shadow: var(--triagly-button-shadow-hover, 0 6px 16px rgba(0, 0, 0, 0.2));
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
.triagly-button .triagly-icon {
|
|
413
|
+
flex-shrink: 0;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
.triagly-button .triagly-btn-label {
|
|
417
|
+
line-height: 1;
|
|
412
418
|
}
|
|
413
419
|
|
|
414
420
|
/* Prevent expandable buttons from shifting on hover */
|
|
@@ -502,8 +508,8 @@
|
|
|
502
508
|
min-width: auto;
|
|
503
509
|
padding: 12px 20px;
|
|
504
510
|
border-radius: 30px;
|
|
505
|
-
background: var(--triagly-button-bg-hover, #
|
|
506
|
-
box-shadow: var(--triagly-button-shadow-hover, 0 6px 16px rgba(
|
|
511
|
+
background: var(--triagly-button-bg-hover, #27272a);
|
|
512
|
+
box-shadow: var(--triagly-button-shadow-hover, 0 6px 16px rgba(0, 0, 0, 0.2));
|
|
507
513
|
}
|
|
508
514
|
.triagly-shape-expandable:hover .triagly-btn-text {
|
|
509
515
|
width: auto;
|
|
@@ -562,18 +568,10 @@
|
|
|
562
568
|
|
|
563
569
|
.triagly-header {
|
|
564
570
|
display: flex;
|
|
565
|
-
justify-content:
|
|
571
|
+
justify-content: flex-end;
|
|
566
572
|
align-items: center;
|
|
567
|
-
padding:
|
|
573
|
+
padding: 8px 12px 0;
|
|
568
574
|
background: var(--triagly-header-bg, #ffffff);
|
|
569
|
-
border-bottom: 1px solid var(--triagly-header-border, #e5e7eb);
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
.triagly-header h3 {
|
|
573
|
-
margin: 0;
|
|
574
|
-
font-size: 18px;
|
|
575
|
-
font-weight: 600;
|
|
576
|
-
color: var(--triagly-header-text, #111827);
|
|
577
575
|
}
|
|
578
576
|
|
|
579
577
|
.triagly-close {
|
|
@@ -631,46 +629,21 @@
|
|
|
631
629
|
.triagly-field input:focus,
|
|
632
630
|
.triagly-field textarea:focus {
|
|
633
631
|
outline: none;
|
|
634
|
-
border-color: var(--triagly-input-border-focus, #
|
|
635
|
-
box-shadow: 0 0 0
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
.triagly-checkbox label {
|
|
639
|
-
display: flex;
|
|
640
|
-
align-items: center;
|
|
641
|
-
gap: 8px;
|
|
642
|
-
cursor: pointer;
|
|
643
|
-
font-weight: 400;
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
.triagly-checkbox label span {
|
|
647
|
-
user-select: none;
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
.triagly-checkbox input {
|
|
651
|
-
width: 16px;
|
|
652
|
-
height: 16px;
|
|
653
|
-
margin: 0;
|
|
654
|
-
cursor: pointer;
|
|
632
|
+
border-color: var(--triagly-input-border-focus, #a1a1aa);
|
|
633
|
+
box-shadow: 0 0 0 2px rgba(161, 161, 170, 0.15);
|
|
655
634
|
}
|
|
656
635
|
|
|
657
636
|
/* Focus visible styles for accessibility */
|
|
658
637
|
.triagly-button:focus-visible,
|
|
659
638
|
.triagly-field input:focus-visible,
|
|
660
639
|
.triagly-field textarea:focus-visible,
|
|
661
|
-
.triagly-checkbox input:focus-visible,
|
|
662
640
|
.triagly-btn-primary:focus-visible,
|
|
663
641
|
.triagly-btn-secondary:focus-visible,
|
|
664
642
|
.triagly-close:focus-visible {
|
|
665
|
-
outline: 2px solid #
|
|
643
|
+
outline: 2px solid #a1a1aa;
|
|
666
644
|
outline-offset: 2px;
|
|
667
645
|
}
|
|
668
646
|
|
|
669
|
-
/* Checkbox label gets visual indicator when checkbox is focused */
|
|
670
|
-
.triagly-checkbox input:focus-visible + span {
|
|
671
|
-
text-decoration: underline;
|
|
672
|
-
}
|
|
673
|
-
|
|
674
647
|
.triagly-turnstile {
|
|
675
648
|
display: flex;
|
|
676
649
|
justify-content: center;
|
|
@@ -696,12 +669,12 @@
|
|
|
696
669
|
}
|
|
697
670
|
|
|
698
671
|
.triagly-btn-primary {
|
|
699
|
-
background: var(--triagly-btn-primary-bg, #
|
|
672
|
+
background: var(--triagly-btn-primary-bg, #18181b);
|
|
700
673
|
color: var(--triagly-btn-primary-text, #ffffff);
|
|
701
674
|
}
|
|
702
675
|
|
|
703
676
|
.triagly-btn-primary:hover:not(:disabled) {
|
|
704
|
-
background: var(--triagly-btn-primary-bg-hover, #
|
|
677
|
+
background: var(--triagly-btn-primary-bg-hover, #27272a);
|
|
705
678
|
}
|
|
706
679
|
|
|
707
680
|
.triagly-btn-primary:disabled {
|
|
@@ -737,6 +710,29 @@
|
|
|
737
710
|
background: var(--triagly-error-bg, #fee2e2);
|
|
738
711
|
color: var(--triagly-error-text, #991b1b);
|
|
739
712
|
}
|
|
713
|
+
|
|
714
|
+
.triagly-footer {
|
|
715
|
+
padding: 12px 24px 16px;
|
|
716
|
+
text-align: right;
|
|
717
|
+
border-top: 1px solid var(--triagly-footer-border, #e5e7eb);
|
|
718
|
+
background: var(--triagly-footer-bg, #f9fafb);
|
|
719
|
+
border-radius: 0 0 var(--triagly-modal-radius, 12px) var(--triagly-modal-radius, 12px);
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
.triagly-branding {
|
|
723
|
+
font-size: 12px;
|
|
724
|
+
color: var(--triagly-footer-text, #6b7280);
|
|
725
|
+
text-decoration: none;
|
|
726
|
+
transition: color 0.2s;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
.triagly-branding:hover {
|
|
730
|
+
color: var(--triagly-footer-text-hover, #18181b);
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
.triagly-branding strong {
|
|
734
|
+
font-weight: 600;
|
|
735
|
+
}
|
|
740
736
|
`;
|
|
741
737
|
document.head.appendChild(style);
|
|
742
738
|
}
|
|
@@ -902,7 +898,6 @@
|
|
|
902
898
|
consoleLogs: data.consoleLogs,
|
|
903
899
|
},
|
|
904
900
|
tags: data.tags,
|
|
905
|
-
screenshot: data.screenshot,
|
|
906
901
|
reporterEmail: data.reporterEmail,
|
|
907
902
|
reporterName: data.reporterName,
|
|
908
903
|
turnstileToken,
|
|
@@ -989,34 +984,6 @@
|
|
|
989
984
|
}
|
|
990
985
|
return browser;
|
|
991
986
|
}
|
|
992
|
-
/**
|
|
993
|
-
* Capture screenshot of current page
|
|
994
|
-
*/
|
|
995
|
-
async function captureScreenshot() {
|
|
996
|
-
try {
|
|
997
|
-
// Use html2canvas library if available
|
|
998
|
-
if (typeof window.html2canvas !== 'undefined') {
|
|
999
|
-
const canvas = await window.html2canvas(document.body, {
|
|
1000
|
-
logging: false,
|
|
1001
|
-
useCORS: true,
|
|
1002
|
-
allowTaint: true,
|
|
1003
|
-
});
|
|
1004
|
-
return canvas.toDataURL('image/png');
|
|
1005
|
-
}
|
|
1006
|
-
// Fallback to native screenshot API if supported (limited browser support)
|
|
1007
|
-
if ('mediaDevices' in navigator && 'getDisplayMedia' in navigator.mediaDevices) {
|
|
1008
|
-
// This requires user interaction and shows a permission dialog
|
|
1009
|
-
// Not ideal for automatic screenshots
|
|
1010
|
-
console.warn('Screenshot capture requires html2canvas library');
|
|
1011
|
-
return null;
|
|
1012
|
-
}
|
|
1013
|
-
return null;
|
|
1014
|
-
}
|
|
1015
|
-
catch (error) {
|
|
1016
|
-
console.error('Screenshot capture failed:', error);
|
|
1017
|
-
return null;
|
|
1018
|
-
}
|
|
1019
|
-
}
|
|
1020
987
|
/**
|
|
1021
988
|
* Simple rate limiter using localStorage
|
|
1022
989
|
*/
|
|
@@ -1237,7 +1204,7 @@
|
|
|
1237
1204
|
theme: 'auto',
|
|
1238
1205
|
position: 'bottom-right',
|
|
1239
1206
|
buttonShape: 'rounded',
|
|
1240
|
-
buttonText: '
|
|
1207
|
+
buttonText: 'Feedback',
|
|
1241
1208
|
placeholderText: 'Describe what happened...',
|
|
1242
1209
|
successMessage: 'Feedback sent successfully!',
|
|
1243
1210
|
errorMessage: 'Failed to send feedback. Please try again.',
|
|
@@ -1292,17 +1259,11 @@
|
|
|
1292
1259
|
}
|
|
1293
1260
|
// Collect metadata
|
|
1294
1261
|
const metadata = collectMetadata(this.config.metadata);
|
|
1295
|
-
// Capture screenshot if requested
|
|
1296
|
-
let screenshot = null;
|
|
1297
|
-
if (data.includeScreenshot) {
|
|
1298
|
-
screenshot = await captureScreenshot();
|
|
1299
|
-
}
|
|
1300
1262
|
// Prepare feedback data
|
|
1301
1263
|
const feedbackData = {
|
|
1302
1264
|
title: data.title,
|
|
1303
1265
|
description: data.description,
|
|
1304
1266
|
reporterEmail: data.reporterEmail,
|
|
1305
|
-
screenshot: screenshot || undefined,
|
|
1306
1267
|
consoleLogs: this.consoleLogger?.getLogs(),
|
|
1307
1268
|
};
|
|
1308
1269
|
// Submit to API with Turnstile token if provided
|