@usero/sdk 0.2.0 → 0.3.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 +86 -0
- package/dist/all-M6KEAHE5.cjs +9110 -0
- package/dist/all-M6KEAHE5.cjs.map +1 -0
- package/dist/all-T4CCPHSL.js +9095 -0
- package/dist/all-T4CCPHSL.js.map +1 -0
- package/dist/chunk-5BLDMQED.cjs +18 -0
- package/dist/chunk-5BLDMQED.cjs.map +1 -0
- package/dist/chunk-NSBPE2FW.js +15 -0
- package/dist/chunk-NSBPE2FW.js.map +1 -0
- package/dist/plugins/session-replay.cjs +180 -0
- package/dist/plugins/session-replay.cjs.map +1 -0
- package/dist/plugins/session-replay.d.cts +75 -0
- package/dist/plugins/session-replay.d.ts +75 -0
- package/dist/plugins/session-replay.js +177 -0
- package/dist/plugins/session-replay.js.map +1 -0
- package/dist/react.cjs +138 -35
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +23 -0
- package/dist/react.d.ts +23 -0
- package/dist/react.js +138 -35
- package/dist/react.js.map +1 -1
- package/dist/usero.iife.js +59 -52
- package/dist/usero.iife.js.map +1 -1
- package/dist/vanilla.cjs +139 -35
- package/dist/vanilla.cjs.map +1 -1
- package/dist/vanilla.d.cts +25 -1
- package/dist/vanilla.d.ts +25 -1
- package/dist/vanilla.js +139 -36
- package/dist/vanilla.js.map +1 -1
- package/package.json +9 -1
package/dist/vanilla.cjs
CHANGED
|
@@ -157,6 +157,25 @@ function getGradientEnd(color) {
|
|
|
157
157
|
return `#${[shiftedR, shiftedG, shiftedB].map((x) => x.toString(16).padStart(2, "0")).join("")}`;
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
+
// src/plugin.ts
|
|
161
|
+
function createPluginLogger(name) {
|
|
162
|
+
const prefix = `[usero:${name}]`;
|
|
163
|
+
return {
|
|
164
|
+
debug: (...args) => {
|
|
165
|
+
if (typeof console !== "undefined") console.debug(prefix, ...args);
|
|
166
|
+
},
|
|
167
|
+
info: (...args) => {
|
|
168
|
+
if (typeof console !== "undefined") console.info(prefix, ...args);
|
|
169
|
+
},
|
|
170
|
+
warn: (...args) => {
|
|
171
|
+
if (typeof console !== "undefined") console.warn(prefix, ...args);
|
|
172
|
+
},
|
|
173
|
+
error: (...args) => {
|
|
174
|
+
if (typeof console !== "undefined") console.error(prefix, ...args);
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
160
179
|
// src/validation.ts
|
|
161
180
|
function validateFeedbackSubmission(data) {
|
|
162
181
|
const errors = [];
|
|
@@ -192,8 +211,8 @@ var FEEDBACK_CSS = `
|
|
|
192
211
|
.fb-es {
|
|
193
212
|
display: flex;
|
|
194
213
|
justify-content: center;
|
|
195
|
-
gap:
|
|
196
|
-
padding-bottom:
|
|
214
|
+
gap: 12px;
|
|
215
|
+
padding-bottom: 8px;
|
|
197
216
|
}
|
|
198
217
|
|
|
199
218
|
.fb-ec {
|
|
@@ -284,7 +303,7 @@ var FEEDBACK_CSS = `
|
|
|
284
303
|
|
|
285
304
|
.fb-sub {
|
|
286
305
|
width: 100%;
|
|
287
|
-
padding:
|
|
306
|
+
padding: 12px 24px;
|
|
288
307
|
border: none;
|
|
289
308
|
border-radius: 12px;
|
|
290
309
|
font-size: 15px;
|
|
@@ -312,7 +331,7 @@ var FEEDBACK_CSS = `
|
|
|
312
331
|
}
|
|
313
332
|
|
|
314
333
|
.fb-cnt {
|
|
315
|
-
padding: 24px;
|
|
334
|
+
padding: 20px 24px 16px;
|
|
316
335
|
overflow: auto;
|
|
317
336
|
max-height: calc(90vh - 48px);
|
|
318
337
|
}
|
|
@@ -325,22 +344,29 @@ var FEEDBACK_CSS = `
|
|
|
325
344
|
|
|
326
345
|
.fb-ta {
|
|
327
346
|
width: 100%;
|
|
328
|
-
min-height:
|
|
329
|
-
padding:
|
|
347
|
+
min-height: 80px;
|
|
348
|
+
padding: 10px;
|
|
330
349
|
border-radius: 8px;
|
|
331
350
|
font-size: 14px;
|
|
332
351
|
font-family: inherit;
|
|
333
352
|
outline: none;
|
|
334
353
|
resize: vertical;
|
|
335
354
|
transition: border-color 150ms ease;
|
|
336
|
-
margin-bottom:
|
|
355
|
+
margin-bottom: 2px;
|
|
337
356
|
box-sizing: border-box;
|
|
338
357
|
}
|
|
339
358
|
|
|
359
|
+
.fb-toolrow {
|
|
360
|
+
display: flex;
|
|
361
|
+
align-items: center;
|
|
362
|
+
justify-content: space-between;
|
|
363
|
+
gap: 12px;
|
|
364
|
+
margin-bottom: 8px;
|
|
365
|
+
}
|
|
366
|
+
|
|
340
367
|
.fb-charcount {
|
|
341
368
|
font-size: 12px;
|
|
342
369
|
margin-left: auto;
|
|
343
|
-
margin-bottom: 8px;
|
|
344
370
|
text-align: right;
|
|
345
371
|
}
|
|
346
372
|
|
|
@@ -351,8 +377,8 @@ var FEEDBACK_CSS = `
|
|
|
351
377
|
.fb-email {
|
|
352
378
|
display: flex;
|
|
353
379
|
flex-direction: column;
|
|
354
|
-
gap:
|
|
355
|
-
margin-bottom:
|
|
380
|
+
gap: 6px;
|
|
381
|
+
margin-bottom: 10px;
|
|
356
382
|
}
|
|
357
383
|
|
|
358
384
|
.fb-email-lbl {
|
|
@@ -488,8 +514,8 @@ var FEEDBACK_CSS = `
|
|
|
488
514
|
.fb-up {
|
|
489
515
|
display: flex;
|
|
490
516
|
flex-direction: column;
|
|
491
|
-
gap:
|
|
492
|
-
margin-bottom:
|
|
517
|
+
gap: 6px;
|
|
518
|
+
margin-bottom: 8px;
|
|
493
519
|
}
|
|
494
520
|
|
|
495
521
|
.fb-upb {
|
|
@@ -591,15 +617,15 @@ var FEEDBACK_CSS = `
|
|
|
591
617
|
.fb-pnl-base {
|
|
592
618
|
width: 100% !important;
|
|
593
619
|
max-width: none !important;
|
|
594
|
-
top:
|
|
595
|
-
max-height:
|
|
620
|
+
top: 4vh !important;
|
|
621
|
+
max-height: 92vh !important;
|
|
596
622
|
}
|
|
597
|
-
.fb-cnt { padding:
|
|
598
|
-
.fb-ta { font-size: 16px !important; min-height:
|
|
623
|
+
.fb-cnt { padding: 16px 18px 14px !important; max-height: calc(100vh - 40px) !important; }
|
|
624
|
+
.fb-ta { font-size: 16px !important; min-height: 64px !important; }
|
|
599
625
|
.fb-ttl { font-size: 18px !important; }
|
|
600
626
|
.fb-ei { font-size: 24px !important; }
|
|
601
627
|
.fb-el { font-size: 11px !important; }
|
|
602
|
-
.fb-sub { padding:
|
|
628
|
+
.fb-sub { padding: 12px 20px !important; font-size: 16px !important; }
|
|
603
629
|
}
|
|
604
630
|
`;
|
|
605
631
|
|
|
@@ -636,6 +662,21 @@ function escapeHtml(value) {
|
|
|
636
662
|
}
|
|
637
663
|
});
|
|
638
664
|
}
|
|
665
|
+
function mergePluginPatches(base, patches) {
|
|
666
|
+
let result = base;
|
|
667
|
+
for (const patch of patches) {
|
|
668
|
+
if (!patch || typeof patch !== "object") continue;
|
|
669
|
+
const { metadata: patchMetadata, ...rest } = patch;
|
|
670
|
+
result = { ...result, ...rest };
|
|
671
|
+
if (patchMetadata && typeof patchMetadata === "object") {
|
|
672
|
+
result.metadata = {
|
|
673
|
+
...result.metadata ?? {},
|
|
674
|
+
...patchMetadata
|
|
675
|
+
};
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
return result;
|
|
679
|
+
}
|
|
639
680
|
function readStoredEmail() {
|
|
640
681
|
if (typeof window === "undefined") return "";
|
|
641
682
|
try {
|
|
@@ -660,7 +701,8 @@ function initUseroFeedbackWidget(props) {
|
|
|
660
701
|
close: () => {
|
|
661
702
|
},
|
|
662
703
|
update: () => {
|
|
663
|
-
}
|
|
704
|
+
},
|
|
705
|
+
whenReady: () => Promise.resolve()
|
|
664
706
|
};
|
|
665
707
|
}
|
|
666
708
|
const { clientId, baseUrl } = props;
|
|
@@ -675,7 +717,8 @@ function initUseroFeedbackWidget(props) {
|
|
|
675
717
|
close: () => {
|
|
676
718
|
},
|
|
677
719
|
update: () => {
|
|
678
|
-
}
|
|
720
|
+
},
|
|
721
|
+
whenReady: () => Promise.resolve()
|
|
679
722
|
};
|
|
680
723
|
}
|
|
681
724
|
let position = props.position ?? "right";
|
|
@@ -692,6 +735,34 @@ function initUseroFeedbackWidget(props) {
|
|
|
692
735
|
let onOpen = props.onOpen;
|
|
693
736
|
let onClose = props.onClose;
|
|
694
737
|
const apiClient = new FeedbackApiClient(baseUrl);
|
|
738
|
+
const pluginList = props.plugins ?? [];
|
|
739
|
+
const pluginStores = /* @__PURE__ */ new Map();
|
|
740
|
+
const pluginContexts = /* @__PURE__ */ new Map();
|
|
741
|
+
const initPromises = [];
|
|
742
|
+
for (const plugin of pluginList) {
|
|
743
|
+
const ctx = {
|
|
744
|
+
clientId,
|
|
745
|
+
baseUrl: baseUrl ?? DEFAULT_API_URL,
|
|
746
|
+
logger: createPluginLogger(plugin.name),
|
|
747
|
+
getStore: () => pluginStores.get(plugin.name),
|
|
748
|
+
setStore: (value) => {
|
|
749
|
+
pluginStores.set(plugin.name, value);
|
|
750
|
+
}
|
|
751
|
+
};
|
|
752
|
+
pluginContexts.set(plugin.name, ctx);
|
|
753
|
+
if (plugin.onInit) {
|
|
754
|
+
const settled = (async () => {
|
|
755
|
+
try {
|
|
756
|
+
await plugin.onInit?.(ctx);
|
|
757
|
+
} catch (err) {
|
|
758
|
+
ctx.logger.error("onInit threw", err);
|
|
759
|
+
}
|
|
760
|
+
})();
|
|
761
|
+
initPromises.push(settled);
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
const readyPromise = initPromises.length === 0 ? Promise.resolve() : Promise.all(initPromises).then(() => {
|
|
765
|
+
});
|
|
695
766
|
let isOpen = false;
|
|
696
767
|
let selectedRating = void 0;
|
|
697
768
|
let comment = "";
|
|
@@ -810,8 +881,24 @@ function initUseroFeedbackWidget(props) {
|
|
|
810
881
|
setSubmitMessage({ type: "error", text: validation.errors.join(", ") });
|
|
811
882
|
return;
|
|
812
883
|
}
|
|
884
|
+
let enrichedSubmission = submission;
|
|
885
|
+
if (pluginList.length > 0) {
|
|
886
|
+
const patchPromises = pluginList.map(async (plugin) => {
|
|
887
|
+
if (!plugin.onFeedbackSubmit) return void 0;
|
|
888
|
+
const ctx = pluginContexts.get(plugin.name);
|
|
889
|
+
if (!ctx) return void 0;
|
|
890
|
+
try {
|
|
891
|
+
return await plugin.onFeedbackSubmit(ctx, submission);
|
|
892
|
+
} catch (err) {
|
|
893
|
+
ctx.logger.error("onFeedbackSubmit threw", err);
|
|
894
|
+
return void 0;
|
|
895
|
+
}
|
|
896
|
+
});
|
|
897
|
+
const patches = await Promise.all(patchPromises);
|
|
898
|
+
enrichedSubmission = mergePluginPatches(submission, patches);
|
|
899
|
+
}
|
|
813
900
|
try {
|
|
814
|
-
const response = await apiClient.submitFeedback(
|
|
901
|
+
const response = await apiClient.submitFeedback(enrichedSubmission);
|
|
815
902
|
if (response.success) {
|
|
816
903
|
if (shareEmail && userEmail) writeStoredEmail(userEmail);
|
|
817
904
|
onSubmit?.(feedbackData);
|
|
@@ -868,17 +955,26 @@ function initUseroFeedbackWidget(props) {
|
|
|
868
955
|
const cls = ["fb-ec", sel && "fb-ec--sel"].filter(Boolean).join(" ");
|
|
869
956
|
return `
|
|
870
957
|
<div class="${cls}" style="background:${bg}">
|
|
871
|
-
<button type="button" class="fb-eb" data-rating="${r}" role="radio" aria-checked="${sel}" aria-label="${r}: ${RATING_LABELS[r]}">
|
|
958
|
+
<button type="button" class="fb-eb" data-rating="${r}" role="radio" aria-checked="${sel}" aria-label="${r}: ${RATING_LABELS[r]}" style="color:${theme.text}">
|
|
872
959
|
<div class="fb-ei"><span role="img" aria-label="${RATING_LABELS[r]}">${EMOJI_MAP[r]}</span></div>
|
|
873
|
-
<div class="fb-el">${RATING_LABELS[r]}</div>
|
|
960
|
+
<div class="fb-el" style="color:${theme.text}">${RATING_LABELS[r]}</div>
|
|
874
961
|
</button>
|
|
875
962
|
</div>
|
|
876
963
|
`;
|
|
877
964
|
}).join("");
|
|
878
965
|
const messageHtml = submitMessage ? `<div class="fb-msg fb-msg--header ${submitMessage.type === "success" ? "fb-msg--ok" : "fb-msg--err"}">${submitMessage.type === "success" ? "\u2713" : "\u26A0"} ${escapeHtml(submitMessage.text)}</div>` : "";
|
|
879
|
-
const
|
|
966
|
+
const uploadBtnHtml = showScreenshotOption ? (() => {
|
|
880
967
|
const atMax = screenshots.length >= MAX_SCREENSHOTS;
|
|
881
968
|
const btnDisabled = isUploadingScreenshot || atMax;
|
|
969
|
+
return `
|
|
970
|
+
<input type="file" accept="image/*" data-role="screenshot-input" style="display:none;" aria-label="Choose screenshot" />
|
|
971
|
+
<button type="button" class="fb-upb ${btnDisabled ? "fb-upb--dis" : ""}" data-role="screenshot-pick" ${btnDisabled ? "disabled" : ""} style="border:1px solid ${theme.border};color:${theme.text};">
|
|
972
|
+
${isUploadingScreenshot ? '<span class="fb-ups"></span> Uploading...' : "\u{1F4F7} Add screenshot"}
|
|
973
|
+
</button>
|
|
974
|
+
`;
|
|
975
|
+
})() : "";
|
|
976
|
+
const uploadExtrasHtml = showScreenshotOption ? (() => {
|
|
977
|
+
const atMax = screenshots.length >= MAX_SCREENSHOTS;
|
|
882
978
|
const previewsHtml = screenshots.map(
|
|
883
979
|
(shot, i) => `
|
|
884
980
|
<div class="fb-sp">
|
|
@@ -889,16 +985,7 @@ function initUseroFeedbackWidget(props) {
|
|
|
889
985
|
).join("");
|
|
890
986
|
const errorHtml = screenshotError ? `<div class="fb-upe">\u26A0 ${escapeHtml(screenshotError)}</div>` : "";
|
|
891
987
|
const limitHtml = atMax ? `<div class="fb-sl">Max ${MAX_SCREENSHOTS}</div>` : "";
|
|
892
|
-
|
|
893
|
-
return `
|
|
894
|
-
<div class="fb-up">
|
|
895
|
-
<input type="file" accept="image/*" data-role="screenshot-input" style="display:none;" aria-label="Choose screenshot" />
|
|
896
|
-
<button type="button" class="fb-upb ${btnDisabled ? "fb-upb--dis" : ""}" data-role="screenshot-pick" ${btnDisabled ? "disabled" : ""} style="border:1px solid ${theme.border};color:${theme.text};">
|
|
897
|
-
${isUploadingScreenshot ? '<span class="fb-ups"></span> Uploading...' : "\u{1F4F7} Add screenshot"}
|
|
898
|
-
</button>
|
|
899
|
-
${extrasHtml}
|
|
900
|
-
</div>
|
|
901
|
-
`;
|
|
988
|
+
return screenshotError || screenshots.length > 0 || atMax ? `<div class="fb-up-extras">${errorHtml}${screenshots.length > 0 ? `<div class="fb-ss">${previewsHtml}</div>` : ""}${limitHtml}</div>` : "";
|
|
902
989
|
})() : "";
|
|
903
990
|
const emailBlockHtml = showEmailOption ? `
|
|
904
991
|
<div class="fb-email">
|
|
@@ -921,8 +1008,11 @@ function initUseroFeedbackWidget(props) {
|
|
|
921
1008
|
<form data-role="form">
|
|
922
1009
|
<div class="fb-es" role="radiogroup" aria-label="Rate experience">${ratingsHtml}</div>
|
|
923
1010
|
<textarea class="fb-ta" data-role="comment" placeholder="${escapeHtml(placeholder)}" aria-label="Comments" maxlength="1000" rows="2" style="border:1px solid ${theme.border};color:${theme.text};background-color:${theme.background};">${escapeHtml(comment)}</textarea>
|
|
924
|
-
<div class="fb-
|
|
925
|
-
|
|
1011
|
+
<div class="fb-toolrow">
|
|
1012
|
+
${uploadBtnHtml}
|
|
1013
|
+
<div class="fb-charcount${lowChars ? " fb-charcount--low" : ""}" data-role="charcount" style="color:${lowChars ? "#dc2626" : theme.text};opacity:${lowChars ? 1 : 0.6};">${remaining} chars remaining</div>
|
|
1014
|
+
</div>
|
|
1015
|
+
${uploadExtrasHtml ? `<div class="fb-up">${uploadExtrasHtml}</div>` : ""}
|
|
926
1016
|
${emailBlockHtml}
|
|
927
1017
|
<button class="fb-sub ${submitDisabled ? "fb-sub--dis" : ""}" type="submit" aria-label="Submit" ${submitDisabled ? "disabled" : ""} style="${submitStyle}">
|
|
928
1018
|
${isSubmitting ? '<span class="fb-spin"></span>' : ""}
|
|
@@ -1053,10 +1143,23 @@ function initUseroFeedbackWidget(props) {
|
|
|
1053
1143
|
destroyed = true;
|
|
1054
1144
|
document.removeEventListener("keydown", onKeyDown);
|
|
1055
1145
|
detachMqlListener();
|
|
1146
|
+
for (const plugin of pluginList) {
|
|
1147
|
+
if (!plugin.onDestroy) continue;
|
|
1148
|
+
const ctx = pluginContexts.get(plugin.name);
|
|
1149
|
+
if (!ctx) continue;
|
|
1150
|
+
try {
|
|
1151
|
+
plugin.onDestroy(ctx);
|
|
1152
|
+
} catch (err) {
|
|
1153
|
+
ctx.logger.error("onDestroy threw", err);
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
pluginStores.clear();
|
|
1157
|
+
pluginContexts.clear();
|
|
1056
1158
|
host.remove();
|
|
1057
1159
|
},
|
|
1058
1160
|
open,
|
|
1059
1161
|
close,
|
|
1162
|
+
whenReady: () => readyPromise,
|
|
1060
1163
|
update: (next) => {
|
|
1061
1164
|
if (destroyed) return;
|
|
1062
1165
|
let needsRender = false;
|
|
@@ -1101,6 +1204,7 @@ function initUseroFeedbackWidget(props) {
|
|
|
1101
1204
|
exports.DARK_THEME = DARK_THEME;
|
|
1102
1205
|
exports.DEFAULT_THEME = DEFAULT_THEME;
|
|
1103
1206
|
exports.initUseroFeedbackWidget = initUseroFeedbackWidget;
|
|
1207
|
+
exports.mergePluginPatches = mergePluginPatches;
|
|
1104
1208
|
exports.mergeTheme = mergeTheme;
|
|
1105
1209
|
exports.resolveTheme = resolveTheme;
|
|
1106
1210
|
//# sourceMappingURL=vanilla.cjs.map
|