makethisbetter 1.9.0 → 1.9.2
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/dist/i18n/de.d.ts +1 -0
- package/dist/i18n/de.d.ts.map +1 -1
- package/dist/i18n/en.d.ts +1 -0
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/es.d.ts +1 -0
- package/dist/i18n/es.d.ts.map +1 -1
- package/dist/i18n/fr.d.ts +1 -0
- package/dist/i18n/fr.d.ts.map +1 -1
- package/dist/i18n/ja.d.ts +1 -0
- package/dist/i18n/ja.d.ts.map +1 -1
- package/dist/i18n/ko.d.ts +1 -0
- package/dist/i18n/ko.d.ts.map +1 -1
- package/dist/i18n/zh-CN.d.ts +1 -0
- package/dist/i18n/zh-CN.d.ts.map +1 -1
- package/dist/makethisbetter.cjs +25 -17
- package/dist/makethisbetter.cjs.map +1 -1
- package/dist/makethisbetter.esm.js +418 -384
- package/dist/makethisbetter.esm.js.map +1 -1
- package/dist/makethisbetter.js +25 -17
- package/dist/makethisbetter.js.map +1 -1
- package/dist/popup/clarify.d.ts +3 -1
- package/dist/popup/clarify.d.ts.map +1 -1
- package/dist/popup/comment.d.ts +2 -0
- package/dist/popup/comment.d.ts.map +1 -1
- package/dist/widget/controller.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/i18n/de.ts +1 -0
- package/src/i18n/en.ts +1 -0
- package/src/i18n/es.ts +1 -0
- package/src/i18n/fr.ts +1 -0
- package/src/i18n/ja.ts +1 -0
- package/src/i18n/ko.ts +1 -0
- package/src/i18n/zh-CN.ts +1 -0
- package/src/popup/clarify.test.ts +90 -23
- package/src/popup/clarify.ts +40 -20
- package/src/popup/comment.test.ts +38 -0
- package/src/popup/comment.ts +15 -8
- package/src/styles/widget.css +64 -34
- package/src/widget/controller.test.ts +38 -9
- package/src/widget/controller.ts +16 -15
package/src/styles/widget.css
CHANGED
|
@@ -338,7 +338,7 @@
|
|
|
338
338
|
z-index: 2147483645;
|
|
339
339
|
display: flex;
|
|
340
340
|
flex-direction: column;
|
|
341
|
-
width: 320px;
|
|
341
|
+
width: min(320px, calc(100vw - 56px));
|
|
342
342
|
background: #fff;
|
|
343
343
|
border: 1px solid rgba(0, 0, 0, 0.1);
|
|
344
344
|
border-radius: 16px;
|
|
@@ -999,7 +999,7 @@
|
|
|
999
999
|
.mtb-clarify {
|
|
1000
1000
|
position: fixed;
|
|
1001
1001
|
z-index: 2147483645;
|
|
1002
|
-
width: 346px;
|
|
1002
|
+
width: min(346px, calc(100vw - 56px));
|
|
1003
1003
|
background: #fff;
|
|
1004
1004
|
border: 1px solid rgba(0, 0, 0, 0.1);
|
|
1005
1005
|
border-radius: 16px;
|
|
@@ -1011,18 +1011,23 @@
|
|
|
1011
1011
|
overflow: hidden;
|
|
1012
1012
|
}
|
|
1013
1013
|
|
|
1014
|
+
.mtb-clarify-continuation {
|
|
1015
|
+
width: min(320px, calc(100vw - 56px));
|
|
1016
|
+
animation: none;
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1014
1019
|
.mtb-clarify-header {
|
|
1015
|
-
padding:
|
|
1020
|
+
padding: 8px 10px;
|
|
1016
1021
|
display: flex;
|
|
1017
1022
|
align-items: center;
|
|
1018
|
-
gap:
|
|
1023
|
+
gap: 7px;
|
|
1019
1024
|
border-bottom: 1px solid rgba(0, 0, 0, 0.06);
|
|
1020
1025
|
}
|
|
1021
1026
|
|
|
1022
1027
|
.mtb-clarify-icon {
|
|
1023
|
-
width:
|
|
1024
|
-
height:
|
|
1025
|
-
border-radius:
|
|
1028
|
+
width: 20px;
|
|
1029
|
+
height: 20px;
|
|
1030
|
+
border-radius: 6px;
|
|
1026
1031
|
background: linear-gradient(140deg, #10b981, #059669);
|
|
1027
1032
|
box-shadow: 0 1px 3px rgba(5, 150, 105, 0.4);
|
|
1028
1033
|
display: flex;
|
|
@@ -1037,14 +1042,14 @@
|
|
|
1037
1042
|
}
|
|
1038
1043
|
|
|
1039
1044
|
.mtb-clarify-title {
|
|
1040
|
-
font-size:
|
|
1045
|
+
font-size: 12px;
|
|
1041
1046
|
font-weight: 650;
|
|
1042
1047
|
line-height: 1.2;
|
|
1043
1048
|
color: #191a1c;
|
|
1044
1049
|
}
|
|
1045
1050
|
|
|
1046
1051
|
.mtb-clarify-subtitle {
|
|
1047
|
-
font-size:
|
|
1052
|
+
font-size: 9.5px;
|
|
1048
1053
|
color: rgba(0, 0, 0, 0.42);
|
|
1049
1054
|
}
|
|
1050
1055
|
|
|
@@ -1064,19 +1069,18 @@
|
|
|
1064
1069
|
|
|
1065
1070
|
.mtb-clarify-messages {
|
|
1066
1071
|
flex: 1;
|
|
1067
|
-
max-height: 250px;
|
|
1068
1072
|
overflow-y: auto;
|
|
1069
|
-
padding:
|
|
1073
|
+
padding: 8px 10px 4px;
|
|
1070
1074
|
display: flex;
|
|
1071
1075
|
flex-direction: column;
|
|
1072
|
-
gap:
|
|
1076
|
+
gap: 6px;
|
|
1073
1077
|
}
|
|
1074
1078
|
|
|
1075
1079
|
.mtb-clarify-bubble {
|
|
1076
1080
|
max-width: 82%;
|
|
1077
|
-
padding:
|
|
1078
|
-
font-size:
|
|
1079
|
-
line-height: 1.
|
|
1081
|
+
padding: 6px 10px;
|
|
1082
|
+
font-size: 12px;
|
|
1083
|
+
line-height: 1.4;
|
|
1080
1084
|
white-space: pre-wrap;
|
|
1081
1085
|
word-break: break-word;
|
|
1082
1086
|
}
|
|
@@ -1086,7 +1090,7 @@
|
|
|
1086
1090
|
background: #ffffff;
|
|
1087
1091
|
color: #191a1c;
|
|
1088
1092
|
border: 1px solid rgba(0, 0, 0, 0.09);
|
|
1089
|
-
border-radius:
|
|
1093
|
+
border-radius: 11px 11px 11px 3px;
|
|
1090
1094
|
}
|
|
1091
1095
|
|
|
1092
1096
|
.mtb-clarify-user {
|
|
@@ -1094,14 +1098,14 @@
|
|
|
1094
1098
|
background: #059669;
|
|
1095
1099
|
color: #fff;
|
|
1096
1100
|
border: 1px solid #059669;
|
|
1097
|
-
border-radius:
|
|
1101
|
+
border-radius: 11px 11px 3px 11px;
|
|
1098
1102
|
}
|
|
1099
1103
|
|
|
1100
1104
|
.mtb-clarify-thinking {
|
|
1101
1105
|
display: flex;
|
|
1102
1106
|
align-items: center;
|
|
1103
1107
|
gap: 4px;
|
|
1104
|
-
padding:
|
|
1108
|
+
padding: 8px 12px;
|
|
1105
1109
|
}
|
|
1106
1110
|
|
|
1107
1111
|
.mtb-clarify-thinking .mtb-dot {
|
|
@@ -1111,20 +1115,20 @@
|
|
|
1111
1115
|
}
|
|
1112
1116
|
|
|
1113
1117
|
.mtb-clarify-footer {
|
|
1114
|
-
padding: 3px
|
|
1118
|
+
padding: 3px 10px 10px;
|
|
1115
1119
|
display: flex;
|
|
1116
1120
|
flex-direction: column;
|
|
1117
1121
|
}
|
|
1118
1122
|
|
|
1119
1123
|
.mtb-clarify-input {
|
|
1120
1124
|
width: 100%;
|
|
1121
|
-
height:
|
|
1122
|
-
padding:
|
|
1125
|
+
height: 40px;
|
|
1126
|
+
padding: 7px 10px;
|
|
1123
1127
|
border: 1px solid rgba(0, 0, 0, 0.12);
|
|
1124
|
-
border-radius:
|
|
1128
|
+
border-radius: 8px;
|
|
1125
1129
|
font-family: inherit;
|
|
1126
|
-
font-size:
|
|
1127
|
-
line-height: 1.
|
|
1130
|
+
font-size: 12px;
|
|
1131
|
+
line-height: 1.4;
|
|
1128
1132
|
color: #191a1c;
|
|
1129
1133
|
outline: none;
|
|
1130
1134
|
background: #fafafa;
|
|
@@ -1145,20 +1149,20 @@
|
|
|
1145
1149
|
|
|
1146
1150
|
.mtb-clarify-actions {
|
|
1147
1151
|
display: flex;
|
|
1148
|
-
gap:
|
|
1149
|
-
margin-top:
|
|
1152
|
+
gap: 6px;
|
|
1153
|
+
margin-top: 6px;
|
|
1150
1154
|
}
|
|
1151
1155
|
|
|
1152
1156
|
.mtb-clarify-skip {
|
|
1153
1157
|
flex: 0 0 auto;
|
|
1154
|
-
height:
|
|
1155
|
-
padding: 0
|
|
1158
|
+
height: 30px;
|
|
1159
|
+
padding: 0 12px;
|
|
1156
1160
|
border: 1px solid rgba(0, 0, 0, 0.12);
|
|
1157
|
-
border-radius:
|
|
1161
|
+
border-radius: 8px;
|
|
1158
1162
|
background: #fff;
|
|
1159
1163
|
cursor: pointer;
|
|
1160
1164
|
font-family: inherit;
|
|
1161
|
-
font-size:
|
|
1165
|
+
font-size: 12px;
|
|
1162
1166
|
font-weight: 550;
|
|
1163
1167
|
color: rgba(0, 0, 0, 0.55);
|
|
1164
1168
|
white-space: nowrap;
|
|
@@ -1171,13 +1175,40 @@
|
|
|
1171
1175
|
|
|
1172
1176
|
.mtb-clarify-send {
|
|
1173
1177
|
flex: 1;
|
|
1178
|
+
height: 30px;
|
|
1179
|
+
display: inline-flex;
|
|
1180
|
+
align-items: center;
|
|
1181
|
+
justify-content: center;
|
|
1182
|
+
gap: 5px;
|
|
1183
|
+
border: none;
|
|
1184
|
+
border-radius: 8px;
|
|
1185
|
+
background: #059669;
|
|
1186
|
+
color: #fff;
|
|
1187
|
+
cursor: pointer;
|
|
1188
|
+
font-family: inherit;
|
|
1189
|
+
font-size: 12px;
|
|
1190
|
+
font-weight: 600;
|
|
1191
|
+
transition: background 0.12s;
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
.mtb-clarify-send:not(:disabled):hover {
|
|
1195
|
+
background: #047857;
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
.mtb-clarify-send:disabled {
|
|
1199
|
+
background: rgba(0, 0, 0, 0.15);
|
|
1200
|
+
cursor: not-allowed;
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
.mtb-clarify-send-feedback {
|
|
1204
|
+
width: 100%;
|
|
1174
1205
|
height: 34px;
|
|
1175
1206
|
display: inline-flex;
|
|
1176
1207
|
align-items: center;
|
|
1177
1208
|
justify-content: center;
|
|
1178
1209
|
gap: 6px;
|
|
1179
1210
|
border: none;
|
|
1180
|
-
border-radius:
|
|
1211
|
+
border-radius: 9px;
|
|
1181
1212
|
background: #059669;
|
|
1182
1213
|
color: #fff;
|
|
1183
1214
|
cursor: pointer;
|
|
@@ -1187,11 +1218,11 @@
|
|
|
1187
1218
|
transition: background 0.12s;
|
|
1188
1219
|
}
|
|
1189
1220
|
|
|
1190
|
-
.mtb-clarify-send:not(:disabled):hover {
|
|
1221
|
+
.mtb-clarify-send-feedback:not(:disabled):hover {
|
|
1191
1222
|
background: #047857;
|
|
1192
1223
|
}
|
|
1193
1224
|
|
|
1194
|
-
.mtb-clarify-send:disabled {
|
|
1225
|
+
.mtb-clarify-send-feedback:disabled {
|
|
1195
1226
|
background: rgba(0, 0, 0, 0.15);
|
|
1196
1227
|
cursor: not-allowed;
|
|
1197
1228
|
}
|
|
@@ -1503,4 +1534,3 @@
|
|
|
1503
1534
|
font-size: 11px;
|
|
1504
1535
|
color: rgba(0, 0, 0, 0.42);
|
|
1505
1536
|
}
|
|
1506
|
-
|
|
@@ -36,7 +36,10 @@ function sessionFlowResponse(
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
async function confirmSubmission(shadow: ShadowRoot): Promise<void> {
|
|
39
|
-
|
|
39
|
+
await vi.waitFor(() => {
|
|
40
|
+
expect(shadow.querySelector('.mtb-clarify-send-feedback')).not.toBeNull()
|
|
41
|
+
})
|
|
42
|
+
shadow.querySelector<HTMLButtonElement>('.mtb-clarify-send-feedback')!.click()
|
|
40
43
|
await vi.waitFor(() => {
|
|
41
44
|
expect(shadow.querySelector('.mtb-success')).not.toBeNull()
|
|
42
45
|
})
|
|
@@ -78,9 +81,10 @@ describe('MakeThisBetter widget flow', () => {
|
|
|
78
81
|
}), { status: 201 })
|
|
79
82
|
}
|
|
80
83
|
if (href.endsWith('/clarification')) {
|
|
81
|
-
return new Response(
|
|
82
|
-
|
|
83
|
-
|
|
84
|
+
return new Response(
|
|
85
|
+
'event: done\ndata: {"messages":[{"role":"assistant","content":"All clear, thanks!"}],"done":true}\n\n',
|
|
86
|
+
{ status: 200, headers: { 'Content-Type': 'text/event-stream' } },
|
|
87
|
+
)
|
|
84
88
|
}
|
|
85
89
|
if (init?.body instanceof FormData) capturedBody = init.body
|
|
86
90
|
return new Response(JSON.stringify({
|
|
@@ -102,6 +106,8 @@ describe('MakeThisBetter widget flow', () => {
|
|
|
102
106
|
overlay.dispatchEvent(new MouseEvent('mouseup', { clientX: 20, clientY: 30, bubbles: true }))
|
|
103
107
|
|
|
104
108
|
const textarea = shadow.querySelector<HTMLTextAreaElement>('.mtb-textarea')!
|
|
109
|
+
const feedbackPopup = shadow.querySelector<HTMLDivElement>('.mtb-popup')!
|
|
110
|
+
const popupPosition = { left: feedbackPopup.style.left, top: feedbackPopup.style.top }
|
|
105
111
|
textarea.value = 'Export is broken'
|
|
106
112
|
textarea.dispatchEvent(new Event('input'))
|
|
107
113
|
shadow.querySelector<HTMLButtonElement>('.mtb-submit-btn')!.click()
|
|
@@ -119,7 +125,19 @@ describe('MakeThisBetter widget flow', () => {
|
|
|
119
125
|
text: 'Export PDF',
|
|
120
126
|
name: 'Export PDF',
|
|
121
127
|
}))
|
|
122
|
-
|
|
128
|
+
await vi.waitFor(() => {
|
|
129
|
+
expect(shadow.querySelector('.mtb-clarify-send-feedback')).not.toBeNull()
|
|
130
|
+
}, { timeout: 5000 })
|
|
131
|
+
const clarification = shadow.querySelector<HTMLDivElement>('.mtb-clarify')!
|
|
132
|
+
expect(clarification).toBe(feedbackPopup)
|
|
133
|
+
expect(clarification.classList.contains('mtb-clarify-continuation')).toBe(true)
|
|
134
|
+
expect({ left: clarification.style.left, top: clarification.style.top }).toEqual(popupPosition)
|
|
135
|
+
expect(shadow.querySelector('.mtb-popup')).toBeNull()
|
|
136
|
+
expect(shadow.querySelector('.mtb-clarify-ai')?.textContent).toBe('All clear, thanks!')
|
|
137
|
+
expect(fetchSpy.mock.calls.some(([url]) => String(url).endsWith('/feedback'))).toBe(false)
|
|
138
|
+
|
|
139
|
+
shadow.querySelector<HTMLButtonElement>('.mtb-clarify-send-feedback')!.click()
|
|
140
|
+
|
|
123
141
|
await vi.waitFor(() => {
|
|
124
142
|
expect(shadow.querySelector('.mtb-success-title')?.textContent).toBe('Sent — thanks!')
|
|
125
143
|
}, { timeout: 5000 })
|
|
@@ -255,8 +273,13 @@ describe('MakeThisBetter widget flow', () => {
|
|
|
255
273
|
textarea.dispatchEvent(new Event('input'))
|
|
256
274
|
shadow.querySelector<HTMLButtonElement>('.mtb-submit-btn')!.click()
|
|
257
275
|
|
|
258
|
-
|
|
259
|
-
|
|
276
|
+
await vi.waitFor(() => {
|
|
277
|
+
expect(shadow.querySelector('.mtb-clarify-send-feedback')).not.toBeNull()
|
|
278
|
+
})
|
|
279
|
+
shadow.querySelector<HTMLButtonElement>('.mtb-clarify-send-feedback')!.click()
|
|
280
|
+
|
|
281
|
+
// The explicit confirmation triggers the /feedback POST. That POST hangs
|
|
282
|
+
// on finalizeResponse, so Exit can still invalidate the pending result.
|
|
260
283
|
await vi.waitFor(() => {
|
|
261
284
|
expect(fetchSpy.mock.calls.some(([url]) => String(url).endsWith('/feedback'))).toBe(true)
|
|
262
285
|
})
|
|
@@ -713,7 +736,7 @@ describe('MakeThisBetter widget flow', () => {
|
|
|
713
736
|
})
|
|
714
737
|
})
|
|
715
738
|
|
|
716
|
-
it('
|
|
739
|
+
it('requires Send feedback when AI clarification is unavailable', async () => {
|
|
717
740
|
const target = document.createElement('button')
|
|
718
741
|
target.id = 'export-btn'
|
|
719
742
|
target.textContent = 'Export PDF'
|
|
@@ -742,7 +765,13 @@ describe('MakeThisBetter widget flow', () => {
|
|
|
742
765
|
textarea.dispatchEvent(new Event('input'))
|
|
743
766
|
shadow.querySelector<HTMLButtonElement>('.mtb-submit-btn')!.click()
|
|
744
767
|
|
|
745
|
-
|
|
768
|
+
await vi.waitFor(() => {
|
|
769
|
+
expect(shadow.querySelector('.mtb-clarify-send-feedback')).not.toBeNull()
|
|
770
|
+
}, { timeout: 5000 })
|
|
771
|
+
expect(fetchSpy.mock.calls.some(([url]) => String(url).endsWith('/feedback'))).toBe(false)
|
|
772
|
+
|
|
773
|
+
shadow.querySelector<HTMLButtonElement>('.mtb-clarify-send-feedback')!.click()
|
|
774
|
+
|
|
746
775
|
await vi.waitFor(() => {
|
|
747
776
|
expect(shadow.querySelector('.mtb-success-title')?.textContent).toBe("Thanks! We've received your feedback.")
|
|
748
777
|
}, { timeout: 5000 })
|
package/src/widget/controller.ts
CHANGED
|
@@ -279,6 +279,7 @@ export class WidgetController {
|
|
|
279
279
|
onSubmit: (description) => this.handleSubmit(description),
|
|
280
280
|
onClose: () => this.exitAll(),
|
|
281
281
|
onMyFeedback: this.buildMyFeedbackHandler(),
|
|
282
|
+
position: this.config.position ?? 'right',
|
|
282
283
|
})
|
|
283
284
|
this.submittingUi = this.popup
|
|
284
285
|
}
|
|
@@ -342,10 +343,11 @@ export class WidgetController {
|
|
|
342
343
|
submissionAttempt: number,
|
|
343
344
|
): Promise<void> {
|
|
344
345
|
if (!submission.ai_clarify_available) {
|
|
345
|
-
this.teardownSubmittingUi()
|
|
346
|
-
this.
|
|
347
|
-
|
|
348
|
-
|
|
346
|
+
const element = this.teardownSubmittingUi(true)
|
|
347
|
+
this.showClarify(submission, pos, {
|
|
348
|
+
element,
|
|
349
|
+
preloadedResult: { messages: [], done: true },
|
|
350
|
+
})
|
|
349
351
|
return
|
|
350
352
|
}
|
|
351
353
|
|
|
@@ -363,24 +365,19 @@ export class WidgetController {
|
|
|
363
365
|
|
|
364
366
|
if (submissionAttempt !== this.submissionAttempt) return
|
|
365
367
|
|
|
366
|
-
this.teardownSubmittingUi()
|
|
368
|
+
const element = this.teardownSubmittingUi(true)
|
|
367
369
|
|
|
368
370
|
if (result) {
|
|
369
|
-
|
|
370
|
-
this.mode = 'clarifying'
|
|
371
|
-
this.tab?.setActive(true)
|
|
372
|
-
await this.finalizeSubmission()
|
|
373
|
-
} else {
|
|
374
|
-
this.showClarify(submission, pos, { preloadedResult: result })
|
|
375
|
-
}
|
|
371
|
+
this.showClarify(submission, pos, { element, preloadedResult: result })
|
|
376
372
|
} else {
|
|
377
|
-
this.showClarify(submission, pos, { pendingClarification: clarifyPromise })
|
|
373
|
+
this.showClarify(submission, pos, { element, pendingClarification: clarifyPromise })
|
|
378
374
|
}
|
|
379
375
|
}
|
|
380
376
|
|
|
381
|
-
private teardownSubmittingUi():
|
|
377
|
+
private teardownSubmittingUi(preservePopup = false): HTMLDivElement | undefined {
|
|
378
|
+
const popupElement = preservePopup ? this.popup?.releaseElement() : undefined
|
|
382
379
|
this.teardownDraw()
|
|
383
|
-
this.popup?.destroy()
|
|
380
|
+
if (!popupElement) this.popup?.destroy()
|
|
384
381
|
this.popup = null
|
|
385
382
|
this.dim?.destroy()
|
|
386
383
|
this.dim = null
|
|
@@ -390,12 +387,14 @@ export class WidgetController {
|
|
|
390
387
|
this.recordingManager?.destroy()
|
|
391
388
|
this.recordingManager = null
|
|
392
389
|
this.submittingUi = null
|
|
390
|
+
return popupElement
|
|
393
391
|
}
|
|
394
392
|
|
|
395
393
|
private showClarify(
|
|
396
394
|
submission: SubmissionSessionResponse,
|
|
397
395
|
pos: { x: number; y: number } | null,
|
|
398
396
|
speculative?: {
|
|
397
|
+
element?: HTMLDivElement
|
|
399
398
|
preloadedResult?: ClarifyStreamResult
|
|
400
399
|
pendingClarification?: Promise<ClarifyStreamResult | null>
|
|
401
400
|
},
|
|
@@ -407,6 +406,8 @@ export class WidgetController {
|
|
|
407
406
|
submissionToken: submission.token,
|
|
408
407
|
apiClient: this.apiClient,
|
|
409
408
|
messages: this.messages,
|
|
409
|
+
element: speculative?.element,
|
|
410
|
+
position: this.config.position ?? 'right',
|
|
410
411
|
x: pos?.x,
|
|
411
412
|
y: pos?.y,
|
|
412
413
|
onFinalize: () => this.finalizeSubmission(),
|