Webdev 8458 migrate item navigator - #64
Conversation
Port @internetarchive/iaux-item-navigator into src/labs/ia-item-navigator, adopting the elements CSS convention, with a demo and tests. Scope: the navigator shell (ia-item-navigator + ia-menu-slider, ia-menu-button, ia-itemnav-loader, ia-no-theater-available) and the viewable-files menu (ia-viewable-files-panel + ia-sort-files-button). The bundled social share panel is left as a follow-up. - Rename to the ia-* convention (tag ia-item-navigator, class IAItemNavigator); sub-elements prefixed likewise. - Loosen deps: modal-manager and shared-resize-observer were type-only imports, now local interfaces (interfaces/service-interfaces.ts) — zero runtime dep. Keep @internetarchive/metadata-service (real runtime use in the item converter). Inline all icons (ellipses, collapse-sidebar, viewable-files, sort) instead of adding icon-package deps. - CSS convention: public theming vars become --item-navigator-* with --x-- private aliases and inline defaults; themeStyles imported per component; palette tokens replace hardcoded colors where they map. - Fix a latent toggle bug: the menu button bound @click=${this.toggleMenu}, passing the event as forceValue; now wrapped so menuOpened stays boolean. - ia-sort-files-button sorts a copy rather than mutating the reactive prop in place; sort icons use currentColor so they theme with the icon fill var. - Demo story (labs, auto-discovered) wires the real viewable-files panel as a menu provider with the sort button as its action; live style settings. - Vitest browser-mode tests (42) covering drawer, provider rendering, responsive mode, no-theater state, menu selection, file listing, PDF flagging, URL building and sort cycling. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Complete the migration by porting the social share panel (from
iaux-in-share-panel) as ia-share-panel, so the item-navigator's bundled menus
are fully migrated.
- Rename to ia-share-panel / IASharePanel; export shareIcon as the provider
icon.
- Inline all 7 social/link icons (share, twitter, facebook, tumblr, pinterest,
email, link) as .fill-color templates in menus/share-icons.ts — no
icon-package deps.
- Upgrade the deprecated document.execCommand('copy') to the async Clipboard
API, falling back to execCommand only where the async API is unavailable;
track the copy-note timeout per note via a WeakMap.
- CSS convention: theming vars become --item-navigator-* with --x-- aliases and
inline defaults; base-font-family from themeStyles replaces the hardcoded
font stack.
- Wire the share panel into the demo as a menu provider.
- 5 Vitest tests: option population, share-URL building, embed snippets,
header toggle, and the copy-note flash.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Move src/labs/ia-item-navigator to src/elements/ia-item-navigator now that the migration is complete, treat it as a production-ready component: - Drop the `labs` flag from the story so it lists under Production-Ready and its import/usage snippets use the @internetarchive/elements/ia-item-navigator path (no /labs segment). - Export the navigator and its consumer-facing menus (viewable-files panel, sort-files button, share panel) from src/elements/index.ts. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #64 +/- ##
==========================================
+ Coverage 78.62% 84.42% +5.80%
==========================================
Files 17 27 +10
Lines 697 1008 +311
Branches 189 255 +66
==========================================
+ Hits 548 851 +303
- Misses 100 108 +8
Partials 49 49 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Fold the useful examples from the upstream demo into the story: - Realistic multi-file item (the "Master Book of American Folk Song" volumes) for the viewable-files panel, including a deliberately long title (wrapping) and PDF entries (PDF flag), with one active file. - A slotted header bar (brand + item title link) and a styled theater mock in slot="main", so the shell's host-content slots are shown in use. - A populated minimized shortcut rail (menuShortcuts) alongside the drawer. - Header, view-available, and fullscreen toggles; fullscreen renders an in-frame "Exit fullscreen" control so the demo can't trap the viewer. - Size shortcut-rail icons consistently with the toggle button, and give viewableFilesIcon the shared .ia-icon class so it themes/sizes like the rest. Kept self-contained: no metadata-service fetch or external image hotlinks. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The components' internal sizing was in rem, calibrated for petabox's 10px root font-size (which the upstream demo set on the document). In the elements demo (default 16px root) everything — icons especially — rendered ~1.6x too large. Make the navigator self-contained instead of depending on the consumer's root: - Set font-size: var(--item-navigator-base-font-size, 10px) on each component's :host and convert internal rem units to em, so sizing resolves against the component's own base. Consumers can override the var to rescale everything. - Normalize buttons with `font: inherit` (and reset the header/social icon wrappers), since form controls don't inherit font-size — otherwise em icons resolved against the browser's default button font-size. - Move menu-button text sizing off the flex container onto the label so the icon box isn't compounded. Verified in the demo: toggle/shortcut icons 24px, menu icon box 42px, labels 16px, close/sort/share icons ~20px — matching the upstream 10px-base scale. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The provider icons inside the open drawer weren't explicitly sized, so they filled the 42px icon box instead of matching the 24px minimized-rail shortcuts. Size the glyph within the menu-button icon box to --item-navigator-icon-width-- (the same var the rail uses) and drop the hardcoded 100% inline size on the demo's placeholder icon so CSS controls it. Drawer icons now render 24px, in line with the shortcuts. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Animate the outer drawer open/close via transform + `inert` (instead of a display:none toggle, which can't transition), matching the inner panel. - Expose the minimized sidebar rail as `part="minimized-menu"` (upstream #27). - Close the menu sub-panel independently of the drawer: the slider emits `menuPanelClosed` and the navigator clears `openMenu` without closing the drawer, so a channel can be reopened afterward (fixes an openMenu desync). - Ease the reader's width/margin in shift mode so the slotted theater glides in sync with the drawer and settles smoothly on resize; overlay stays instant. - Add tests for the independent sub-panel close. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Enable menu-button labels in the demo (component ships icon-only by default). - Point demo data at the real `masterbookofamericanfolksong00shep` item so the viewable-file and share links resolve; keep PDF flags via file_source. - Bind the settings checkboxes with `.checked` so exiting fullscreen from the theater unchecks the Fullscreen box. - Add an "Animate" toggle that enables/disables all navigator animations via --item-navigator-animation-timing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Fullscreen: the base `#frame { height: inherit }` overrode `top/bottom: 0`
on the fixed element, so fullscreen was stuck at the wrapper height. Release
height (height: auto; min-height: 0) so the inset fills the viewport.
- Slider header: `selectedMenuAction` defaults to Lit's `nothing` sentinel,
which is truthy — so renderMenuHeader always applied `with-secondary-action`
and an empty action span. Compare against `nothing` explicitly.
- Add tests covering the previously-uncovered paths (item attribute converter,
shared-resize-observer wiring, menu-event handlers, shortcut rail, clipboard
fallback + copy-note timeout, sort comparators, viewable-files scroll
branches, slider focus restoration). All runtime component files are now at
100% statements/branches/functions/lines; 76 tests pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…imation The minimized shortcut rail floats over the frame's left edge while the drawer is closed. Previously the reader reserved that width with a margin, so on a shift-mode open it animated from 42px to the drawer width while the drawer slid from 0 — leaving a shrinking gap so the theater appeared to trail the drawer. Reserve the rail's width with non-transitioned padding on the reader's content (only while closed) instead. The reader box now animates 0 -> drawer width in lockstep with the drawer (identical timing/easing), and the padding snaps away on open, so the theater stays flush with the drawer through the slide while still clearing the rail when closed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Theming: - Merge subpanel/separator/share borders into --item-navigator-border-color - Collapse all text onto --item-navigator-text-color - Merge icon knobs into --item-navigator-icon-color / -active-color / -inactive-color - Rename --item-navigator-textarea-bg -> --item-navigator-share-embed-bg - Drop no-op --item-navigator-share-icon-bg; remove dead loader fill=#333 Demo: - Styles panel shows the CSS var each control sets, plus a Reset button - List all theming/layout toggles; empty apply reverts to component defaults - Realistic archive.org cat items; clicking a viewable file swaps the theater iframe Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
| d="m9 0c4.9705627 0 9 4.02943725 9 9 0 4.9705627-4.0294373 9-9 9-4.97056275 0-9-4.0294373-9-9 0-4.97056275 4.02943725-9 9-9zm1.6976167 5.28352881c-.365258-.3556459-.9328083-.37581056-1.32099801-.06558269l-.09308988.0844372-3 3.08108108-.08194436.09533317c-.27484337.36339327-.26799482.87009349.01656959 1.22592581l.084491.09308363 3 2.91891889.09533796.0818904c.3633964.2746544.8699472.2677153 1.2256839-.0167901l.093059-.0844712.0818904-.095338c.2746544-.3633964.2677153-.8699472-.0167901-1.2256839l-.0844712-.093059-2.283355-2.2222741 2.3024712-2.36338332.0819252-.09530804c.2997677-.39632298.2644782-.96313393-.1007797-1.31877983z" | ||
| fill-rule="evenodd" | ||
| /> | ||
| </svg> |
There was a problem hiding this comment.
Can we move these into standalone svg files so we're not packaging them as part of the JS bundle?
| computer. | ||
| </p> | ||
| <a href=${this.downloadUrl}>Show all files</a> | ||
| </section> |
There was a problem hiding this comment.
We do this in offshoot here... how does this work with offshoot's? https://git.archive.org/www/offshoot/-/blob/main/src/scenes/details-page/theater/ia-theater-unavailable.ts#L71
There was a problem hiding this comment.
we can remove. this is legacy from porting, currently live in petabox
| /** Handler invoked by a shared resize observer when its target resizes. */ | ||
| export interface SharedResizeObserverResizeHandlerInterface { | ||
| handleResize(entry: ResizeObserverEntry): void; | ||
| } |
There was a problem hiding this comment.
Can we import this from @internetarchive/shared-resize-observer instead of re-creating it?
| * `HTMLElement` captures that contract without depending on | ||
| * `@internetarchive/modal-manager`. | ||
| */ | ||
| export type ModalManagerInterface = HTMLElement; |
There was a problem hiding this comment.
What happens when we use the actual ModalManager?
|
|
||
| /** Icon for the viewable-files menu shortcut / menu entry. */ | ||
| export const viewableFilesIcon = html` | ||
| <svg |
There was a problem hiding this comment.
Same comment... can we externalize this so it doesn't inflate the bundle size?
| * matching the current `subPrefix`. Populated by the host via `fileList` | ||
| * (typically re-ordered by an `ia-sort-files-button`). | ||
| */ | ||
| @customElement('ia-viewable-files-panel') |
There was a problem hiding this comment.
Looking at a lot of these custom elements, I think we should somehow scope their names to the element they're a part of since they're going to exist in the global namespace, ie ia-itemnav-viewable-files-panel
| inline: 'nearest', | ||
| }); | ||
| } | ||
| }, 350); |
There was a problem hiding this comment.
What is the intended behavior here? This feels code smelly to put an arbitrary 350ms timeout on this scroll. Can we be more deterministic about this?
| } | ||
|
|
||
| render(): TemplateResult { | ||
| return html`${this.fileList.length ? this.fileListTemplate : nothing}`; |
There was a problem hiding this comment.
Do you need to wrap this in html since you're just returning the template or nothing?
| * The contract a theater host implements to feed menu providers and shortcuts | ||
| * to the item navigator. | ||
| */ | ||
| export interface CustomTheaterInterface extends LitElement { |
There was a problem hiding this comment.
Based on the comment regarding "providers and shortcuts", this interface seems to be doing a lot more than that... passing itemMD, baseHost, observer, modal, etc. Can we scope this more concretely to those behaviors?
Also, how does this interact with offshoot's <ia-theater>?
| * A tiny adapter that satisfies the navigator's `SharedResizeObserverInterface` | ||
| * using a single native `ResizeObserver`, so the demo can show the responsive | ||
| * overlay/shift behavior without depending on | ||
| * `@internetarchive/shared-resize-observer`. |
There was a problem hiding this comment.
Why not just import the shared resize observer?
|
Can we scope the name of all of the elements, ie |
| ModalManagerInterface, | ||
| SharedResizeObserverInterface, | ||
| SharedResizeObserverResizeHandlerInterface, | ||
| } from './interfaces/service-interfaces'; |
There was a problem hiding this comment.
What happens when we use the actual Modal Manager and Shared Resize Observer?
WEBDEV-8458 Migrate item-navigator into elements
Ports
@internetarchive/iaux-item-navigatorinto the elements repo as aproduction component (
ia-item-navigator), re-styled to the elements CSSconventions, with a live demo and full test coverage.
<ia-item-navigator>, then expand Import, Usage & Settings for the live toggles/theming controls.main(for comparison): https://internetarchive.github.io/elements/What's included
The full upstream package (16 source files) — the navigator shell and both bundled menus:
ia-item-navigator— fullscreen-capable frame:header/mainslots, a collapsible drawer driven by amenuContentsprovider array, a minimizedmenuShortcutsrail, responsive overlay/shift, loader, and no-theater placeholder.ia-menu-slider,ia-menu-button,ia-itemnav-loader,ia-no-theater-available— the shell's internal pieces.ia-viewable-files-panel+ia-sort-files-button— viewable-files menu (scrollable volume list, active-file highlight, PDF flagging, tri-state title sort).ia-share-panel— social share links + copyable iframe/bbcode embed snippets.Lives at
src/elements/ia-item-navigator/; exported fromsrc/elements/index.ts.Key decisions
ia-*/IA*convention across all tags and classes (upstream mixediaux-*, un-prefixed, and Lit-2 casing).modal-manager/shared-resize-observerwere type-only upstream → replaced with local interfaces; all 11 icons inlined as Lit templates. Only new runtime dep is@internetarchive/metadata-service(genuinely used in theitemconverter).--item-navigator-*with private--x--aliases + inline defaults. Consolidated onto a small palette:--item-navigator-border-color,--item-navigator-text-color,--item-navigator-icon-color/-active-color/-inactive-color,--item-navigator-share-embed-bg, plus surface/animation knobs.--item-navigator-base-font-size) withemunits, reproducing petabox's scale without forcing a 10px root on the rest of the demo.Notable fixes vs. source
@click=${this.toggleMenu}, settingmenuOpenedto aPointerEvent(only "worked" because truthy) → now stays boolean.execCommand('copy')→ async Clipboard API (with fallback); sort works on a copy instead of mutating the reactive prop; dropped a dead never-rendered method.Demo
Self-contained
ia-item-navigatorstory (Production-Ready): realistic archive.org items (images / PDFs / video) where clicking a viewable file swaps the theater iframe; slotted header + theater; share panel + populated shortcut rail; and a Styles panel that lists every theming/layout toggle, shows the CSS var each control sets, and has a Reset.Testing
npm run build,npm run lint, and the madge circular check all pass.Follow-up (out of scope, tracked)
Shared dark-surface palette tokens for the near-blacks / border / scrim that have no house equivalent today — WEBDEV-8796 / #66.
QA Steps
Setup: open the live demo → Production-Ready →
<ia-item-navigator>, expand Import, Usage & Settings.::part(minimized-menu)targets the rail.npm test(76 navigator tests),npm run build,npm run lintpass.