WEBDEV-8951 Add a mediatype center icon to ia-status-indicator - #91
Open
iisa wants to merge 10 commits into
Open
WEBDEV-8951 Add a mediatype center icon to ia-status-indicator#91iisa wants to merge 10 commits into
iisa wants to merge 10 commits into
Conversation
ia-status-indicator rendered a ring with three animated dots and nothing else — the middle was not addressable. PR #64 then brought in a second loader, ia-itemnav-loading-view, differing only in putting a static book glyph inside a spinning ring. This closes that gap so the details-page theater can show what kind of item is loading, and gives the bespoke item-nav loader a path to retirement. Note the ticket's original framing was wrong: ia-status-indicator has always lived in elements (added in WEBDEV-8019, #17), and offshoot only consumes it. Nothing needed moving — the gap was capability. New API: - mediatype: renders one of 10 bundled glyphs in the ring's center - icon slot: escape hatch for arbitrary glyphs (e.g. item-nav's book) - hideDots: bare-ring escape hatch, replacing loadingStyle="ring" - mode and mediatype now reflect, for CSS attribute hooks Center resolution in loading mode: slotted icon, then mediatype glyph, then nothing when hideDots is set, then the default dots. Two ring geometries are kept deliberately — the original 120x120 when the center is dots or empty, the roomier 100x100 when a glyph is present — so existing call sites see no visual change. Glyphs are drawn with a CSS mask rather than <img> so they recolor with the ring, and ship as separate .svg assets to keep path data out of the JS bundle. The mask url() is quoted: bundlers inline small SVGs as data: URIs containing apostrophes, and an unquoted url() silently drops the whole declaration and paints a solid block. Breaking changes: - loadingStyle is removed. Consumers passing "ring-dots" can drop the attribute; "ring" becomes hideDots. - 'ready' is removed from LoadingStatus. The component still renders its space-reserving placeholder for any unrecognised mode, and that fallback is now documented — ia-otp-form relies on it for its idle state and renders the indicator unconditionally, so removing the render outright would shift its input row. Unmapped mediatypes (account, data, movies) fall back to the dots rather than a broken mask. 40 component tests at 100% coverage; verified in-browser that the mask resolves, the glyph stays static while the ring spins, all 10 glyphs are distinct and unclipped, recolouring drives glyph and ring together, and the otp-form row measures 60px in both idle and loading. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #91 +/- ##
==========================================
- Coverage 81.12% 78.57% -2.55%
==========================================
Files 27 27
Lines 927 999 +72
Branches 227 250 +23
==========================================
+ Hits 752 785 +33
- Misses 113 152 +39
Partials 62 62 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
… story The story only exposed a raw Width text field and the theme colour vars, so checking the mediatype glyph at a realistic size meant typing values by hand, and there was no way to see it white-on-black the way the theater and bookreader render it. - Size presets for the widths consumers actually use: 1.25rem (default), 3rem (otp-form), 4rem (home, details router), 5rem (theater, bookreader), 6rem (account settings). Each button shows its width and names the consumer in its tooltip. - Dark surface toggle: white icon and ring on black, matching the theater's --primary-text-color override. - Reset, returning size, surface, mode, mediatype and hideDots to defaults. Size and surface are applied inline on the demo element so they take precedence over the Styles panel. The panel's own radios don't follow Reset, so they can read stale until re-applied. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The presets belong next to the value they set, so they now render under their own input in the Styles panel rather than in a separate settings form. Adds two optional fields to StyleInputSettings, both generic enough for any story to use: - `presets`, rendered as buttons below the input. Choosing one fills the input and applies in a single click, so the value also flows into the generated STYLING snippet. - `section`, which groups consecutive inputs under a heading. The three colour inputs are now "Loading" / "Success" / "Error" under a "Color" heading instead of repeating "Color - " in every label. Width gets the widths consumers actually use; Loading gets White and Black. The dark-surface toggle now sets only the background. It previously forced the text colour white inline, which overrode the panel — the same way the inline width did before the presets moved. Anything the panel owns has to stay out of the demo element's inline style, or the panel's own controls look broken. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Two fixes to the Styles panel:
- Presets rendered beside their input rather than below it. The cause was the
pre-existing `.style-input-cell { display: flex }`, which laid the input and
the preset group out as a row. The input and its range readout now share a
`.style-input-row`, and the cell itself stacks, so presets sit under the
value they set.
- The panel had no way back to defaults. `Reset` now restores every input to
its `defaultValue` and applies, sitting beside `Apply`.
The story's own reset is relabelled "Reset props & surface" — with a Reset in
the Styles panel, two unqualified Reset buttons in one panel were ambiguous
about scope.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Drops the Surface section. A dark background is not an independent choice — it is what a light indicator needs to be visible at all — so it now follows the Color > Loading value instead of being toggled by hand. Picking the White preset puts the indicator on black; going back to Black or hitting the Styles panel's Reset takes it off. `stylesApplied` now bubbles and is composed, so a story can react to the vars its own panel applies. Without that the event stopped at story-template's shadow boundary and the story could not see the colour at all. Light is measured by perceived luminance rather than matching #ffffff, so a hand-typed near-white behaves the same as the preset. Unparseable colours leave the surface alone rather than guessing. The story's reset is now just "Reset props" — the surface is no longer something it owns. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
White earns its place because it is the theater's treatment and pairs with the dark surface. Black was just a second way to reach a dark-on-light default the colour picker and the Styles panel's Reset already cover. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Three changes to the props panel, all generic to any story: - `section` groups consecutive inputs under a heading, mirroring the Styles panel. The three accessible-title fields now sit together at the bottom under "Accessible titles" as Loading / Success / Error, instead of being interleaved with the behavioural props and repeating the prefix in every label. - Radios apply on change, so choosing a mode or mediatype updates the demo and the usage example without a trip to Apply. Text fields still need it. - Props sitting at their default are left out of the usage example. Consumers only need to see what they are actually changing, so the example collapses back to a bare tag once everything is default. They are still assigned to the component, otherwise selecting a default would not reset it. That last one needed story-template to stop treating an empty stringifiedProps as "nothing to do" — an empty string is the meaningful case where every prop is at its default. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Whether presets belong under an input or beside it depends on how many there are. Width's five buttons need their own row; the loading colour's single swatch-and-button pair reads better on one line. Adds `presetsInline` to StyleInputSettings, defaulting to the stacked layout, and sets it on the loading colour. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A reflecting property is most naturally written as an attribute in markup, so
the example should show it that way rather than as a Lit property binding.
Adds `reflects` to PropInputSettings. Marked props render as `name="value"`,
or as a bare attribute when boolean, since a reflected boolean is present or
absent rather than ="false". Everything else keeps the `.prop=${value}` form,
so the two mix in one example: mode, mediatype and hidedots as attributes,
the accessible titles as bindings.
The attribute name is the lowercased property name, matching what Lit actually
reflects -- hence `hidedots`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Every other icon in elements sits flat in its component's directory -- ia-combo-box/caret-closed.svg, ia-dropdown-search-bar/search.svg, ia-snow/flake.svg -- so the mediatype glyphs follow rather than inventing an icons/ subdirectory for themselves. These are reusable domain iconography rather than component chrome, and elements has no shared asset location the way offshoot's src/assets/img does. Where they should ultimately live is WEBDEV-8817's call (migrating offshoot's ia-icon into elements), and offshoot still holds its own copy of all ten. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
WEBDEV-8951
Preview: https://internetarchive.github.io/elements/pr/pr-91/#elem-ia-status-indicator
Extend and upgrade the status indicator so that it can carry a mediatype icon in the centre of its ring, not just the three animated dots it draws today.
API
modeLoadingStatusloadingmediatypeMediaTypeIconhideDotsbooleanfalseloadingStyleSlot:
icon— for glyphs with no mediatype, e.g. item-nav's book.Behaviour
The centre is a mediatype icon or the dots, never both. In
loading, first match wins:iconmediatypeglyph — static, monochrome with the ringhideDotsis setTwo ring geometries, both kept. 120x120 for dots, a roomier 100x100 for a glyph. Unifying them would shift every existing call site for no gain.
success/errorignoremediatype— they replace the whole SVG, anderrorhas no ring.readyis merged intoloading. It only meant "reserve space, draw nothing". Gone from the type, but the component still renders that placeholder for any unrecognised mode —ia-otp-formdepends on it for its idle state.Unmapped mediatypes degrade to dots.
account,data,movieshave no glyph here.Breaking changes
Consumer updates are separate tickets.
loadingStyleremoved. Four offshoot sites pass"ring-dots"(the default) — drop the attribute.home-page.ts:215passes"ring"→hideDots.readyremoved fromLoadingStatus. Offshoot's duplicatedValidationStatusneeds narrowing. No runtime change —ia-signup-input.ts:98already guards it.Implementation
Glyphs are CSS masks, not
<img>—<img>can't be recoloured. They ship as separate.svgfiles to keep path data out of the bundle. The maskurl()stays quoted: bundlers inline these asdata:URIs containing apostrophes, and an unquotedurl()silently drops the declaration and paints a solid block.MediaTypeIconis a local union, not@internetarchive/field-parsers— no runtime dep for a type, and it can't promise a glyph we don't ship.Known duplication: this branches off
main, so the mask rendering is inline rather than importingmaskedIcon()from #64. Once #64 lands, a follow-up moves the helper somewhere shared and retiresia-itemnav-loading-view.Demo
Checking a glyph at a realistic size meant typing values by hand, so the story gained real controls. The additions are generic and available to any story:
StyleInputSettings.presets— one-click values, rendered under the input, or beside it withpresetsInline. Width carries the widths consumers actually use; Loading carries White.StyleInputSettings.section/PropInputSettings.section— groups consecutive inputs under a heading, giving the Styles panel aColorgroup and the Settings panel anAccessible titlesgroup instead of repeating the prefix in every label.Resetin the Styles panel, which had no way back to defaults.PropInputSettings.reflectsrenders reflecting props as attributes rather than property bindings — closer to how a consumer writes them.stylesAppliedto bubble and be composed, since it previously stopped at story-template's shadow boundary.Testing
40 component tests, 100% coverage on
ia-status-indicator. 213 pass repo-wide.madge --circularclean, build clean, 0 ESLint errors. The 10 new SVGs land indist/.Prettier drift in
demo/story-template.test.tsis pre-existing onmain(WEBDEV-8971).QA
Open the preview at
#elem-ia-status-indicator.Component
Hide dotstrue with mediatypenone→ bare ringModesuccess, then error, with a mediatype set → mode glyph wins, no centre glypharia-hidden, exactly one<title>Styles panel
Widthpresets sit under the input; one click applies, no ApplyColorheading groups Loading / Success / ErrorWhitepreset sits beside the swatch, not under itWhite→ glyph and ring both white, and the demo gains a black background so they stay visibleurl()quoting has regressed — check computedmask-image, not just the visualReset→ all four inputs back to defaults, background offSettings panel
Accessible titlesheading groups Loading / Success / Error at the bottom; text fields, still need Apply<ia-status-indicator></ia-status-indicator>Reset props→ mode, mediatype, hideDots back to defaults; example back to the bare tagElsewhere
#elem-ia-otp-form— flip Validation Status idle → loading, the input row must not jump100%keyframe exists because Safari needs it)🤖 Generated with Claude Code