@fullsession.io/fs-feedback-widget 1.12.0 → 1.14.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.14.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,14 @@
32
32
 
33
33
 
34
34
  .fs-thanks-txt {
35
- width: 61%;
36
- padding: 20px 0;
35
+ max-width: 100%;
36
+ padding: 20px;
37
37
  text-align: center;
38
38
  align-self: center;
39
- padding-bottom: 20px;
40
- overflow: hidden;
39
+ padding-bottom: 30px;
40
+ overflow-y: auto;
41
+ max-height: 100%;
42
+ margin: auto;
41
43
  }
42
44
 
43
45
  fsContainerApp {
@@ -107,6 +109,7 @@ fsContainerApp {
107
109
  margin-left: var(--widgetMarginLeft);
108
110
  -webkit-box-shadow: rgba(0, 0, 0, 0.35) 0px 6px 100px 0px;
109
111
  box-shadow: rgba(0, 0, 0, 0.35) 0px 6px 100px 0px;
112
+ box-sizing: border-box;
110
113
  }
111
114
 
112
115
  .fsContModal {
@@ -121,7 +124,10 @@ fsContainerApp {
121
124
  display: flex;
122
125
  flex-direction: column;
123
126
  pointer-events: auto;
124
- height: auto;
127
+ width: 320px;
128
+ min-height: 100px;
129
+ max-height: 250px;
130
+ border-radius: 5px;
125
131
  background-color: rgb(255, 255, 255);
126
132
  margin-right: var(--widgetMarginRight);
127
133
  margin-left: var(--widgetMarginLeft);
@@ -134,7 +140,7 @@ fsContainerApp {
134
140
  color: #ffff;
135
141
  font-weight: 300;
136
142
  cursor: pointer;
137
- margin-top: 2px;
143
+ margin: auto;
138
144
  }
139
145
 
140
146
  .fsCloseCont {
@@ -155,12 +161,94 @@ fsContainerApp {
155
161
  margin-left: 90% !important;
156
162
  }
157
163
 
164
+ /* Mobile Responsive Styles */
165
+ @media (max-width: 768px) {
166
+ .fsCont {
167
+ width: 90vw;
168
+ max-width: 320px;
169
+ margin-right: 5vw;
170
+ margin-left: 5vw;
171
+ box-sizing: border-box;
172
+ }
173
+
174
+ .fsContNps {
175
+ width: 95vw !important;
176
+ max-width: 400px;
177
+ box-sizing: border-box;
178
+ }
179
+
180
+ .fsThanksMessageCont {
181
+ width: 90vw;
182
+ max-width: 320px;
183
+ margin-right: 5vw;
184
+ margin-left: 5vw;
185
+ box-sizing: border-box;
186
+ }
187
+
188
+ .fsWidget {
189
+ width: 32px;
190
+ height: 110px;
191
+ }
192
+
193
+ #fsFeedbackTxt {
194
+ font-size: 13px;
195
+ }
196
+
197
+ .fsCloseCont {
198
+ margin-left: 82%;
199
+ }
200
+
201
+ .fsNpsCloseCont {
202
+ margin-left: 88% !important;
203
+ }
204
+
205
+ .fs-thanks-txt {
206
+ max-width: 100%;
207
+ padding: 15px 15px 25px;
208
+ font-size: 14px;
209
+ }
210
+ }
158
211
 
159
-
160
-
161
-
162
- /* @media (min-width: 640px) {
163
- body {
164
- max-width: none;
165
- }
166
- } */
212
+ @media (max-width: 480px) {
213
+ .fsCont {
214
+ width: 95vw;
215
+ max-width: 300px;
216
+ box-sizing: border-box;
217
+ }
218
+
219
+ .fsContNps {
220
+ width: 98vw !important;
221
+ max-width: 380px;
222
+ box-sizing: border-box;
223
+ }
224
+
225
+ .fsThanksMessageCont {
226
+ width: 95vw;
227
+ max-width: 300px;
228
+ box-sizing: border-box;
229
+ }
230
+
231
+ .fsWidget {
232
+ width: 30px;
233
+ height: 100px;
234
+ }
235
+
236
+ #fsFeedbackTxt {
237
+ font-size: 12px;
238
+ }
239
+
240
+ .fsCloseCont {
241
+ width: 24px;
242
+ height: 24px;
243
+ margin-left: 80%;
244
+ }
245
+
246
+ #fsCloseIcon {
247
+ font-size: 13px;
248
+ }
249
+
250
+ .fs-thanks-txt {
251
+ font-size: 13px;
252
+ padding: 12px 12px 22px;
253
+ }
254
+ }
@@ -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>