@internetarchive/elements 1.1.3-webdev-9240.0 → 1.1.3

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 (62) hide show
  1. package/README.md +1 -1
  2. package/dist/src/elements/ia-status-indicator/ia-status-indicator.d.ts +16 -1
  3. package/dist/src/elements/ia-status-indicator/ia-status-indicator.d.ts.map +1 -1
  4. package/dist/src/elements/ia-status-indicator/ia-status-indicator.js +136 -8
  5. package/dist/src/elements/ia-status-indicator/ia-status-indicator.js.map +1 -1
  6. package/package.json +1 -9
  7. package/dist/src/elements/ia-reviews/assets/delete-icon.svg +0 -8
  8. package/dist/src/elements/ia-reviews/assets/star-basic.svg +0 -6
  9. package/dist/src/elements/ia-reviews/assets/star-selected.svg +0 -8
  10. package/dist/src/elements/ia-reviews/assets/star-unselected.svg +0 -8
  11. package/dist/src/elements/ia-reviews/ia-review-form.d.ts +0 -103
  12. package/dist/src/elements/ia-reviews/ia-review-form.d.ts.map +0 -1
  13. package/dist/src/elements/ia-reviews/ia-review-form.js +0 -685
  14. package/dist/src/elements/ia-reviews/ia-review-form.js.map +0 -1
  15. package/dist/src/elements/ia-reviews/ia-review.d.ts +0 -51
  16. package/dist/src/elements/ia-reviews/ia-review.d.ts.map +0 -1
  17. package/dist/src/elements/ia-reviews/ia-review.js +0 -344
  18. package/dist/src/elements/ia-reviews/ia-review.js.map +0 -1
  19. package/dist/src/elements/ia-reviews/ia-reviews.d.ts +0 -68
  20. package/dist/src/elements/ia-reviews/ia-reviews.d.ts.map +0 -1
  21. package/dist/src/elements/ia-reviews/ia-reviews.js +0 -354
  22. package/dist/src/elements/ia-reviews/ia-reviews.js.map +0 -1
  23. package/dist/src/elements/ia-reviews/mocks/mock-fetch-handler.d.ts +0 -23
  24. package/dist/src/elements/ia-reviews/mocks/mock-fetch-handler.d.ts.map +0 -1
  25. package/dist/src/elements/ia-reviews/mocks/mock-fetch-handler.js +0 -37
  26. package/dist/src/elements/ia-reviews/mocks/mock-fetch-handler.js.map +0 -1
  27. package/dist/src/elements/ia-reviews/mocks/mock-review-service.d.ts +0 -12
  28. package/dist/src/elements/ia-reviews/mocks/mock-review-service.d.ts.map +0 -1
  29. package/dist/src/elements/ia-reviews/mocks/mock-review-service.js +0 -19
  30. package/dist/src/elements/ia-reviews/mocks/mock-review-service.js.map +0 -1
  31. package/dist/src/elements/ia-reviews/models.d.ts +0 -38
  32. package/dist/src/elements/ia-reviews/models.d.ts.map +0 -1
  33. package/dist/src/elements/ia-reviews/models.js +0 -2
  34. package/dist/src/elements/ia-reviews/models.js.map +0 -1
  35. package/dist/src/elements/ia-reviews/review-service.d.ts +0 -53
  36. package/dist/src/elements/ia-reviews/review-service.d.ts.map +0 -1
  37. package/dist/src/elements/ia-reviews/review-service.js +0 -97
  38. package/dist/src/elements/ia-reviews/review-service.js.map +0 -1
  39. package/dist/src/elements/ia-reviews/utils/collapse-space.d.ts +0 -13
  40. package/dist/src/elements/ia-reviews/utils/collapse-space.d.ts.map +0 -1
  41. package/dist/src/elements/ia-reviews/utils/collapse-space.js +0 -19
  42. package/dist/src/elements/ia-reviews/utils/collapse-space.js.map +0 -1
  43. package/dist/src/elements/ia-reviews/utils/friendly-truncate.d.ts +0 -14
  44. package/dist/src/elements/ia-reviews/utils/friendly-truncate.d.ts.map +0 -1
  45. package/dist/src/elements/ia-reviews/utils/friendly-truncate.js +0 -65
  46. package/dist/src/elements/ia-reviews/utils/friendly-truncate.js.map +0 -1
  47. package/dist/src/elements/ia-reviews/utils/link-urls-in-text.d.ts +0 -9
  48. package/dist/src/elements/ia-reviews/utils/link-urls-in-text.d.ts.map +0 -1
  49. package/dist/src/elements/ia-reviews/utils/link-urls-in-text.js +0 -40
  50. package/dist/src/elements/ia-reviews/utils/link-urls-in-text.js.map +0 -1
  51. package/dist/src/elements/ia-reviews/utils/sanitize-review-body.d.ts +0 -9
  52. package/dist/src/elements/ia-reviews/utils/sanitize-review-body.d.ts.map +0 -1
  53. package/dist/src/elements/ia-reviews/utils/sanitize-review-body.js +0 -29
  54. package/dist/src/elements/ia-reviews/utils/sanitize-review-body.js.map +0 -1
  55. package/dist/src/elements/ia-reviews/utils/truncate-screenname.d.ts +0 -13
  56. package/dist/src/elements/ia-reviews/utils/truncate-screenname.d.ts.map +0 -1
  57. package/dist/src/elements/ia-reviews/utils/truncate-screenname.js +0 -19
  58. package/dist/src/elements/ia-reviews/utils/truncate-screenname.js.map +0 -1
  59. package/dist/src/elements/index.d.ts +0 -43
  60. package/dist/src/elements/index.d.ts.map +0 -1
  61. package/dist/src/elements/index.js +0 -43
  62. package/dist/src/elements/index.js.map +0 -1
package/README.md CHANGED
@@ -141,7 +141,7 @@ src
141
141
  - ia-foobar.test.ts // the element's tests
142
142
  - ia-foobar-story.ts // an element that demos your element
143
143
  ```
144
- Export your component in `src/index.ts`
144
+ Consumers import each element by its own subpath (`@internetarchive/elements/ia-button/ia-button`). There's no package root export, so there's no barrel file to update.
145
145
 
146
146
  ### Naming
147
147
  Custom elements all share one global registry, and that registry is shared with every other script on the host page. Give each element a name specific enough that nothing else would plausibly want it.
@@ -1,4 +1,4 @@
1
- import { CSSResultGroup, LitElement, TemplateResult } from 'lit';
1
+ import { CSSResultGroup, LitElement, PropertyValues, TemplateResult } from 'lit';
2
2
  export type LoadingStatus = 'ready' | 'loading' | 'success' | 'error';
3
3
  /**
4
4
  * The mediatype glyphs this element ships. These are *icon* names, which do not
@@ -23,7 +23,22 @@ export declare class IAStatusIndicator extends LitElement {
23
23
  mediatype?: MediaTypeIcon;
24
24
  hideDots: boolean;
25
25
  private hasSlottedIcon;
26
+ private _outgoingModes;
27
+ private _canAnimate;
28
+ private _fadeTimers;
26
29
  render(): TemplateResult;
30
+ /**
31
+ * One mode's artwork, stacked in the same cell as the other layers so that
32
+ * a mode change fades between them. At rest only the active layer has
33
+ * content; an outgoing one is emptied as soon as its fade is over, so the
34
+ * shadow tree holds a single mode's markup and a single `<title>`.
35
+ */
36
+ private layerTemplate;
37
+ private modeTemplate;
38
+ willUpdate(changedProps: PropertyValues): void;
39
+ private stopFadingOut;
40
+ firstUpdated(): void;
41
+ disconnectedCallback(): void;
27
42
  /**
28
43
  * The `ready` state: reserves the indicator's space without drawing, so a
29
44
  * consumer's layout doesn't shift once the indicator appears.
@@ -1 +1 @@
1
- {"version":3,"file":"ia-status-indicator.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-status-indicator/ia-status-indicator.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,cAAc,EAEd,UAAU,EAIV,cAAc,EACf,MAAM,KAAK,CAAC;AAoBb,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;AAEtE;;;;GAIG;AACH,MAAM,MAAM,aAAa,GACrB,OAAO,GACP,YAAY,GACZ,OAAO,GACP,QAAQ,GACR,QAAQ,GACR,UAAU,GACV,OAAO,GACP,IAAI,GACJ,OAAO,GACP,KAAK,CAAC;AAeV;;;;;;;;GAQG;AACH,qBACa,iBAAkB,SAAQ,UAAU;IAEnB,YAAY,SAAqB;IAGjC,YAAY,SAAkB;IAG9B,UAAU,SAAgB;IAG1B,IAAI,EAAE,aAAa,CAAa;IAGhC,SAAS,CAAC,EAAE,aAAa,CAAC;IAGzB,QAAQ,UAAS;IAGrC,OAAO,CAAC,cAAc,CAAS;IAExC,MAAM,IAAI,cAAc;IASxB;;;OAGG;IACH,OAAO,KAAK,mBAAmB,GAE9B;IAED;;;;;OAKG;IACH,OAAO,KAAK,gBAAgB,GAG3B;IAED,6EAA6E;IAC7E,OAAO,KAAK,aAAa,GAExB;IAED;;;;;;OAMG;IACH,OAAO,KAAK,wBAAwB,GAYnC;IAED,oEAAoE;IACpE,OAAO,KAAK,aAAa,GA4BxB;IAED,8DAA8D;IAC9D,OAAO,KAAK,WAAW,GAoBtB;IAED;;;OAGG;IACH,OAAO,KAAK,qBAAqB,GAKhC;IAED,OAAO,CAAC,oBAAoB;IAK5B,wCAAwC;IACxC,OAAO,KAAK,wBAAwB,GAyBnC;IAED,gCAAgC;IAChC,OAAO,KAAK,sBAAsB,GAkBjC;IAED,MAAM,KAAK,MAAM,IAAI,cAAc,CA4HlC;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,qBAAqB,EAAE,iBAAiB,CAAC;KAC1C;CACF"}
1
+ {"version":3,"file":"ia-status-indicator.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-status-indicator/ia-status-indicator.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,cAAc,EAEd,UAAU,EAEV,cAAc,EAGd,cAAc,EACf,MAAM,KAAK,CAAC;AAyBb,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;AAEtE;;;;GAIG;AACH,MAAM,MAAM,aAAa,GACrB,OAAO,GACP,YAAY,GACZ,OAAO,GACP,QAAQ,GACR,QAAQ,GACR,UAAU,GACV,OAAO,GACP,IAAI,GACJ,OAAO,GACP,KAAK,CAAC;AAeV;;;;;;;;GAQG;AACH,qBACa,iBAAkB,SAAQ,UAAU;IAEnB,YAAY,SAAqB;IAGjC,YAAY,SAAkB;IAG9B,UAAU,SAAgB;IAG1B,IAAI,EAAE,aAAa,CAAa;IAGhC,SAAS,CAAC,EAAE,aAAa,CAAC;IAGzB,QAAQ,UAAS;IAGrC,OAAO,CAAC,cAAc,CAAS;IAG/B,OAAO,CAAC,cAAc,CAAyC;IAG/D,OAAO,CAAC,WAAW,CAAS;IAGrC,OAAO,CAAC,WAAW,CAA2D;IAE9E,MAAM,IAAI,cAAc;IAYxB;;;;;OAKG;IACH,OAAO,CAAC,aAAa;IAerB,OAAO,CAAC,YAAY;IAapB,UAAU,CAAC,YAAY,EAAE,cAAc,GAAG,IAAI;IAmB9C,OAAO,CAAC,aAAa;IAUrB,YAAY,IAAI,IAAI;IAYpB,oBAAoB,IAAI,IAAI;IAS5B;;;OAGG;IACH,OAAO,KAAK,mBAAmB,GAE9B;IAED;;;;;OAKG;IACH,OAAO,KAAK,gBAAgB,GAG3B;IAED,6EAA6E;IAC7E,OAAO,KAAK,aAAa,GAExB;IAED;;;;;;OAMG;IACH,OAAO,KAAK,wBAAwB,GAYnC;IAED,oEAAoE;IACpE,OAAO,KAAK,aAAa,GA4BxB;IAED,8DAA8D;IAC9D,OAAO,KAAK,WAAW,GAoBtB;IAED;;;OAGG;IACH,OAAO,KAAK,qBAAqB,GAKhC;IAED,OAAO,CAAC,oBAAoB;IAK5B,wCAAwC;IACxC,OAAO,KAAK,wBAAwB,GAyBnC;IAED,gCAAgC;IAChC,OAAO,KAAK,sBAAsB,GAkBjC;IAED,MAAM,KAAK,MAAM,IAAI,cAAc,CAgKlC;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,qBAAqB,EAAE,iBAAiB,CAAC;KAC1C;CACF"}
@@ -1,9 +1,8 @@
1
1
  import { __decorate } from "tslib";
2
- import { css, html, LitElement, nothing, svg, } from 'lit';
2
+ import { css, unsafeCSS, html, LitElement, nothing, svg, } from 'lit';
3
3
  import { property, state } from 'lit/decorators.js';
4
4
  import { customElement } from '../../util/custom-element.js';
5
5
  import { msg } from '@lit/localize';
6
- import { choose } from 'lit/directives/choose.js';
7
6
  import themeStyles from '../../themes/theme-styles.js';
8
7
  import { maskedIcon } from '../../util/masked-icon.js';
9
8
  import audioIcon from './icons/audio.svg';
@@ -16,6 +15,10 @@ import textsIcon from './icons/texts.svg';
16
15
  import tvIcon from './icons/tv.svg';
17
16
  import videoIcon from './icons/video.svg';
18
17
  import webIcon from './icons/web.svg';
18
+ /** How long a mode change takes to fade. Drives both the CSS and the timer. */
19
+ const FADE_DURATION_MS = 250;
20
+ /** One layer per mode, always rendered in this order. See render(). */
21
+ const LAYER_ORDER = ['ready', 'loading', 'success', 'error'];
19
22
  const MEDIATYPE_ICONS = {
20
23
  audio: audioIcon,
21
24
  collection: collectionIcon,
@@ -52,14 +55,97 @@ let IAStatusIndicator = class IAStatusIndicator extends LitElement {
52
55
  this.hideDots = false;
53
56
  /* Whether a consumer has slotted their own center icon */
54
57
  this.hasSlottedIcon = false;
58
+ /* The modes still fading out after a change. More than one when changes overlap. */
59
+ this._outgoingModes = new Set();
60
+ /* Set once the first render is done, so the element doesn't fade in on mount */
61
+ this._canAnimate = false;
62
+ /* One per outgoing mode, clearing it once its own fade is over */
63
+ this._fadeTimers = new Map();
55
64
  }
56
65
  render() {
57
- return html `${choose(this.mode, [
58
- ['ready', () => this.placeholderTemplate],
59
- ['loading', () => this.loadingIndicatorTemplate],
60
- ['success', () => this.successIndicatorTemplate],
61
- ['error', () => this.errorIndicatorTemplate],
62
- ])}`;
66
+ // Every mode has its own layer element that never moves, whatever order
67
+ // the changes come in. Moving an element cancels the transition it's in
68
+ // the middle of, so a layer partway through a fade would snap to its end
69
+ // value. A layer only has content while it's on screen.
70
+ return html `
71
+ <div class="layers ${this._canAnimate ? 'animate' : ''}">
72
+ ${LAYER_ORDER.map((mode) => this.layerTemplate(mode))}
73
+ </div>
74
+ `;
75
+ }
76
+ /**
77
+ * One mode's artwork, stacked in the same cell as the other layers so that
78
+ * a mode change fades between them. At rest only the active layer has
79
+ * content; an outgoing one is emptied as soon as its fade is over, so the
80
+ * shadow tree holds a single mode's markup and a single `<title>`.
81
+ */
82
+ layerTemplate(mode) {
83
+ // `mode` is a public string attribute, so a consumer can hand us anything.
84
+ // An unrecognised one matches no layer and draws nothing.
85
+ const isActive = mode === this.mode;
86
+ const isOutgoing = !isActive && this._outgoingModes.has(mode);
87
+ const state = isActive ? 'active' : isOutgoing ? 'outgoing' : '';
88
+ return html `<div
89
+ class="layer ${state}"
90
+ aria-hidden=${isActive ? nothing : 'true'}
91
+ >
92
+ ${isActive || isOutgoing ? this.modeTemplate(mode) : nothing}
93
+ </div>`;
94
+ }
95
+ modeTemplate(mode) {
96
+ switch (mode) {
97
+ case 'ready':
98
+ return this.placeholderTemplate;
99
+ case 'loading':
100
+ return this.loadingIndicatorTemplate;
101
+ case 'success':
102
+ return this.successIndicatorTemplate;
103
+ case 'error':
104
+ return this.errorIndicatorTemplate;
105
+ }
106
+ }
107
+ willUpdate(changedProps) {
108
+ if (!changedProps.has('mode'))
109
+ return;
110
+ // Hold on to the mode we're leaving so both can be on screen together for
111
+ // the length of the fade.
112
+ const previous = changedProps.get('mode');
113
+ if (previous === undefined || previous === this.mode)
114
+ return;
115
+ // The mode coming back in may still be fading out from an earlier change.
116
+ // Its layer just turns around, so it's no longer outgoing.
117
+ this.stopFadingOut(this.mode);
118
+ this._outgoingModes = new Set(this._outgoingModes).add(previous);
119
+ clearTimeout(this._fadeTimers.get(previous));
120
+ this._fadeTimers.set(previous, setTimeout(() => this.stopFadingOut(previous), FADE_DURATION_MS));
121
+ }
122
+ stopFadingOut(mode) {
123
+ clearTimeout(this._fadeTimers.get(mode));
124
+ this._fadeTimers.delete(mode);
125
+ if (!this._outgoingModes.has(mode))
126
+ return;
127
+ const outgoing = new Set(this._outgoingModes);
128
+ outgoing.delete(mode);
129
+ this._outgoingModes = outgoing;
130
+ }
131
+ firstUpdated() {
132
+ // Fading applies to mode changes, not to the element appearing. Waiting a
133
+ // frame is what makes that true: enabling it inline would put the
134
+ // transition in the element's very first computed style, and it would
135
+ // fade up from nothing on mount.
136
+ requestAnimationFrame(() => {
137
+ requestAnimationFrame(() => {
138
+ this._canAnimate = true;
139
+ });
140
+ });
141
+ }
142
+ disconnectedCallback() {
143
+ this._fadeTimers.forEach((timer) => clearTimeout(timer));
144
+ this._fadeTimers.clear();
145
+ // Nothing reschedules these timers, so leaving the modes set would strand
146
+ // the outgoing layers on reconnect.
147
+ this._outgoingModes = new Set();
148
+ super.disconnectedCallback();
63
149
  }
64
150
  /**
65
151
  * The `ready` state: reserves the indicator's space without drawing, so a
@@ -238,6 +324,36 @@ let IAStatusIndicator = class IAStatusIndicator extends LitElement {
238
324
  width: var(--indicator-width--);
239
325
  }
240
326
 
327
+ /* Every mode occupies the same cell, so the element keeps one size */
328
+ .layers {
329
+ display: grid;
330
+ }
331
+
332
+ .layer {
333
+ grid-area: 1 / 1;
334
+ opacity: 0;
335
+ }
336
+
337
+ .animate .layer {
338
+ transition: opacity ${unsafeCSS(FADE_DURATION_MS)}ms ease-out;
339
+ }
340
+
341
+ .layer.active {
342
+ opacity: 1;
343
+ }
344
+
345
+ /* A ring on its way out would otherwise keep animating unseen */
346
+ .layer.outgoing .loading-ring,
347
+ .layer.outgoing .loading-dots > * {
348
+ animation-play-state: paused;
349
+ }
350
+
351
+ @media (prefers-reduced-motion: reduce) {
352
+ .animate .layer {
353
+ transition: none;
354
+ }
355
+ }
356
+
241
357
  .placeholder {
242
358
  height: var(--indicator-width--);
243
359
  }
@@ -276,6 +392,12 @@ let IAStatusIndicator = class IAStatusIndicator extends LitElement {
276
392
  background-color: var(--loading-icon-color--);
277
393
  }
278
394
 
395
+ /* Block, so the svg isn't padded out by the line box it would sit in */
396
+ .success-indicator,
397
+ .error-indicator {
398
+ display: block;
399
+ }
400
+
279
401
  .success-icon {
280
402
  fill: var(--success-icon-color--);
281
403
  }
@@ -363,6 +485,12 @@ __decorate([
363
485
  __decorate([
364
486
  state()
365
487
  ], IAStatusIndicator.prototype, "hasSlottedIcon", void 0);
488
+ __decorate([
489
+ state()
490
+ ], IAStatusIndicator.prototype, "_outgoingModes", void 0);
491
+ __decorate([
492
+ state()
493
+ ], IAStatusIndicator.prototype, "_canAnimate", void 0);
366
494
  IAStatusIndicator = __decorate([
367
495
  customElement('ia-status-indicator')
368
496
  ], IAStatusIndicator);
@@ -1 +1 @@
1
- {"version":3,"file":"ia-status-indicator.js","sourceRoot":"","sources":["../../../../src/elements/ia-status-indicator/ia-status-indicator.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n css,\n CSSResultGroup,\n html,\n LitElement,\n nothing,\n svg,\n SVGTemplateResult,\n TemplateResult,\n} from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { customElement } from '@src/util/custom-element';\nimport { msg } from '@lit/localize';\nimport { choose } from 'lit/directives/choose.js';\n\nimport themeStyles from '@src/themes/theme-styles';\nimport { maskedIcon } from '@src/util/masked-icon';\n\nimport audioIcon from './icons/audio.svg';\nimport collectionIcon from './icons/collection.svg';\nimport etreeIcon from './icons/etree.svg';\nimport imagesIcon from './icons/images.svg';\nimport searchIcon from './icons/search.svg';\nimport softwareIcon from './icons/software.svg';\nimport textsIcon from './icons/texts.svg';\nimport tvIcon from './icons/tv.svg';\nimport videoIcon from './icons/video.svg';\nimport webIcon from './icons/web.svg';\n\nexport type LoadingStatus = 'ready' | 'loading' | 'success' | 'error';\n\n/**\n * The mediatype glyphs this element ships. These are *icon* names, which do not\n * map one-to-one onto archive.org mediatype values — a consumer holding a\n * `MediaType` translates at its own call site (e.g. `movies` -> `video`).\n */\nexport type MediaTypeIcon =\n | 'audio'\n | 'collection'\n | 'etree'\n | 'images'\n | 'search'\n | 'software'\n | 'texts'\n | 'tv'\n | 'video'\n | 'web';\n\nconst MEDIATYPE_ICONS: Record<MediaTypeIcon, string> = {\n audio: audioIcon,\n collection: collectionIcon,\n etree: etreeIcon,\n images: imagesIcon,\n search: searchIcon,\n software: softwareIcon,\n texts: textsIcon,\n tv: tvIcon,\n video: videoIcon,\n web: webIcon,\n};\n\n/**\n * Renders an SVG indicator, which defaults to an animated circular indicator.\n *\n * In `loading` mode the middle of the ring resolves in this order:\n * 1. slotted `icon` content\n * 2. the `mediatype` glyph\n * 3. nothing, when `hideDots` is set\n * 4. three animated dots (the default)\n */\n@customElement('ia-status-indicator')\nexport class IAStatusIndicator extends LitElement {\n /* An optional title to use for the loading state of the indicator. Will be used for screen readers. */\n @property({ type: String }) loadingTitle = msg('Loading...');\n\n /* An optional title to use for the success state of the indicator. Will be used for screen readers. */\n @property({ type: String }) successTitle = msg('Success');\n\n /* An optional title to use for the error state of the indicator. Will be used for screen readers. */\n @property({ type: String }) errorTitle = msg('Error');\n\n /* The state of the indicator that should be shown */\n @property({ type: String }) mode: LoadingStatus = 'loading';\n\n /* An optional mediatype glyph to render in the middle of the loading ring */\n @property({ type: String }) mediatype?: MediaTypeIcon;\n\n /* Renders a bare ring, with no dots in the middle. Ignored when a center icon is present. */\n @property({ type: Boolean }) hideDots = false;\n\n /* Whether a consumer has slotted their own center icon */\n @state() private hasSlottedIcon = false;\n\n render(): TemplateResult {\n return html`${choose(this.mode, [\n ['ready', () => this.placeholderTemplate],\n ['loading', () => this.loadingIndicatorTemplate],\n ['success', () => this.successIndicatorTemplate],\n ['error', () => this.errorIndicatorTemplate],\n ])}`;\n }\n\n /**\n * The `ready` state: reserves the indicator's space without drawing, so a\n * consumer's layout doesn't shift once the indicator appears.\n */\n private get placeholderTemplate(): TemplateResult {\n return html`<div class=\"placeholder\"></div>`;\n }\n\n /**\n * The asset URL for the current mediatype, if it maps to a glyph we ship.\n *\n * Unmapped values (e.g. archive.org's `account` or `data`) resolve to\n * undefined and degrade to the default dots rather than a broken mask.\n */\n private get mediatypeIconUrl(): string | undefined {\n if (!this.mediatype) return undefined;\n return MEDIATYPE_ICONS[this.mediatype];\n }\n\n /** Whether the middle of the ring is occupied by a glyph rather than dots */\n private get hasCenterIcon(): boolean {\n return this.hasSlottedIcon || !!this.mediatypeIconUrl;\n }\n\n /**\n * A circular loading indicator to render when processing.\n *\n * Two ring geometries are kept deliberately: the original 120x120 ring is\n * tuned for the dots, and the roomier 100x100 ring leaves space for a center\n * glyph. Keeping both means existing consumers see no visual change.\n */\n private get loadingIndicatorTemplate(): TemplateResult {\n const hasCenterIcon = this.hasCenterIcon;\n return html`\n <div class=\"indicator\">\n ${hasCenterIcon ? this.iconRingSvg : this.dottedRingSvg}\n <span class=\"center\" ?hidden=${!hasCenterIcon}>\n <slot name=\"icon\" @slotchange=${this.handleIconSlotChange}>\n ${this.mediatypeIconTemplate}\n </slot>\n </span>\n </div>\n `;\n }\n\n /** The original ring, with the three animated dots in the middle */\n private get dottedRingSvg(): SVGTemplateResult {\n return svg`\n <svg\n class=\"loading-indicator\"\n viewBox=\"0 0 120 120\"\n preserveAspectRatio=\"none\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n role=\"status\"\n >\n <title>${this.loadingTitle}</title>\n <g stroke=\"none\" stroke-width=\"1\" fill-rule=\"evenodd\">\n <path\n class=\"loading-ring\"\n d=\"M60,10 C69.8019971,10 78.9452178,12.8205573 86.6623125,17.6943223 L76.4086287,27.9484118 C71.4880919,25.4243078 65.9103784,24 60,24 C40.117749,24 24,40.117749 24,60 C24,79.882251 40.117749,96 60,96 C79.882251,96 96,79.882251 96,60 C96,53.3014663 94.1704984,47.0302355 90.9839104,41.6587228 L101.110332,31.5326452 C106.715332,39.6116982 110,49.4222615 110,60 C110,87.6142375 87.6142375,110 60,110 C32.3857625,110 10,87.6142375 10,60 C10,32.3857625 32.3857625,10 60,10 Z\"\n ></path>\n <g\n class=\"loading-dots ${this.hideDots ? 'hidden' : ''}\"\n transform=\"translate(40.000000, 55.000000)\"\n >\n <circle id=\"left-dot\" cx=\"5\" cy=\"5\" r=\"5\"></circle>\n <circle id=\"middle-dot\" cx=\"20\" cy=\"5\" r=\"5\"></circle>\n <circle id=\"right-dot\" cx=\"35\" cy=\"5\" r=\"5\"></circle>\n </g>\n </g>\n </svg>\n `;\n }\n\n /** The roomier ring, used when a glyph occupies the middle */\n private get iconRingSvg(): SVGTemplateResult {\n return svg`\n <svg\n class=\"loading-indicator icon-ring\"\n viewBox=\"0 0 100 100\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n role=\"status\"\n >\n <title>${this.loadingTitle}</title>\n <g fill-rule=\"evenodd\">\n <path\n class=\"loading-ring\"\n fill-rule=\"nonzero\"\n d=\"m17.8618849 11.6970233c18.5864635-15.59603144 45.6875867-15.59603102 64.2740497.000001 1.9271446 1.6170806 2.1785128 4.4902567.5614466 6.4174186-1.6170661 1.9271618-4.4902166 2.1785323-6.4173612.5614517-15.1996922-12.75416882-37.3625282-12.75416916-52.5622206-.000001-15.19969387 12.7541707-19.04823077 34.5805019-9.1273354 51.7641499 9.9208955 17.183646 30.7471499 24.7638499 49.3923323 17.9774983 18.6451823-6.7863521 29.7266014-25.9801026 26.2811129-45.5206248-.436848-2.4775114 1.2174186-4.8400696 3.6949079-5.2769215 2.4774893-.4368518 4.8400264 1.2174296 5.2768744 3.694941 4.2132065 23.8945096-9.3373563 47.3649806-32.137028 55.6634567-22.799672 8.2984758-48.2663986-.9707372-60.39785211-21.9832155-12.1314534-21.012481-7.42539173-47.7021198 11.16107351-63.2981544z\"\n ></path>\n </g>\n </svg>\n `;\n }\n\n /**\n * The bundled mediatype glyph. `maskedIcon` supplies the mask geometry and\n * the decorative `aria-hidden`; this component supplies the size and paint.\n */\n private get mediatypeIconTemplate(): TemplateResult | typeof nothing {\n const url = this.mediatypeIconUrl;\n if (!url) return nothing;\n\n return maskedIcon(url);\n }\n\n private handleIconSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this.hasSlottedIcon = slot.assignedNodes({ flatten: false }).length > 0;\n }\n\n /** A check mark to render on success */\n private get successIndicatorTemplate(): TemplateResult {\n return html`\n <svg\n class=\"success-indicator\"\n viewBox=\"0 0 120 120\"\n preserveAspectRatio=\"none\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n role=\"status\"\n >\n <title>${this.successTitle}</title>\n <g stroke=\"none\" stroke-width=\"1\" fill-rule=\"evenodd\">\n <path\n class=\"success-icon\"\n d=\"M60,10 C70.5816709,10 80.3955961,13.2871104 88.4763646,18.8959201 L78.3502633,29.0214223 C72.9767592,25.8315427 66.7022695,24 60,24 C40.117749,24 24,40.117749 24,60 C24,79.882251 40.117749,96 60,96 C79.882251,96 96,79.882251 96,60 L95.995,59.46 L108.327675,47.128668 C109.350926,50.9806166 109.925886,55.015198 109.993301,59.1731586 L110,60 C110,87.6142375 87.6142375,110 60,110 C32.3857625,110 10,87.6142375 10,60 C10,32.3857625 32.3857625,10 60,10 Z\"\n ></path>\n <polygon\n class=\"success-icon\"\n transform=\"translate(75.000000, 41.500000) rotate(44.000000) translate(-75.000000, -41.500000) \"\n points=\"96 85 54 85 54 65 76 64.999 76 -2 96 -2\"\n ></polygon>\n </g>\n </svg>\n `;\n }\n\n /** An \"!\" to render on error */\n private get errorIndicatorTemplate(): TemplateResult {\n return html`\n <svg\n class=\"error-indicator\"\n viewBox=\"0 0 120 120\"\n preserveAspectRatio=\"none\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n role=\"status\"\n >\n <title>${this.errorTitle}</title>\n <path\n class=\"error-icon\"\n d=\"m56.4612493 8.80450354 41.8901185 75.94632926c1.7706782 2.8433173 2.1150372 5.2623412 1.0330766 7.2570716-1.0819604 1.9947304-3.26978 2.9920956-6.5634587 2.9920956h-85.69973905c-3.29367873 0-5.46954894-.9973652-6.52761065-2.9920956-1.0580617-1.9947304-.70175345-4.4137543 1.06892476-7.2570716l41.89011844-75.12308969c1.8184757-2.84331737 3.9693609-4.37738627 6.4526556-4.60220671s4.6341799 1.03483527 6.4526556 3.77896714zm28.5387507 75.19549646-35.037482-62-34.962518 62zm-31-34.7484359v-10.2515641h-8v10.2515641l2.089172 14.7484359h3.8184713zm-8 19.7484359v8h8v-8z\"\n />\n </svg>\n `;\n }\n\n static get styles(): CSSResultGroup {\n return [\n themeStyles,\n css`\n :host {\n --indicator-width--: var(--icon-width);\n\n /* Loading */\n --loading-ring-color--: var(--primary-text-color);\n --loading-dot-color--: var(--primary-text-color);\n --loading-icon-color--: var(--primary-text-color);\n\n /* Success */\n --success-icon-color--: var(--color-success);\n\n /* Error */\n --error-icon-color--: var(--color-danger);\n\n display: inline-block;\n width: var(--indicator-width--);\n }\n\n .placeholder {\n height: var(--indicator-width--);\n }\n\n /* Stacks the center glyph over the ring */\n .indicator {\n position: relative;\n display: block;\n }\n\n .indicator svg {\n display: block;\n width: 100%;\n height: auto;\n }\n\n .center {\n position: absolute;\n inset: 0;\n display: grid;\n place-items: center;\n }\n\n .center[hidden] {\n display: none;\n }\n\n /*\n * Sized to fit within the icon ring's inner diameter. maskedIcon sets\n * the mask itself; background-color is what paints the glyph, so it\n * recolors with the ring.\n */\n .ia-icon {\n width: 50%;\n height: 50%;\n background-color: var(--loading-icon-color--);\n }\n\n .success-icon {\n fill: var(--success-icon-color--);\n }\n\n .error-icon {\n fill: var(--error-icon-color--);\n }\n\n .loading-ring {\n fill: var(--loading-ring-color--);\n animation: rotate 1.3s infinite linear;\n transform-origin: 50px 50px;\n transform-box: fill-box;\n }\n\n .loading-dots {\n fill: var(--loading-dot-color--);\n transition: opacity 0.25s ease-out;\n }\n\n .loading-dots.hidden {\n display: none;\n }\n\n .loading-dots > * {\n opacity: 0;\n animation: dot 1.3s infinite;\n }\n\n .loading-dots #left-dot {\n animation-delay: 0.2s;\n }\n\n .loading-dots #middle-dot {\n animation-delay: 0.4s;\n }\n\n .loading-dots #right-dot {\n animation-delay: 0.6s;\n }\n\n @keyframes rotate {\n 0% {\n transform: rotate(-360deg);\n }\n 100% {\n /* This frame is supposed to be inferred, but Safari doesn't rotate it unless we're explicit */\n transform: rotate(0deg);\n }\n }\n\n @keyframes dot {\n 0% {\n opacity: 0;\n }\n 25% {\n opacity: 1;\n }\n 100% {\n opacity: 0;\n }\n }\n `,\n ];\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ia-status-indicator': IAStatusIndicator;\n }\n}\n"]}
1
+ {"version":3,"file":"ia-status-indicator.js","sourceRoot":"","sources":["../../../../src/elements/ia-status-indicator/ia-status-indicator.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n css,\n unsafeCSS,\n CSSResultGroup,\n html,\n LitElement,\n nothing,\n PropertyValues,\n svg,\n SVGTemplateResult,\n TemplateResult,\n} from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { customElement } from '@src/util/custom-element';\nimport { msg } from '@lit/localize';\n\nimport themeStyles from '@src/themes/theme-styles';\nimport { maskedIcon } from '@src/util/masked-icon';\n\nimport audioIcon from './icons/audio.svg';\nimport collectionIcon from './icons/collection.svg';\nimport etreeIcon from './icons/etree.svg';\nimport imagesIcon from './icons/images.svg';\nimport searchIcon from './icons/search.svg';\nimport softwareIcon from './icons/software.svg';\nimport textsIcon from './icons/texts.svg';\nimport tvIcon from './icons/tv.svg';\nimport videoIcon from './icons/video.svg';\nimport webIcon from './icons/web.svg';\n\n/** How long a mode change takes to fade. Drives both the CSS and the timer. */\nconst FADE_DURATION_MS = 250;\n\n/** One layer per mode, always rendered in this order. See render(). */\nconst LAYER_ORDER: LoadingStatus[] = ['ready', 'loading', 'success', 'error'];\n\nexport type LoadingStatus = 'ready' | 'loading' | 'success' | 'error';\n\n/**\n * The mediatype glyphs this element ships. These are *icon* names, which do not\n * map one-to-one onto archive.org mediatype values — a consumer holding a\n * `MediaType` translates at its own call site (e.g. `movies` -> `video`).\n */\nexport type MediaTypeIcon =\n | 'audio'\n | 'collection'\n | 'etree'\n | 'images'\n | 'search'\n | 'software'\n | 'texts'\n | 'tv'\n | 'video'\n | 'web';\n\nconst MEDIATYPE_ICONS: Record<MediaTypeIcon, string> = {\n audio: audioIcon,\n collection: collectionIcon,\n etree: etreeIcon,\n images: imagesIcon,\n search: searchIcon,\n software: softwareIcon,\n texts: textsIcon,\n tv: tvIcon,\n video: videoIcon,\n web: webIcon,\n};\n\n/**\n * Renders an SVG indicator, which defaults to an animated circular indicator.\n *\n * In `loading` mode the middle of the ring resolves in this order:\n * 1. slotted `icon` content\n * 2. the `mediatype` glyph\n * 3. nothing, when `hideDots` is set\n * 4. three animated dots (the default)\n */\n@customElement('ia-status-indicator')\nexport class IAStatusIndicator extends LitElement {\n /* An optional title to use for the loading state of the indicator. Will be used for screen readers. */\n @property({ type: String }) loadingTitle = msg('Loading...');\n\n /* An optional title to use for the success state of the indicator. Will be used for screen readers. */\n @property({ type: String }) successTitle = msg('Success');\n\n /* An optional title to use for the error state of the indicator. Will be used for screen readers. */\n @property({ type: String }) errorTitle = msg('Error');\n\n /* The state of the indicator that should be shown */\n @property({ type: String }) mode: LoadingStatus = 'loading';\n\n /* An optional mediatype glyph to render in the middle of the loading ring */\n @property({ type: String }) mediatype?: MediaTypeIcon;\n\n /* Renders a bare ring, with no dots in the middle. Ignored when a center icon is present. */\n @property({ type: Boolean }) hideDots = false;\n\n /* Whether a consumer has slotted their own center icon */\n @state() private hasSlottedIcon = false;\n\n /* The modes still fading out after a change. More than one when changes overlap. */\n @state() private _outgoingModes: ReadonlySet<LoadingStatus> = new Set();\n\n /* Set once the first render is done, so the element doesn't fade in on mount */\n @state() private _canAnimate = false;\n\n /* One per outgoing mode, clearing it once its own fade is over */\n private _fadeTimers = new Map<LoadingStatus, ReturnType<typeof setTimeout>>();\n\n render(): TemplateResult {\n // Every mode has its own layer element that never moves, whatever order\n // the changes come in. Moving an element cancels the transition it's in\n // the middle of, so a layer partway through a fade would snap to its end\n // value. A layer only has content while it's on screen.\n return html`\n <div class=\"layers ${this._canAnimate ? 'animate' : ''}\">\n ${LAYER_ORDER.map((mode) => this.layerTemplate(mode))}\n </div>\n `;\n }\n\n /**\n * One mode's artwork, stacked in the same cell as the other layers so that\n * a mode change fades between them. At rest only the active layer has\n * content; an outgoing one is emptied as soon as its fade is over, so the\n * shadow tree holds a single mode's markup and a single `<title>`.\n */\n private layerTemplate(mode: LoadingStatus): TemplateResult {\n // `mode` is a public string attribute, so a consumer can hand us anything.\n // An unrecognised one matches no layer and draws nothing.\n const isActive = mode === this.mode;\n const isOutgoing = !isActive && this._outgoingModes.has(mode);\n const state = isActive ? 'active' : isOutgoing ? 'outgoing' : '';\n\n return html`<div\n class=\"layer ${state}\"\n aria-hidden=${isActive ? nothing : 'true'}\n >\n ${isActive || isOutgoing ? this.modeTemplate(mode) : nothing}\n </div>`;\n }\n\n private modeTemplate(mode: LoadingStatus): TemplateResult {\n switch (mode) {\n case 'ready':\n return this.placeholderTemplate;\n case 'loading':\n return this.loadingIndicatorTemplate;\n case 'success':\n return this.successIndicatorTemplate;\n case 'error':\n return this.errorIndicatorTemplate;\n }\n }\n\n willUpdate(changedProps: PropertyValues): void {\n if (!changedProps.has('mode')) return;\n // Hold on to the mode we're leaving so both can be on screen together for\n // the length of the fade.\n const previous = changedProps.get('mode') as LoadingStatus | undefined;\n if (previous === undefined || previous === this.mode) return;\n\n // The mode coming back in may still be fading out from an earlier change.\n // Its layer just turns around, so it's no longer outgoing.\n this.stopFadingOut(this.mode);\n\n this._outgoingModes = new Set(this._outgoingModes).add(previous);\n clearTimeout(this._fadeTimers.get(previous));\n this._fadeTimers.set(\n previous,\n setTimeout(() => this.stopFadingOut(previous), FADE_DURATION_MS),\n );\n }\n\n private stopFadingOut(mode: LoadingStatus): void {\n clearTimeout(this._fadeTimers.get(mode));\n this._fadeTimers.delete(mode);\n if (!this._outgoingModes.has(mode)) return;\n\n const outgoing = new Set(this._outgoingModes);\n outgoing.delete(mode);\n this._outgoingModes = outgoing;\n }\n\n firstUpdated(): void {\n // Fading applies to mode changes, not to the element appearing. Waiting a\n // frame is what makes that true: enabling it inline would put the\n // transition in the element's very first computed style, and it would\n // fade up from nothing on mount.\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n this._canAnimate = true;\n });\n });\n }\n\n disconnectedCallback(): void {\n this._fadeTimers.forEach((timer) => clearTimeout(timer));\n this._fadeTimers.clear();\n // Nothing reschedules these timers, so leaving the modes set would strand\n // the outgoing layers on reconnect.\n this._outgoingModes = new Set();\n super.disconnectedCallback();\n }\n\n /**\n * The `ready` state: reserves the indicator's space without drawing, so a\n * consumer's layout doesn't shift once the indicator appears.\n */\n private get placeholderTemplate(): TemplateResult {\n return html`<div class=\"placeholder\"></div>`;\n }\n\n /**\n * The asset URL for the current mediatype, if it maps to a glyph we ship.\n *\n * Unmapped values (e.g. archive.org's `account` or `data`) resolve to\n * undefined and degrade to the default dots rather than a broken mask.\n */\n private get mediatypeIconUrl(): string | undefined {\n if (!this.mediatype) return undefined;\n return MEDIATYPE_ICONS[this.mediatype];\n }\n\n /** Whether the middle of the ring is occupied by a glyph rather than dots */\n private get hasCenterIcon(): boolean {\n return this.hasSlottedIcon || !!this.mediatypeIconUrl;\n }\n\n /**\n * A circular loading indicator to render when processing.\n *\n * Two ring geometries are kept deliberately: the original 120x120 ring is\n * tuned for the dots, and the roomier 100x100 ring leaves space for a center\n * glyph. Keeping both means existing consumers see no visual change.\n */\n private get loadingIndicatorTemplate(): TemplateResult {\n const hasCenterIcon = this.hasCenterIcon;\n return html`\n <div class=\"indicator\">\n ${hasCenterIcon ? this.iconRingSvg : this.dottedRingSvg}\n <span class=\"center\" ?hidden=${!hasCenterIcon}>\n <slot name=\"icon\" @slotchange=${this.handleIconSlotChange}>\n ${this.mediatypeIconTemplate}\n </slot>\n </span>\n </div>\n `;\n }\n\n /** The original ring, with the three animated dots in the middle */\n private get dottedRingSvg(): SVGTemplateResult {\n return svg`\n <svg\n class=\"loading-indicator\"\n viewBox=\"0 0 120 120\"\n preserveAspectRatio=\"none\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n role=\"status\"\n >\n <title>${this.loadingTitle}</title>\n <g stroke=\"none\" stroke-width=\"1\" fill-rule=\"evenodd\">\n <path\n class=\"loading-ring\"\n d=\"M60,10 C69.8019971,10 78.9452178,12.8205573 86.6623125,17.6943223 L76.4086287,27.9484118 C71.4880919,25.4243078 65.9103784,24 60,24 C40.117749,24 24,40.117749 24,60 C24,79.882251 40.117749,96 60,96 C79.882251,96 96,79.882251 96,60 C96,53.3014663 94.1704984,47.0302355 90.9839104,41.6587228 L101.110332,31.5326452 C106.715332,39.6116982 110,49.4222615 110,60 C110,87.6142375 87.6142375,110 60,110 C32.3857625,110 10,87.6142375 10,60 C10,32.3857625 32.3857625,10 60,10 Z\"\n ></path>\n <g\n class=\"loading-dots ${this.hideDots ? 'hidden' : ''}\"\n transform=\"translate(40.000000, 55.000000)\"\n >\n <circle id=\"left-dot\" cx=\"5\" cy=\"5\" r=\"5\"></circle>\n <circle id=\"middle-dot\" cx=\"20\" cy=\"5\" r=\"5\"></circle>\n <circle id=\"right-dot\" cx=\"35\" cy=\"5\" r=\"5\"></circle>\n </g>\n </g>\n </svg>\n `;\n }\n\n /** The roomier ring, used when a glyph occupies the middle */\n private get iconRingSvg(): SVGTemplateResult {\n return svg`\n <svg\n class=\"loading-indicator icon-ring\"\n viewBox=\"0 0 100 100\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n role=\"status\"\n >\n <title>${this.loadingTitle}</title>\n <g fill-rule=\"evenodd\">\n <path\n class=\"loading-ring\"\n fill-rule=\"nonzero\"\n d=\"m17.8618849 11.6970233c18.5864635-15.59603144 45.6875867-15.59603102 64.2740497.000001 1.9271446 1.6170806 2.1785128 4.4902567.5614466 6.4174186-1.6170661 1.9271618-4.4902166 2.1785323-6.4173612.5614517-15.1996922-12.75416882-37.3625282-12.75416916-52.5622206-.000001-15.19969387 12.7541707-19.04823077 34.5805019-9.1273354 51.7641499 9.9208955 17.183646 30.7471499 24.7638499 49.3923323 17.9774983 18.6451823-6.7863521 29.7266014-25.9801026 26.2811129-45.5206248-.436848-2.4775114 1.2174186-4.8400696 3.6949079-5.2769215 2.4774893-.4368518 4.8400264 1.2174296 5.2768744 3.694941 4.2132065 23.8945096-9.3373563 47.3649806-32.137028 55.6634567-22.799672 8.2984758-48.2663986-.9707372-60.39785211-21.9832155-12.1314534-21.012481-7.42539173-47.7021198 11.16107351-63.2981544z\"\n ></path>\n </g>\n </svg>\n `;\n }\n\n /**\n * The bundled mediatype glyph. `maskedIcon` supplies the mask geometry and\n * the decorative `aria-hidden`; this component supplies the size and paint.\n */\n private get mediatypeIconTemplate(): TemplateResult | typeof nothing {\n const url = this.mediatypeIconUrl;\n if (!url) return nothing;\n\n return maskedIcon(url);\n }\n\n private handleIconSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this.hasSlottedIcon = slot.assignedNodes({ flatten: false }).length > 0;\n }\n\n /** A check mark to render on success */\n private get successIndicatorTemplate(): TemplateResult {\n return html`\n <svg\n class=\"success-indicator\"\n viewBox=\"0 0 120 120\"\n preserveAspectRatio=\"none\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n role=\"status\"\n >\n <title>${this.successTitle}</title>\n <g stroke=\"none\" stroke-width=\"1\" fill-rule=\"evenodd\">\n <path\n class=\"success-icon\"\n d=\"M60,10 C70.5816709,10 80.3955961,13.2871104 88.4763646,18.8959201 L78.3502633,29.0214223 C72.9767592,25.8315427 66.7022695,24 60,24 C40.117749,24 24,40.117749 24,60 C24,79.882251 40.117749,96 60,96 C79.882251,96 96,79.882251 96,60 L95.995,59.46 L108.327675,47.128668 C109.350926,50.9806166 109.925886,55.015198 109.993301,59.1731586 L110,60 C110,87.6142375 87.6142375,110 60,110 C32.3857625,110 10,87.6142375 10,60 C10,32.3857625 32.3857625,10 60,10 Z\"\n ></path>\n <polygon\n class=\"success-icon\"\n transform=\"translate(75.000000, 41.500000) rotate(44.000000) translate(-75.000000, -41.500000) \"\n points=\"96 85 54 85 54 65 76 64.999 76 -2 96 -2\"\n ></polygon>\n </g>\n </svg>\n `;\n }\n\n /** An \"!\" to render on error */\n private get errorIndicatorTemplate(): TemplateResult {\n return html`\n <svg\n class=\"error-indicator\"\n viewBox=\"0 0 120 120\"\n preserveAspectRatio=\"none\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n role=\"status\"\n >\n <title>${this.errorTitle}</title>\n <path\n class=\"error-icon\"\n d=\"m56.4612493 8.80450354 41.8901185 75.94632926c1.7706782 2.8433173 2.1150372 5.2623412 1.0330766 7.2570716-1.0819604 1.9947304-3.26978 2.9920956-6.5634587 2.9920956h-85.69973905c-3.29367873 0-5.46954894-.9973652-6.52761065-2.9920956-1.0580617-1.9947304-.70175345-4.4137543 1.06892476-7.2570716l41.89011844-75.12308969c1.8184757-2.84331737 3.9693609-4.37738627 6.4526556-4.60220671s4.6341799 1.03483527 6.4526556 3.77896714zm28.5387507 75.19549646-35.037482-62-34.962518 62zm-31-34.7484359v-10.2515641h-8v10.2515641l2.089172 14.7484359h3.8184713zm-8 19.7484359v8h8v-8z\"\n />\n </svg>\n `;\n }\n\n static get styles(): CSSResultGroup {\n return [\n themeStyles,\n css`\n :host {\n --indicator-width--: var(--icon-width);\n\n /* Loading */\n --loading-ring-color--: var(--primary-text-color);\n --loading-dot-color--: var(--primary-text-color);\n --loading-icon-color--: var(--primary-text-color);\n\n /* Success */\n --success-icon-color--: var(--color-success);\n\n /* Error */\n --error-icon-color--: var(--color-danger);\n\n display: inline-block;\n width: var(--indicator-width--);\n }\n\n /* Every mode occupies the same cell, so the element keeps one size */\n .layers {\n display: grid;\n }\n\n .layer {\n grid-area: 1 / 1;\n opacity: 0;\n }\n\n .animate .layer {\n transition: opacity ${unsafeCSS(FADE_DURATION_MS)}ms ease-out;\n }\n\n .layer.active {\n opacity: 1;\n }\n\n /* A ring on its way out would otherwise keep animating unseen */\n .layer.outgoing .loading-ring,\n .layer.outgoing .loading-dots > * {\n animation-play-state: paused;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .animate .layer {\n transition: none;\n }\n }\n\n .placeholder {\n height: var(--indicator-width--);\n }\n\n /* Stacks the center glyph over the ring */\n .indicator {\n position: relative;\n display: block;\n }\n\n .indicator svg {\n display: block;\n width: 100%;\n height: auto;\n }\n\n .center {\n position: absolute;\n inset: 0;\n display: grid;\n place-items: center;\n }\n\n .center[hidden] {\n display: none;\n }\n\n /*\n * Sized to fit within the icon ring's inner diameter. maskedIcon sets\n * the mask itself; background-color is what paints the glyph, so it\n * recolors with the ring.\n */\n .ia-icon {\n width: 50%;\n height: 50%;\n background-color: var(--loading-icon-color--);\n }\n\n /* Block, so the svg isn't padded out by the line box it would sit in */\n .success-indicator,\n .error-indicator {\n display: block;\n }\n\n .success-icon {\n fill: var(--success-icon-color--);\n }\n\n .error-icon {\n fill: var(--error-icon-color--);\n }\n\n .loading-ring {\n fill: var(--loading-ring-color--);\n animation: rotate 1.3s infinite linear;\n transform-origin: 50px 50px;\n transform-box: fill-box;\n }\n\n .loading-dots {\n fill: var(--loading-dot-color--);\n transition: opacity 0.25s ease-out;\n }\n\n .loading-dots.hidden {\n display: none;\n }\n\n .loading-dots > * {\n opacity: 0;\n animation: dot 1.3s infinite;\n }\n\n .loading-dots #left-dot {\n animation-delay: 0.2s;\n }\n\n .loading-dots #middle-dot {\n animation-delay: 0.4s;\n }\n\n .loading-dots #right-dot {\n animation-delay: 0.6s;\n }\n\n @keyframes rotate {\n 0% {\n transform: rotate(-360deg);\n }\n 100% {\n /* This frame is supposed to be inferred, but Safari doesn't rotate it unless we're explicit */\n transform: rotate(0deg);\n }\n }\n\n @keyframes dot {\n 0% {\n opacity: 0;\n }\n 25% {\n opacity: 1;\n }\n 100% {\n opacity: 0;\n }\n }\n `,\n ];\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ia-status-indicator': IAStatusIndicator;\n }\n}\n"]}
package/package.json CHANGED
@@ -1,9 +1,8 @@
1
1
  {
2
2
  "name": "@internetarchive/elements",
3
- "version": "1.1.3-webdev-9240.0",
3
+ "version": "1.1.3",
4
4
  "description": "A web component library from the Internet Archive.",
5
5
  "license": "AGPL-3.0-only",
6
- "types": "./dist/src/elements/index.d.ts",
7
6
  "type": "module",
8
7
  "packageManager": "pnpm@12.4.0",
9
8
  "engines": {
@@ -33,14 +32,10 @@
33
32
  "ghpages:build": "wireit"
34
33
  },
35
34
  "dependencies": {
36
- "@internetarchive/fetch-handler": "^1.4.0",
37
35
  "@internetarchive/ia-clearable-text-input": "^1.1.1",
38
36
  "@internetarchive/ia-dropdown": "^2.2.0",
39
- "@internetarchive/metadata-service": "^1.0.4",
40
- "@internetarchive/recaptcha-manager": "^1.0.0",
41
37
  "@lit/localize": "^0.12.2",
42
38
  "dayjs": "^1.11.23",
43
- "dompurify": "^3.2.5",
44
39
  "lit": "^2.8.0 || ^3.3.2",
45
40
  "magic-snowflakes": "^7.0.2",
46
41
  "tslib": "^2.8.1"
@@ -49,13 +44,11 @@
49
44
  "@eslint/eslintrc": "^3.3.5",
50
45
  "@eslint/js": "^9.39.1",
51
46
  "@open-wc/testing-helpers": "^3.0.1",
52
- "@types/grecaptcha": "^3.0.9",
53
47
  "@typescript-eslint/eslint-plugin": "^8.46.4",
54
48
  "@typescript-eslint/parser": "^8.46.4",
55
49
  "@vitest/browser": "^4.0.8",
56
50
  "@vitest/browser-playwright": "^4.0.8",
57
51
  "@vitest/coverage-v8": "^4.0.8",
58
- "axe-core": "^4.10.2",
59
52
  "eslint": "^9.39.1",
60
53
  "eslint-config-prettier": "^10.1.8",
61
54
  "eslint-plugin-html": "^8.1.3",
@@ -76,7 +69,6 @@
76
69
  "wireit": "^0.14.12"
77
70
  },
78
71
  "exports": {
79
- ".": "./dist/src/index.js",
80
72
  "./*": "./dist/src/elements/*.js",
81
73
  "./labs/*": "./dist/src/labs/*.js"
82
74
  },
@@ -1,8 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
2
- <rect width="24" height="24" fill="white"/>
3
- <path d="M5 7.5H19L18 21H6L5 7.5Z" stroke="#000000" stroke-linejoin="round"/>
4
- <path d="M15.5 9.5L15 19" stroke="#000000" stroke-linecap="round" stroke-linejoin="round"/>
5
- <path d="M12 9.5V19" stroke="#000000" stroke-linecap="round" stroke-linejoin="round"/>
6
- <path d="M8.5 9.5L9 19" stroke="#000000" stroke-linecap="round" stroke-linejoin="round"/>
7
- <path d="M16 5H19C20.1046 5 21 5.89543 21 7V7.5H3V7C3 5.89543 3.89543 5 5 5H8M16 5L15 3H9L8 5M16 5H8" stroke="#000000" stroke-linejoin="round"/>
8
- </svg>
@@ -1,6 +0,0 @@
1
- <svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
2
- <path
3
- d="m81.0388846 100-30.9636029-22.5595033-30.7410319 22.5595033 10.6670595-37.3922042-30.0013093-25.2155916h37.5556428l12.5196389-37.3922042 12.3690754 37.3922042h37.5556429l-29.7034563 25.2155916z"
4
- fill="#2C2C2C"
5
- />
6
- </svg>
@@ -1,8 +0,0 @@
1
- <svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
2
- <path
3
- d="m81.0388846 100-30.9636029-22.5595033-30.7410319 22.5595033 10.6670595-37.3922042-30.0013093-25.2155916h37.5556428l12.5196389-37.3922042 12.3690754 37.3922042h37.5556429l-29.7034563 25.2155916z"
4
- fill="#c2820a"
5
- stroke="#c2820a"
6
- stroke-width="3px"
7
- />
8
- </svg>
@@ -1,8 +0,0 @@
1
- <svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
2
- <path
3
- d="m81.0388846 100-30.9636029-22.5595033-30.7410319 22.5595033 10.6670595-37.3922042-30.0013093-25.2155916h37.5556428l12.5196389-37.3922042 12.3690754 37.3922042h37.5556429l-29.7034563 25.2155916z"
4
- fill="#ffffff"
5
- stroke="#c2820a"
6
- stroke-width="3px"
7
- />
8
- </svg>
@@ -1,103 +0,0 @@
1
- import { LitElement, PropertyValues, CSSResultGroup } from 'lit';
2
- import type { RecaptchaManagerInterface } from '@internetarchive/recaptcha-manager';
3
- import '../../elements/ia-button/ia-button.js';
4
- import { Review } from '@internetarchive/metadata-service';
5
- import type { ReviewServiceInterface } from './models.js';
6
- import './ia-review.js';
7
- /**
8
- * Renders a form to edit a given IA review.
9
- */
10
- export declare class IAReviewForm extends LitElement {
11
- identifier?: string;
12
- /** Form submitter's screenname, if applicable. Defaults to "Anonymous". */
13
- submitterScreenname?: string;
14
- /** Form submitter's itemname, if applicable */
15
- submitterItemname?: string;
16
- oldReview?: Review;
17
- unrecoverableError?: string;
18
- maxSubjectLength?: number;
19
- maxBodyLength?: number;
20
- reviewService?: ReviewServiceInterface;
21
- recaptchaManager?: RecaptchaManagerInterface;
22
- bypassRecaptcha: boolean;
23
- private recaptchaWidget?;
24
- private currentStars;
25
- private currentSubjectLength;
26
- private currentBodyLength;
27
- recoverableError?: string;
28
- private formError?;
29
- private recaptchaUnavailable;
30
- private formCanSubmit;
31
- submissionInProgress: boolean;
32
- private reviewForm;
33
- render(): import("lit").TemplateResult<1>;
34
- protected willUpdate(changed: PropertyValues): void;
35
- /** Error to render instead of form inputs */
36
- private get unrecoverableErrorTemplate();
37
- /** Error to render next to submit button */
38
- private get recoverableErrorTemplate();
39
- private get unrecoverableErrorMessage();
40
- private get recoverableErrorMessage();
41
- private get recaptchaErrorMessage();
42
- private get genericErrorMessage();
43
- private get recaptchaMessageTemplate();
44
- /** Clickable group of stars */
45
- private get starsInputTemplate();
46
- /** Subject input and character counter */
47
- private get subjectInputTemplate();
48
- /** Body input and character counter */
49
- private get bodyInputTemplate();
50
- /** Buttons to render at bottom of form */
51
- private get actionButtonsTemplate();
52
- /**
53
- * Renders a star icon, using its number and the current star rating
54
- * to determine whether it should appear selected or not
55
- *
56
- * @param {number} num The number of the current star
57
- * @returns {HTMLTemplateResult} The correct icon, rendered within a button
58
- */
59
- private renderStar;
60
- /**
61
- * Sets up ReCaptcha for the form, if possible.
62
- *
63
- * On failure, replaces form inputs with the ReCaptcha error message.
64
- */
65
- private setupRecaptcha;
66
- /**
67
- * Uses DOMpurify to sanitize any error message before render.
68
- *
69
- * @param {string} errorMsg The error message to be sanitized
70
- * @returns {string} The sanitized error message
71
- */
72
- private sanitizeErrorMsg;
73
- /** Handles validation and recaptcha execution on form submission */
74
- private handleSubmit;
75
- /**
76
- * Generates a review object from the submitted review,
77
- * for optimistic display on success.
78
- *
79
- * @returns {Review} The review to display
80
- */
81
- private generateSubmittedReview;
82
- /**
83
- * Converts date to string if it is a Date, otherwise
84
- * leaves unchanged.
85
- */
86
- private dateToString;
87
- /**
88
- * Executes the ReCaptcha challenge for the form.
89
- * Attempts form submission on success.
90
- * */
91
- private getRecaptchaToken;
92
- private handleRecaptchaError;
93
- private stopSubmission;
94
- private cancelReviewEdit;
95
- private handleStarClicked;
96
- private handleClearBtnClicked;
97
- private setStars;
98
- private handleSubjectChanged;
99
- private handleBodyChanged;
100
- private checkSubmissionAllowed;
101
- static get styles(): CSSResultGroup;
102
- }
103
- //# sourceMappingURL=ia-review-form.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ia-review-form.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-reviews/ia-review-form.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,UAAU,EAGV,cAAc,EACd,cAAc,EACf,MAAM,KAAK,CAAC;AAQb,OAAO,KAAK,EACV,yBAAyB,EAE1B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,mCAAmC,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,mCAAmC,CAAC;AAK3D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AACvD,OAAO,aAAa,CAAC;AAErB;;GAEG;AACH,qBAEa,YAAa,SAAQ,UAAU;IAEd,UAAU,CAAC,EAAE,MAAM,CAAC;IAEhD,2EAA2E;IAC/C,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAEzD,+CAA+C;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAG3B,SAAS,CAAC,EAAE,MAAM,CAAC;IAGnB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAG5B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAG1B,aAAa,CAAC,EAAE,MAAM,CAAC;IAGvB,aAAa,CAAC,EAAE,sBAAsB,CAAC;IAGvC,gBAAgB,CAAC,EAAE,yBAAyB,CAAC;IAG5C,eAAe,EAAE,OAAO,CAAS;IAG9D,OAAO,CAAC,eAAe,CAAC,CAA2B;IAInD,OAAO,CAAC,YAAY,CAAa;IAIjC,OAAO,CAAC,oBAAoB,CAAa;IAIzC,OAAO,CAAC,iBAAiB,CAAa;IAItC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAI1B,OAAO,CAAC,SAAS,CAAC,CAA0B;IAI5C,OAAO,CAAC,oBAAoB,CAAkB;IAI9C,OAAO,CAAC,aAAa,CAAkB;IAIvC,oBAAoB,EAAE,OAAO,CAAS;IAItC,OAAO,CAAC,UAAU,CAAmB;IAErC,MAAM;IAeN,SAAS,CAAC,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAoCnD,6CAA6C;IAC7C,OAAO,KAAK,0BAA0B,GAYrC;IAED,4CAA4C;IAC5C,OAAO,KAAK,wBAAwB,GAUnC;IAGD,OAAO,KAAK,yBAAyB,GAIpC;IAGD,OAAO,KAAK,uBAAuB,GAWlC;IAGD,OAAO,KAAK,qBAAqB,GAEhC;IAED,OAAO,KAAK,mBAAmB,GAI9B;IAED,OAAO,KAAK,wBAAwB,GAwBnC;IAED,+BAA+B;IAC/B,OAAO,KAAK,kBAAkB,GAuB7B;IAED,0CAA0C;IAC1C,OAAO,KAAK,oBAAoB,GAqC/B;IAED,uCAAuC;IACvC,OAAO,KAAK,iBAAiB,GAoC5B;IAED,0CAA0C;IAC1C,OAAO,KAAK,qBAAqB,GAoBhC;IAED;;;;;;OAMG;IACH,OAAO,CAAC,UAAU;IA4BlB;;;;OAIG;YACW,cAAc;IAQ5B;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB;IAIxB,oEAAoE;YACtD,YAAY;IAyD1B;;;;;OAKG;IACH,OAAO,CAAC,uBAAuB;IAoB/B;;;OAGG;IACH,OAAO,CAAC,YAAY;IAKpB;;;SAGK;YACS,iBAAiB;IAgB/B,OAAO,CAAC,oBAAoB;IAM5B,OAAO,CAAC,cAAc;IAOtB,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,iBAAiB;IAMzB,OAAO,CAAC,qBAAqB;IAM7B,OAAO,CAAC,QAAQ;IAKhB,OAAO,CAAC,oBAAoB;IAM5B,OAAO,CAAC,iBAAiB;IAMzB,OAAO,CAAC,sBAAsB;IA2B9B,MAAM,KAAK,MAAM,IAAI,cAAc,CAgJlC;CACF"}