@fullsession.io/fs-feedback-widget 1.12.0 → 1.13.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fullsession.io/fs-feedback-widget",
3
- "version": "1.12.0",
3
+ "version": "1.13.0",
4
4
  "scripts": {
5
5
  "build": "rollup -c",
6
6
  "dev": "rollup -c -w",
@@ -5,68 +5,32 @@
5
5
  export let emotIconType;
6
6
  export let width = "40px";
7
7
  export let height = "40px";
8
- let emotIcons =
8
+ // Recompute emotIcons and icons reactively when `emotIconType` changes
9
+ $: emotIcons =
9
10
  emotIconType == "0"
10
11
  ? icons_1
11
12
  : emotIconType == "1"
12
13
  ? icons_2
13
14
  : emotIconType == "2"
14
15
  ? icons_3
15
- : null;
16
- let icons = [
17
- {
18
- box: 50,
19
- name: "love",
20
- svg: emotIcons[0],
21
- },
22
- {
23
- box: 50,
24
- name: "unSelectedLove",
25
- svg: emotIcons[1],
26
- },
27
- {
28
- box: 50,
29
- name: "like",
30
- svg: emotIcons[2],
31
- },
32
- {
33
- box: 50,
34
- name: "unSelectedLike",
35
- svg: emotIcons[3],
36
- },
37
- {
38
- box: 50,
39
- name: "neutral",
40
- svg: emotIcons[4],
41
- },
42
- {
43
- box: 50,
44
- name: "unSelectedNeutral",
45
- svg: emotIcons[5],
46
- },
47
- {
48
- box: 50,
49
- name: "dislike",
50
- svg: emotIcons[6],
51
- },
52
- {
53
- box: 50,
54
- name: "unSelectedDislike",
55
- svg: emotIcons[7],
56
- },
16
+ : icons_1;
57
17
 
58
- {
59
- box: 50,
60
- name: "hate",
61
- svg: emotIcons[8],
62
- },
63
- {
64
- box: 50,
65
- name: "unSelectedHate",
66
- svg: emotIcons[9],
67
- },
68
- ];
69
- let displayIcon = icons.find((e) => e.name === name);
18
+ $: icons = emotIcons
19
+ ? [
20
+ { box: 50, name: "love", svg: emotIcons[0] },
21
+ { box: 50, name: "unSelectedLove", svg: emotIcons[1] },
22
+ { box: 50, name: "like", svg: emotIcons[2] },
23
+ { box: 50, name: "unSelectedLike", svg: emotIcons[3] },
24
+ { box: 50, name: "neutral", svg: emotIcons[4] },
25
+ { box: 50, name: "unSelectedNeutral", svg: emotIcons[5] },
26
+ { box: 50, name: "dislike", svg: emotIcons[6] },
27
+ { box: 50, name: "unSelectedDislike", svg: emotIcons[7] },
28
+ { box: 50, name: "hate", svg: emotIcons[8] },
29
+ { box: 50, name: "unSelectedHate", svg: emotIcons[9] },
30
+ ]
31
+ : [];
32
+
33
+ $: displayIcon = icons.find((e) => e.name === name) || icons[0];
70
34
  </script>
71
35
 
72
36
  {#if emotIconType === "2"}
@@ -32,12 +32,13 @@
32
32
 
33
33
 
34
34
  .fs-thanks-txt {
35
- width: 61%;
36
- padding: 20px 0;
35
+ width: 100%;
36
+ padding: 20px;
37
37
  text-align: center;
38
38
  align-self: center;
39
39
  padding-bottom: 20px;
40
- overflow: hidden;
40
+ overflow-y: auto;
41
+ max-height: 100%;
41
42
  }
42
43
 
43
44
  fsContainerApp {
@@ -121,7 +122,9 @@ fsContainerApp {
121
122
  display: flex;
122
123
  flex-direction: column;
123
124
  pointer-events: auto;
124
- height: auto;
125
+ width: 320px;
126
+ height: 150px;
127
+ border-radius: 5px;
125
128
  background-color: rgb(255, 255, 255);
126
129
  margin-right: var(--widgetMarginRight);
127
130
  margin-left: var(--widgetMarginLeft);
@@ -155,12 +158,88 @@ fsContainerApp {
155
158
  margin-left: 90% !important;
156
159
  }
157
160
 
161
+ /* Mobile Responsive Styles */
162
+ @media (max-width: 768px) {
163
+ .fsCont {
164
+ width: 90vw;
165
+ max-width: 320px;
166
+ margin-right: 5vw;
167
+ margin-left: 5vw;
168
+ }
169
+
170
+ .fsContNps {
171
+ width: 95vw !important;
172
+ max-width: 400px;
173
+ }
174
+
175
+ .fsThanksMessageCont {
176
+ width: 90vw;
177
+ max-width: 320px;
178
+ margin-right: 5vw;
179
+ margin-left: 5vw;
180
+ }
181
+
182
+ .fsWidget {
183
+ width: 32px;
184
+ height: 110px;
185
+ }
186
+
187
+ #fsFeedbackTxt {
188
+ font-size: 13px;
189
+ }
190
+
191
+ .fsCloseCont {
192
+ margin-left: 82%;
193
+ }
194
+
195
+ .fsNpsCloseCont {
196
+ margin-left: 88% !important;
197
+ }
198
+
199
+ .fs-thanks-txt {
200
+ width: 100%;
201
+ padding: 15px;
202
+ font-size: 14px;
203
+ }
204
+ }
158
205
 
159
-
160
-
161
-
162
- /* @media (min-width: 640px) {
163
- body {
164
- max-width: none;
165
- }
166
- } */
206
+ @media (max-width: 480px) {
207
+ .fsCont {
208
+ width: 95vw;
209
+ max-width: 300px;
210
+ }
211
+
212
+ .fsContNps {
213
+ width: 98vw !important;
214
+ max-width: 380px;
215
+ }
216
+
217
+ .fsThanksMessageCont {
218
+ width: 95vw;
219
+ max-width: 300px;
220
+ }
221
+
222
+ .fsWidget {
223
+ width: 30px;
224
+ height: 100px;
225
+ }
226
+
227
+ #fsFeedbackTxt {
228
+ font-size: 12px;
229
+ }
230
+
231
+ .fsCloseCont {
232
+ width: 24px;
233
+ height: 24px;
234
+ margin-left: 80%;
235
+ }
236
+
237
+ #fsCloseIcon {
238
+ font-size: 13px;
239
+ }
240
+
241
+ .fs-thanks-txt {
242
+ font-size: 13px;
243
+ padding: 12px;
244
+ }
245
+ }
@@ -1,6 +1,8 @@
1
1
  <script>
2
2
  import Icons from "../Icons/reactionIcons.svelte";
3
3
  import "../widgetPages/reactionpage.css";
4
+ import { onMount } from "svelte";
5
+
4
6
  export let feedbackData;
5
7
  export let wgType;
6
8
  $: widgetComponent = 1;
@@ -24,27 +26,39 @@
24
26
  $: widgetEmailReqMsg = feedbackData.wgEmailReqMsg;
25
27
  $: widgetPlaceholder = feedbackData.wgFeedbackPlaceholder;
26
28
  $: widgetEmotIconType = feedbackData.wgReactionStyle;
27
- $: document.documentElement.style.setProperty(
28
- "--pointerMargin",
29
- pointerMargin + "%"
30
- );
31
- $: document.documentElement.style.setProperty("--hateDisplay", hateDisplay);
32
- $: document.documentElement.style.setProperty(
33
- "--dislikeDisplay",
34
- dislikeDisplay
35
- );
36
- $: document.documentElement.style.setProperty(
37
- "--neutralDisplay",
38
- neutralDisplay
39
- );
40
- $: document.documentElement.style.setProperty("--likeDisplay", likeDisplay);
41
- $: document.documentElement.style.setProperty("--loveDisplay", loveDisplay);
42
- $: document.documentElement.style.setProperty("--buttonColor", buttonColor);
29
+
30
+ // Set CSS custom properties only once on mount, then update individually as needed
31
+ // This avoids triggering multiple style recalculations on every reactive update
32
+ onMount(() => {
33
+ const root = document.documentElement.style;
34
+ root.setProperty("--pointerMargin", pointerMargin + "%");
35
+ root.setProperty("--hateDisplay", hateDisplay);
36
+ root.setProperty("--dislikeDisplay", dislikeDisplay);
37
+ root.setProperty("--neutralDisplay", neutralDisplay);
38
+ root.setProperty("--likeDisplay", likeDisplay);
39
+ root.setProperty("--loveDisplay", loveDisplay);
40
+ root.setProperty("--buttonColor", buttonColor);
41
+ });
42
+
43
+ // Update CSS properties only when specific values change
44
+ $: if (typeof window !== 'undefined') {
45
+ document.documentElement.style.setProperty("--pointerMargin", pointerMargin + "%");
46
+ }
47
+ $: if (typeof window !== 'undefined') {
48
+ document.documentElement.style.setProperty("--hateDisplay", hateDisplay);
49
+ document.documentElement.style.setProperty("--dislikeDisplay", dislikeDisplay);
50
+ document.documentElement.style.setProperty("--neutralDisplay", neutralDisplay);
51
+ document.documentElement.style.setProperty("--likeDisplay", likeDisplay);
52
+ document.documentElement.style.setProperty("--loveDisplay", loveDisplay);
53
+ }
54
+ $: if (typeof window !== 'undefined') {
55
+ document.documentElement.style.setProperty("--buttonColor", buttonColor);
56
+ }
43
57
 
44
58
  let count = 0;
45
- $: buttonState = false;
59
+ let buttonState = false;
60
+ let emailError = "";
46
61
  let checkTextAreaInterval;
47
- let checkEmailAreaInterval;
48
62
 
49
63
  export let closeHandler = (
50
64
  email,
@@ -54,13 +68,6 @@
54
68
  ) => {};
55
69
  export let closeHandlerBeforeFinishing = (email, comment, reactionType) => {};
56
70
 
57
- // const commentButtonDisable = () =>{
58
-
59
- // let source = document.querySelector(".fsTextArea");
60
-
61
- // source.addEventListener('propertychange', commentHandler);
62
-
63
- // }
64
71
  const commentHandler = () => {
65
72
  let input = document.querySelector(".fsTextArea");
66
73
 
@@ -73,27 +80,30 @@
73
80
  comment = input.value;
74
81
  };
75
82
 
76
- // const EmailButtonDisable = () =>{
77
-
78
- // let source = document.querySelector("#fsEmailTextArea");
79
-
80
- // source.addEventListener('propertychange', emailHandler);
81
-
82
- // }
83
-
84
- const emailHandler = () => {
85
- let input = document.querySelector("#fsEmailTextArea");
83
+ // Ultra-fast email handler - just updates value, no validation during typing
84
+ const emailHandler = (event) => {
85
+ email = event.target.value;
86
+ emailError = ""; // Clear error when user types
87
+ // Enable button if there's any content
88
+ buttonState = email.length > 0;
89
+ };
86
90
 
87
- if (
88
- !/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(input.value) ||
89
- input.value === ""
90
- ) {
91
- buttonState = false; //button remains disabled
92
- } else {
93
- buttonState = true; //button is enabled
94
- email = "";
95
- email = document.getElementById("fsEmailTextArea").value;
91
+ // Validate only when user clicks Send - much better performance
92
+ const validateAndSubmitEmail = () => {
93
+ const trimmedEmail = email.trim();
94
+
95
+ // Quick client-side validation
96
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
97
+
98
+ if (!trimmedEmail || !emailRegex.test(trimmedEmail)) {
99
+ emailError = "Please enter a valid email address";
100
+ buttonState = false;
101
+ return;
96
102
  }
103
+
104
+ // Valid - proceed with submission
105
+ emailError = "";
106
+ closeHandler(email, comment, reactionType, questionAnswer);
97
107
  };
98
108
 
99
109
  const changeStyle = (prevState) => {
@@ -199,8 +209,10 @@
199
209
  };
200
210
 
201
211
  const endEmailInterval = () => {
202
- clearInterval(checkEmailAreaInterval);
203
- document.querySelector("#fsEmailTextArea").value = "";
212
+ const el = document.querySelector("#fsEmailTextArea");
213
+ if (el) el.value = "";
214
+ email = "";
215
+ emailError = "";
204
216
  };
205
217
  </script>
206
218
 
@@ -399,12 +411,16 @@
399
411
  </div>
400
412
  <div id="fsEmailInputCont">
401
413
  <input
402
- type="text"
414
+ type="email"
403
415
  id="fsEmailTextArea"
404
416
  placeholder="email@domain.com"
405
- on:keyup={() => emailHandler()}
417
+ autocomplete="email"
418
+ on:input={emailHandler}
406
419
  />
407
420
  </div>
421
+ {#if emailError}
422
+ <div class="fsEmailError">{emailError}</div>
423
+ {/if}
408
424
  <div class="fsEmailFooter">
409
425
  <p
410
426
  id="fsSkipText"
@@ -420,9 +436,7 @@
420
436
  {:else if buttonState == true}
421
437
  <button
422
438
  class="fsSendButtonContCommentComp"
423
- on:click={() =>
424
- closeHandler(email, comment, reactionType, questionAnswer)}
425
- on:click={() => endEmailInterval()}
439
+ on:click={validateAndSubmitEmail}
426
440
  >
427
441
  <p class="fsSendButtonCommentComponent">Send</p>
428
442
  </button>