@internetarchive/ia-item-navigator 0.0.4-4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +1 -12
- package/demo/app-root.ts +180 -23
- package/demo/index.html +4 -0
- package/dist/demo/app-root.d.ts +16 -4
- package/dist/demo/app-root.js +163 -30
- package/dist/demo/app-root.js.map +1 -1
- package/dist/src/item-navigator.d.ts +1 -5
- package/dist/src/item-navigator.js +30 -32
- package/dist/src/item-navigator.js.map +1 -1
- package/dist/test/ia-item-navigator.test.js +12 -14
- package/dist/test/ia-item-navigator.test.js.map +1 -1
- package/package.json +1 -1
- package/src/item-navigator.ts +28 -31
- package/test/ia-item-navigator.test.ts +13 -15
package/src/item-navigator.ts
CHANGED
@@ -37,9 +37,6 @@ import {
|
|
37
37
|
} from './interfaces/menu-interfaces';
|
38
38
|
import './no-theater-available';
|
39
39
|
|
40
|
-
export enum ItemType {
|
41
|
-
OPEN = 'open',
|
42
|
-
}
|
43
40
|
@customElement('ia-item-navigator')
|
44
41
|
export class ItemNavigator
|
45
42
|
extends LitElement
|
@@ -55,7 +52,7 @@ export class ItemNavigator
|
|
55
52
|
})
|
56
53
|
item?: MetadataResponse;
|
57
54
|
|
58
|
-
@property({ type:
|
55
|
+
@property({ type: Boolean }) viewAvailable: Boolean = true;
|
59
56
|
|
60
57
|
@property({ type: String }) baseHost = 'archive.org';
|
61
58
|
|
@@ -92,9 +89,9 @@ export class ItemNavigator
|
|
92
89
|
|
93
90
|
@query('#frame') private frame!: HTMLDivElement;
|
94
91
|
|
95
|
-
@query('slot[name="
|
92
|
+
@query('slot[name="header"]') private headerSlot!: HTMLSlotElement;
|
96
93
|
|
97
|
-
@query('slot[name="
|
94
|
+
@query('slot[name="main"]') private mainSlot!: HTMLSlotElement;
|
98
95
|
|
99
96
|
disconnectedCallback() {
|
100
97
|
this.removeResizeObserver();
|
@@ -151,12 +148,6 @@ export class ItemNavigator
|
|
151
148
|
return this.viewportInFullscreen ? 'Internet Archive' : '';
|
152
149
|
}
|
153
150
|
|
154
|
-
get readerHeightStyle(): string {
|
155
|
-
const calcFSHeight = `calc(100% - ${this.headerSlot?.offsetHeight || 0}px)`;
|
156
|
-
|
157
|
-
return this.headerSlot?.offsetHeight > 0 ? `height: ${calcFSHeight}` : '';
|
158
|
-
}
|
159
|
-
|
160
151
|
get loadingArea() {
|
161
152
|
return html`
|
162
153
|
<div class="loading-area">
|
@@ -180,13 +171,16 @@ export class ItemNavigator
|
|
180
171
|
|
181
172
|
render(): TemplateResult {
|
182
173
|
const displayReaderClass = this.loaded ? '' : 'hidden';
|
174
|
+
const headerHeight =
|
175
|
+
(this.headerSlot?.assignedNodes()[0] as HTMLElement)?.offsetHeight || 0;
|
183
176
|
return html`
|
184
177
|
<div id="frame" class=${this.menuClass}>
|
185
178
|
<slot
|
186
|
-
name="
|
179
|
+
name="header"
|
180
|
+
style=${`height: ${headerHeight}px`}
|
187
181
|
@slotchange=${(e: Event) => this.slotChange(e, 'header')}
|
188
182
|
></slot>
|
189
|
-
<div class="menu-and-reader"
|
183
|
+
<div class="menu-and-reader">
|
190
184
|
${this.shouldRenderMenu ? this.renderSideMenu : nothing}
|
191
185
|
<div id="reader" class=${displayReaderClass}>
|
192
186
|
${this.renderViewport}
|
@@ -205,19 +199,15 @@ export class ItemNavigator
|
|
205
199
|
}
|
206
200
|
|
207
201
|
get renderViewport(): TemplateResult | typeof nothing {
|
208
|
-
if (!this.
|
209
|
-
return nothing;
|
210
|
-
}
|
211
|
-
if (this.itemType !== ItemType.OPEN) {
|
202
|
+
if (!this.viewAvailable) {
|
212
203
|
return this.noTheaterView;
|
213
204
|
}
|
214
205
|
|
215
206
|
const slotVisibility = !this.loaded ? 'opacity: 0;' : 'opacity: 1;';
|
216
207
|
return html`
|
217
|
-
<div slot="
|
208
|
+
<div slot="main" style=${slotVisibility}>
|
218
209
|
<slot
|
219
|
-
name="
|
220
|
-
style=${this.readerHeightStyle}
|
210
|
+
name="main"
|
221
211
|
@slotchange=${(e: Event) => this.slotChange(e, 'main')}
|
222
212
|
></slot>
|
223
213
|
</div>
|
@@ -348,7 +338,9 @@ export class ItemNavigator
|
|
348
338
|
|
349
339
|
/** Misc Render */
|
350
340
|
get menuClass(): string {
|
351
|
-
const
|
341
|
+
const hasMenuOrShortcuts =
|
342
|
+
this.menuContents?.length || this.menuShortcuts?.length;
|
343
|
+
const drawerState = this.menuOpened && hasMenuOrShortcuts ? 'open' : '';
|
352
344
|
const fullscreenState = this.viewportInFullscreen ? 'fullscreen' : '';
|
353
345
|
return `${drawerState} ${fullscreenState} ${this.openMenuState}`;
|
354
346
|
}
|
@@ -364,8 +356,6 @@ export class ItemNavigator
|
|
364
356
|
:host,
|
365
357
|
#frame,
|
366
358
|
.menu-and-reader {
|
367
|
-
min-height: inherit;
|
368
|
-
height: inherit;
|
369
359
|
position: relative;
|
370
360
|
overflow: hidden;
|
371
361
|
display: block;
|
@@ -373,7 +363,6 @@ export class ItemNavigator
|
|
373
363
|
|
374
364
|
:host,
|
375
365
|
#frame,
|
376
|
-
.menu-and-reader,
|
377
366
|
.loading-area,
|
378
367
|
.loading-view {
|
379
368
|
min-height: inherit;
|
@@ -382,7 +371,6 @@ export class ItemNavigator
|
|
382
371
|
|
383
372
|
slot {
|
384
373
|
display: block;
|
385
|
-
overflow: hidden;
|
386
374
|
width: 100%;
|
387
375
|
}
|
388
376
|
|
@@ -394,6 +382,8 @@ export class ItemNavigator
|
|
394
382
|
#frame {
|
395
383
|
background-color: ${theaterBg};
|
396
384
|
color-scheme: dark;
|
385
|
+
display: flex;
|
386
|
+
flex-direction: column;
|
397
387
|
}
|
398
388
|
|
399
389
|
#frame.fullscreen {
|
@@ -406,18 +396,23 @@ export class ItemNavigator
|
|
406
396
|
}
|
407
397
|
|
408
398
|
.loading-view {
|
399
|
+
height: 100%;
|
409
400
|
display: flex;
|
410
401
|
align-items: center;
|
411
402
|
justify-content: center;
|
412
403
|
}
|
413
404
|
|
405
|
+
.loading-area {
|
406
|
+
width: 100%;
|
407
|
+
}
|
408
|
+
|
414
409
|
ia-itemnav-loader {
|
415
410
|
display: block;
|
416
411
|
width: 100%;
|
417
412
|
}
|
418
413
|
|
419
414
|
.hidden {
|
420
|
-
display: none;
|
415
|
+
display: none !important;
|
421
416
|
}
|
422
417
|
|
423
418
|
button {
|
@@ -433,6 +428,8 @@ export class ItemNavigator
|
|
433
428
|
|
434
429
|
.menu-and-reader {
|
435
430
|
position: relative;
|
431
|
+
display: flex;
|
432
|
+
flex: 1;
|
436
433
|
}
|
437
434
|
|
438
435
|
nav button {
|
@@ -495,13 +492,13 @@ export class ItemNavigator
|
|
495
492
|
z-index: 1;
|
496
493
|
transform: translateX(0);
|
497
494
|
width: 100%;
|
498
|
-
|
495
|
+
display: flex;
|
499
496
|
}
|
500
497
|
|
501
498
|
#reader > * {
|
502
499
|
width: 100%;
|
503
500
|
display: flex;
|
504
|
-
|
501
|
+
flex: 1;
|
505
502
|
}
|
506
503
|
|
507
504
|
.open.overlay #reader {
|
@@ -515,8 +512,8 @@ export class ItemNavigator
|
|
515
512
|
}
|
516
513
|
|
517
514
|
.open.shift #reader {
|
518
|
-
width: calc(100% -
|
519
|
-
|
515
|
+
width: calc(100% - ${subnavWidth});
|
516
|
+
margin-left: ${subnavWidth};
|
520
517
|
transition: ${transitionEffect};
|
521
518
|
}
|
522
519
|
`;
|
@@ -4,7 +4,7 @@ import Sinon from 'sinon';
|
|
4
4
|
|
5
5
|
import { SharedResizeObserver } from '@internetarchive/shared-resize-observer';
|
6
6
|
import { ModalManager } from '@internetarchive/modal-manager';
|
7
|
-
import { ItemNavigator
|
7
|
+
import { ItemNavigator } from '../src/item-navigator';
|
8
8
|
import '../src/item-navigator';
|
9
9
|
|
10
10
|
import { ItemStub, menuProvider, shortcut } from '../test/ia-stub';
|
@@ -22,25 +22,24 @@ afterEach(() => {
|
|
22
22
|
|
23
23
|
describe('ItemNavigator', () => {
|
24
24
|
describe('Theaters', () => {
|
25
|
-
it('shows <ia-no-theater-available>
|
25
|
+
it('shows <ia-no-theater-available> if told', async () => {
|
26
26
|
const el = await fixture<ItemNavigator>(
|
27
27
|
html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`
|
28
28
|
);
|
29
|
+
el.viewAvailable = false;
|
30
|
+
await el.updateComplete;
|
31
|
+
expect(el.viewAvailable).to.be.false;
|
29
32
|
expect(el.shadowRoot?.querySelector('ia-no-theater-available')).to.exist;
|
30
|
-
expect(el.itemType).to.not.equal(ItemType.OPEN);
|
31
33
|
});
|
32
|
-
it('opens main slot
|
34
|
+
it('opens main slot by default', async () => {
|
33
35
|
const el = await fixture<ItemNavigator>(
|
34
36
|
html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`
|
35
37
|
);
|
36
|
-
el.itemType = ItemType.OPEN;
|
37
|
-
await el.updateComplete;
|
38
38
|
|
39
|
-
expect(el.
|
39
|
+
expect(el.viewAvailable).to.be.true;
|
40
40
|
expect(el.shadowRoot?.querySelector('ia-no-theater-available')).to.be
|
41
41
|
.null;
|
42
|
-
expect(el.shadowRoot?.querySelector('slot[name="
|
43
|
-
.exist;
|
42
|
+
expect(el.shadowRoot?.querySelector('slot[name="main"]')).to.exist;
|
44
43
|
});
|
45
44
|
});
|
46
45
|
describe('`el.loaded`', () => {
|
@@ -65,14 +64,16 @@ describe('ItemNavigator', () => {
|
|
65
64
|
html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`
|
66
65
|
);
|
67
66
|
|
67
|
+
el.loaded = true;
|
68
|
+
await el.updateComplete;
|
68
69
|
const mainTheaterSection = el.shadowRoot?.querySelector('#reader');
|
69
70
|
expect(mainTheaterSection?.classList.contains('hide')).to.be.false;
|
70
71
|
expect(el.loaded).to.be.true;
|
71
72
|
// `loaded` property is reflected as DOM attribute
|
72
73
|
expect(el.hasAttribute('loaded')).to.equal(true);
|
73
|
-
expect(el.shadowRoot?.querySelector('
|
74
|
+
expect(el.shadowRoot?.querySelector('slot[name="main"]')).to.exist;
|
74
75
|
});
|
75
|
-
it('listens to `@loadingStateUpdated` to update `loaded`', async () => {
|
76
|
+
it('listens to `@loadingStateUpdated` to update `loaded` for <no-theater-available>', async () => {
|
76
77
|
const el = await fixture<ItemNavigator>(
|
77
78
|
html`<ia-item-navigator></ia-item-navigator>`
|
78
79
|
);
|
@@ -81,15 +82,12 @@ describe('ItemNavigator', () => {
|
|
81
82
|
const spy = Sinon.spy();
|
82
83
|
el.loadingStateUpdated = spy;
|
83
84
|
el.loaded = null;
|
85
|
+
el.viewAvailable = false;
|
84
86
|
await el.updateComplete;
|
85
87
|
// check base properties
|
86
88
|
expect(el.loaded).to.equal(null);
|
87
89
|
expect(el.item).to.be.undefined;
|
88
90
|
|
89
|
-
// hydrate item
|
90
|
-
el.item = new ItemStub();
|
91
|
-
await el.updateComplete;
|
92
|
-
|
93
91
|
// spy fires
|
94
92
|
expect(spy.called).to.equal(true);
|
95
93
|
expect(spy.callCount).to.equal(1);
|