@internetarchive/elements 0.3.0 → 0.4.1

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 (109) hide show
  1. package/dist/src/elements/ia-audio-element/ia-audio-element.d.ts.map +1 -1
  2. package/dist/src/elements/ia-audio-element/ia-audio-element.js +2 -1
  3. package/dist/src/elements/ia-audio-element/ia-audio-element.js.map +1 -1
  4. package/dist/src/elements/ia-button/ia-button.d.ts.map +1 -1
  5. package/dist/src/elements/ia-button/ia-button.js +2 -1
  6. package/dist/src/elements/ia-button/ia-button.js.map +1 -1
  7. package/dist/src/elements/ia-combo-box/ia-combo-box.d.ts.map +1 -1
  8. package/dist/src/elements/ia-combo-box/ia-combo-box.js +2 -1
  9. package/dist/src/elements/ia-combo-box/ia-combo-box.js.map +1 -1
  10. package/dist/src/elements/ia-dropdown-search-bar/ia-dropdown-search-bar.d.ts.map +1 -1
  11. package/dist/src/elements/ia-dropdown-search-bar/ia-dropdown-search-bar.js +2 -1
  12. package/dist/src/elements/ia-dropdown-search-bar/ia-dropdown-search-bar.js.map +1 -1
  13. package/dist/src/elements/ia-expandable-search-bar/ia-expandable-search-bar.d.ts.map +1 -1
  14. package/dist/src/elements/ia-expandable-search-bar/ia-expandable-search-bar.js +2 -1
  15. package/dist/src/elements/ia-expandable-search-bar/ia-expandable-search-bar.js.map +1 -1
  16. package/dist/src/elements/ia-expandable-search-bar/ia-quick-search.d.ts.map +1 -1
  17. package/dist/src/elements/ia-expandable-search-bar/ia-quick-search.js +2 -1
  18. package/dist/src/elements/ia-expandable-search-bar/ia-quick-search.js.map +1 -1
  19. package/dist/src/elements/ia-image-viewer/ia-image-viewer.d.ts +147 -0
  20. package/dist/src/elements/ia-image-viewer/ia-image-viewer.d.ts.map +1 -0
  21. package/dist/src/elements/ia-image-viewer/ia-image-viewer.js +534 -0
  22. package/dist/src/elements/ia-image-viewer/ia-image-viewer.js.map +1 -0
  23. package/dist/src/elements/ia-image-viewer/ia-imgview-controls.d.ts +22 -0
  24. package/dist/src/elements/ia-image-viewer/ia-imgview-controls.d.ts.map +1 -0
  25. package/dist/src/elements/ia-image-viewer/ia-imgview-controls.js +146 -0
  26. package/dist/src/elements/ia-image-viewer/ia-imgview-controls.js.map +1 -0
  27. package/dist/src/elements/ia-image-viewer/ia-imgview-slide.d.ts +44 -0
  28. package/dist/src/elements/ia-image-viewer/ia-imgview-slide.d.ts.map +1 -0
  29. package/dist/src/elements/ia-image-viewer/ia-imgview-slide.js +214 -0
  30. package/dist/src/elements/ia-image-viewer/ia-imgview-slide.js.map +1 -0
  31. package/dist/src/elements/ia-image-viewer/image-viewer-gestures.d.ts +79 -0
  32. package/dist/src/elements/ia-image-viewer/image-viewer-gestures.d.ts.map +1 -0
  33. package/dist/src/elements/ia-image-viewer/image-viewer-gestures.js +254 -0
  34. package/dist/src/elements/ia-image-viewer/image-viewer-gestures.js.map +1 -0
  35. package/dist/src/elements/ia-image-viewer/models.d.ts +20 -0
  36. package/dist/src/elements/ia-image-viewer/models.d.ts.map +1 -0
  37. package/dist/src/elements/ia-image-viewer/models.js +2 -0
  38. package/dist/src/elements/ia-image-viewer/models.js.map +1 -0
  39. package/dist/src/elements/ia-item-navigator/ia-item-navigator.d.ts.map +1 -1
  40. package/dist/src/elements/ia-item-navigator/ia-item-navigator.js +2 -1
  41. package/dist/src/elements/ia-item-navigator/ia-item-navigator.js.map +1 -1
  42. package/dist/src/elements/ia-item-navigator/ia-itemnav-menu-button.d.ts.map +1 -1
  43. package/dist/src/elements/ia-item-navigator/ia-itemnav-menu-button.js +2 -1
  44. package/dist/src/elements/ia-item-navigator/ia-itemnav-menu-button.js.map +1 -1
  45. package/dist/src/elements/ia-item-navigator/ia-itemnav-menu-slider.d.ts.map +1 -1
  46. package/dist/src/elements/ia-item-navigator/ia-itemnav-menu-slider.js +2 -1
  47. package/dist/src/elements/ia-item-navigator/ia-itemnav-menu-slider.js.map +1 -1
  48. package/dist/src/elements/ia-item-navigator/ia-itemnav-no-theater-available.d.ts.map +1 -1
  49. package/dist/src/elements/ia-item-navigator/ia-itemnav-no-theater-available.js +2 -1
  50. package/dist/src/elements/ia-item-navigator/ia-itemnav-no-theater-available.js.map +1 -1
  51. package/dist/src/elements/ia-item-navigator/menus/ia-itemnav-share-panel.d.ts.map +1 -1
  52. package/dist/src/elements/ia-item-navigator/menus/ia-itemnav-share-panel.js +2 -1
  53. package/dist/src/elements/ia-item-navigator/menus/ia-itemnav-share-panel.js.map +1 -1
  54. package/dist/src/elements/ia-item-navigator/menus/ia-itemnav-sort-files-button.d.ts.map +1 -1
  55. package/dist/src/elements/ia-item-navigator/menus/ia-itemnav-sort-files-button.js +2 -1
  56. package/dist/src/elements/ia-item-navigator/menus/ia-itemnav-sort-files-button.js.map +1 -1
  57. package/dist/src/elements/ia-item-navigator/menus/ia-itemnav-viewable-files-panel.d.ts.map +1 -1
  58. package/dist/src/elements/ia-item-navigator/menus/ia-itemnav-viewable-files-panel.js +2 -1
  59. package/dist/src/elements/ia-item-navigator/menus/ia-itemnav-viewable-files-panel.js.map +1 -1
  60. package/dist/src/elements/ia-otp-form/ia-otp-form.d.ts.map +1 -1
  61. package/dist/src/elements/ia-otp-form/ia-otp-form.js +2 -1
  62. package/dist/src/elements/ia-otp-form/ia-otp-form.js.map +1 -1
  63. package/dist/src/elements/ia-otp-input/ia-otp-input.d.ts.map +1 -1
  64. package/dist/src/elements/ia-otp-input/ia-otp-input.js +2 -1
  65. package/dist/src/elements/ia-otp-input/ia-otp-input.js.map +1 -1
  66. package/dist/src/elements/ia-playback-controls/ia-playback-controls.d.ts.map +1 -1
  67. package/dist/src/elements/ia-playback-controls/ia-playback-controls.js +2 -1
  68. package/dist/src/elements/ia-playback-controls/ia-playback-controls.js.map +1 -1
  69. package/dist/src/elements/ia-radio-player/ia-radio-player.d.ts.map +1 -1
  70. package/dist/src/elements/ia-radio-player/ia-radio-player.js +2 -1
  71. package/dist/src/elements/ia-radio-player/ia-radio-player.js.map +1 -1
  72. package/dist/src/elements/ia-radio-player/ia-search-results-switcher.d.ts.map +1 -1
  73. package/dist/src/elements/ia-radio-player/ia-search-results-switcher.js +2 -1
  74. package/dist/src/elements/ia-radio-player/ia-search-results-switcher.js.map +1 -1
  75. package/dist/src/elements/ia-scrubber-bar/ia-scrubber-bar.d.ts.map +1 -1
  76. package/dist/src/elements/ia-scrubber-bar/ia-scrubber-bar.js +2 -1
  77. package/dist/src/elements/ia-scrubber-bar/ia-scrubber-bar.js.map +1 -1
  78. package/dist/src/elements/ia-scrubber-bar/ia-section-marker.d.ts.map +1 -1
  79. package/dist/src/elements/ia-scrubber-bar/ia-section-marker.js +2 -1
  80. package/dist/src/elements/ia-scrubber-bar/ia-section-marker.js.map +1 -1
  81. package/dist/src/elements/ia-sr-only-text/ia-sr-only-text.js +1 -1
  82. package/dist/src/elements/ia-sr-only-text/ia-sr-only-text.js.map +1 -1
  83. package/dist/src/elements/ia-status-indicator/ia-status-indicator.d.ts.map +1 -1
  84. package/dist/src/elements/ia-status-indicator/ia-status-indicator.js +2 -1
  85. package/dist/src/elements/ia-status-indicator/ia-status-indicator.js.map +1 -1
  86. package/dist/src/elements/ia-transcript-view/ia-transcript-entry.d.ts.map +1 -1
  87. package/dist/src/elements/ia-transcript-view/ia-transcript-entry.js +2 -1
  88. package/dist/src/elements/ia-transcript-view/ia-transcript-entry.js.map +1 -1
  89. package/dist/src/elements/ia-transcript-view/ia-transcript-view.d.ts.map +1 -1
  90. package/dist/src/elements/ia-transcript-view/ia-transcript-view.js +2 -1
  91. package/dist/src/elements/ia-transcript-view/ia-transcript-view.js.map +1 -1
  92. package/dist/src/elements/ia-waveform-progress/ia-waveform-progress.d.ts.map +1 -1
  93. package/dist/src/elements/ia-waveform-progress/ia-waveform-progress.js +2 -1
  94. package/dist/src/elements/ia-waveform-progress/ia-waveform-progress.js.map +1 -1
  95. package/dist/src/elements/index.d.ts +1 -0
  96. package/dist/src/elements/index.d.ts.map +1 -1
  97. package/dist/src/elements/index.js +1 -0
  98. package/dist/src/elements/index.js.map +1 -1
  99. package/dist/src/labs/ia-snow/ia-snow.js +1 -1
  100. package/dist/src/labs/ia-snow/ia-snow.js.map +1 -1
  101. package/dist/src/util/custom-element.d.ts +39 -0
  102. package/dist/src/util/custom-element.d.ts.map +1 -0
  103. package/dist/src/util/custom-element.js +50 -0
  104. package/dist/src/util/custom-element.js.map +1 -0
  105. package/dist/src/util/prefers-reduced-motion.d.ts +10 -0
  106. package/dist/src/util/prefers-reduced-motion.d.ts.map +1 -0
  107. package/dist/src/util/prefers-reduced-motion.js +12 -0
  108. package/dist/src/util/prefers-reduced-motion.js.map +1 -0
  109. package/package.json +1 -1
@@ -0,0 +1,254 @@
1
+ import { prefersReducedMotion } from '../../util/prefers-reduced-motion.js';
2
+ /** Minimum horizontal travel before a gesture counts as a swipe at all */
3
+ const SWIPE_THRESHOLD = 30;
4
+ /** Minimum swipe distance (fraction of width) to commit navigation */
5
+ const SWIPE_COMMIT_FRACTION = 0.25;
6
+ /** Minimum velocity (px/ms) for a flick to commit regardless of distance */
7
+ const SWIPE_FLICK_VELOCITY = 0.3;
8
+ /** Longest the track takes to settle after the finger lifts */
9
+ const SETTLE_MAX_MS = 300;
10
+ /** How long a snap-back takes when the swipe didn't go far enough */
11
+ const SNAP_BACK_MS = 200;
12
+ /** Horizontal wheel travel that adds up to one navigation */
13
+ const WHEEL_THRESHOLD = 80;
14
+ /** How long after an animation to keep ignoring wheel inertia */
15
+ const WHEEL_COOLDOWN_MS = 300;
16
+ /** How far a finger travels before the gesture locks in as horizontal */
17
+ const SWIPE_LOCK_DISTANCE = 10;
18
+ /**
19
+ * Touch, wheel and keyboard navigation for the image viewer.
20
+ *
21
+ * A drag is driven imperatively: it translates the track directly and asks the
22
+ * viewer to insert neighbouring slides by hand, because a re-render mid-gesture
23
+ * would replace the element the touch started on and the browser would fire
24
+ * touchcancel.
25
+ */
26
+ export class ImageViewerGestures {
27
+ constructor(host) {
28
+ /** Whether a drag is in progress. The viewer reads this while rendering. */
29
+ this.dragging = false;
30
+ /**
31
+ * The element the touch and wheel listeners are currently on, so they can
32
+ * follow the image area when it's replaced. A boolean wouldn't: the area is
33
+ * removed whenever the image list empties, and a later refill renders a
34
+ * different element.
35
+ */
36
+ this.listeningTo = null;
37
+ this.touchStartX = null;
38
+ this.touchStartY = null;
39
+ this.touchStartTime = 0;
40
+ /** Whether the current gesture has locked in as a horizontal swipe */
41
+ this.swiping = false;
42
+ /** Set when a swipe completes, so the tap it ends on doesn't open the image */
43
+ this.swipeHandled = false;
44
+ this.dragOffsetX = 0;
45
+ this.wheelDeltaX = 0;
46
+ this.wheelAnimating = false;
47
+ this.wheelAnimationEndTime = 0;
48
+ this.onTouchStart = (e) => {
49
+ if (this.host.imageCount <= 1)
50
+ return;
51
+ this.host.settleIfAnimating();
52
+ const touch = e.touches[0];
53
+ this.touchStartX = touch.clientX;
54
+ this.touchStartY = touch.clientY;
55
+ this.touchStartTime = e.timeStamp;
56
+ this.swiping = false;
57
+ this.dragOffsetX = 0;
58
+ };
59
+ this.onTouchMove = (e) => {
60
+ if (this.touchStartX === null || this.touchStartY === null)
61
+ return;
62
+ const dx = e.touches[0].clientX - this.touchStartX;
63
+ const dy = e.touches[0].clientY - this.touchStartY;
64
+ const locksHorizontal = Math.abs(dx) > Math.abs(dy) && Math.abs(dx) > SWIPE_LOCK_DISTANCE;
65
+ if (!this.swiping && locksHorizontal) {
66
+ this.swiping = true;
67
+ this.dragging = true;
68
+ this.host.preloadAroundIndex(this.host.currentIndex);
69
+ this.host.insertDragSlides();
70
+ }
71
+ if (!this.swiping)
72
+ return;
73
+ e.preventDefault();
74
+ this.dragOffsetX = dx;
75
+ this.applyDragTransform();
76
+ };
77
+ this.onTouchEnd = (e) => {
78
+ if (this.touchStartX === null)
79
+ return;
80
+ const dx = e.changedTouches[0].clientX - this.touchStartX;
81
+ const elapsed = e.timeStamp - this.touchStartTime;
82
+ this.touchStartX = null;
83
+ this.touchStartY = null;
84
+ if (!this.swiping)
85
+ return;
86
+ this.swiping = false;
87
+ const track = this.host.slideTrack;
88
+ const area = this.host.imageArea;
89
+ if (!track || !area) {
90
+ this.dragging = false;
91
+ return;
92
+ }
93
+ const width = area.offsetWidth;
94
+ const velocity = Math.abs(dx) / Math.max(elapsed, 1);
95
+ const pastThreshold = Math.abs(dx) > width * SWIPE_COMMIT_FRACTION;
96
+ const flicked = velocity > SWIPE_FLICK_VELOCITY;
97
+ const shouldCommit = (pastThreshold || flicked) && Math.abs(dx) >= SWIPE_THRESHOLD;
98
+ const direction = dx < 0 ? 'next' : 'prev';
99
+ this.swipeHandled = true;
100
+ // The rest of the way is proportional to how far the finger already got,
101
+ // so a nearly complete swipe finishes almost instantly.
102
+ const remainingFraction = (width - Math.abs(dx)) / width;
103
+ const completionDuration = shouldCommit
104
+ ? Math.round(Math.max(100, Math.min(SETTLE_MAX_MS, remainingFraction * SETTLE_MAX_MS)))
105
+ : SNAP_BACK_MS;
106
+ const finalTransform = !shouldCommit
107
+ ? 'translateX(-100%)'
108
+ : direction === 'next'
109
+ ? 'translateX(-200%)'
110
+ : 'translateX(0%)';
111
+ const finish = () => {
112
+ track.style.transition = '';
113
+ track.style.transform = '';
114
+ if (shouldCommit)
115
+ this.host.commitDrag(direction);
116
+ this.dragging = false;
117
+ this.dragOffsetX = 0;
118
+ // Remove the hand-inserted slides before the viewer renders, since it
119
+ // doesn't track them and would leave them in the track.
120
+ this.host.removeDragSlides();
121
+ this.host.preloadAroundIndex(this.host.currentIndex);
122
+ this.host.requestUpdate();
123
+ };
124
+ // With reduced motion there's nothing to transition, and a zero-duration
125
+ // transition doesn't fire transitionend, so settle straight away rather
126
+ // than waiting on the timeout that would otherwise cover for it.
127
+ if (prefersReducedMotion()) {
128
+ track.style.transform = finalTransform;
129
+ finish();
130
+ return;
131
+ }
132
+ track.style.transition = `transform ${completionDuration}ms ease-out`;
133
+ track.style.transform = finalTransform;
134
+ let settled = false;
135
+ const onTransitionDone = () => {
136
+ if (settled)
137
+ return;
138
+ settled = true;
139
+ track.removeEventListener('transitionend', onTransitionDone);
140
+ finish();
141
+ };
142
+ track.addEventListener('transitionend', onTransitionDone);
143
+ // Fallback in case transitionend doesn't fire
144
+ setTimeout(onTransitionDone, completionDuration + 50);
145
+ };
146
+ this.onWheel = (e) => {
147
+ if (this.host.imageCount <= 1)
148
+ return;
149
+ // Ignore vertical-dominant scrolls
150
+ if (Math.abs(e.deltaY) > Math.abs(e.deltaX))
151
+ return;
152
+ if (e.deltaX === 0)
153
+ return;
154
+ e.preventDefault();
155
+ // Block during animation and for a brief cooldown after to absorb inertia
156
+ const inCooldown = performance.now() - this.wheelAnimationEndTime < WHEEL_COOLDOWN_MS;
157
+ if (this.wheelAnimating || inCooldown) {
158
+ this.wheelDeltaX = 0;
159
+ return;
160
+ }
161
+ this.wheelDeltaX += e.deltaX;
162
+ if (Math.abs(this.wheelDeltaX) < WHEEL_THRESHOLD)
163
+ return;
164
+ const forward = this.wheelDeltaX > 0;
165
+ this.wheelDeltaX = 0;
166
+ this.wheelAnimating = true;
167
+ if (forward)
168
+ this.host.showNext();
169
+ else
170
+ this.host.showPrevious();
171
+ };
172
+ this.onKeydown = (e) => {
173
+ if (this.host.imageCount <= 1)
174
+ return;
175
+ const target = e.target;
176
+ if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA')
177
+ return;
178
+ if (target.isContentEditable)
179
+ return;
180
+ if (e.key === 'ArrowLeft')
181
+ this.host.showPrevious();
182
+ else if (e.key === 'ArrowRight')
183
+ this.host.showNext();
184
+ };
185
+ this.host = host;
186
+ host.addController(this);
187
+ }
188
+ hostConnected() {
189
+ document.addEventListener('keydown', this.onKeydown);
190
+ // Reconnecting doesn't schedule an update, so the gesture listeners have
191
+ // to be put back here rather than waiting for one.
192
+ this.attachListeners();
193
+ }
194
+ hostUpdated() {
195
+ this.attachListeners();
196
+ }
197
+ hostDisconnected() {
198
+ document.removeEventListener('keydown', this.onKeydown);
199
+ this.detachListeners();
200
+ }
201
+ /**
202
+ * Whether a swipe just ended on this tap, meaning the click that follows it
203
+ * should be ignored rather than treated as opening the image.
204
+ */
205
+ consumeSwipeTap() {
206
+ if (!this.swipeHandled)
207
+ return false;
208
+ this.swipeHandled = false;
209
+ return true;
210
+ }
211
+ /** Lets wheel navigation resume once a slide animation has finished. */
212
+ animationSettled() {
213
+ this.wheelAnimating = false;
214
+ this.wheelAnimationEndTime = performance.now();
215
+ this.wheelDeltaX = 0;
216
+ }
217
+ /**
218
+ * Points the gesture listeners at the current image area, moving them off
219
+ * the previous one. The area isn't rendered until there are images to show,
220
+ * and it's torn down and rebuilt whenever the list empties and refills, so
221
+ * this runs on every update and re-attaches whenever the element changes.
222
+ */
223
+ attachListeners() {
224
+ const area = this.host.imageArea;
225
+ if (area === this.listeningTo)
226
+ return;
227
+ this.detachListeners();
228
+ if (!area)
229
+ return;
230
+ this.listeningTo = area;
231
+ area.addEventListener('touchstart', this.onTouchStart, { passive: true });
232
+ area.addEventListener('touchmove', this.onTouchMove, { passive: false });
233
+ area.addEventListener('touchend', this.onTouchEnd, { passive: true });
234
+ area.addEventListener('wheel', this.onWheel, { passive: false });
235
+ }
236
+ detachListeners() {
237
+ const area = this.listeningTo;
238
+ if (!area)
239
+ return;
240
+ area.removeEventListener('touchstart', this.onTouchStart);
241
+ area.removeEventListener('touchmove', this.onTouchMove);
242
+ area.removeEventListener('touchend', this.onTouchEnd);
243
+ area.removeEventListener('wheel', this.onWheel);
244
+ this.listeningTo = null;
245
+ }
246
+ /** Applies the drag offset to the track during touch gestures. */
247
+ applyDragTransform() {
248
+ const track = this.host.slideTrack;
249
+ if (!this.dragging || !track)
250
+ return;
251
+ track.style.transform = `translateX(calc(-100% + ${this.dragOffsetX}px))`;
252
+ }
253
+ }
254
+ //# sourceMappingURL=image-viewer-gestures.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-viewer-gestures.js","sourceRoot":"","sources":["../../../../src/elements/ia-image-viewer/image-viewer-gestures.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveController, ReactiveControllerHost } from 'lit';\n\nimport { prefersReducedMotion } from '@src/util/prefers-reduced-motion';\nimport type { SlideDirection } from './models';\n\n/** What the gesture controller needs from the viewer it drives. */\nexport type ImageViewerGestureHost = ReactiveControllerHost & {\n readonly imageCount: number;\n\n readonly currentIndex: number;\n\n /** The element gestures are tracked against, once it has rendered. */\n readonly imageArea?: HTMLElement;\n\n /** The element a drag translates. */\n readonly slideTrack?: HTMLElement;\n\n /** Commits an in-flight slide animation so a new one starts from rest. */\n settleIfAnimating(): void;\n\n showNext(): void;\n\n showPrevious(): void;\n\n preloadAroundIndex(index: number): void;\n\n /** Adds the neighbouring slides a drag reveals on either side. */\n insertDragSlides(): void;\n\n removeDragSlides(): void;\n\n /** Advances to the neighbouring image a completed drag landed on. */\n commitDrag(direction: SlideDirection): void;\n};\n\n/** Minimum horizontal travel before a gesture counts as a swipe at all */\nconst SWIPE_THRESHOLD = 30;\n\n/** Minimum swipe distance (fraction of width) to commit navigation */\nconst SWIPE_COMMIT_FRACTION = 0.25;\n\n/** Minimum velocity (px/ms) for a flick to commit regardless of distance */\nconst SWIPE_FLICK_VELOCITY = 0.3;\n\n/** Longest the track takes to settle after the finger lifts */\nconst SETTLE_MAX_MS = 300;\n\n/** How long a snap-back takes when the swipe didn't go far enough */\nconst SNAP_BACK_MS = 200;\n\n/** Horizontal wheel travel that adds up to one navigation */\nconst WHEEL_THRESHOLD = 80;\n\n/** How long after an animation to keep ignoring wheel inertia */\nconst WHEEL_COOLDOWN_MS = 300;\n\n/** How far a finger travels before the gesture locks in as horizontal */\nconst SWIPE_LOCK_DISTANCE = 10;\n\n/**\n * Touch, wheel and keyboard navigation for the image viewer.\n *\n * A drag is driven imperatively: it translates the track directly and asks the\n * viewer to insert neighbouring slides by hand, because a re-render mid-gesture\n * would replace the element the touch started on and the browser would fire\n * touchcancel.\n */\nexport class ImageViewerGestures implements ReactiveController {\n /** Whether a drag is in progress. The viewer reads this while rendering. */\n dragging = false;\n\n private host: ImageViewerGestureHost;\n\n /**\n * The element the touch and wheel listeners are currently on, so they can\n * follow the image area when it's replaced. A boolean wouldn't: the area is\n * removed whenever the image list empties, and a later refill renders a\n * different element.\n */\n private listeningTo: HTMLElement | null = null;\n\n private touchStartX: number | null = null;\n\n private touchStartY: number | null = null;\n\n private touchStartTime = 0;\n\n /** Whether the current gesture has locked in as a horizontal swipe */\n private swiping = false;\n\n /** Set when a swipe completes, so the tap it ends on doesn't open the image */\n private swipeHandled = false;\n\n private dragOffsetX = 0;\n\n private wheelDeltaX = 0;\n\n private wheelAnimating = false;\n\n private wheelAnimationEndTime = 0;\n\n constructor(host: ImageViewerGestureHost) {\n this.host = host;\n host.addController(this);\n }\n\n hostConnected(): void {\n document.addEventListener('keydown', this.onKeydown);\n // Reconnecting doesn't schedule an update, so the gesture listeners have\n // to be put back here rather than waiting for one.\n this.attachListeners();\n }\n\n hostUpdated(): void {\n this.attachListeners();\n }\n\n hostDisconnected(): void {\n document.removeEventListener('keydown', this.onKeydown);\n this.detachListeners();\n }\n\n /**\n * Whether a swipe just ended on this tap, meaning the click that follows it\n * should be ignored rather than treated as opening the image.\n */\n consumeSwipeTap(): boolean {\n if (!this.swipeHandled) return false;\n this.swipeHandled = false;\n return true;\n }\n\n /** Lets wheel navigation resume once a slide animation has finished. */\n animationSettled(): void {\n this.wheelAnimating = false;\n this.wheelAnimationEndTime = performance.now();\n this.wheelDeltaX = 0;\n }\n\n /**\n * Points the gesture listeners at the current image area, moving them off\n * the previous one. The area isn't rendered until there are images to show,\n * and it's torn down and rebuilt whenever the list empties and refills, so\n * this runs on every update and re-attaches whenever the element changes.\n */\n private attachListeners(): void {\n const area = this.host.imageArea;\n if (area === this.listeningTo) return;\n this.detachListeners();\n if (!area) return;\n\n this.listeningTo = area;\n area.addEventListener('touchstart', this.onTouchStart, { passive: true });\n area.addEventListener('touchmove', this.onTouchMove, { passive: false });\n area.addEventListener('touchend', this.onTouchEnd, { passive: true });\n area.addEventListener('wheel', this.onWheel, { passive: false });\n }\n\n private detachListeners(): void {\n const area = this.listeningTo;\n if (!area) return;\n area.removeEventListener('touchstart', this.onTouchStart);\n area.removeEventListener('touchmove', this.onTouchMove);\n area.removeEventListener('touchend', this.onTouchEnd);\n area.removeEventListener('wheel', this.onWheel);\n this.listeningTo = null;\n }\n\n private onTouchStart = (e: TouchEvent): void => {\n if (this.host.imageCount <= 1) return;\n this.host.settleIfAnimating();\n const touch = e.touches[0];\n this.touchStartX = touch.clientX;\n this.touchStartY = touch.clientY;\n this.touchStartTime = e.timeStamp;\n this.swiping = false;\n this.dragOffsetX = 0;\n };\n\n private onTouchMove = (e: TouchEvent): void => {\n if (this.touchStartX === null || this.touchStartY === null) return;\n const dx = e.touches[0].clientX - this.touchStartX;\n const dy = e.touches[0].clientY - this.touchStartY;\n\n const locksHorizontal =\n Math.abs(dx) > Math.abs(dy) && Math.abs(dx) > SWIPE_LOCK_DISTANCE;\n if (!this.swiping && locksHorizontal) {\n this.swiping = true;\n this.dragging = true;\n this.host.preloadAroundIndex(this.host.currentIndex);\n this.host.insertDragSlides();\n }\n\n if (!this.swiping) return;\n e.preventDefault();\n\n this.dragOffsetX = dx;\n this.applyDragTransform();\n };\n\n private onTouchEnd = (e: TouchEvent): void => {\n if (this.touchStartX === null) return;\n const dx = e.changedTouches[0].clientX - this.touchStartX;\n const elapsed = e.timeStamp - this.touchStartTime;\n this.touchStartX = null;\n this.touchStartY = null;\n\n if (!this.swiping) return;\n this.swiping = false;\n\n const track = this.host.slideTrack;\n const area = this.host.imageArea;\n if (!track || !area) {\n this.dragging = false;\n return;\n }\n\n const width = area.offsetWidth;\n const velocity = Math.abs(dx) / Math.max(elapsed, 1);\n const pastThreshold = Math.abs(dx) > width * SWIPE_COMMIT_FRACTION;\n const flicked = velocity > SWIPE_FLICK_VELOCITY;\n const shouldCommit =\n (pastThreshold || flicked) && Math.abs(dx) >= SWIPE_THRESHOLD;\n const direction: SlideDirection = dx < 0 ? 'next' : 'prev';\n\n this.swipeHandled = true;\n\n // The rest of the way is proportional to how far the finger already got,\n // so a nearly complete swipe finishes almost instantly.\n const remainingFraction = (width - Math.abs(dx)) / width;\n const completionDuration = shouldCommit\n ? Math.round(\n Math.max(\n 100,\n Math.min(SETTLE_MAX_MS, remainingFraction * SETTLE_MAX_MS),\n ),\n )\n : SNAP_BACK_MS;\n\n const finalTransform = !shouldCommit\n ? 'translateX(-100%)'\n : direction === 'next'\n ? 'translateX(-200%)'\n : 'translateX(0%)';\n\n const finish = (): void => {\n track.style.transition = '';\n track.style.transform = '';\n\n if (shouldCommit) this.host.commitDrag(direction);\n\n this.dragging = false;\n this.dragOffsetX = 0;\n // Remove the hand-inserted slides before the viewer renders, since it\n // doesn't track them and would leave them in the track.\n this.host.removeDragSlides();\n this.host.preloadAroundIndex(this.host.currentIndex);\n this.host.requestUpdate();\n };\n\n // With reduced motion there's nothing to transition, and a zero-duration\n // transition doesn't fire transitionend, so settle straight away rather\n // than waiting on the timeout that would otherwise cover for it.\n if (prefersReducedMotion()) {\n track.style.transform = finalTransform;\n finish();\n return;\n }\n\n track.style.transition = `transform ${completionDuration}ms ease-out`;\n track.style.transform = finalTransform;\n\n let settled = false;\n const onTransitionDone = (): void => {\n if (settled) return;\n settled = true;\n track.removeEventListener('transitionend', onTransitionDone);\n finish();\n };\n\n track.addEventListener('transitionend', onTransitionDone);\n // Fallback in case transitionend doesn't fire\n setTimeout(onTransitionDone, completionDuration + 50);\n };\n\n /** Applies the drag offset to the track during touch gestures. */\n private applyDragTransform(): void {\n const track = this.host.slideTrack;\n if (!this.dragging || !track) return;\n track.style.transform = `translateX(calc(-100% + ${this.dragOffsetX}px))`;\n }\n\n private onWheel = (e: WheelEvent): void => {\n if (this.host.imageCount <= 1) return;\n\n // Ignore vertical-dominant scrolls\n if (Math.abs(e.deltaY) > Math.abs(e.deltaX)) return;\n if (e.deltaX === 0) return;\n\n e.preventDefault();\n\n // Block during animation and for a brief cooldown after to absorb inertia\n const inCooldown =\n performance.now() - this.wheelAnimationEndTime < WHEEL_COOLDOWN_MS;\n if (this.wheelAnimating || inCooldown) {\n this.wheelDeltaX = 0;\n return;\n }\n\n this.wheelDeltaX += e.deltaX;\n if (Math.abs(this.wheelDeltaX) < WHEEL_THRESHOLD) return;\n\n const forward = this.wheelDeltaX > 0;\n this.wheelDeltaX = 0;\n this.wheelAnimating = true;\n if (forward) this.host.showNext();\n else this.host.showPrevious();\n };\n\n private onKeydown = (e: KeyboardEvent): void => {\n if (this.host.imageCount <= 1) return;\n const target = e.target as HTMLElement;\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA') return;\n if (target.isContentEditable) return;\n if (e.key === 'ArrowLeft') this.host.showPrevious();\n else if (e.key === 'ArrowRight') this.host.showNext();\n };\n}\n"]}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * One image the viewer can show.
3
+ *
4
+ * Deliberately plain data. The viewer doesn't know where the images come from
5
+ * or how their URLs were built, so a host can feed it archive.org derivatives,
6
+ * a local directory listing, or anything else.
7
+ */
8
+ export type ImageViewerImage = {
9
+ /** Identifies the image within the set. Used as the key in change events. */
10
+ name: string;
11
+ /** Where to load the image from, and where the link points. */
12
+ url: string;
13
+ /** Alt text. Falls back to `name` when absent. */
14
+ title?: string;
15
+ };
16
+ /** Which way the viewer is moving through the set. */
17
+ export type SlideDirection = 'next' | 'prev';
18
+ /** Which edge the viewer just wrapped around. */
19
+ export type WrapEdge = 'start' | 'end';
20
+ //# sourceMappingURL=models.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-image-viewer/models.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,6EAA6E;IAC7E,IAAI,EAAE,MAAM,CAAC;IAEb,+DAA+D;IAC/D,GAAG,EAAE,MAAM,CAAC;IAEZ,kDAAkD;IAClD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,sDAAsD;AACtD,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,MAAM,CAAC;AAE7C,iDAAiD;AACjD,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,KAAK,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=models.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.js","sourceRoot":"","sources":["../../../../src/elements/ia-image-viewer/models.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * One image the viewer can show.\n *\n * Deliberately plain data. The viewer doesn't know where the images come from\n * or how their URLs were built, so a host can feed it archive.org derivatives,\n * a local directory listing, or anything else.\n */\nexport type ImageViewerImage = {\n /** Identifies the image within the set. Used as the key in change events. */\n name: string;\n\n /** Where to load the image from, and where the link points. */\n url: string;\n\n /** Alt text. Falls back to `name` when absent. */\n title?: string;\n};\n\n/** Which way the viewer is moving through the set. */\nexport type SlideDirection = 'next' | 'prev';\n\n/** Which edge the viewer just wrapped around. */\nexport type WrapEdge = 'start' | 'end';\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ia-item-navigator.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-item-navigator/ia-item-navigator.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,UAAU,EACV,cAAc,EACd,OAAO,EACP,KAAK,cAAc,EACpB,MAAM,KAAK,CAAC;AAMb,OAAO,0BAA0B,CAAC;AAClC,OAAO,mCAAmC,CAAC;AAG3C,OAAO,EACL,uBAAuB,EACvB,wBAAwB,EACxB,wBAAwB,EACxB,yBAAyB,EACzB,wBAAwB,EACxB,qBAAqB,EACtB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,MAAM,EACP,MAAM,8BAA8B,CAAC;AAEtC;;;;;;;;;GASG;AACH,qBACa,eAAgB,SAAQ,UAAU;IAC7C,mCAAmC;IACP,UAAU,CAAC,EAAE,MAAM,CAAC;IAEJ,aAAa,EAAE,OAAO,CAAQ;IAE9C,QAAQ,SAAiB;IAExB,QAAQ,UAAS;IAEnB,YAAY,EAAE,qBAAqB,EAAE,CAAM;IAE3C,aAAa,EAAE,qBAAqB,EAAE,CAAM;IAGvE,oBAAoB,EAAE,OAAO,GAAG,IAAI,CAAQ;IAEA,UAAU,UAAS;IAEpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAE7D;;;;;;;;;OASG;IAC0D,MAAM,EAAE,OAAO,CACpE;IAER;;;;;OAKG;IACM,OAAO,CAAC,cAAc,CAAS;IAEP,OAAO,CAAC,UAAU,CAAuB;IAE7C,OAAO,CAAC,gBAAgB,CAAqB;IAE1E,UAAU,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI;IAanD,MAAM,IAAI,cAAc;IAkBxB,IAAI,aAAa,IAAI,cAAc,CAKlC;IAED,IAAI,cAAc,IAAI,cAAc,GAAG,OAAO,OAAO,CAcpD;IAED,mBAAmB,CAAC,CAAC,EAAE,wBAAwB,GAAG,IAAI;IAKtD,4BAA4B;IAC5B,wBAAwB,CAAC,CAAC,EAAE,qBAAqB,GAAG,IAAI;IAUxD,gCAAgC;IAEhC,gBAAgB;IAChB,IAAI,gBAAgB,IAAI,OAAO,CAE9B;IAED,UAAU,CAAC,UAAU,GAAE,OAAO,GAAG,SAAqB,GAAG,IAAI;IAM7D;;;;OAIG;IACH,OAAO,CAAC,kBAAkB;IAU1B;;;OAGG;IACH,SAAS,IAAI,IAAI;IAKjB,WAAW,CAAC,CAAC,EAAE,wBAAwB,GAAG,IAAI;IAM9C;;;;OAIG;IACH,cAAc,IAAI,IAAI;IAKtB,eAAe,CAAC,CAAC,EAAE,wBAAwB,GAAG,IAAI;IAKlD,gBAAgB,CAAC,CAAC,EAAE,yBAAyB,GAAG,IAAI;IAIpD,kDAAkD;IAClD,oBAAoB,CAAC,CAAC,EAAE,uBAAuB,GAAG,IAAI;IActD,IAAI,gBAAgB,IAAI,cAAc,CAcrC;IAED,IAAI,cAAc,IAAI,MAAM,GAAG,EAAE,CAEhC;IAED,IAAI,cAAc,IAAI,cAAc,CA2BnC;IACD,oBAAoB;IAEpB,qBAAqB;IACrB,YAAY,CAAC,cAAc,GAAE,MAAW,GAAG,IAAI;IAa/C,IAAI,SAAS,IAAI,cAAc,CAuB9B;IACD,yBAAyB;IAEzB,kBAAkB;IAClB,IAAI,SAAS,IAAI,MAAM,CAUtB;IAED,MAAM,KAAK,MAAM,IAAI,cAAc,CAoRlC;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,mBAAmB,EAAE,eAAe,CAAC;KACtC;CACF"}
1
+ {"version":3,"file":"ia-item-navigator.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-item-navigator/ia-item-navigator.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,UAAU,EACV,cAAc,EACd,OAAO,EACP,KAAK,cAAc,EACpB,MAAM,KAAK,CAAC;AAOb,OAAO,0BAA0B,CAAC;AAClC,OAAO,mCAAmC,CAAC;AAG3C,OAAO,EACL,uBAAuB,EACvB,wBAAwB,EACxB,wBAAwB,EACxB,yBAAyB,EACzB,wBAAwB,EACxB,qBAAqB,EACtB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,MAAM,EACP,MAAM,8BAA8B,CAAC;AAEtC;;;;;;;;;GASG;AACH,qBACa,eAAgB,SAAQ,UAAU;IAC7C,mCAAmC;IACP,UAAU,CAAC,EAAE,MAAM,CAAC;IAEJ,aAAa,EAAE,OAAO,CAAQ;IAE9C,QAAQ,SAAiB;IAExB,QAAQ,UAAS;IAEnB,YAAY,EAAE,qBAAqB,EAAE,CAAM;IAE3C,aAAa,EAAE,qBAAqB,EAAE,CAAM;IAGvE,oBAAoB,EAAE,OAAO,GAAG,IAAI,CAAQ;IAEA,UAAU,UAAS;IAEpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAE7D;;;;;;;;;OASG;IAC0D,MAAM,EAAE,OAAO,CACpE;IAER;;;;;OAKG;IACM,OAAO,CAAC,cAAc,CAAS;IAEP,OAAO,CAAC,UAAU,CAAuB;IAE7C,OAAO,CAAC,gBAAgB,CAAqB;IAE1E,UAAU,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI;IAanD,MAAM,IAAI,cAAc;IAkBxB,IAAI,aAAa,IAAI,cAAc,CAKlC;IAED,IAAI,cAAc,IAAI,cAAc,GAAG,OAAO,OAAO,CAcpD;IAED,mBAAmB,CAAC,CAAC,EAAE,wBAAwB,GAAG,IAAI;IAKtD,4BAA4B;IAC5B,wBAAwB,CAAC,CAAC,EAAE,qBAAqB,GAAG,IAAI;IAUxD,gCAAgC;IAEhC,gBAAgB;IAChB,IAAI,gBAAgB,IAAI,OAAO,CAE9B;IAED,UAAU,CAAC,UAAU,GAAE,OAAO,GAAG,SAAqB,GAAG,IAAI;IAM7D;;;;OAIG;IACH,OAAO,CAAC,kBAAkB;IAU1B;;;OAGG;IACH,SAAS,IAAI,IAAI;IAKjB,WAAW,CAAC,CAAC,EAAE,wBAAwB,GAAG,IAAI;IAM9C;;;;OAIG;IACH,cAAc,IAAI,IAAI;IAKtB,eAAe,CAAC,CAAC,EAAE,wBAAwB,GAAG,IAAI;IAKlD,gBAAgB,CAAC,CAAC,EAAE,yBAAyB,GAAG,IAAI;IAIpD,kDAAkD;IAClD,oBAAoB,CAAC,CAAC,EAAE,uBAAuB,GAAG,IAAI;IActD,IAAI,gBAAgB,IAAI,cAAc,CAcrC;IAED,IAAI,cAAc,IAAI,MAAM,GAAG,EAAE,CAEhC;IAED,IAAI,cAAc,IAAI,cAAc,CA2BnC;IACD,oBAAoB;IAEpB,qBAAqB;IACrB,YAAY,CAAC,cAAc,GAAE,MAAW,GAAG,IAAI;IAa/C,IAAI,SAAS,IAAI,cAAc,CAuB9B;IACD,yBAAyB;IAEzB,kBAAkB;IAClB,IAAI,SAAS,IAAI,MAAM,CAUtB;IAED,MAAM,KAAK,MAAM,IAAI,cAAc,CAoRlC;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,mBAAmB,EAAE,eAAe,CAAC;KACtC;CACF"}
@@ -1,6 +1,7 @@
1
1
  import { __decorate } from "tslib";
2
2
  import { css, html, LitElement, nothing, } from 'lit';
3
- import { customElement, property, state, query } from 'lit/decorators.js';
3
+ import { property, state, query } from 'lit/decorators.js';
4
+ import { customElement } from '../../util/custom-element.js';
4
5
  import { classMap } from 'lit/directives/class-map.js';
5
6
  import themeStyles from '../../themes/theme-styles.js';
6
7
  import { ellipsesIcon } from './icons.js';
@@ -1 +1 @@
1
- {"version":3,"file":"ia-item-navigator.js","sourceRoot":"","sources":["../../../../src/elements/ia-item-navigator/ia-item-navigator.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n css,\n html,\n LitElement,\n TemplateResult,\n nothing,\n type CSSResultGroup,\n} from 'lit';\nimport { customElement, property, state, query } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport themeStyles from '@src/themes/theme-styles';\n\nimport { ellipsesIcon } from './icons';\nimport './ia-itemnav-menu-slider';\nimport './ia-itemnav-no-theater-available';\nimport type { IAItemNavMenuSlider } from './ia-itemnav-menu-slider';\n\nimport {\n ToggleSideMenuOpenEvent,\n ToggleSidePanelOpenEvent,\n SetSideMenuContentsEvent,\n SetSideMenuShortcutsEvent,\n LoadingStateUpdatedEvent,\n ManageFullscreenEvent,\n} from './interfaces/event-interfaces';\nimport {\n MenuProviderInterface,\n MenuShortcutInterface,\n MenuId,\n} from './interfaces/menu-interfaces';\n\n/**\n * A fullscreen-capable frame that hosts an Archive.org item's theater. The\n * consumer projects a header bar and the theater itself into the `header` and\n * `main` slots; a collapsible left drawer (`ia-itemnav-menu-slider`) is driven by a\n * data array of menu providers, and a minimized rail shows shortcut icons.\n *\n * The navigator is a shell — it does not know how to render any particular\n * viewer. Menu panel bodies are opaque `TemplateResult`s supplied by the\n * consumer via `menuContents`.\n */\n@customElement('ia-item-navigator')\nexport class IAItemNavigator extends LitElement {\n /** archive.org item identifier. */\n @property({ type: String }) identifier?: string;\n\n @property({ type: Boolean, reflect: true }) viewAvailable: boolean = true;\n\n @property({ type: String }) baseHost = 'archive.org';\n\n @property({ type: Boolean }) signedIn = false;\n\n @property({ type: Array }) menuContents: MenuProviderInterface[] = [];\n\n @property({ type: Array }) menuShortcuts: MenuShortcutInterface[] = [];\n\n @property({ type: Boolean, reflect: true, attribute: true })\n viewportInFullscreen: boolean | null = null;\n\n @property({ type: Boolean, reflect: true }) menuOpened = false;\n\n @property({ type: String, reflect: true }) openMenu?: MenuId;\n\n /**\n * Whether the slotted theater is ready. While false the reader stays\n * hidden and the frame is empty.\n *\n * The navigator used to fill that gap with its own spinner, but a shell\n * shouldn't decide what loading looks like — and its glyph and fullscreen\n * caption were branding a consumer couldn't override. An indicator returns\n * once WEBDEV-8951 moves the shared status indicators into elements, so the\n * navigator can use that one instead of carrying its own.\n */\n @property({ type: Boolean, reflect: true, attribute: true }) loaded: boolean =\n false;\n\n /**\n * Set for the render where the drawer opens straight to a panel, so the\n * panel holds still and rides in. Every other path clears it, rather\n * than waiting for the drawer's `transitionend` — that never fires when\n * animations are disabled, which would strand the flag on.\n */\n @state() private drawerEntering = false;\n\n @query('ia-itemnav-menu-slider') private menuSlider!: IAItemNavMenuSlider;\n\n @query('button.toggle-menu') private toggleMenuButton!: HTMLButtonElement;\n\n slotChange(e: Event, type: 'header' | 'main'): void {\n const slottedContent = (\n e.target as HTMLSlotElement\n ).assignedNodes()?.[0] as HTMLElement;\n\n this.dispatchEvent(\n new CustomEvent('slotChange', {\n detail: { slot: slottedContent, type },\n }),\n );\n this.requestUpdate();\n }\n\n render(): TemplateResult {\n const displayReaderClass = this.loaded ? '' : 'hidden';\n return html`\n <div id=\"frame\" class=${this.menuClass}>\n <slot\n name=\"header\"\n @slotchange=${(e: Event) => this.slotChange(e, 'header')}\n ></slot>\n <div class=\"menu-and-reader\">\n ${this.shouldRenderMenu ? this.renderSideMenu : nothing}\n <div id=\"reader\" class=${displayReaderClass}>\n ${this.renderViewport}\n </div>\n </div>\n </div>\n `;\n }\n\n get noTheaterView(): TemplateResult {\n return html`<ia-itemnav-no-theater-available\n .identifier=${this.identifier}\n @loadingStateUpdated=${this.loadingStateUpdated}\n ></ia-itemnav-no-theater-available>`;\n }\n\n get renderViewport(): TemplateResult | typeof nothing {\n if (!this.viewAvailable) {\n return this.noTheaterView;\n }\n\n const slotVisibility = !this.loaded ? 'opacity: 0;' : 'opacity: 1;';\n return html`\n <div slot=\"main\" style=${slotVisibility}>\n <slot\n name=\"main\"\n @slotchange=${(e: Event) => this.slotChange(e, 'main')}\n ></slot>\n </div>\n `;\n }\n\n loadingStateUpdated(e: LoadingStateUpdatedEvent): void {\n const { loaded } = e.detail;\n this.loaded = loaded ?? false;\n }\n\n /** Fullscreen Management */\n manageViewportFullscreen(e: ManageFullscreenEvent): void {\n const fullscreenStatus = !!e.detail.isFullScreen;\n this.viewportInFullscreen = !fullscreenStatus ? null : fullscreenStatus;\n\n const event = new CustomEvent('fullscreenToggled', {\n detail: e.detail,\n }) as ManageFullscreenEvent;\n\n this.dispatchEvent(event);\n }\n /** End Fullscreen Management */\n\n /** Side menu */\n get shouldRenderMenu(): boolean {\n return !!this.menuContents?.length;\n }\n\n toggleMenu(forceValue: boolean | undefined = undefined): void {\n this.drawerEntering = false;\n this.menuOpened = forceValue !== undefined ? forceValue : !this.menuOpened;\n this.moveFocusForDrawer();\n }\n\n /**\n * Opening the drawer moves focus into it; closing hands focus back to the\n * toggle. Without this, opening from the shortcut rail would leave focus on\n * a button that is about to be hidden, dropping it to the document.\n */\n private moveFocusForDrawer(): void {\n this.updateComplete.then(() => {\n if (this.menuOpened) {\n this.menuSlider?.focusDrawer();\n } else {\n this.toggleMenuButton?.focus();\n }\n });\n }\n\n /**\n * Closing the drawer also closes whatever panel was open inside it, so the\n * two can't disagree and a stale panel can't reappear on the next open.\n */\n closeMenu(): void {\n this.openMenu = undefined;\n this.toggleMenu(false);\n }\n\n setOpenMenu(e: ToggleSidePanelOpenEvent): void {\n this.drawerEntering = false;\n const { id } = e.detail;\n this.openMenu = id !== this.openMenu ? id : undefined;\n }\n\n /**\n * Clears the open channel when the slider closes its sub-panel, without\n * closing the drawer. Keeps `openMenu` in sync with the slider so the same\n * channel can be reopened afterwards.\n */\n closeSidePanel(): void {\n this.drawerEntering = false;\n this.openMenu = undefined;\n }\n\n setMenuContents(e: SetSideMenuContentsEvent): void {\n const updatedContents = [...e.detail];\n this.menuContents = updatedContents;\n }\n\n setMenuShortcuts(e: SetSideMenuShortcutsEvent): void {\n this.menuShortcuts = [...e.detail];\n }\n\n /** Toggles Side Menu & Sets viewable subpanel */\n manageSideMenuEvents(e: ToggleSideMenuOpenEvent): void {\n const { menuId, action } = e.detail;\n if (!menuId) {\n return;\n }\n\n if (action === 'open') {\n this.openShortcut(menuId);\n } else if (action === 'toggle') {\n this.openMenu = menuId;\n this.toggleMenu();\n }\n }\n\n get menuToggleButton(): TemplateResult {\n const label = this.menuOpened ? 'Close side panel' : 'Open side panel';\n return html`\n <button\n class=\"toggle-menu\"\n @click=${() => this.toggleMenu()}\n title=${label}\n aria-label=${label}\n aria-expanded=${this.menuOpened}\n aria-controls=\"menu\"\n >\n ${ellipsesIcon}\n </button>\n `;\n }\n\n get selectedMenuId(): MenuId | '' {\n return this.openMenu || '';\n }\n\n get renderSideMenu(): TemplateResult {\n return html`\n <nav aria-label=\"Item navigation\">\n <div\n class=\"minimized ${classMap({ hidden: this.menuOpened })}\"\n part=\"minimized-menu\"\n >\n ${this.shortcuts} ${this.menuToggleButton}\n </div>\n <!-- Closed drawers are inert, so what is off-screen is also out of\n the tab order and the accessibility tree. -->\n <div\n id=\"menu\"\n role=\"group\"\n aria-label=\"Item navigation menu\"\n ?inert=${!this.menuOpened}\n >\n <ia-itemnav-menu-slider\n .menus=${this.menuContents}\n .selectedMenu=${this.selectedMenuId}\n @menuTypeSelected=${this.setOpenMenu}\n @menuPanelClosed=${this.closeSidePanel}\n @menuSliderClosed=${this.closeMenu}\n ></ia-itemnav-menu-slider>\n </div>\n </nav>\n `;\n }\n /** End Side menu */\n\n /** Menu Shortcuts */\n openShortcut(selectedMenuId: MenuId = ''): void {\n // Opening straight to a panel is one movement: the drawer carries the\n // panel in, so the panel must not also slide (see `.drawer-entering`).\n // Only when the drawer is actually closed — switching shortcuts while it\n // is already open should still animate the panel across.\n this.drawerEntering = !this.menuOpened;\n this.openMenu = selectedMenuId;\n this.menuOpened = true;\n // The rail hides itself once the drawer opens, taking the focused\n // shortcut with it, so focus has to be placed deliberately.\n this.moveFocusForDrawer();\n }\n\n get shortcuts(): TemplateResult {\n const shortcuts = this.menuShortcuts.map(({ icon, id, label }) => {\n if (id === 'fullscreen') {\n return html`${icon}`;\n }\n\n return html`\n <li>\n <button\n class=\"shortcut ${id}\"\n @click=${() => this.openShortcut(id)}\n title=${label}\n aria-label=${label}\n aria-expanded=${this.menuOpened && this.openMenu === id}\n >\n ${icon}\n </button>\n </li>\n `;\n });\n return html`<ul class=\"shortcuts\" role=\"list\">\n ${shortcuts}\n </ul>`;\n }\n /** End Menu Shortcuts */\n\n /** Misc Render */\n get menuClass(): string {\n const hasMenuOrShortcuts =\n this.menuContents?.length || this.menuShortcuts?.length;\n const drawerState = this.menuOpened && hasMenuOrShortcuts ? 'open' : '';\n const fullscreenState = this.viewportInFullscreen ? 'fullscreen' : '';\n // When the side menu renders, the minimized rail floats over the left edge;\n // `has-menu` lets the reader reserve its width so the theater isn't covered.\n const railState = this.shouldRenderMenu ? 'has-menu' : '';\n const enteringState = this.drawerEntering ? 'drawer-entering' : '';\n return `${drawerState} ${fullscreenState} ${railState} ${enteringState}`;\n }\n\n static get styles(): CSSResultGroup {\n const subnavWidth = css`var(--item-navigator-menu-width--)`;\n const transitionTiming = css`var(--item-navigator-animation-timing--)`;\n const transitionEffect = css`transform ${transitionTiming} ease-out`;\n const menuMargin = css`var(--item-navigator-menu-margin--)`;\n const theaterBg = css`var(--item-navigator-theater-bg-color--)`;\n const iconSize = css`var(--item-navigator-icon-size--)`;\n\n return [\n themeStyles,\n css`\n :host {\n --item-navigator-menu-width--: var(\n --item-navigator-menu-width,\n 320px\n );\n --item-navigator-animation-timing--: var(\n --item-navigator-animation-timing,\n 200ms\n );\n --item-navigator-menu-margin--: var(\n --item-navigator-menu-margin,\n 42px\n );\n --item-navigator-theater-bg-color--: var(\n --item-navigator-theater-bg-color,\n #000\n );\n /* Every glyph is square, so one knob sizes both axes. */\n --item-navigator-icon-size--: var(--item-navigator-icon-size, 2.4em);\n /* Icons follow the adjustable text color by default. */\n --item-navigator-icon-color--: var(\n --item-navigator-icon-color,\n var(--item-navigator-text-color, var(--true-white))\n );\n\n /*\n * The component's internal sizing is expressed in em against this\n * base (10px matches petabox's base font size, which the upstream\n * demo set on the document root). Anchoring it here makes the\n * navigator self-contained — its scale no longer depends on the\n * consumer's root font-size. Override to rescale everything.\n */\n --item-navigator-base-font-size--: var(\n --item-navigator-base-font-size,\n 10px\n );\n font-size: var(--item-navigator-base-font-size--);\n }\n\n :host,\n #frame,\n .menu-and-reader {\n position: relative;\n overflow: hidden;\n display: block;\n }\n\n :host,\n #frame {\n min-height: inherit;\n height: inherit;\n }\n\n slot {\n display: block;\n width: 100%;\n }\n\n slot * {\n display: block;\n height: inherit;\n }\n\n #frame {\n background-color: ${theaterBg};\n color-scheme: dark;\n display: flex;\n flex-direction: column;\n /*\n * The overlay/shift breakpoint keys off the navigator's own width,\n * not the viewport's, so the frame is the query container. This\n * replaces a host-injected resize observer that set the class from\n * JS: layout drives it now, so there is nothing to inject, register\n * or tear down. The inline-size type contains width only, leaving the\n * flex column's height behaviour alone.\n */\n container-type: inline-size;\n container-name: navframe;\n }\n\n #frame.fullscreen {\n position: fixed;\n top: 0;\n bottom: 0;\n left: 0;\n right: 0;\n z-index: 9;\n /*\n * Override the inherited height/min-height from the base #frame rule:\n * on a fixed element an explicit height wins over top/bottom, so the\n * inset (0 on all sides) can't fill the viewport unless height is\n * released back to auto.\n */\n height: auto;\n min-height: 0;\n }\n\n .hidden {\n display: none !important;\n }\n\n button {\n /* Buttons don't inherit font-size from the UA stylesheet; inherit it\n so em-sized icons resolve against the component's base, not the\n browser's default button font-size. */\n font: inherit;\n cursor: pointer;\n padding: 0;\n border: 0;\n }\n\n .menu-and-reader {\n position: relative;\n display: flex;\n flex: 1;\n }\n\n nav button {\n background: none;\n }\n\n nav .minimized {\n background: rgba(0, 0, 0, 0.7);\n padding-top: 6px;\n position: absolute;\n width: ${menuMargin};\n z-index: 2;\n left: 0;\n border-bottom-right-radius: 5%;\n }\n\n nav .minimized button {\n margin-bottom: 0.2em;\n margin: auto;\n display: inline-flex;\n vertical-align: middle;\n align-items: center;\n justify-content: center;\n width: ${menuMargin};\n height: ${menuMargin};\n }\n\n nav .minimized button > * {\n /** Prevent the icon's SVG description from stealing tooltip message */\n pointer-events: none;\n }\n\n nav .minimized button.toggle-menu > * {\n border: 2px solid var(--item-navigator-icon-color--);\n border-radius: ${iconSize};\n width: ${iconSize};\n height: ${iconSize};\n margin: auto;\n }\n\n /* The rail is a list for assistive tech; strip the list chrome so it\n still reads as a row of icons. */\n .shortcuts,\n .shortcuts li {\n list-style: none;\n padding: 0;\n margin: 0;\n }\n\n .toggle-menu .ia-icon,\n .shortcuts .ia-icon {\n width: ${iconSize};\n height: ${iconSize};\n }\n\n /* Our glyphs are masked spans: the mask supplies the shape, this\n supplies the paint. */\n span.ia-icon {\n background-color: var(--item-navigator-icon-color--);\n }\n\n /* Host-supplied icons may still be inline svg, so keep theming those\n the original way. */\n .ia-icon .fill-color {\n fill: var(--item-navigator-icon-color--);\n }\n\n #menu {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n z-index: 3;\n overflow: hidden;\n width: ${subnavWidth};\n transform: translateX(calc(${subnavWidth} * -1));\n transition: ${transitionEffect};\n }\n\n #reader {\n position: relative;\n z-index: 1;\n transform: translateX(0);\n width: 100%;\n display: flex;\n /*\n * Ease the reader's size/position changes so the slotted theater\n * glides in sync with the sliding drawer (shift mode) and settles\n * smoothly on resize, rather than snapping. Overlay mode opts out\n * below so the full-width theater tracks resizes instantly.\n */\n transition:\n width ${transitionTiming} ease-out,\n margin-left ${transitionTiming} ease-out,\n transform ${transitionTiming} ease-out;\n }\n\n #reader > * {\n width: 100%;\n display: flex;\n flex: 1;\n }\n\n /*\n * The minimized rail floats over the frame's left edge while the drawer\n * is closed, so pad the theater content by its width to avoid overlap.\n * This lives on the reader's content (not the reader box) and isn't\n * transitioned, so it snaps away on open — letting the reader box track\n * the drawer's edge exactly during the shift, rather than trailing it.\n */\n .has-menu:not(.open) #reader > * {\n box-sizing: border-box;\n padding-left: ${menuMargin};\n }\n\n /* Opening straight to a panel is one movement. The panel is nested in\n #menu, so its own slide would compose with the drawer's transform\n and send it twice the distance in the same time — arriving late and\n travelling at double speed. Holding it still lets the drawer carry\n it in. */\n .drawer-entering #menu {\n --item-navigator-panel-transition--: none;\n }\n\n .open #menu {\n width: ${subnavWidth};\n transform: translateX(0);\n transition: ${transitionEffect};\n }\n\n /* Shift: the drawer pushes the theater aside. */\n .open #reader {\n width: calc(100% - ${subnavWidth});\n margin-left: ${subnavWidth};\n }\n\n /*\n * Overlay: too narrow to give the drawer its own column, so it covers\n * a full-width theater. The transition is dropped here so the theater\n * tracks resizes instantly instead of easing behind them.\n */\n @container navframe (max-width: 600px) {\n .open #reader {\n width: 100%;\n margin-left: 0;\n transition: none;\n }\n }\n `,\n ];\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ia-item-navigator': IAItemNavigator;\n }\n}\n"]}
1
+ {"version":3,"file":"ia-item-navigator.js","sourceRoot":"","sources":["../../../../src/elements/ia-item-navigator/ia-item-navigator.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n css,\n html,\n LitElement,\n TemplateResult,\n nothing,\n type CSSResultGroup,\n} from 'lit';\nimport { property, state, query } from 'lit/decorators.js';\nimport { customElement } from '@src/util/custom-element';\nimport { classMap } from 'lit/directives/class-map.js';\nimport themeStyles from '@src/themes/theme-styles';\n\nimport { ellipsesIcon } from './icons';\nimport './ia-itemnav-menu-slider';\nimport './ia-itemnav-no-theater-available';\nimport type { IAItemNavMenuSlider } from './ia-itemnav-menu-slider';\n\nimport {\n ToggleSideMenuOpenEvent,\n ToggleSidePanelOpenEvent,\n SetSideMenuContentsEvent,\n SetSideMenuShortcutsEvent,\n LoadingStateUpdatedEvent,\n ManageFullscreenEvent,\n} from './interfaces/event-interfaces';\nimport {\n MenuProviderInterface,\n MenuShortcutInterface,\n MenuId,\n} from './interfaces/menu-interfaces';\n\n/**\n * A fullscreen-capable frame that hosts an Archive.org item's theater. The\n * consumer projects a header bar and the theater itself into the `header` and\n * `main` slots; a collapsible left drawer (`ia-itemnav-menu-slider`) is driven by a\n * data array of menu providers, and a minimized rail shows shortcut icons.\n *\n * The navigator is a shell — it does not know how to render any particular\n * viewer. Menu panel bodies are opaque `TemplateResult`s supplied by the\n * consumer via `menuContents`.\n */\n@customElement('ia-item-navigator')\nexport class IAItemNavigator extends LitElement {\n /** archive.org item identifier. */\n @property({ type: String }) identifier?: string;\n\n @property({ type: Boolean, reflect: true }) viewAvailable: boolean = true;\n\n @property({ type: String }) baseHost = 'archive.org';\n\n @property({ type: Boolean }) signedIn = false;\n\n @property({ type: Array }) menuContents: MenuProviderInterface[] = [];\n\n @property({ type: Array }) menuShortcuts: MenuShortcutInterface[] = [];\n\n @property({ type: Boolean, reflect: true, attribute: true })\n viewportInFullscreen: boolean | null = null;\n\n @property({ type: Boolean, reflect: true }) menuOpened = false;\n\n @property({ type: String, reflect: true }) openMenu?: MenuId;\n\n /**\n * Whether the slotted theater is ready. While false the reader stays\n * hidden and the frame is empty.\n *\n * The navigator used to fill that gap with its own spinner, but a shell\n * shouldn't decide what loading looks like — and its glyph and fullscreen\n * caption were branding a consumer couldn't override. An indicator returns\n * once WEBDEV-8951 moves the shared status indicators into elements, so the\n * navigator can use that one instead of carrying its own.\n */\n @property({ type: Boolean, reflect: true, attribute: true }) loaded: boolean =\n false;\n\n /**\n * Set for the render where the drawer opens straight to a panel, so the\n * panel holds still and rides in. Every other path clears it, rather\n * than waiting for the drawer's `transitionend` — that never fires when\n * animations are disabled, which would strand the flag on.\n */\n @state() private drawerEntering = false;\n\n @query('ia-itemnav-menu-slider') private menuSlider!: IAItemNavMenuSlider;\n\n @query('button.toggle-menu') private toggleMenuButton!: HTMLButtonElement;\n\n slotChange(e: Event, type: 'header' | 'main'): void {\n const slottedContent = (\n e.target as HTMLSlotElement\n ).assignedNodes()?.[0] as HTMLElement;\n\n this.dispatchEvent(\n new CustomEvent('slotChange', {\n detail: { slot: slottedContent, type },\n }),\n );\n this.requestUpdate();\n }\n\n render(): TemplateResult {\n const displayReaderClass = this.loaded ? '' : 'hidden';\n return html`\n <div id=\"frame\" class=${this.menuClass}>\n <slot\n name=\"header\"\n @slotchange=${(e: Event) => this.slotChange(e, 'header')}\n ></slot>\n <div class=\"menu-and-reader\">\n ${this.shouldRenderMenu ? this.renderSideMenu : nothing}\n <div id=\"reader\" class=${displayReaderClass}>\n ${this.renderViewport}\n </div>\n </div>\n </div>\n `;\n }\n\n get noTheaterView(): TemplateResult {\n return html`<ia-itemnav-no-theater-available\n .identifier=${this.identifier}\n @loadingStateUpdated=${this.loadingStateUpdated}\n ></ia-itemnav-no-theater-available>`;\n }\n\n get renderViewport(): TemplateResult | typeof nothing {\n if (!this.viewAvailable) {\n return this.noTheaterView;\n }\n\n const slotVisibility = !this.loaded ? 'opacity: 0;' : 'opacity: 1;';\n return html`\n <div slot=\"main\" style=${slotVisibility}>\n <slot\n name=\"main\"\n @slotchange=${(e: Event) => this.slotChange(e, 'main')}\n ></slot>\n </div>\n `;\n }\n\n loadingStateUpdated(e: LoadingStateUpdatedEvent): void {\n const { loaded } = e.detail;\n this.loaded = loaded ?? false;\n }\n\n /** Fullscreen Management */\n manageViewportFullscreen(e: ManageFullscreenEvent): void {\n const fullscreenStatus = !!e.detail.isFullScreen;\n this.viewportInFullscreen = !fullscreenStatus ? null : fullscreenStatus;\n\n const event = new CustomEvent('fullscreenToggled', {\n detail: e.detail,\n }) as ManageFullscreenEvent;\n\n this.dispatchEvent(event);\n }\n /** End Fullscreen Management */\n\n /** Side menu */\n get shouldRenderMenu(): boolean {\n return !!this.menuContents?.length;\n }\n\n toggleMenu(forceValue: boolean | undefined = undefined): void {\n this.drawerEntering = false;\n this.menuOpened = forceValue !== undefined ? forceValue : !this.menuOpened;\n this.moveFocusForDrawer();\n }\n\n /**\n * Opening the drawer moves focus into it; closing hands focus back to the\n * toggle. Without this, opening from the shortcut rail would leave focus on\n * a button that is about to be hidden, dropping it to the document.\n */\n private moveFocusForDrawer(): void {\n this.updateComplete.then(() => {\n if (this.menuOpened) {\n this.menuSlider?.focusDrawer();\n } else {\n this.toggleMenuButton?.focus();\n }\n });\n }\n\n /**\n * Closing the drawer also closes whatever panel was open inside it, so the\n * two can't disagree and a stale panel can't reappear on the next open.\n */\n closeMenu(): void {\n this.openMenu = undefined;\n this.toggleMenu(false);\n }\n\n setOpenMenu(e: ToggleSidePanelOpenEvent): void {\n this.drawerEntering = false;\n const { id } = e.detail;\n this.openMenu = id !== this.openMenu ? id : undefined;\n }\n\n /**\n * Clears the open channel when the slider closes its sub-panel, without\n * closing the drawer. Keeps `openMenu` in sync with the slider so the same\n * channel can be reopened afterwards.\n */\n closeSidePanel(): void {\n this.drawerEntering = false;\n this.openMenu = undefined;\n }\n\n setMenuContents(e: SetSideMenuContentsEvent): void {\n const updatedContents = [...e.detail];\n this.menuContents = updatedContents;\n }\n\n setMenuShortcuts(e: SetSideMenuShortcutsEvent): void {\n this.menuShortcuts = [...e.detail];\n }\n\n /** Toggles Side Menu & Sets viewable subpanel */\n manageSideMenuEvents(e: ToggleSideMenuOpenEvent): void {\n const { menuId, action } = e.detail;\n if (!menuId) {\n return;\n }\n\n if (action === 'open') {\n this.openShortcut(menuId);\n } else if (action === 'toggle') {\n this.openMenu = menuId;\n this.toggleMenu();\n }\n }\n\n get menuToggleButton(): TemplateResult {\n const label = this.menuOpened ? 'Close side panel' : 'Open side panel';\n return html`\n <button\n class=\"toggle-menu\"\n @click=${() => this.toggleMenu()}\n title=${label}\n aria-label=${label}\n aria-expanded=${this.menuOpened}\n aria-controls=\"menu\"\n >\n ${ellipsesIcon}\n </button>\n `;\n }\n\n get selectedMenuId(): MenuId | '' {\n return this.openMenu || '';\n }\n\n get renderSideMenu(): TemplateResult {\n return html`\n <nav aria-label=\"Item navigation\">\n <div\n class=\"minimized ${classMap({ hidden: this.menuOpened })}\"\n part=\"minimized-menu\"\n >\n ${this.shortcuts} ${this.menuToggleButton}\n </div>\n <!-- Closed drawers are inert, so what is off-screen is also out of\n the tab order and the accessibility tree. -->\n <div\n id=\"menu\"\n role=\"group\"\n aria-label=\"Item navigation menu\"\n ?inert=${!this.menuOpened}\n >\n <ia-itemnav-menu-slider\n .menus=${this.menuContents}\n .selectedMenu=${this.selectedMenuId}\n @menuTypeSelected=${this.setOpenMenu}\n @menuPanelClosed=${this.closeSidePanel}\n @menuSliderClosed=${this.closeMenu}\n ></ia-itemnav-menu-slider>\n </div>\n </nav>\n `;\n }\n /** End Side menu */\n\n /** Menu Shortcuts */\n openShortcut(selectedMenuId: MenuId = ''): void {\n // Opening straight to a panel is one movement: the drawer carries the\n // panel in, so the panel must not also slide (see `.drawer-entering`).\n // Only when the drawer is actually closed — switching shortcuts while it\n // is already open should still animate the panel across.\n this.drawerEntering = !this.menuOpened;\n this.openMenu = selectedMenuId;\n this.menuOpened = true;\n // The rail hides itself once the drawer opens, taking the focused\n // shortcut with it, so focus has to be placed deliberately.\n this.moveFocusForDrawer();\n }\n\n get shortcuts(): TemplateResult {\n const shortcuts = this.menuShortcuts.map(({ icon, id, label }) => {\n if (id === 'fullscreen') {\n return html`${icon}`;\n }\n\n return html`\n <li>\n <button\n class=\"shortcut ${id}\"\n @click=${() => this.openShortcut(id)}\n title=${label}\n aria-label=${label}\n aria-expanded=${this.menuOpened && this.openMenu === id}\n >\n ${icon}\n </button>\n </li>\n `;\n });\n return html`<ul class=\"shortcuts\" role=\"list\">\n ${shortcuts}\n </ul>`;\n }\n /** End Menu Shortcuts */\n\n /** Misc Render */\n get menuClass(): string {\n const hasMenuOrShortcuts =\n this.menuContents?.length || this.menuShortcuts?.length;\n const drawerState = this.menuOpened && hasMenuOrShortcuts ? 'open' : '';\n const fullscreenState = this.viewportInFullscreen ? 'fullscreen' : '';\n // When the side menu renders, the minimized rail floats over the left edge;\n // `has-menu` lets the reader reserve its width so the theater isn't covered.\n const railState = this.shouldRenderMenu ? 'has-menu' : '';\n const enteringState = this.drawerEntering ? 'drawer-entering' : '';\n return `${drawerState} ${fullscreenState} ${railState} ${enteringState}`;\n }\n\n static get styles(): CSSResultGroup {\n const subnavWidth = css`var(--item-navigator-menu-width--)`;\n const transitionTiming = css`var(--item-navigator-animation-timing--)`;\n const transitionEffect = css`transform ${transitionTiming} ease-out`;\n const menuMargin = css`var(--item-navigator-menu-margin--)`;\n const theaterBg = css`var(--item-navigator-theater-bg-color--)`;\n const iconSize = css`var(--item-navigator-icon-size--)`;\n\n return [\n themeStyles,\n css`\n :host {\n --item-navigator-menu-width--: var(\n --item-navigator-menu-width,\n 320px\n );\n --item-navigator-animation-timing--: var(\n --item-navigator-animation-timing,\n 200ms\n );\n --item-navigator-menu-margin--: var(\n --item-navigator-menu-margin,\n 42px\n );\n --item-navigator-theater-bg-color--: var(\n --item-navigator-theater-bg-color,\n #000\n );\n /* Every glyph is square, so one knob sizes both axes. */\n --item-navigator-icon-size--: var(--item-navigator-icon-size, 2.4em);\n /* Icons follow the adjustable text color by default. */\n --item-navigator-icon-color--: var(\n --item-navigator-icon-color,\n var(--item-navigator-text-color, var(--true-white))\n );\n\n /*\n * The component's internal sizing is expressed in em against this\n * base (10px matches petabox's base font size, which the upstream\n * demo set on the document root). Anchoring it here makes the\n * navigator self-contained — its scale no longer depends on the\n * consumer's root font-size. Override to rescale everything.\n */\n --item-navigator-base-font-size--: var(\n --item-navigator-base-font-size,\n 10px\n );\n font-size: var(--item-navigator-base-font-size--);\n }\n\n :host,\n #frame,\n .menu-and-reader {\n position: relative;\n overflow: hidden;\n display: block;\n }\n\n :host,\n #frame {\n min-height: inherit;\n height: inherit;\n }\n\n slot {\n display: block;\n width: 100%;\n }\n\n slot * {\n display: block;\n height: inherit;\n }\n\n #frame {\n background-color: ${theaterBg};\n color-scheme: dark;\n display: flex;\n flex-direction: column;\n /*\n * The overlay/shift breakpoint keys off the navigator's own width,\n * not the viewport's, so the frame is the query container. This\n * replaces a host-injected resize observer that set the class from\n * JS: layout drives it now, so there is nothing to inject, register\n * or tear down. The inline-size type contains width only, leaving the\n * flex column's height behaviour alone.\n */\n container-type: inline-size;\n container-name: navframe;\n }\n\n #frame.fullscreen {\n position: fixed;\n top: 0;\n bottom: 0;\n left: 0;\n right: 0;\n z-index: 9;\n /*\n * Override the inherited height/min-height from the base #frame rule:\n * on a fixed element an explicit height wins over top/bottom, so the\n * inset (0 on all sides) can't fill the viewport unless height is\n * released back to auto.\n */\n height: auto;\n min-height: 0;\n }\n\n .hidden {\n display: none !important;\n }\n\n button {\n /* Buttons don't inherit font-size from the UA stylesheet; inherit it\n so em-sized icons resolve against the component's base, not the\n browser's default button font-size. */\n font: inherit;\n cursor: pointer;\n padding: 0;\n border: 0;\n }\n\n .menu-and-reader {\n position: relative;\n display: flex;\n flex: 1;\n }\n\n nav button {\n background: none;\n }\n\n nav .minimized {\n background: rgba(0, 0, 0, 0.7);\n padding-top: 6px;\n position: absolute;\n width: ${menuMargin};\n z-index: 2;\n left: 0;\n border-bottom-right-radius: 5%;\n }\n\n nav .minimized button {\n margin-bottom: 0.2em;\n margin: auto;\n display: inline-flex;\n vertical-align: middle;\n align-items: center;\n justify-content: center;\n width: ${menuMargin};\n height: ${menuMargin};\n }\n\n nav .minimized button > * {\n /** Prevent the icon's SVG description from stealing tooltip message */\n pointer-events: none;\n }\n\n nav .minimized button.toggle-menu > * {\n border: 2px solid var(--item-navigator-icon-color--);\n border-radius: ${iconSize};\n width: ${iconSize};\n height: ${iconSize};\n margin: auto;\n }\n\n /* The rail is a list for assistive tech; strip the list chrome so it\n still reads as a row of icons. */\n .shortcuts,\n .shortcuts li {\n list-style: none;\n padding: 0;\n margin: 0;\n }\n\n .toggle-menu .ia-icon,\n .shortcuts .ia-icon {\n width: ${iconSize};\n height: ${iconSize};\n }\n\n /* Our glyphs are masked spans: the mask supplies the shape, this\n supplies the paint. */\n span.ia-icon {\n background-color: var(--item-navigator-icon-color--);\n }\n\n /* Host-supplied icons may still be inline svg, so keep theming those\n the original way. */\n .ia-icon .fill-color {\n fill: var(--item-navigator-icon-color--);\n }\n\n #menu {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n z-index: 3;\n overflow: hidden;\n width: ${subnavWidth};\n transform: translateX(calc(${subnavWidth} * -1));\n transition: ${transitionEffect};\n }\n\n #reader {\n position: relative;\n z-index: 1;\n transform: translateX(0);\n width: 100%;\n display: flex;\n /*\n * Ease the reader's size/position changes so the slotted theater\n * glides in sync with the sliding drawer (shift mode) and settles\n * smoothly on resize, rather than snapping. Overlay mode opts out\n * below so the full-width theater tracks resizes instantly.\n */\n transition:\n width ${transitionTiming} ease-out,\n margin-left ${transitionTiming} ease-out,\n transform ${transitionTiming} ease-out;\n }\n\n #reader > * {\n width: 100%;\n display: flex;\n flex: 1;\n }\n\n /*\n * The minimized rail floats over the frame's left edge while the drawer\n * is closed, so pad the theater content by its width to avoid overlap.\n * This lives on the reader's content (not the reader box) and isn't\n * transitioned, so it snaps away on open — letting the reader box track\n * the drawer's edge exactly during the shift, rather than trailing it.\n */\n .has-menu:not(.open) #reader > * {\n box-sizing: border-box;\n padding-left: ${menuMargin};\n }\n\n /* Opening straight to a panel is one movement. The panel is nested in\n #menu, so its own slide would compose with the drawer's transform\n and send it twice the distance in the same time — arriving late and\n travelling at double speed. Holding it still lets the drawer carry\n it in. */\n .drawer-entering #menu {\n --item-navigator-panel-transition--: none;\n }\n\n .open #menu {\n width: ${subnavWidth};\n transform: translateX(0);\n transition: ${transitionEffect};\n }\n\n /* Shift: the drawer pushes the theater aside. */\n .open #reader {\n width: calc(100% - ${subnavWidth});\n margin-left: ${subnavWidth};\n }\n\n /*\n * Overlay: too narrow to give the drawer its own column, so it covers\n * a full-width theater. The transition is dropped here so the theater\n * tracks resizes instantly instead of easing behind them.\n */\n @container navframe (max-width: 600px) {\n .open #reader {\n width: 100%;\n margin-left: 0;\n transition: none;\n }\n }\n `,\n ];\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ia-item-navigator': IAItemNavigator;\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ia-itemnav-menu-button.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-item-navigator/ia-itemnav-menu-button.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,UAAU,EACV,cAAc,EACd,KAAK,cAAc,EACpB,MAAM,KAAK,CAAC;AAKb;;;;GAIG;AACH,qBACa,mBAAoB,SAAQ,UAAU;IACjD,MAAM,CAAC,iBAAiB;;;;;;;;;MAGtB;IAE0B,IAAI,EAAE,cAAc,GAAG,MAAM,CAAM;IAEnC,IAAI,SAAM;IAEV,KAAK,SAAM;IAEX,WAAW,EAAE,cAAc,GAAG,MAAM,CAAM;IAE1C,QAAQ,SAAM;IAEb,QAAQ,UAAS;IAEjB,UAAU,UAAS;IAEhD,OAAO,CAAC,CAAC,EAAE,KAAK,GAAG,IAAI;IAKvB,6BAA6B,IAAI,IAAI;IAYrC,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,IAAI,QAAQ,IAAI,cAAc,CAW7B;IAED,IAAI,UAAU,IAAI,cAAc,CAa/B;IAED,IAAI,WAAW,IAAI,cAAc,CAWhC;IAED,MAAM,IAAI,cAAc;IAIxB,MAAM,KAAK,MAAM,IAAI,cAAc,CA2IlC;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,wBAAwB,EAAE,mBAAmB,CAAC;KAC/C;CACF"}
1
+ {"version":3,"file":"ia-itemnav-menu-button.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-item-navigator/ia-itemnav-menu-button.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,UAAU,EACV,cAAc,EACd,KAAK,cAAc,EACpB,MAAM,KAAK,CAAC;AAMb;;;;GAIG;AACH,qBACa,mBAAoB,SAAQ,UAAU;IACjD,MAAM,CAAC,iBAAiB;;;;;;;;;MAGtB;IAE0B,IAAI,EAAE,cAAc,GAAG,MAAM,CAAM;IAEnC,IAAI,SAAM;IAEV,KAAK,SAAM;IAEX,WAAW,EAAE,cAAc,GAAG,MAAM,CAAM;IAE1C,QAAQ,SAAM;IAEb,QAAQ,UAAS;IAEjB,UAAU,UAAS;IAEhD,OAAO,CAAC,CAAC,EAAE,KAAK,GAAG,IAAI;IAKvB,6BAA6B,IAAI,IAAI;IAYrC,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,IAAI,QAAQ,IAAI,cAAc,CAW7B;IAED,IAAI,UAAU,IAAI,cAAc,CAa/B;IAED,IAAI,WAAW,IAAI,cAAc,CAWhC;IAED,MAAM,IAAI,cAAc;IAIxB,MAAM,KAAK,MAAM,IAAI,cAAc,CA2IlC;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,wBAAwB,EAAE,mBAAmB,CAAC;KAC/C;CACF"}
@@ -1,6 +1,7 @@
1
1
  import { __decorate } from "tslib";
2
2
  import { css, html, LitElement, } from 'lit';
3
- import { customElement, property } from 'lit/decorators.js';
3
+ import { property } from 'lit/decorators.js';
4
+ import { customElement } from '../../util/custom-element.js';
4
5
  import { ifDefined } from 'lit/directives/if-defined.js';
5
6
  import themeStyles from '../../themes/theme-styles.js';
6
7
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"ia-itemnav-menu-button.js","sourceRoot":"","sources":["../../../../src/elements/ia-item-navigator/ia-itemnav-menu-button.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n css,\n html,\n LitElement,\n TemplateResult,\n type CSSResultGroup,\n} from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport themeStyles from '@src/themes/theme-styles';\n\n/**\n * A single entry in the item navigator's side menu. Renders either a button\n * (default) or a link (when `href` is set) with an icon, label and optional\n * detail text, and emits `menuTypeSelected` when activated.\n */\n@customElement('ia-itemnav-menu-button')\nexport class IAItemNavMenuButton extends LitElement {\n static shadowRootOptions = {\n ...LitElement.shadowRootOptions,\n delegatesFocus: true,\n };\n\n @property({ type: Object }) icon: TemplateResult | string = '';\n\n @property({ type: String }) href = '';\n\n @property({ type: String }) label = '';\n\n @property({ type: Object }) menuDetails: TemplateResult | string = '';\n\n @property({ type: String }) buttonId = '';\n\n @property({ type: Boolean }) selected = false;\n\n @property({ type: Boolean }) followable = false;\n\n onClick(e: Event): void {\n e.preventDefault();\n this.dispatchMenuTypeSelectedEvent();\n }\n\n dispatchMenuTypeSelectedEvent(): void {\n this.dispatchEvent(\n new CustomEvent('menuTypeSelected', {\n bubbles: true,\n composed: true,\n detail: {\n id: this.buttonId,\n },\n }),\n );\n }\n\n get iconClass(): string {\n return this.selected ? 'active' : '';\n }\n\n get menuItem(): TemplateResult {\n return html`\n <span\n class=\"icon ${this.iconClass}\"\n aria-hidden=\"true\"\n title=${this.label}\n >${this.icon}</span\n >\n <span class=\"label\">${this.label}</span>\n <span class=\"menu-details\">${this.menuDetails}</span>\n `;\n }\n\n get linkButton(): TemplateResult {\n // A followable link really does navigate, so it is a link and nothing\n // more; only the in-place variant is a disclosure.\n return html`\n <a\n href=${this.href}\n class=\"menu-item\"\n aria-label=${this.label}\n aria-expanded=${ifDefined(this.followable ? undefined : this.selected)}\n @click=${this.followable ? undefined : this.onClick}\n >${this.menuItem}</a\n >\n `;\n }\n\n get clickButton(): TemplateResult {\n return html`\n <button\n class=\"menu-item\"\n aria-label=${this.label}\n aria-expanded=${this.selected}\n @click=${this.onClick}\n >\n ${this.menuItem}\n </button>\n `;\n }\n\n render(): TemplateResult {\n return this.href ? this.linkButton : this.clickButton;\n }\n\n static get styles(): CSSResultGroup {\n return [\n themeStyles,\n css`\n :host {\n --item-navigator-text-color--: var(\n --item-navigator-text-color,\n var(--true-white)\n );\n --item-navigator-active-button-bg--: var(\n --item-navigator-active-button-bg,\n var(--mid-gray)\n );\n --item-navigator-menu-button-label-display--: var(\n --item-navigator-menu-button-label-display,\n none\n );\n --item-navigator-icon-inactive-color--: var(\n --item-navigator-icon-inactive-color,\n var(--lighter-gray)\n );\n --item-navigator-icon-active-color--: var(\n --item-navigator-icon-active-color,\n var(--item-navigator-text-color--)\n );\n /* Every glyph is square, so one knob sizes both axes. */\n --item-navigator-icon-size--: var(--item-navigator-icon-size, 2.4em);\n\n /* 10px base (petabox scale); internal sizing is em against it. */\n --item-navigator-base-font-size--: var(\n --item-navigator-base-font-size,\n 10px\n );\n font-size: var(--item-navigator-base-font-size--);\n }\n\n a {\n display: inline-block;\n text-decoration: none;\n }\n\n button.menu-item {\n -webkit-appearance: none;\n appearance: none;\n /* Inherit font-size so the em-sized icon/label resolve against the\n component base rather than the UA default button font-size. */\n font: inherit;\n }\n\n .menu-item {\n display: inline-flex;\n width: 100%;\n padding: 0;\n text-align: left;\n background: transparent;\n align-items: center;\n border: none;\n cursor: pointer;\n transition: background-color 0.2s;\n border-radius: 6px;\n }\n\n .menu-item:hover {\n background-color: rgba(255, 255, 255, 0.1);\n }\n\n .label {\n display: var(--item-navigator-menu-button-label-display--);\n padding: 0;\n font-size: 1.6em;\n font-weight: 400;\n color: var(--item-navigator-text-color--);\n text-align: left;\n vertical-align: middle;\n margin-left: 1em;\n }\n\n .menu-details {\n color: var(--item-navigator-text-color--);\n display: inline-block;\n margin-left: 0.5em;\n font-style: italic;\n font-size: 1.5em;\n }\n\n .menu-item > .icon {\n position: relative;\n display: inline-flex;\n min-width: 4.2em;\n max-width: 4.2em;\n height: 4.2em;\n vertical-align: middle;\n align-items: center;\n justify-content: center;\n }\n\n .menu-item > .icon > * {\n /* Prevent tooltip containing icon literal description */\n pointer-events: none;\n }\n\n /* Size the glyph within the icon box to match the shortcut-rail\n icons, rather than letting the svg fill the whole box. */\n .menu-item > .icon .ia-icon {\n width: var(--item-navigator-icon-size--);\n height: var(--item-navigator-icon-size--);\n }\n\n /* The open entry's icon shares the panel's background and rounds into\n it, so it has to sit above the panel to read as one shape. The rest\n stay below: they have no background of their own, so the panel would\n slide visibly behind them. */\n .menu-item[aria-expanded='true'] .icon {\n z-index: 2;\n background-color: var(--item-navigator-active-button-bg--);\n border-radius: 1em 0 0 1em;\n }\n\n /* Our glyphs are masked spans: the mask supplies the shape, these\n supply the paint. */\n .icon span.ia-icon {\n background-color: var(--item-navigator-icon-inactive-color--);\n }\n\n .icon.active span.ia-icon {\n background-color: var(--item-navigator-icon-active-color--);\n }\n\n /* Host-supplied icons may still be inline svg, so keep theming those\n the original way. */\n .icon .fill-color {\n fill: var(--item-navigator-icon-inactive-color--);\n }\n\n .icon.active .fill-color {\n fill: var(--item-navigator-icon-active-color--);\n }\n `,\n ];\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ia-itemnav-menu-button': IAItemNavMenuButton;\n }\n}\n"]}
1
+ {"version":3,"file":"ia-itemnav-menu-button.js","sourceRoot":"","sources":["../../../../src/elements/ia-item-navigator/ia-itemnav-menu-button.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n css,\n html,\n LitElement,\n TemplateResult,\n type CSSResultGroup,\n} from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { customElement } from '@src/util/custom-element';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport themeStyles from '@src/themes/theme-styles';\n\n/**\n * A single entry in the item navigator's side menu. Renders either a button\n * (default) or a link (when `href` is set) with an icon, label and optional\n * detail text, and emits `menuTypeSelected` when activated.\n */\n@customElement('ia-itemnav-menu-button')\nexport class IAItemNavMenuButton extends LitElement {\n static shadowRootOptions = {\n ...LitElement.shadowRootOptions,\n delegatesFocus: true,\n };\n\n @property({ type: Object }) icon: TemplateResult | string = '';\n\n @property({ type: String }) href = '';\n\n @property({ type: String }) label = '';\n\n @property({ type: Object }) menuDetails: TemplateResult | string = '';\n\n @property({ type: String }) buttonId = '';\n\n @property({ type: Boolean }) selected = false;\n\n @property({ type: Boolean }) followable = false;\n\n onClick(e: Event): void {\n e.preventDefault();\n this.dispatchMenuTypeSelectedEvent();\n }\n\n dispatchMenuTypeSelectedEvent(): void {\n this.dispatchEvent(\n new CustomEvent('menuTypeSelected', {\n bubbles: true,\n composed: true,\n detail: {\n id: this.buttonId,\n },\n }),\n );\n }\n\n get iconClass(): string {\n return this.selected ? 'active' : '';\n }\n\n get menuItem(): TemplateResult {\n return html`\n <span\n class=\"icon ${this.iconClass}\"\n aria-hidden=\"true\"\n title=${this.label}\n >${this.icon}</span\n >\n <span class=\"label\">${this.label}</span>\n <span class=\"menu-details\">${this.menuDetails}</span>\n `;\n }\n\n get linkButton(): TemplateResult {\n // A followable link really does navigate, so it is a link and nothing\n // more; only the in-place variant is a disclosure.\n return html`\n <a\n href=${this.href}\n class=\"menu-item\"\n aria-label=${this.label}\n aria-expanded=${ifDefined(this.followable ? undefined : this.selected)}\n @click=${this.followable ? undefined : this.onClick}\n >${this.menuItem}</a\n >\n `;\n }\n\n get clickButton(): TemplateResult {\n return html`\n <button\n class=\"menu-item\"\n aria-label=${this.label}\n aria-expanded=${this.selected}\n @click=${this.onClick}\n >\n ${this.menuItem}\n </button>\n `;\n }\n\n render(): TemplateResult {\n return this.href ? this.linkButton : this.clickButton;\n }\n\n static get styles(): CSSResultGroup {\n return [\n themeStyles,\n css`\n :host {\n --item-navigator-text-color--: var(\n --item-navigator-text-color,\n var(--true-white)\n );\n --item-navigator-active-button-bg--: var(\n --item-navigator-active-button-bg,\n var(--mid-gray)\n );\n --item-navigator-menu-button-label-display--: var(\n --item-navigator-menu-button-label-display,\n none\n );\n --item-navigator-icon-inactive-color--: var(\n --item-navigator-icon-inactive-color,\n var(--lighter-gray)\n );\n --item-navigator-icon-active-color--: var(\n --item-navigator-icon-active-color,\n var(--item-navigator-text-color--)\n );\n /* Every glyph is square, so one knob sizes both axes. */\n --item-navigator-icon-size--: var(--item-navigator-icon-size, 2.4em);\n\n /* 10px base (petabox scale); internal sizing is em against it. */\n --item-navigator-base-font-size--: var(\n --item-navigator-base-font-size,\n 10px\n );\n font-size: var(--item-navigator-base-font-size--);\n }\n\n a {\n display: inline-block;\n text-decoration: none;\n }\n\n button.menu-item {\n -webkit-appearance: none;\n appearance: none;\n /* Inherit font-size so the em-sized icon/label resolve against the\n component base rather than the UA default button font-size. */\n font: inherit;\n }\n\n .menu-item {\n display: inline-flex;\n width: 100%;\n padding: 0;\n text-align: left;\n background: transparent;\n align-items: center;\n border: none;\n cursor: pointer;\n transition: background-color 0.2s;\n border-radius: 6px;\n }\n\n .menu-item:hover {\n background-color: rgba(255, 255, 255, 0.1);\n }\n\n .label {\n display: var(--item-navigator-menu-button-label-display--);\n padding: 0;\n font-size: 1.6em;\n font-weight: 400;\n color: var(--item-navigator-text-color--);\n text-align: left;\n vertical-align: middle;\n margin-left: 1em;\n }\n\n .menu-details {\n color: var(--item-navigator-text-color--);\n display: inline-block;\n margin-left: 0.5em;\n font-style: italic;\n font-size: 1.5em;\n }\n\n .menu-item > .icon {\n position: relative;\n display: inline-flex;\n min-width: 4.2em;\n max-width: 4.2em;\n height: 4.2em;\n vertical-align: middle;\n align-items: center;\n justify-content: center;\n }\n\n .menu-item > .icon > * {\n /* Prevent tooltip containing icon literal description */\n pointer-events: none;\n }\n\n /* Size the glyph within the icon box to match the shortcut-rail\n icons, rather than letting the svg fill the whole box. */\n .menu-item > .icon .ia-icon {\n width: var(--item-navigator-icon-size--);\n height: var(--item-navigator-icon-size--);\n }\n\n /* The open entry's icon shares the panel's background and rounds into\n it, so it has to sit above the panel to read as one shape. The rest\n stay below: they have no background of their own, so the panel would\n slide visibly behind them. */\n .menu-item[aria-expanded='true'] .icon {\n z-index: 2;\n background-color: var(--item-navigator-active-button-bg--);\n border-radius: 1em 0 0 1em;\n }\n\n /* Our glyphs are masked spans: the mask supplies the shape, these\n supply the paint. */\n .icon span.ia-icon {\n background-color: var(--item-navigator-icon-inactive-color--);\n }\n\n .icon.active span.ia-icon {\n background-color: var(--item-navigator-icon-active-color--);\n }\n\n /* Host-supplied icons may still be inline svg, so keep theming those\n the original way. */\n .icon .fill-color {\n fill: var(--item-navigator-icon-inactive-color--);\n }\n\n .icon.active .fill-color {\n fill: var(--item-navigator-icon-active-color--);\n }\n `,\n ];\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ia-itemnav-menu-button': IAItemNavMenuButton;\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ia-itemnav-menu-slider.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-item-navigator/ia-itemnav-menu-slider.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,UAAU,EACV,OAAO,EACP,KAAK,cAAc,EACnB,cAAc,EACd,KAAK,cAAc,EACpB,MAAM,KAAK,CAAC;AAIb,OAAO,0BAA0B,CAAC;AAElC,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAOrE;;;GAGG;AACH,qBACa,mBAAoB,SAAQ,UAAU;IACtB,KAAK,EAAE,qBAAqB,EAAE,CAAM;IAE/D;;;;OAIG;IACyB,YAAY,SAAM;IAElB,kBAAkB,EAC1C,cAAc,GACd,OAAO,OAAO,CAAW;IAEV,OAAO,CAAC,KAAK,CAAC,CAAc;IAE1B,OAAO,CAAC,QAAQ,CAAC,CAAmB;IAE1B,OAAO,CAAC,iBAAiB,CAAC,CAAc;IAEvE,mEAAmE;IACnE,OAAO,CAAC,aAAa,CAAQ;IAE7B,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAYhD;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAQ7B,OAAO,CAAC,aAAa;IAQrB;;;;OAIG;IACH,WAAW,IAAI,IAAI;IAWnB,oDAAoD;IACpD,SAAS,IAAI,IAAI;IAQjB,uDAAuD;IACvD,UAAU,IAAI,IAAI;IAQlB,sDAAsD;IACtD,aAAa,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;IAUzC,IAAI,mBAAmB,IAAI,qBAAqB,GAAG,SAAS,CAE3D;IAID,IAAI,iBAAiB,IAAI,MAAM,CAE9B;IAED,IAAI,SAAS,IAAI,cAAc,EAAE,CAgBhC;IAED,IAAI,gBAAgB,IAAI,cAAc,CA4BrC;IAED,IAAI,WAAW,IAAI,cAAc,CAWhC;IAED,kBAAkB;IAClB,MAAM,IAAI,cAAc;IA+BxB,MAAM,KAAK,MAAM,IAAI,cAAc,CAyLlC;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,wBAAwB,EAAE,mBAAmB,CAAC;KAC/C;CACF"}
1
+ {"version":3,"file":"ia-itemnav-menu-slider.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-item-navigator/ia-itemnav-menu-slider.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,UAAU,EACV,OAAO,EACP,KAAK,cAAc,EACnB,cAAc,EACd,KAAK,cAAc,EACpB,MAAM,KAAK,CAAC;AAKb,OAAO,0BAA0B,CAAC;AAElC,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAOrE;;;GAGG;AACH,qBACa,mBAAoB,SAAQ,UAAU;IACtB,KAAK,EAAE,qBAAqB,EAAE,CAAM;IAE/D;;;;OAIG;IACyB,YAAY,SAAM;IAElB,kBAAkB,EAC1C,cAAc,GACd,OAAO,OAAO,CAAW;IAEV,OAAO,CAAC,KAAK,CAAC,CAAc;IAE1B,OAAO,CAAC,QAAQ,CAAC,CAAmB;IAE1B,OAAO,CAAC,iBAAiB,CAAC,CAAc;IAEvE,mEAAmE;IACnE,OAAO,CAAC,aAAa,CAAQ;IAE7B,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAYhD;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAQ7B,OAAO,CAAC,aAAa;IAQrB;;;;OAIG;IACH,WAAW,IAAI,IAAI;IAWnB,oDAAoD;IACpD,SAAS,IAAI,IAAI;IAQjB,uDAAuD;IACvD,UAAU,IAAI,IAAI;IAQlB,sDAAsD;IACtD,aAAa,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;IAUzC,IAAI,mBAAmB,IAAI,qBAAqB,GAAG,SAAS,CAE3D;IAID,IAAI,iBAAiB,IAAI,MAAM,CAE9B;IAED,IAAI,SAAS,IAAI,cAAc,EAAE,CAgBhC;IAED,IAAI,gBAAgB,IAAI,cAAc,CA4BrC;IAED,IAAI,WAAW,IAAI,cAAc,CAWhC;IAED,kBAAkB;IAClB,MAAM,IAAI,cAAc;IA+BxB,MAAM,KAAK,MAAM,IAAI,cAAc,CAyLlC;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,wBAAwB,EAAE,mBAAmB,CAAC;KAC/C;CACF"}
@@ -1,6 +1,7 @@
1
1
  import { __decorate } from "tslib";
2
2
  import { css, html, LitElement, nothing, } from 'lit';
3
- import { customElement, property, query } from 'lit/decorators.js';
3
+ import { property, query } from 'lit/decorators.js';
4
+ import { customElement } from '../../util/custom-element.js';
4
5
  import themeStyles from '../../themes/theme-styles.js';
5
6
  import { collapseSidebarIcon } from './icons.js';
6
7
  import './ia-itemnav-menu-button.js';