@inploi/plugin-feedback 6.1.0 → 6.2.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/cdn/index.js +5 -5
- package/dist/components/feedback-widget.test.d.ts +1 -0
- package/dist/feedback.d.ts +11 -0
- package/dist/i18n.d.ts +18 -0
- package/dist/plugin-feedback.cjs +97 -28
- package/dist/plugin-feedback.js +97 -28
- package/package.json +4 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/feedback.d.ts
CHANGED
|
@@ -31,9 +31,18 @@ export type FeedbackPluginParams = {
|
|
|
31
31
|
negative: PaletteParams;
|
|
32
32
|
};
|
|
33
33
|
terms: Partial<FeedbackTranslationTerms>;
|
|
34
|
+
locale?: string;
|
|
34
35
|
size: 'sm' | 'md' | 'lg';
|
|
36
|
+
/**
|
|
37
|
+
* The rating to show, for a host that draws the same key's ratings in more than one place: each follows the one
|
|
38
|
+
* rating (pass back what `onScore` reports). Absent, the widget keeps its own.
|
|
39
|
+
*/
|
|
40
|
+
score?: 0 | 1 | -1;
|
|
35
41
|
onLeaveComment?: () => void;
|
|
42
|
+
/** A rating, once it has been logged. */
|
|
36
43
|
onRate?: (rate: 0 | 1 | -1) => void;
|
|
44
|
+
/** The rating as it's pressed (1 or -1), or cleared (0: pressed again, which logs nothing, or its log failed). */
|
|
45
|
+
onScore?: (score: 0 | 1 | -1) => void;
|
|
37
46
|
};
|
|
38
47
|
export interface FeedbackPluginRenderParams extends FeedbackPluginParams {
|
|
39
48
|
host?: HTMLElement;
|
|
@@ -62,6 +71,8 @@ export declare const feedbackPlugin: () => ({ apiClient, logger, analytics }: {
|
|
|
62
71
|
}>;
|
|
63
72
|
/** Renders the Job Alerts Plugin inside the container element. */
|
|
64
73
|
render: (params: FeedbackPluginRenderParams) => Promise<void>;
|
|
74
|
+
/** Release one target's widget (and its portals), leaving any other target's. */
|
|
75
|
+
unmount: (target: HTMLElement) => void;
|
|
65
76
|
/** Release components, portals and document listeners when an owning widget unmounts. */
|
|
66
77
|
destroy: () => void;
|
|
67
78
|
'~brand': "@inploi/plugin-feedback";
|
package/dist/i18n.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export declare const TranslationProvider: (props: {
|
|
2
2
|
terms?: Partial<import('@inploi/i18n/translation').TranslationDict<{
|
|
3
3
|
readonly a11y_label: "How was your experience?";
|
|
4
|
+
readonly positive_label: "Good";
|
|
5
|
+
readonly negative_label: "Bad";
|
|
4
6
|
readonly positive_heading: "Thanks!";
|
|
5
7
|
readonly negative_heading: "We’re sorry to hear that";
|
|
6
8
|
readonly positive_text: "Would you like to tell us more about your experience?";
|
|
@@ -10,11 +12,14 @@ export declare const TranslationProvider: (props: {
|
|
|
10
12
|
readonly skip: "No, thanks";
|
|
11
13
|
readonly submitted_heading: "Thank you!";
|
|
12
14
|
readonly submitted_text: "Your feedback has been sent and will be used to improve our products.";
|
|
15
|
+
readonly comment_minimum: "Please type more characters in the comment box";
|
|
13
16
|
}>> | undefined;
|
|
14
17
|
locale: string | undefined;
|
|
15
18
|
children?: import('preact').ComponentChildren;
|
|
16
19
|
}) => import("preact").JSX.Element, createTFunction: <T extends {
|
|
17
20
|
readonly a11y_label: "How was your experience?";
|
|
21
|
+
readonly positive_label: "Good";
|
|
22
|
+
readonly negative_label: "Bad";
|
|
18
23
|
readonly positive_heading: "Thanks!";
|
|
19
24
|
readonly negative_heading: "We’re sorry to hear that";
|
|
20
25
|
readonly positive_text: "Would you like to tell us more about your experience?";
|
|
@@ -24,8 +29,11 @@ export declare const TranslationProvider: (props: {
|
|
|
24
29
|
readonly skip: "No, thanks";
|
|
25
30
|
readonly submitted_heading: "Thank you!";
|
|
26
31
|
readonly submitted_text: "Your feedback has been sent and will be used to improve our products.";
|
|
32
|
+
readonly comment_minimum: "Please type more characters in the comment box";
|
|
27
33
|
} = {
|
|
28
34
|
readonly a11y_label: "How was your experience?";
|
|
35
|
+
readonly positive_label: "Good";
|
|
36
|
+
readonly negative_label: "Bad";
|
|
29
37
|
readonly positive_heading: "Thanks!";
|
|
30
38
|
readonly negative_heading: "We’re sorry to hear that";
|
|
31
39
|
readonly positive_text: "Would you like to tell us more about your experience?";
|
|
@@ -35,9 +43,12 @@ export declare const TranslationProvider: (props: {
|
|
|
35
43
|
readonly skip: "No, thanks";
|
|
36
44
|
readonly submitted_heading: "Thank you!";
|
|
37
45
|
readonly submitted_text: "Your feedback has been sent and will be used to improve our products.";
|
|
46
|
+
readonly comment_minimum: "Please type more characters in the comment box";
|
|
38
47
|
}>(options: {
|
|
39
48
|
overrides: Partial<import('@inploi/i18n/translation').TranslationDict<{
|
|
40
49
|
readonly a11y_label: "How was your experience?";
|
|
50
|
+
readonly positive_label: "Good";
|
|
51
|
+
readonly negative_label: "Bad";
|
|
41
52
|
readonly positive_heading: "Thanks!";
|
|
42
53
|
readonly negative_heading: "We’re sorry to hear that";
|
|
43
54
|
readonly positive_text: "Would you like to tell us more about your experience?";
|
|
@@ -47,10 +58,13 @@ export declare const TranslationProvider: (props: {
|
|
|
47
58
|
readonly skip: "No, thanks";
|
|
48
59
|
readonly submitted_heading: "Thank you!";
|
|
49
60
|
readonly submitted_text: "Your feedback has been sent and will be used to improve our products.";
|
|
61
|
+
readonly comment_minimum: "Please type more characters in the comment box";
|
|
50
62
|
}>>;
|
|
51
63
|
locale: string | undefined;
|
|
52
64
|
}) => import('@inploi/i18n/translation').TFn<T>, useTranslation: <T extends {
|
|
53
65
|
readonly a11y_label: "How was your experience?";
|
|
66
|
+
readonly positive_label: "Good";
|
|
67
|
+
readonly negative_label: "Bad";
|
|
54
68
|
readonly positive_heading: "Thanks!";
|
|
55
69
|
readonly negative_heading: "We’re sorry to hear that";
|
|
56
70
|
readonly positive_text: "Would you like to tell us more about your experience?";
|
|
@@ -60,8 +74,11 @@ export declare const TranslationProvider: (props: {
|
|
|
60
74
|
readonly skip: "No, thanks";
|
|
61
75
|
readonly submitted_heading: "Thank you!";
|
|
62
76
|
readonly submitted_text: "Your feedback has been sent and will be used to improve our products.";
|
|
77
|
+
readonly comment_minimum: "Please type more characters in the comment box";
|
|
63
78
|
} = {
|
|
64
79
|
readonly a11y_label: "How was your experience?";
|
|
80
|
+
readonly positive_label: "Good";
|
|
81
|
+
readonly negative_label: "Bad";
|
|
65
82
|
readonly positive_heading: "Thanks!";
|
|
66
83
|
readonly negative_heading: "We’re sorry to hear that";
|
|
67
84
|
readonly positive_text: "Would you like to tell us more about your experience?";
|
|
@@ -71,6 +88,7 @@ export declare const TranslationProvider: (props: {
|
|
|
71
88
|
readonly skip: "No, thanks";
|
|
72
89
|
readonly submitted_heading: "Thank you!";
|
|
73
90
|
readonly submitted_text: "Your feedback has been sent and will be used to improve our products.";
|
|
91
|
+
readonly comment_minimum: "Please type more characters in the comment box";
|
|
74
92
|
}>() => {
|
|
75
93
|
t: import('@inploi/i18n/translation').TFn<T>;
|
|
76
94
|
locale: string | undefined;
|
package/dist/plugin-feedback.cjs
CHANGED
|
@@ -5348,6 +5348,8 @@ var createTranslation = (defaultTerms) => {
|
|
|
5348
5348
|
};
|
|
5349
5349
|
const { TranslationProvider, createTFunction, useTranslation } = createTranslation({
|
|
5350
5350
|
a11y_label: "How was your experience?",
|
|
5351
|
+
positive_label: "Good",
|
|
5352
|
+
negative_label: "Bad",
|
|
5351
5353
|
positive_heading: "Thanks!",
|
|
5352
5354
|
negative_heading: "We’re sorry to hear that",
|
|
5353
5355
|
positive_text: "Would you like to tell us more about your experience?",
|
|
@@ -5356,7 +5358,8 @@ const { TranslationProvider, createTFunction, useTranslation } = createTranslati
|
|
|
5356
5358
|
submitting: "Sending feedback...",
|
|
5357
5359
|
skip: "No, thanks",
|
|
5358
5360
|
submitted_heading: "Thank you!",
|
|
5359
|
-
submitted_text: "Your feedback has been sent and will be used to improve our products."
|
|
5361
|
+
submitted_text: "Your feedback has been sent and will be used to improve our products.",
|
|
5362
|
+
comment_minimum: "Please type more characters in the comment box"
|
|
5360
5363
|
});
|
|
5361
5364
|
var COLOR_SHADES = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"];
|
|
5362
5365
|
var OKLCH_PRESETS = {
|
|
@@ -5617,12 +5620,12 @@ function noop() {
|
|
|
5617
5620
|
}
|
|
5618
5621
|
const options = [
|
|
5619
5622
|
{
|
|
5620
|
-
label: "
|
|
5623
|
+
label: "positive_label",
|
|
5621
5624
|
icon: /* @__PURE__ */ u$1(Icon, { name: "happy" }),
|
|
5622
5625
|
value: 1,
|
|
5623
5626
|
variant: "positive"
|
|
5624
5627
|
},
|
|
5625
|
-
{ label: "
|
|
5628
|
+
{ label: "negative_label", icon: /* @__PURE__ */ u$1(Icon, { name: "sad" }), value: -1, variant: "negative" }
|
|
5626
5629
|
];
|
|
5627
5630
|
const submitWithMetaEnter = (e2) => {
|
|
5628
5631
|
const isSubmitCombo = e2.key === "Enter" && e2.metaKey;
|
|
@@ -5640,41 +5643,65 @@ const Label = () => {
|
|
|
5640
5643
|
const FeedbackWidget = ({ analytics, params, logger }) => {
|
|
5641
5644
|
const variants = getThemeVariants(params.theme).join(" ");
|
|
5642
5645
|
const id = g$1();
|
|
5643
|
-
const
|
|
5646
|
+
const ratings = A$1(null);
|
|
5647
|
+
const t2 = T$1(
|
|
5648
|
+
() => createTFunction({ overrides: params.terms ?? {}, locale: params.locale }),
|
|
5649
|
+
[params.terms, params.locale]
|
|
5650
|
+
);
|
|
5651
|
+
const [score, setScore] = d(params.score ?? 0);
|
|
5652
|
+
const presses = A$1(0);
|
|
5653
|
+
const held = A$1(params.score);
|
|
5654
|
+
held.current = params.score;
|
|
5655
|
+
y(() => {
|
|
5656
|
+
if (params.score !== void 0)
|
|
5657
|
+
setScore(params.score);
|
|
5658
|
+
}, [params.score]);
|
|
5644
5659
|
const [open, setOpen] = d();
|
|
5645
|
-
return /* @__PURE__ */ u$1(TranslationProvider, { locale:
|
|
5660
|
+
return /* @__PURE__ */ u$1(TranslationProvider, { locale: params.locale, terms: params.terms, children: /* @__PURE__ */ u$1("div", { role: "group", "aria-labelledby": `${id}-label`, class: variants, children: [
|
|
5646
5661
|
/* @__PURE__ */ u$1("span", { id: `${id}-label`, className: "sr-only", children: /* @__PURE__ */ u$1(Label, {}) }),
|
|
5647
|
-
/* @__PURE__ */ u$1("div", { class: "isolate flex", children: options.map((option) => /* @__PURE__ */ u$1(
|
|
5662
|
+
/* @__PURE__ */ u$1("div", { ref: ratings, class: "isolate flex", children: options.map((option) => /* @__PURE__ */ u$1(
|
|
5648
5663
|
$cb5cc270b50c6fcd$export$be92b6f5f03c0fe9,
|
|
5649
5664
|
{
|
|
5650
5665
|
open: open === option.value,
|
|
5651
|
-
onOpenChange: () => {
|
|
5652
|
-
if (
|
|
5653
|
-
|
|
5654
|
-
|
|
5666
|
+
onOpenChange: (next) => {
|
|
5667
|
+
if (next)
|
|
5668
|
+
setOpen(option.value);
|
|
5669
|
+
else
|
|
5670
|
+
setOpen((current) => current === option.value ? void 0 : current);
|
|
5655
5671
|
},
|
|
5656
5672
|
children: [
|
|
5657
5673
|
/* @__PURE__ */ u$1(
|
|
5658
5674
|
$cb5cc270b50c6fcd$export$41fb9f06171c75f4,
|
|
5659
5675
|
{
|
|
5660
|
-
"aria-label": option.label,
|
|
5676
|
+
"aria-label": t2(option.label),
|
|
5661
5677
|
"aria-pressed": score === option.value,
|
|
5662
5678
|
class: buttonClass({ colorScheme: option.variant, size: params.size }),
|
|
5663
5679
|
onClick: (e2) => {
|
|
5680
|
+
var _a, _b;
|
|
5664
5681
|
const newVal = option.value === score ? 0 : option.value;
|
|
5682
|
+
const press = ++presses.current;
|
|
5665
5683
|
setScore(newVal);
|
|
5666
5684
|
if (newVal === 0) {
|
|
5667
5685
|
e2.preventDefault();
|
|
5668
5686
|
setOpen(void 0);
|
|
5687
|
+
(_a = params.onScore) == null ? void 0 : _a.call(params, 0);
|
|
5669
5688
|
return;
|
|
5670
5689
|
}
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
(
|
|
5674
|
-
|
|
5675
|
-
|
|
5676
|
-
|
|
5677
|
-
|
|
5690
|
+
(_b = params.onScore) == null ? void 0 : _b.call(params, newVal);
|
|
5691
|
+
analytics.log({ event: "FEEDBACK", properties: { key: params.key, score: newVal } }).then(
|
|
5692
|
+
() => {
|
|
5693
|
+
var _a2;
|
|
5694
|
+
return (_a2 = params.onRate) == null ? void 0 : _a2.call(params, newVal);
|
|
5695
|
+
},
|
|
5696
|
+
(e22) => {
|
|
5697
|
+
var _a2;
|
|
5698
|
+
logger.error(e22);
|
|
5699
|
+
if (press !== presses.current || held.current !== void 0 && held.current !== newVal)
|
|
5700
|
+
return;
|
|
5701
|
+
setScore(0);
|
|
5702
|
+
(_a2 = params.onScore) == null ? void 0 : _a2.call(params, 0);
|
|
5703
|
+
}
|
|
5704
|
+
);
|
|
5678
5705
|
},
|
|
5679
5706
|
children: /* @__PURE__ */ u$1("div", { class: "ease-expo-out duration-medium scale-75 transition-transform group-aria-[pressed=true]:scale-100", children: option.icon })
|
|
5680
5707
|
}
|
|
@@ -5682,10 +5709,26 @@ const FeedbackWidget = ({ analytics, params, logger }) => {
|
|
|
5682
5709
|
/* @__PURE__ */ u$1($cb5cc270b50c6fcd$export$602eac185826482c, { container: params.host, children: /* @__PURE__ */ u$1("div", { "data-widget": FEEDBACK_WIDGET_ID, "data-key": params.key, children: /* @__PURE__ */ u$1("div", { class: clsx$1("absolute isolate z-50", variants), children: /* @__PURE__ */ u$1(
|
|
5683
5710
|
$cb5cc270b50c6fcd$export$7c6e2c02157bb7d2,
|
|
5684
5711
|
{
|
|
5712
|
+
"aria-labelledby": `${id}-${option.value}-heading`,
|
|
5713
|
+
onInteractOutside: (event) => {
|
|
5714
|
+
var _a;
|
|
5715
|
+
const target = event.detail.originalEvent.target;
|
|
5716
|
+
if (target instanceof Element && ((_a = ratings.current) == null ? void 0 : _a.contains(target.closest("button[aria-pressed]"))))
|
|
5717
|
+
event.preventDefault();
|
|
5718
|
+
},
|
|
5685
5719
|
collisionPadding: 16,
|
|
5686
5720
|
class: "data-[state=open]:animate-slideDownAndFade bg-lowest ring-neutral-5 shadow-surface-lg isolate w-64 max-w-[var(--radix-popover-content-available-width)] rounded-lg p-2 ring-1 will-change-[transform,opacity]",
|
|
5687
5721
|
sideOffset: 5,
|
|
5688
|
-
children: /* @__PURE__ */ u$1(
|
|
5722
|
+
children: /* @__PURE__ */ u$1(
|
|
5723
|
+
CommentForm,
|
|
5724
|
+
{
|
|
5725
|
+
analytics,
|
|
5726
|
+
params,
|
|
5727
|
+
onClose: () => setOpen(0),
|
|
5728
|
+
score,
|
|
5729
|
+
headingId: `${id}-${option.value}-heading`
|
|
5730
|
+
}
|
|
5731
|
+
)
|
|
5689
5732
|
}
|
|
5690
5733
|
) }) }) })
|
|
5691
5734
|
]
|
|
@@ -5698,20 +5741,40 @@ const CommentForm = ({
|
|
|
5698
5741
|
params,
|
|
5699
5742
|
onClose,
|
|
5700
5743
|
score,
|
|
5701
|
-
analytics
|
|
5744
|
+
analytics,
|
|
5745
|
+
headingId
|
|
5702
5746
|
}) => {
|
|
5703
5747
|
const { t: t2 } = useTranslation();
|
|
5704
5748
|
const id = g$1();
|
|
5749
|
+
const form = A$1(null);
|
|
5750
|
+
const success = A$1(null);
|
|
5751
|
+
const transferFocus = A$1(false);
|
|
5705
5752
|
const [submission, setSubmission] = d({ state: "idle" });
|
|
5753
|
+
_(() => {
|
|
5754
|
+
var _a;
|
|
5755
|
+
if (submission.state === "success" && transferFocus.current)
|
|
5756
|
+
(_a = success.current) == null ? void 0 : _a.focus({ preventScroll: true });
|
|
5757
|
+
}, [submission.state]);
|
|
5706
5758
|
if (submission.state === "success") {
|
|
5707
|
-
return /* @__PURE__ */ u$1(
|
|
5708
|
-
|
|
5709
|
-
|
|
5710
|
-
|
|
5759
|
+
return /* @__PURE__ */ u$1(
|
|
5760
|
+
"div",
|
|
5761
|
+
{
|
|
5762
|
+
ref: success,
|
|
5763
|
+
tabIndex: -1,
|
|
5764
|
+
role: "status",
|
|
5765
|
+
"aria-labelledby": headingId,
|
|
5766
|
+
class: "flex flex-col gap-1 text-balance p-4 text-center",
|
|
5767
|
+
children: [
|
|
5768
|
+
/* @__PURE__ */ u$1("p", { id: headingId, class: "text-neutral-12 text-pretty text-base font-semibold leading-tight tracking-tight", children: t2("submitted_heading") }),
|
|
5769
|
+
/* @__PURE__ */ u$1("p", { class: "text-neutral-11 text-pretty text-sm leading-tight", children: t2("submitted_text") })
|
|
5770
|
+
]
|
|
5771
|
+
}
|
|
5772
|
+
);
|
|
5711
5773
|
}
|
|
5712
5774
|
return /* @__PURE__ */ u$1(
|
|
5713
5775
|
"form",
|
|
5714
5776
|
{
|
|
5777
|
+
ref: form,
|
|
5715
5778
|
class: "flex flex-col gap-2.5 p-2",
|
|
5716
5779
|
onSubmit: (e2) => {
|
|
5717
5780
|
e2.preventDefault();
|
|
@@ -5719,7 +5782,7 @@ const CommentForm = ({
|
|
|
5719
5782
|
const formData = new FormData(e2.currentTarget);
|
|
5720
5783
|
const comment = formData.get("comment");
|
|
5721
5784
|
if (typeof comment !== "string" || comment.length <= 5) {
|
|
5722
|
-
setSubmission({ state: "error", error: "
|
|
5785
|
+
setSubmission({ state: "error", error: t2("comment_minimum") });
|
|
5723
5786
|
return;
|
|
5724
5787
|
}
|
|
5725
5788
|
Promise.all([
|
|
@@ -5727,8 +5790,9 @@ const CommentForm = ({
|
|
|
5727
5790
|
/** Min delay of 500ms so it feels like it’s doing stuff */
|
|
5728
5791
|
new Promise((resolve) => setTimeout(resolve, 1e3))
|
|
5729
5792
|
]).then(() => {
|
|
5730
|
-
var _a;
|
|
5793
|
+
var _a, _b, _c;
|
|
5731
5794
|
(_a = params.onLeaveComment) == null ? void 0 : _a.call(params);
|
|
5795
|
+
transferFocus.current = Boolean((_c = (_b = form.current) == null ? void 0 : _b.closest('[role="dialog"]')) == null ? void 0 : _c.contains(document.activeElement));
|
|
5732
5796
|
setSubmission({ state: "success" });
|
|
5733
5797
|
}).catch((e22) => {
|
|
5734
5798
|
if (e22 instanceof Error) {
|
|
@@ -5742,7 +5806,7 @@ const CommentForm = ({
|
|
|
5742
5806
|
/* @__PURE__ */ u$1("input", { type: "hidden", name: "key", value: params.key }),
|
|
5743
5807
|
/* @__PURE__ */ u$1("fieldset", { class: "flex flex-col gap-4", children: [
|
|
5744
5808
|
/* @__PURE__ */ u$1("label", { htmlFor: id, class: "flex flex-col gap-1", children: [
|
|
5745
|
-
/* @__PURE__ */ u$1("p", { class: "text-neutral-12 text-pretty text-base font-semibold leading-tight tracking-tight", children: t2(score === -1 ? "negative_heading" : "positive_heading") }),
|
|
5809
|
+
/* @__PURE__ */ u$1("p", { id: headingId, class: "text-neutral-12 text-pretty text-base font-semibold leading-tight tracking-tight", children: t2(score === -1 ? "negative_heading" : "positive_heading") }),
|
|
5746
5810
|
/* @__PURE__ */ u$1("p", { class: "text-neutral-11 text-pretty text-sm leading-tight", children: t2(score === -1 ? "negative_text" : "positive_text") })
|
|
5747
5811
|
] }),
|
|
5748
5812
|
/* @__PURE__ */ u$1("div", { class: "flex flex-col gap-2", children: [
|
|
@@ -5756,7 +5820,7 @@ const CommentForm = ({
|
|
|
5756
5820
|
id
|
|
5757
5821
|
}
|
|
5758
5822
|
),
|
|
5759
|
-
submission.state === "error" ? /* @__PURE__ */ u$1("div", { role: "alert", class: "
|
|
5823
|
+
submission.state === "error" ? /* @__PURE__ */ u$1("div", { role: "alert", class: "flex gap-1 text-balance text-xs", children: [
|
|
5760
5824
|
/* @__PURE__ */ u$1(Icon, { name: "warning", class: "size-[1lh] flex-none" }),
|
|
5761
5825
|
submission.error
|
|
5762
5826
|
] }) : null
|
|
@@ -6760,6 +6824,11 @@ const feedbackPlugin = () => sdk.createPlugin(({ apiClient, logger, analytics })
|
|
|
6760
6824
|
targets.add(target);
|
|
6761
6825
|
fn2(_$2(App, { params }), target);
|
|
6762
6826
|
},
|
|
6827
|
+
/** Release one target's widget (and its portals), leaving any other target's. */
|
|
6828
|
+
unmount: (target) => {
|
|
6829
|
+
J$1(null, target);
|
|
6830
|
+
targets.delete(target);
|
|
6831
|
+
},
|
|
6763
6832
|
/** Release components, portals and document listeners when an owning widget unmounts. */
|
|
6764
6833
|
destroy: () => {
|
|
6765
6834
|
for (const target of targets)
|
package/dist/plugin-feedback.js
CHANGED
|
@@ -5346,6 +5346,8 @@ var createTranslation = (defaultTerms) => {
|
|
|
5346
5346
|
};
|
|
5347
5347
|
const { TranslationProvider, createTFunction, useTranslation } = createTranslation({
|
|
5348
5348
|
a11y_label: "How was your experience?",
|
|
5349
|
+
positive_label: "Good",
|
|
5350
|
+
negative_label: "Bad",
|
|
5349
5351
|
positive_heading: "Thanks!",
|
|
5350
5352
|
negative_heading: "We’re sorry to hear that",
|
|
5351
5353
|
positive_text: "Would you like to tell us more about your experience?",
|
|
@@ -5354,7 +5356,8 @@ const { TranslationProvider, createTFunction, useTranslation } = createTranslati
|
|
|
5354
5356
|
submitting: "Sending feedback...",
|
|
5355
5357
|
skip: "No, thanks",
|
|
5356
5358
|
submitted_heading: "Thank you!",
|
|
5357
|
-
submitted_text: "Your feedback has been sent and will be used to improve our products."
|
|
5359
|
+
submitted_text: "Your feedback has been sent and will be used to improve our products.",
|
|
5360
|
+
comment_minimum: "Please type more characters in the comment box"
|
|
5358
5361
|
});
|
|
5359
5362
|
var COLOR_SHADES = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"];
|
|
5360
5363
|
var OKLCH_PRESETS = {
|
|
@@ -5615,12 +5618,12 @@ function noop() {
|
|
|
5615
5618
|
}
|
|
5616
5619
|
const options = [
|
|
5617
5620
|
{
|
|
5618
|
-
label: "
|
|
5621
|
+
label: "positive_label",
|
|
5619
5622
|
icon: /* @__PURE__ */ u$1(Icon, { name: "happy" }),
|
|
5620
5623
|
value: 1,
|
|
5621
5624
|
variant: "positive"
|
|
5622
5625
|
},
|
|
5623
|
-
{ label: "
|
|
5626
|
+
{ label: "negative_label", icon: /* @__PURE__ */ u$1(Icon, { name: "sad" }), value: -1, variant: "negative" }
|
|
5624
5627
|
];
|
|
5625
5628
|
const submitWithMetaEnter = (e2) => {
|
|
5626
5629
|
const isSubmitCombo = e2.key === "Enter" && e2.metaKey;
|
|
@@ -5638,41 +5641,65 @@ const Label = () => {
|
|
|
5638
5641
|
const FeedbackWidget = ({ analytics, params, logger }) => {
|
|
5639
5642
|
const variants = getThemeVariants(params.theme).join(" ");
|
|
5640
5643
|
const id = g$1();
|
|
5641
|
-
const
|
|
5644
|
+
const ratings = A$1(null);
|
|
5645
|
+
const t2 = T$1(
|
|
5646
|
+
() => createTFunction({ overrides: params.terms ?? {}, locale: params.locale }),
|
|
5647
|
+
[params.terms, params.locale]
|
|
5648
|
+
);
|
|
5649
|
+
const [score, setScore] = d(params.score ?? 0);
|
|
5650
|
+
const presses = A$1(0);
|
|
5651
|
+
const held = A$1(params.score);
|
|
5652
|
+
held.current = params.score;
|
|
5653
|
+
y(() => {
|
|
5654
|
+
if (params.score !== void 0)
|
|
5655
|
+
setScore(params.score);
|
|
5656
|
+
}, [params.score]);
|
|
5642
5657
|
const [open, setOpen] = d();
|
|
5643
|
-
return /* @__PURE__ */ u$1(TranslationProvider, { locale:
|
|
5658
|
+
return /* @__PURE__ */ u$1(TranslationProvider, { locale: params.locale, terms: params.terms, children: /* @__PURE__ */ u$1("div", { role: "group", "aria-labelledby": `${id}-label`, class: variants, children: [
|
|
5644
5659
|
/* @__PURE__ */ u$1("span", { id: `${id}-label`, className: "sr-only", children: /* @__PURE__ */ u$1(Label, {}) }),
|
|
5645
|
-
/* @__PURE__ */ u$1("div", { class: "isolate flex", children: options.map((option) => /* @__PURE__ */ u$1(
|
|
5660
|
+
/* @__PURE__ */ u$1("div", { ref: ratings, class: "isolate flex", children: options.map((option) => /* @__PURE__ */ u$1(
|
|
5646
5661
|
$cb5cc270b50c6fcd$export$be92b6f5f03c0fe9,
|
|
5647
5662
|
{
|
|
5648
5663
|
open: open === option.value,
|
|
5649
|
-
onOpenChange: () => {
|
|
5650
|
-
if (
|
|
5651
|
-
|
|
5652
|
-
|
|
5664
|
+
onOpenChange: (next) => {
|
|
5665
|
+
if (next)
|
|
5666
|
+
setOpen(option.value);
|
|
5667
|
+
else
|
|
5668
|
+
setOpen((current) => current === option.value ? void 0 : current);
|
|
5653
5669
|
},
|
|
5654
5670
|
children: [
|
|
5655
5671
|
/* @__PURE__ */ u$1(
|
|
5656
5672
|
$cb5cc270b50c6fcd$export$41fb9f06171c75f4,
|
|
5657
5673
|
{
|
|
5658
|
-
"aria-label": option.label,
|
|
5674
|
+
"aria-label": t2(option.label),
|
|
5659
5675
|
"aria-pressed": score === option.value,
|
|
5660
5676
|
class: buttonClass({ colorScheme: option.variant, size: params.size }),
|
|
5661
5677
|
onClick: (e2) => {
|
|
5678
|
+
var _a, _b;
|
|
5662
5679
|
const newVal = option.value === score ? 0 : option.value;
|
|
5680
|
+
const press = ++presses.current;
|
|
5663
5681
|
setScore(newVal);
|
|
5664
5682
|
if (newVal === 0) {
|
|
5665
5683
|
e2.preventDefault();
|
|
5666
5684
|
setOpen(void 0);
|
|
5685
|
+
(_a = params.onScore) == null ? void 0 : _a.call(params, 0);
|
|
5667
5686
|
return;
|
|
5668
5687
|
}
|
|
5669
|
-
|
|
5670
|
-
|
|
5671
|
-
(
|
|
5672
|
-
|
|
5673
|
-
|
|
5674
|
-
|
|
5675
|
-
|
|
5688
|
+
(_b = params.onScore) == null ? void 0 : _b.call(params, newVal);
|
|
5689
|
+
analytics.log({ event: "FEEDBACK", properties: { key: params.key, score: newVal } }).then(
|
|
5690
|
+
() => {
|
|
5691
|
+
var _a2;
|
|
5692
|
+
return (_a2 = params.onRate) == null ? void 0 : _a2.call(params, newVal);
|
|
5693
|
+
},
|
|
5694
|
+
(e22) => {
|
|
5695
|
+
var _a2;
|
|
5696
|
+
logger.error(e22);
|
|
5697
|
+
if (press !== presses.current || held.current !== void 0 && held.current !== newVal)
|
|
5698
|
+
return;
|
|
5699
|
+
setScore(0);
|
|
5700
|
+
(_a2 = params.onScore) == null ? void 0 : _a2.call(params, 0);
|
|
5701
|
+
}
|
|
5702
|
+
);
|
|
5676
5703
|
},
|
|
5677
5704
|
children: /* @__PURE__ */ u$1("div", { class: "ease-expo-out duration-medium scale-75 transition-transform group-aria-[pressed=true]:scale-100", children: option.icon })
|
|
5678
5705
|
}
|
|
@@ -5680,10 +5707,26 @@ const FeedbackWidget = ({ analytics, params, logger }) => {
|
|
|
5680
5707
|
/* @__PURE__ */ u$1($cb5cc270b50c6fcd$export$602eac185826482c, { container: params.host, children: /* @__PURE__ */ u$1("div", { "data-widget": FEEDBACK_WIDGET_ID, "data-key": params.key, children: /* @__PURE__ */ u$1("div", { class: clsx$1("absolute isolate z-50", variants), children: /* @__PURE__ */ u$1(
|
|
5681
5708
|
$cb5cc270b50c6fcd$export$7c6e2c02157bb7d2,
|
|
5682
5709
|
{
|
|
5710
|
+
"aria-labelledby": `${id}-${option.value}-heading`,
|
|
5711
|
+
onInteractOutside: (event) => {
|
|
5712
|
+
var _a;
|
|
5713
|
+
const target = event.detail.originalEvent.target;
|
|
5714
|
+
if (target instanceof Element && ((_a = ratings.current) == null ? void 0 : _a.contains(target.closest("button[aria-pressed]"))))
|
|
5715
|
+
event.preventDefault();
|
|
5716
|
+
},
|
|
5683
5717
|
collisionPadding: 16,
|
|
5684
5718
|
class: "data-[state=open]:animate-slideDownAndFade bg-lowest ring-neutral-5 shadow-surface-lg isolate w-64 max-w-[var(--radix-popover-content-available-width)] rounded-lg p-2 ring-1 will-change-[transform,opacity]",
|
|
5685
5719
|
sideOffset: 5,
|
|
5686
|
-
children: /* @__PURE__ */ u$1(
|
|
5720
|
+
children: /* @__PURE__ */ u$1(
|
|
5721
|
+
CommentForm,
|
|
5722
|
+
{
|
|
5723
|
+
analytics,
|
|
5724
|
+
params,
|
|
5725
|
+
onClose: () => setOpen(0),
|
|
5726
|
+
score,
|
|
5727
|
+
headingId: `${id}-${option.value}-heading`
|
|
5728
|
+
}
|
|
5729
|
+
)
|
|
5687
5730
|
}
|
|
5688
5731
|
) }) }) })
|
|
5689
5732
|
]
|
|
@@ -5696,20 +5739,40 @@ const CommentForm = ({
|
|
|
5696
5739
|
params,
|
|
5697
5740
|
onClose,
|
|
5698
5741
|
score,
|
|
5699
|
-
analytics
|
|
5742
|
+
analytics,
|
|
5743
|
+
headingId
|
|
5700
5744
|
}) => {
|
|
5701
5745
|
const { t: t2 } = useTranslation();
|
|
5702
5746
|
const id = g$1();
|
|
5747
|
+
const form = A$1(null);
|
|
5748
|
+
const success = A$1(null);
|
|
5749
|
+
const transferFocus = A$1(false);
|
|
5703
5750
|
const [submission, setSubmission] = d({ state: "idle" });
|
|
5751
|
+
_(() => {
|
|
5752
|
+
var _a;
|
|
5753
|
+
if (submission.state === "success" && transferFocus.current)
|
|
5754
|
+
(_a = success.current) == null ? void 0 : _a.focus({ preventScroll: true });
|
|
5755
|
+
}, [submission.state]);
|
|
5704
5756
|
if (submission.state === "success") {
|
|
5705
|
-
return /* @__PURE__ */ u$1(
|
|
5706
|
-
|
|
5707
|
-
|
|
5708
|
-
|
|
5757
|
+
return /* @__PURE__ */ u$1(
|
|
5758
|
+
"div",
|
|
5759
|
+
{
|
|
5760
|
+
ref: success,
|
|
5761
|
+
tabIndex: -1,
|
|
5762
|
+
role: "status",
|
|
5763
|
+
"aria-labelledby": headingId,
|
|
5764
|
+
class: "flex flex-col gap-1 text-balance p-4 text-center",
|
|
5765
|
+
children: [
|
|
5766
|
+
/* @__PURE__ */ u$1("p", { id: headingId, class: "text-neutral-12 text-pretty text-base font-semibold leading-tight tracking-tight", children: t2("submitted_heading") }),
|
|
5767
|
+
/* @__PURE__ */ u$1("p", { class: "text-neutral-11 text-pretty text-sm leading-tight", children: t2("submitted_text") })
|
|
5768
|
+
]
|
|
5769
|
+
}
|
|
5770
|
+
);
|
|
5709
5771
|
}
|
|
5710
5772
|
return /* @__PURE__ */ u$1(
|
|
5711
5773
|
"form",
|
|
5712
5774
|
{
|
|
5775
|
+
ref: form,
|
|
5713
5776
|
class: "flex flex-col gap-2.5 p-2",
|
|
5714
5777
|
onSubmit: (e2) => {
|
|
5715
5778
|
e2.preventDefault();
|
|
@@ -5717,7 +5780,7 @@ const CommentForm = ({
|
|
|
5717
5780
|
const formData = new FormData(e2.currentTarget);
|
|
5718
5781
|
const comment = formData.get("comment");
|
|
5719
5782
|
if (typeof comment !== "string" || comment.length <= 5) {
|
|
5720
|
-
setSubmission({ state: "error", error: "
|
|
5783
|
+
setSubmission({ state: "error", error: t2("comment_minimum") });
|
|
5721
5784
|
return;
|
|
5722
5785
|
}
|
|
5723
5786
|
Promise.all([
|
|
@@ -5725,8 +5788,9 @@ const CommentForm = ({
|
|
|
5725
5788
|
/** Min delay of 500ms so it feels like it’s doing stuff */
|
|
5726
5789
|
new Promise((resolve) => setTimeout(resolve, 1e3))
|
|
5727
5790
|
]).then(() => {
|
|
5728
|
-
var _a;
|
|
5791
|
+
var _a, _b, _c;
|
|
5729
5792
|
(_a = params.onLeaveComment) == null ? void 0 : _a.call(params);
|
|
5793
|
+
transferFocus.current = Boolean((_c = (_b = form.current) == null ? void 0 : _b.closest('[role="dialog"]')) == null ? void 0 : _c.contains(document.activeElement));
|
|
5730
5794
|
setSubmission({ state: "success" });
|
|
5731
5795
|
}).catch((e22) => {
|
|
5732
5796
|
if (e22 instanceof Error) {
|
|
@@ -5740,7 +5804,7 @@ const CommentForm = ({
|
|
|
5740
5804
|
/* @__PURE__ */ u$1("input", { type: "hidden", name: "key", value: params.key }),
|
|
5741
5805
|
/* @__PURE__ */ u$1("fieldset", { class: "flex flex-col gap-4", children: [
|
|
5742
5806
|
/* @__PURE__ */ u$1("label", { htmlFor: id, class: "flex flex-col gap-1", children: [
|
|
5743
|
-
/* @__PURE__ */ u$1("p", { class: "text-neutral-12 text-pretty text-base font-semibold leading-tight tracking-tight", children: t2(score === -1 ? "negative_heading" : "positive_heading") }),
|
|
5807
|
+
/* @__PURE__ */ u$1("p", { id: headingId, class: "text-neutral-12 text-pretty text-base font-semibold leading-tight tracking-tight", children: t2(score === -1 ? "negative_heading" : "positive_heading") }),
|
|
5744
5808
|
/* @__PURE__ */ u$1("p", { class: "text-neutral-11 text-pretty text-sm leading-tight", children: t2(score === -1 ? "negative_text" : "positive_text") })
|
|
5745
5809
|
] }),
|
|
5746
5810
|
/* @__PURE__ */ u$1("div", { class: "flex flex-col gap-2", children: [
|
|
@@ -5754,7 +5818,7 @@ const CommentForm = ({
|
|
|
5754
5818
|
id
|
|
5755
5819
|
}
|
|
5756
5820
|
),
|
|
5757
|
-
submission.state === "error" ? /* @__PURE__ */ u$1("div", { role: "alert", class: "
|
|
5821
|
+
submission.state === "error" ? /* @__PURE__ */ u$1("div", { role: "alert", class: "flex gap-1 text-balance text-xs", children: [
|
|
5758
5822
|
/* @__PURE__ */ u$1(Icon, { name: "warning", class: "size-[1lh] flex-none" }),
|
|
5759
5823
|
submission.error
|
|
5760
5824
|
] }) : null
|
|
@@ -6758,6 +6822,11 @@ const feedbackPlugin = () => createPlugin(({ apiClient, logger, analytics }) =>
|
|
|
6758
6822
|
targets.add(target);
|
|
6759
6823
|
fn2(_$2(App, { params }), target);
|
|
6760
6824
|
},
|
|
6825
|
+
/** Release one target's widget (and its portals), leaving any other target's. */
|
|
6826
|
+
unmount: (target) => {
|
|
6827
|
+
J$1(null, target);
|
|
6828
|
+
targets.delete(target);
|
|
6829
|
+
},
|
|
6761
6830
|
/** Release components, portals and document listeners when an owning widget unmounts. */
|
|
6762
6831
|
destroy: () => {
|
|
6763
6832
|
for (const target of targets)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inploi/plugin-feedback",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/plugin-feedback.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -56,9 +56,9 @@
|
|
|
56
56
|
"clsx": "^2.0.0",
|
|
57
57
|
"zustand": "^4.5.2",
|
|
58
58
|
"zustand-context": "^1.0.0",
|
|
59
|
-
"@inploi/core": "1.
|
|
59
|
+
"@inploi/core": "1.22.0",
|
|
60
60
|
"@inploi/design-tokens": "0.2.1",
|
|
61
|
-
"@inploi/sdk": "2.
|
|
61
|
+
"@inploi/sdk": "2.7.0",
|
|
62
62
|
"eslint-config-custom": "0.1.0",
|
|
63
63
|
"@inploi/i18n": "0.1.5"
|
|
64
64
|
},
|
|
@@ -73,6 +73,7 @@
|
|
|
73
73
|
"build:cdn": "VITE_MOCKS=false vite build --mode=cdn",
|
|
74
74
|
"preview": "vite preview",
|
|
75
75
|
"_test": "bun test src/",
|
|
76
|
+
"test:coverage": "bun test src/ --coverage --coverage-reporter=lcov",
|
|
76
77
|
"_test:watch": "bun test src/ --watch",
|
|
77
78
|
"_test:int": "playwright test",
|
|
78
79
|
"_test:ui": "playwright test --ui",
|