@internetarchive/elements 0.4.1 → 0.4.2-webdev-9107.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.
Files changed (45) hide show
  1. package/dist/src/elements/ia-reviews/assets/delete-icon.svg +8 -0
  2. package/dist/src/elements/ia-reviews/assets/star-basic.svg +6 -0
  3. package/dist/src/elements/ia-reviews/assets/star-selected.svg +8 -0
  4. package/dist/src/elements/ia-reviews/assets/star-unselected.svg +8 -0
  5. package/dist/src/elements/ia-reviews/ia-review-form.d.ts +104 -0
  6. package/dist/src/elements/ia-reviews/ia-review-form.d.ts.map +1 -0
  7. package/dist/src/elements/ia-reviews/ia-review-form.js +678 -0
  8. package/dist/src/elements/ia-reviews/ia-review-form.js.map +1 -0
  9. package/dist/src/elements/ia-reviews/ia-review.d.ts +49 -0
  10. package/dist/src/elements/ia-reviews/ia-review.d.ts.map +1 -0
  11. package/dist/src/elements/ia-reviews/ia-review.js +349 -0
  12. package/dist/src/elements/ia-reviews/ia-review.js.map +1 -0
  13. package/dist/src/elements/ia-reviews/ia-reviews.d.ts +63 -0
  14. package/dist/src/elements/ia-reviews/ia-reviews.d.ts.map +1 -0
  15. package/dist/src/elements/ia-reviews/ia-reviews.js +357 -0
  16. package/dist/src/elements/ia-reviews/ia-reviews.js.map +1 -0
  17. package/dist/src/elements/ia-reviews/mocks/mock-fetch-handler.d.ts +8 -0
  18. package/dist/src/elements/ia-reviews/mocks/mock-fetch-handler.d.ts.map +1 -0
  19. package/dist/src/elements/ia-reviews/mocks/mock-fetch-handler.js +15 -0
  20. package/dist/src/elements/ia-reviews/mocks/mock-fetch-handler.js.map +1 -0
  21. package/dist/src/elements/ia-reviews/utils/collapse-space.d.ts +13 -0
  22. package/dist/src/elements/ia-reviews/utils/collapse-space.d.ts.map +1 -0
  23. package/dist/src/elements/ia-reviews/utils/collapse-space.js +19 -0
  24. package/dist/src/elements/ia-reviews/utils/collapse-space.js.map +1 -0
  25. package/dist/src/elements/ia-reviews/utils/friendly-truncate.d.ts +14 -0
  26. package/dist/src/elements/ia-reviews/utils/friendly-truncate.d.ts.map +1 -0
  27. package/dist/src/elements/ia-reviews/utils/friendly-truncate.js +65 -0
  28. package/dist/src/elements/ia-reviews/utils/friendly-truncate.js.map +1 -0
  29. package/dist/src/elements/ia-reviews/utils/link-urls-in-text.d.ts +9 -0
  30. package/dist/src/elements/ia-reviews/utils/link-urls-in-text.d.ts.map +1 -0
  31. package/dist/src/elements/ia-reviews/utils/link-urls-in-text.js +40 -0
  32. package/dist/src/elements/ia-reviews/utils/link-urls-in-text.js.map +1 -0
  33. package/dist/src/elements/ia-reviews/utils/sanitize-review-body.d.ts +9 -0
  34. package/dist/src/elements/ia-reviews/utils/sanitize-review-body.d.ts.map +1 -0
  35. package/dist/src/elements/ia-reviews/utils/sanitize-review-body.js +29 -0
  36. package/dist/src/elements/ia-reviews/utils/sanitize-review-body.js.map +1 -0
  37. package/dist/src/elements/ia-reviews/utils/truncate-screenname.d.ts +13 -0
  38. package/dist/src/elements/ia-reviews/utils/truncate-screenname.d.ts.map +1 -0
  39. package/dist/src/elements/ia-reviews/utils/truncate-screenname.js +19 -0
  40. package/dist/src/elements/ia-reviews/utils/truncate-screenname.js.map +1 -0
  41. package/dist/src/elements/index.d.ts +3 -0
  42. package/dist/src/elements/index.d.ts.map +1 -1
  43. package/dist/src/elements/index.js +3 -0
  44. package/dist/src/elements/index.js.map +1 -1
  45. package/package.json +17 -1
@@ -0,0 +1,678 @@
1
+ import { __decorate } from "tslib";
2
+ import { html, css, LitElement, nothing, } from 'lit';
3
+ import { property, state, query } from 'lit/decorators.js';
4
+ import { customElement } from '../../util/custom-element.js';
5
+ import { msg } from '@lit/localize';
6
+ import { unsafeHTML } from 'lit/directives/unsafe-html.js';
7
+ import DOMPurify from 'dompurify';
8
+ import '../../elements/ia-button/ia-button.js';
9
+ import { Review } from '@internetarchive/metadata-service';
10
+ import starSelected from './assets/star-selected.svg';
11
+ import starUnselected from './assets/star-unselected.svg';
12
+ import './ia-review.js';
13
+ /**
14
+ * Renders a form to edit a given IA review.
15
+ */
16
+ let IAReviewForm = class IAReviewForm extends LitElement {
17
+ constructor() {
18
+ super(...arguments);
19
+ /* The token for the review edit */
20
+ this.token = '';
21
+ /* The host for archive endpoints and data */
22
+ this.baseHost = 'https://archive.org';
23
+ /* The path for the endpoint we're submitting to */
24
+ this.endpointPath = '/write-review.php';
25
+ /** Form submitter's screenname, if applicable */
26
+ this.submitterScreenname = 'Anonymous';
27
+ /* Optionally avoid using recaptcha for the form */
28
+ this.bypassRecaptcha = false;
29
+ /* Number of stars currently selected */
30
+ this.currentStars = 0;
31
+ /* Length of review subject currently filled in */
32
+ this.currentSubjectLength = 0;
33
+ /* Length of review body currently filled in */
34
+ this.currentBodyLength = 0;
35
+ /* Whether to enable the submit button */
36
+ this.formCanSubmit = false;
37
+ /* Whether to show a loading indicator for the form */
38
+ this.submissionInProgress = false;
39
+ /* Error to show if recaptcha cannot be loaded */
40
+ this.RECAPTCHA_ERROR_MESSAGE = 'Could not validate review. Please try again later.';
41
+ this.GENERIC_ERROR_MESSAGE = "There's been a temporary error. Please wait a moment and try again.";
42
+ }
43
+ render() {
44
+ return html `<form id="review-form" @submit=${this.handleSubmit}>
45
+ ${this.unrecoverableError
46
+ ? this.unrecoverableErrorTemplate
47
+ : html `
48
+ <span class="inputs">
49
+ ${this.starsInputTemplate} ${this.subjectInputTemplate}
50
+ ${this.bodyInputTemplate} ${this.hiddenInputsTemplate}
51
+ </span>
52
+ `}
53
+ ${this.recaptchaMessageTemplate} ${this.recoverableErrorTemplate}
54
+ ${this.actionButtonsTemplate}
55
+ </form>`;
56
+ }
57
+ willUpdate(changed) {
58
+ // Fill in previous review, if provided
59
+ if (changed.has('oldReview')) {
60
+ this.currentStars = this.oldReview?.stars ?? 0;
61
+ this.currentSubjectLength = this.oldReview?.reviewtitle?.length ?? 0;
62
+ this.currentBodyLength = this.oldReview?.reviewbody?.length ?? 0;
63
+ }
64
+ // Set up ReCaptcha, if possible
65
+ if (changed.has('recaptchaManager') &&
66
+ !this.bypassRecaptcha &&
67
+ this.recaptchaManager) {
68
+ this.setupRecaptcha();
69
+ }
70
+ // Disable form if unrecoverable error added
71
+ if (changed.has('unrecoverableError')) {
72
+ this.formCanSubmit = this.checkSubmissionAllowed();
73
+ }
74
+ // Ensure new subject and body have correct length
75
+ if (changed.has('currentSubjectLength') ||
76
+ changed.has('currentBodyLength') ||
77
+ changed.has('maxSubjectLength') ||
78
+ changed.has('maxBodyLength')) {
79
+ this.formCanSubmit = this.checkSubmissionAllowed();
80
+ }
81
+ }
82
+ /** Error to render instead of form inputs */
83
+ get unrecoverableErrorTemplate() {
84
+ return this.unrecoverableError
85
+ ? html `
86
+ <div class="unrecoverable-error">
87
+ <span class="error-msg">${msg(this.unrecoverableError)}</span>
88
+ </div>
89
+ `
90
+ : nothing;
91
+ }
92
+ /** Error to render next to submit button */
93
+ get recoverableErrorTemplate() {
94
+ return this.recoverableError
95
+ ? html `
96
+ <div class="recoverable-error">
97
+ ${unsafeHTML(this.sanitizeErrorMsg(msg(this.recoverableError)))}
98
+ </div>
99
+ `
100
+ : nothing;
101
+ }
102
+ get recaptchaMessageTemplate() {
103
+ if (this.bypassRecaptcha)
104
+ return nothing;
105
+ return html `
106
+ <span class="recaptcha-disclaimer"
107
+ >${msg(html `This site is protected by reCAPTCHA and the Google
108
+ <a
109
+ target="_blank"
110
+ class="inline-link"
111
+ href="https://policies.google.com/privacy"
112
+ >Privacy Policy</a
113
+ >
114
+ and
115
+ <a
116
+ target="_blank"
117
+ class="inline-link"
118
+ href="https://policies.google.com/terms"
119
+ >Terms of Service</a
120
+ >
121
+ apply.`)}</span
122
+ >
123
+ `;
124
+ }
125
+ /** Clickable group of stars */
126
+ get starsInputTemplate() {
127
+ return html `
128
+ <div class="form-heading rating">
129
+ <label for="stars-field">${msg('Rating (optional)')}</label>
130
+ </div>
131
+ <input
132
+ type="hidden"
133
+ name="field_stars"
134
+ id="stars-input"
135
+ .value=${this.currentStars.toString()}
136
+ required
137
+ />
138
+ <div class="stars">
139
+ ${[1, 2, 3, 4, 5].map((num) => this.renderStar(num))}
140
+ <button
141
+ type="button"
142
+ class="clear-stars-btn"
143
+ @click=${this.handleClearBtnClicked}
144
+ >
145
+ ${msg('Clear')}
146
+ </button>
147
+ </div>
148
+ `;
149
+ }
150
+ /** Subject input and character counter */
151
+ get subjectInputTemplate() {
152
+ return html `
153
+ <span id="subject-input" class="input-box ${this.maxSubjectLength &&
154
+ this.currentSubjectLength > this.maxSubjectLength
155
+ ? 'error'
156
+ : ''}"
157
+ ><div class="form-heading">
158
+ <label for="field_reviewtitle">${msg('Subject')}</label>
159
+ ${this.maxSubjectLength
160
+ ? html `<div class="char-count subject">
161
+ ${this.currentSubjectLength}/${this.maxSubjectLength}
162
+ </div>`
163
+ : nothing}
164
+ </div>
165
+ <input
166
+ type="text"
167
+ name="field_reviewtitle"
168
+ id="field_reviewtitle"
169
+ .value=${this.oldReview?.reviewtitle ?? ''}
170
+ @input=${this.handleSubjectChanged}
171
+ required
172
+ />${this.maxSubjectLength
173
+ ? html `
174
+ <div class="input-error">
175
+ ${msg(`Subject may only have ${this.maxSubjectLength} characters`)}
176
+ </div>
177
+ `
178
+ : nothing}</div></span>
179
+ `;
180
+ }
181
+ /** Body input and character counter */
182
+ get bodyInputTemplate() {
183
+ return html `
184
+ <span
185
+ id="body-input"
186
+ class="input-box ${this.maxBodyLength &&
187
+ this.currentBodyLength > this.maxBodyLength
188
+ ? 'error'
189
+ : ''}"
190
+ ><div class="form-heading">
191
+ <label for="field_reviewbody">${msg('Review')}</label>
192
+ ${this.maxBodyLength
193
+ ? html `<div class="char-count body">
194
+ ${this.currentBodyLength}/${this.maxBodyLength}
195
+ </div>`
196
+ : nothing}
197
+ </div>
198
+ <textarea
199
+ name="field_reviewbody"
200
+ id="field_reviewbody"
201
+ .value=${this.oldReview?.reviewbody ?? ''}
202
+ rows="10"
203
+ cols="50"
204
+ required
205
+ @input=${this.handleBodyChanged}
206
+ ></textarea>
207
+ ${this.maxBodyLength
208
+ ? html `
209
+ <div class="input-error">
210
+ ${msg(`Review may only have ${this.maxBodyLength} characters`)}
211
+ </div>
212
+ `
213
+ : nothing}
214
+ </span>
215
+ `;
216
+ }
217
+ /** Hidden inputs we use to store other information for form submission */
218
+ get hiddenInputsTemplate() {
219
+ return html `
220
+ <input type="hidden" name="field_reviewtoken" .value=${this.token} />
221
+ ${this.identifier
222
+ ? html `<input
223
+ type="hidden"
224
+ name="identifier"
225
+ .value=${this.identifier}
226
+ />`
227
+ : nothing}
228
+ `;
229
+ }
230
+ /** Buttons to render at bottom of form */
231
+ get actionButtonsTemplate() {
232
+ return html `<div class="action-btns">
233
+ <ia-button
234
+ mode="secondary"
235
+ class="cancel-btn"
236
+ data-testid="cancel-btn"
237
+ @click=${this.cancelReviewEdit}
238
+ >
239
+ ${msg('Cancel')}
240
+ </ia-button>
241
+ <ia-button
242
+ mode="primary"
243
+ type="submit"
244
+ class="submit-btn"
245
+ .disabled=${!this.formCanSubmit}
246
+ .loading=${this.submissionInProgress}
247
+ >
248
+ ${msg('Submit review')}
249
+ </ia-button>
250
+ </div>`;
251
+ }
252
+ /**
253
+ * Renders a star icon, using its number and the current star rating
254
+ * to determine whether it should appear selected or not
255
+ *
256
+ * @param {number} num The number of the current star
257
+ * @returns {HTMLTemplateResult} The correct icon, rendered within a button
258
+ */
259
+ renderStar(num) {
260
+ const isSelected = num === this.currentStars;
261
+ const ratingLabel = msg(`Rate ${num > 1 ? `${num} stars` : '1 star'}`);
262
+ return html `
263
+ <button
264
+ class="star star-${num}"
265
+ title=${isSelected ? msg('Clear rating') : ratingLabel}
266
+ @click=${(e) => this.handleStarClicked(e, num)}
267
+ >
268
+ ${num <= this.currentStars
269
+ ? html `<img
270
+ class="star-selected"
271
+ src=${starSelected}
272
+ alt=""
273
+ aria-hidden="true"
274
+ />`
275
+ : html `<img
276
+ class="star-unselected"
277
+ src=${starUnselected}
278
+ alt=""
279
+ aria-hidden="true"
280
+ />`}
281
+ </button>
282
+ `;
283
+ }
284
+ /**
285
+ * Sets up ReCaptcha for the form, if possible.
286
+ *
287
+ * On failure, replaces form inputs with the ReCaptcha error message.
288
+ */
289
+ async setupRecaptcha() {
290
+ try {
291
+ this.recaptchaWidget = await this.recaptchaManager?.getRecaptchaWidget();
292
+ }
293
+ catch {
294
+ this.unrecoverableError = this.RECAPTCHA_ERROR_MESSAGE;
295
+ }
296
+ }
297
+ /**
298
+ * Uses DOMpurify to sanitize any error message before render.
299
+ *
300
+ * @param {string} errorMsg The error message to be sanitized
301
+ * @returns {string} The sanitized error message
302
+ */
303
+ sanitizeErrorMsg(errorMsg) {
304
+ return DOMPurify.sanitize(errorMsg, { ALLOWED_TAGS: ['a', 'b', 'br'] });
305
+ }
306
+ /** Handles validation and recaptcha execution on form submission */
307
+ async handleSubmit(e) {
308
+ e.preventDefault();
309
+ // Prevent disallowed or double submission
310
+ if (!this.formCanSubmit || this.submissionInProgress)
311
+ return;
312
+ // Set loading behavior
313
+ this.submissionInProgress = true;
314
+ this.recoverableError = '';
315
+ // Check for HTML errors
316
+ if (!this.reviewForm.reportValidity()) {
317
+ return this.stopSubmission();
318
+ }
319
+ if (!this.fetchHandler) {
320
+ this.recoverableError = this.GENERIC_ERROR_MESSAGE;
321
+ return this.stopSubmission();
322
+ }
323
+ try {
324
+ const formData = new URLSearchParams();
325
+ if (!this.bypassRecaptcha) {
326
+ const recaptchaToken = await this.getRecaptchaToken();
327
+ if (!recaptchaToken)
328
+ return this.handleRecaptchaError();
329
+ formData.append('g-recaptcha-response', recaptchaToken ?? '');
330
+ }
331
+ for (const entry of new FormData(this.reviewForm)) {
332
+ formData.append(entry[0], entry[1]);
333
+ }
334
+ // Indicates to the backend that submission is intended
335
+ formData.append('submitter', 'review-form');
336
+ const result = await this.fetchHandler.fetchApiResponse(`${this.baseHost}${this.endpointPath}`, {
337
+ method: 'POST',
338
+ includeCredentials: true,
339
+ body: formData,
340
+ });
341
+ if (result?.success === true) {
342
+ this.submissionInProgress = false;
343
+ const newReview = this.generateSubmittedReview();
344
+ // Emit a reviewUpdated event
345
+ const event = new CustomEvent('reviewUpdated', {
346
+ detail: newReview,
347
+ });
348
+ this.dispatchEvent(event);
349
+ }
350
+ else {
351
+ this.recoverableError = result.error ?? this.GENERIC_ERROR_MESSAGE;
352
+ this.stopSubmission();
353
+ }
354
+ }
355
+ catch (e) {
356
+ console.error(e);
357
+ this.recoverableError = this.GENERIC_ERROR_MESSAGE;
358
+ this.stopSubmission();
359
+ }
360
+ }
361
+ /**
362
+ * Generates a review object from the submitted review,
363
+ * for optimistic display on success.
364
+ *
365
+ * @returns {Review} The review to display
366
+ */
367
+ generateSubmittedReview() {
368
+ const today = new Date().toDateString();
369
+ const newReview = new Review({
370
+ reviewtitle: this.reviewForm.field_reviewtitle.value,
371
+ reviewbody: this.reviewForm.field_reviewbody.value,
372
+ stars: this.reviewForm.field_stars.value,
373
+ reviewdate: today,
374
+ reviewer: this.oldReview?.reviewer ?? this.submitterScreenname,
375
+ reviewer_itemname: this.oldReview?.reviewer_itemname ?? this.submitterItemname,
376
+ createdate: this.dateToString(this.oldReview?.createdate) ?? today,
377
+ });
378
+ return newReview;
379
+ }
380
+ /**
381
+ * Converts date to string if it is a Date, otherwise
382
+ * leaves unchanged.
383
+ */
384
+ dateToString(date) {
385
+ if (date instanceof Date)
386
+ return date.toDateString();
387
+ return date;
388
+ }
389
+ /**
390
+ * Executes the ReCaptcha challenge for the form.
391
+ * Attempts form submission on success.
392
+ * */
393
+ async getRecaptchaToken() {
394
+ if (!this.recaptchaWidget) {
395
+ this.handleRecaptchaError();
396
+ return;
397
+ }
398
+ try {
399
+ const recaptchaToken = await this.recaptchaWidget.execute();
400
+ return recaptchaToken;
401
+ }
402
+ catch {
403
+ this.handleRecaptchaError();
404
+ return;
405
+ }
406
+ }
407
+ /* Handles a recaptcha error during submission */
408
+ handleRecaptchaError() {
409
+ this.recoverableError = this.RECAPTCHA_ERROR_MESSAGE;
410
+ this.stopSubmission();
411
+ }
412
+ /* Handles canceled form submission */
413
+ stopSubmission() {
414
+ if (this.submissionInProgress) {
415
+ this.submissionInProgress = false;
416
+ }
417
+ }
418
+ /* Emits an event to close the form */
419
+ cancelReviewEdit() {
420
+ const event = new CustomEvent('reviewEditCanceled');
421
+ this.dispatchEvent(event);
422
+ }
423
+ /* Prevents form submission and sets stars based on number clicked */
424
+ handleStarClicked(e, num) {
425
+ e.preventDefault();
426
+ this.setStars(num);
427
+ }
428
+ /* Clear stars if requested */
429
+ handleClearBtnClicked(e) {
430
+ e.preventDefault();
431
+ this.currentStars = 0;
432
+ }
433
+ /* Updates star count, resetting to 0 if the currently selected star is clicked */
434
+ setStars(num) {
435
+ this.currentStars = num === this.currentStars ? 0 : num;
436
+ }
437
+ /* Updates subject input length */
438
+ handleSubjectChanged(e) {
439
+ const subjectInput = e.target;
440
+ this.currentSubjectLength = subjectInput.value.length;
441
+ }
442
+ /* Updates body input length */
443
+ handleBodyChanged(e) {
444
+ const bodyInput = e.target;
445
+ this.currentBodyLength = bodyInput.value.length;
446
+ }
447
+ /* Checks if submission should be allowed */
448
+ checkSubmissionAllowed() {
449
+ // Form must not have an unrecoverable error
450
+ if (this.unrecoverableError) {
451
+ return false;
452
+ }
453
+ // Subject and body must not be empty
454
+ if (!this.currentBodyLength || !this.currentSubjectLength) {
455
+ return false;
456
+ }
457
+ // Subject must be correct length
458
+ if (!!this.maxSubjectLength &&
459
+ this.currentSubjectLength > this.maxSubjectLength) {
460
+ return false;
461
+ }
462
+ // Body must be correct length
463
+ if (!!this.maxBodyLength && this.currentBodyLength > this.maxBodyLength) {
464
+ return false;
465
+ }
466
+ return true;
467
+ }
468
+ static get styles() {
469
+ return [
470
+ css `
471
+ .form-heading {
472
+ display: flex;
473
+ flex-direction: row;
474
+ justify-content: space-between;
475
+ padding-top: 15px;
476
+ }
477
+
478
+ .form-heading.rating {
479
+ padding-top: 0;
480
+ }
481
+
482
+ .form-heading label {
483
+ font-size: 1.6rem;
484
+ font-weight: bold;
485
+ }
486
+
487
+ label {
488
+ display: inline-block;
489
+ margin-bottom: 5px;
490
+ }
491
+
492
+ textarea,
493
+ input[type='text'],
494
+ .unrecoverable-error {
495
+ padding: 5px;
496
+ width: calc(100% - 10px);
497
+ font-family: inherit;
498
+ border-radius: 5px;
499
+ border: 1px solid var(--container-border-color, #999999);
500
+ }
501
+
502
+ .input-box.error input,
503
+ .input-box.error textarea {
504
+ border: 2px solid var(--container-error-color, #ea0202);
505
+ }
506
+
507
+ .input-box.error .char-count,
508
+ .input-error,
509
+ .unrecoverable-error,
510
+ .recoverable-error {
511
+ color: var(--container-error-color, #ea0202);
512
+ }
513
+
514
+ .input-error {
515
+ display: none;
516
+ }
517
+
518
+ .input-box.error .input-error {
519
+ display: block;
520
+ text-align: right;
521
+ padding-top: 5px;
522
+ }
523
+
524
+ .inline-link {
525
+ color: var(--container-link-color, #4f65f5);
526
+ text-decoration: none;
527
+ }
528
+
529
+ .inline-link:hover {
530
+ text-decoration: underline;
531
+ }
532
+
533
+ .stars {
534
+ display: flex;
535
+ flex-direction: row;
536
+ gap: 2px;
537
+ align-items: center;
538
+ }
539
+
540
+ .star {
541
+ all: unset;
542
+ height: 30px;
543
+ width: 30px;
544
+ }
545
+
546
+ .star-selected,
547
+ .star-unselected {
548
+ display: block;
549
+ width: 100%;
550
+ height: 100%;
551
+ }
552
+
553
+ .star:hover {
554
+ cursor: pointer;
555
+ }
556
+
557
+ .clear-stars-btn,
558
+ .recoverable-error a {
559
+ padding: 0 5px;
560
+ color: var(--container-link-color, #4f65f5);
561
+ font-family: inherit;
562
+ border: none;
563
+ background: transparent;
564
+ display: inline-block;
565
+ padding-top: 5px;
566
+ }
567
+
568
+ .clear-stars-btn:hover,
569
+ .recoverable-error a:hover {
570
+ cursor: pointer;
571
+ text-decoration: underline;
572
+ }
573
+
574
+ .action-btns {
575
+ width: 100%;
576
+ display: flex;
577
+ justify-content: flex-end;
578
+ gap: 10px;
579
+ padding-top: 15px;
580
+ }
581
+
582
+ .ia-button:disabled {
583
+ opacity: 0.75;
584
+ }
585
+
586
+ .ia-button:disabled:hover {
587
+ cursor: not-allowed;
588
+ }
589
+
590
+ .unrecoverable-error {
591
+ min-height: 50px;
592
+ padding: 5px;
593
+ text-align: center;
594
+ display: flex;
595
+ flex-direction: column;
596
+ justify-content: center;
597
+ background-color: var(--container-bg-color, #fbfbfd);
598
+ }
599
+
600
+ .recaptcha-disclaimer {
601
+ font-size: 1.2rem;
602
+ }
603
+
604
+ @media only screen and (max-width: 350px) {
605
+ .action-btns {
606
+ flex-direction: column-reverse;
607
+ align-items: center;
608
+ }
609
+ }
610
+ `,
611
+ ];
612
+ }
613
+ };
614
+ __decorate([
615
+ property({ type: String })
616
+ ], IAReviewForm.prototype, "identifier", void 0);
617
+ __decorate([
618
+ property({ type: String })
619
+ ], IAReviewForm.prototype, "token", void 0);
620
+ __decorate([
621
+ property({ type: String })
622
+ ], IAReviewForm.prototype, "baseHost", void 0);
623
+ __decorate([
624
+ property({ type: String })
625
+ ], IAReviewForm.prototype, "endpointPath", void 0);
626
+ __decorate([
627
+ property({ type: String })
628
+ ], IAReviewForm.prototype, "submitterScreenname", void 0);
629
+ __decorate([
630
+ property({ type: String })
631
+ ], IAReviewForm.prototype, "submitterItemname", void 0);
632
+ __decorate([
633
+ property({ type: Object })
634
+ ], IAReviewForm.prototype, "oldReview", void 0);
635
+ __decorate([
636
+ property({ type: String })
637
+ ], IAReviewForm.prototype, "unrecoverableError", void 0);
638
+ __decorate([
639
+ property({ type: Number })
640
+ ], IAReviewForm.prototype, "maxSubjectLength", void 0);
641
+ __decorate([
642
+ property({ type: Number })
643
+ ], IAReviewForm.prototype, "maxBodyLength", void 0);
644
+ __decorate([
645
+ property({ type: Object })
646
+ ], IAReviewForm.prototype, "fetchHandler", void 0);
647
+ __decorate([
648
+ property({ type: Object })
649
+ ], IAReviewForm.prototype, "recaptchaManager", void 0);
650
+ __decorate([
651
+ property({ type: Boolean })
652
+ ], IAReviewForm.prototype, "bypassRecaptcha", void 0);
653
+ __decorate([
654
+ state()
655
+ ], IAReviewForm.prototype, "currentStars", void 0);
656
+ __decorate([
657
+ state()
658
+ ], IAReviewForm.prototype, "currentSubjectLength", void 0);
659
+ __decorate([
660
+ state()
661
+ ], IAReviewForm.prototype, "currentBodyLength", void 0);
662
+ __decorate([
663
+ state()
664
+ ], IAReviewForm.prototype, "recoverableError", void 0);
665
+ __decorate([
666
+ state()
667
+ ], IAReviewForm.prototype, "formCanSubmit", void 0);
668
+ __decorate([
669
+ state()
670
+ ], IAReviewForm.prototype, "submissionInProgress", void 0);
671
+ __decorate([
672
+ query('#review-form')
673
+ ], IAReviewForm.prototype, "reviewForm", void 0);
674
+ IAReviewForm = __decorate([
675
+ customElement('ia-review-form')
676
+ ], IAReviewForm);
677
+ export { IAReviewForm };
678
+ //# sourceMappingURL=ia-review-form.js.map