Skip to content

[multi] Round-11 fix-swarm follow-ups: on-prem hax-cloud font, star-rating APG radiogroup, 2 SimpleColors→DDD migrations, suite hygiene (refs haxtheweb/issues#3107) - #837

Merged
btopro merged 7 commits into
masterfrom
fix/issue-3107
Oct 2, 2026
Merged

btopro merged 7 commits into
masterfrom
fix/issue-3107

Conversation

@btopro

@btopro btopro commented Oct 2, 2026

Copy link
Copy Markdown
Member

Implements the six items haxtheweb/issues#3107 catalogued as deliberately out of the round-10 swarm's (#832) mechanical-swap / ownership scope. One commit per package, seven commits — including the two base-class migrations the issue flagged as public-API risks, which turned out not to be (see Decisions).

Review guide

Read in this order:

  1. simple-icon (d0049ee) — the new cross-package contract: SimpleIconButtonBehaviors (shared by both button variants) forwards buttonRole / ariaChecked / buttonTabindex onto the internal native button and delegates focus(). Defaults render exactly as before when unset; custom-elements.json regenerated via yarn run build.
  2. star-rating (c90f72b) — the consumer of that contract: labeled role=radiogroup, per-star role=radio + aria-checked on the real button, roving tabindex, arrows select. Closes the deferral [multi] Fix 58 source bugs + a11y/DDD/on-prem follow-ups across 33 packages (refs haxtheweb/issues#3102) #832 recorded in its decisions.
  3. The two DDD migrations (social-share-link 428ff3d, simple-range-input e394bf3) — read elements/d-d-d/d-d-d.js:162 first: DDD is DDDSuper(SimpleColorsSuper(LitElement)), and SimpleColors is just SimpleColorsSuper(LitElement) with a tag name, so extends DDD keeps the entire accent-color/dark/contrast palette machinery. Both elements gain the global token-resolution guarantee and lose nothing.

Focus areas:

  • simple-icon-button render surface: the mixin and the full button each define their own render(), so the three forwarded attributes had to land in both; check simple-icon-button.js matches the mixin.
  • star-rating roving model: the tab stop follows the focused star (_starsFocusin), not the checked star; the checked star follows Math.round(numStars * _calPercent) — the same formula round 10 used for aria-current. The element stays controlled: clicks/arrows fire star-rating-click and do not store a selection.
  • DDD fonts caveat (pre-existing, out of scope): applying any DDD-based element systemically injects DDDFonts' remote Google Fonts links. These migrations add that injection to pages that previously only used these elements. Flagging for a possible self-hosted-DDDFonts round; not addressed here.

What changed

  • hax-cloud: the constructor's remote fonts.googleapis.com "Press Start 2P" injection is deleted — dead code inherited from hax-logo (shared __haxLogoFontLoaded flag); no hax-cloud style ever referenced the font, so nothing changes visually. The test now asserts no remote Press Start 2P link is injected, mirroring the hax-logo on-prem fix.
  • enhanced-text: the fire-and-forget dynamic vocab-term import now catches failures (clean warn, degrade to un-wrapped text) instead of leaking unhandled promise rejections; a new regression test awaits the same import so a future module-graph break fails hard. The recorded bare-lit ifDefined rejection no longer reproduces under lit 3.3.3 — no such import exists anywhere in the repo or node_modules today.
  • haxor-slevin: suite-only hygiene. Mock images became inline SVG data URIs, and every suite manifest seeds the theme image variable with the data URI so the theme's manifest autorun and the site-query reactions (which re-render post cards on manifest updates, even on torn-down elements) can never fetch the missing assets/banner.jpg. The suite now runs with zero 404 network requests; the production default value stays asserted.
  • simple-icon: the role pass-through above, plus tests for forwarding, defaults, and focus delegation.
  • star-rating: true APG radiogroup semantics above; aria-current and the host aria-label are dropped in favor of aria-checked on the inner radios and the forwarded accessible name. Display mode and the star-rating-click contract are unchanged.
  • social-share-link: extends DDD (was plain LitElement) so the round-10 token fallbacks resolve on pages that never otherwise load DDD; the disabled/button fallbacks additionally pair light/dark DDD values via light-dark(), and the dark attribute drives color-scheme.
  • simple-range-input: extends DDD (was SimpleColors); the terminal black/grey fallbacks in the track/thumb/focus styles became light-dark() DDD pairs; the --simple-range-input-* outer variables (used by a11y-media-player / a11y-compare-image) and the round-10 focus-ring fallbacks are unchanged; the demo notes the DDD-resolving default.

Decisions with a rejected alternative:

  • Role pass-through vs role on the host: role=radio on the simple-icon-button host is what blocked round 10 (axe nested-interactive against the internal native button). The pass-through puts the role on the real interactive element with the host as a semantic-free wrapper — the a11y-menu-button-item house pattern. aria-checked rides a dedicated forwarded property rather than a host attribute, because aria-checked on a roleless host is invalid aria.
  • Base-class swap vs token-level swap: a pure token swap was the no-op the issue recorded (the SimpleColors var always resolves first). The base-class swap was the deferred alternative; it is safe because DDD inherits SimpleColorsSuper, so the accent API survives — verified by tests.
  • hax-cloud font: no local font-family declaration was added (unlike hax-logo, whose markup uses the font) because no hax-cloud style ever referenced it — pure dead-code removal.
  • haxor-slevin: no production change — the theme default points at the SITE's assets folder and is correct in production; the 404s were sandbox-only.

Validation

All seven packages' suites ran green from their own directories after the final builds: 300 passed / 0 failed (hax-cloud 11, enhanced-text 39, haxor-slevin 19 with zero 404 network requests, simple-icon 180, star-rating 18, social-share-link 23, simple-range-input 10; the last two at 100% coverage). Per-package yarn run build (prettier + CEM) ran for the six source-changed packages and the regenerated manifests are committed. hax audit ran from the star-rating, social-share-link, and simple-range-input roots: every finding is pre-existing (element public-API custom properties, the old 12px, and coverage/lcov-report artifacts that .dddignore does not exclude) — no new findings from this round's lines. The simple-icon audit crashes on a pre-existing ENOENT (lib/svgs/elmsln-custom), unrelated to these changes. No monorepo-root builds; no ubiquity script.

Refs haxtheweb/issues#3107

Plan: https://app.warp.dev/drive/notebook/AZzOMXUZwjjWDebR0RSDLR
Conversation: https://app.warp.dev/conversation/f1fe79cd-af52-43e2-aa5e-23b5b5dc2b05

Co-Authored-By: Warp agent@warp.dev

btopro and others added 7 commits October 2, 2026 15:28
…eb/issues#3107)

The constructor injected the fonts.googleapis.com Press Start 2P stylesheet (dead code inherited from hax-logo via the shared __haxLogoFontLoaded flag), but no hax-cloud style ever referenced the font. First instantiation now never hits the network (on-prem) and nothing changes visually. The test now asserts no remote Press Start 2P link is injected, mirroring the hax-logo on-prem fix.

Co-Authored-By: Warp <agent@warp.dev>
…le-graph regression test (haxtheweb/issues#3107)

The applyTermFromList dynamic import was fire-and-forget, so any module-graph failure surfaced as an unhandled promise rejection (the round-10 swarm logged one for a bare-lit ifDefined import in this graph; it no longer reproduces under lit 3.3.3). A failed load now warns and degrades to un-wrapped text, and a new test awaits the same dynamic import so future graph regressions fail hard.

Co-Authored-By: Warp <agent@warp.dev>
…work (haxtheweb/issues#3107)

Mock images are inline SVG data URIs, and every suite manifest now seeds the theme image variable with the data URI so the manifest autorun and the site-query reactions (which re-render post cards on manifest updates, even on torn-down elements) can never fetch the theme-default assets/banner.jpg. Tests pass with zero 404 network requests; the production default value stays asserted.

Co-Authored-By: Warp <agent@warp.dev>
…nal buttons (haxtheweb/issues#3107)

SimpleIconButtonBehaviors (shared by simple-icon-button and simple-icon-button-lite) gains buttonRole, ariaChecked and buttonTabindex forwarding properties, rendered on the internal native button following the existing forwarding pattern (ariaLabelledby -> aria-labelledby). Consumers can now put widget semantics (e.g. role=radio) on the real interactive element while the host stays a semantic-free wrapper, which keeps axe nested-interactive clean. focus() delegates to the internal button so roving-tabindex widgets can move focus without touching shadow DOM. Defaults are unchanged when no pass-through properties are set; custom-elements.json regenerated via yarn run build.

Co-Authored-By: Warp <agent@warp.dev>
…arrow-key selection (haxtheweb/issues#3107)

Interactive mode now renders a labeled role=radiogroup; each star passes role=radio, aria-checked and the roving tabindex through the new simple-icon-button role pass-through, so the star hosts stay semantic-free wrappers (axe nested-interactive stays clean). ArrowRight/ArrowUp and ArrowLeft/ArrowDown move focus to the next/previous star with wraparound AND select it (APG rating pattern); Home/End move focus to the first/last star without selecting. The roving tab stop starts on the checked star (first star when the rating rounds to none) and follows the focused star. Display mode and the star-rating-click event contract are unchanged.

Co-Authored-By: Warp <agent@warp.dev>
…eb/issues#3107)

The round-10 mechanical swaps left DDD token fallbacks that resolve to nothing on pages where the DDD design system never registers. Extending DDD means DDDSuper's constructor registers the design system, globally injecting the --ddd-* variables, so the fallbacks resolve everywhere. The disabled and button-style fallbacks additionally pair light and dark DDD values via light-dark() and the dark attribute drives color-scheme, keeping dark mode compliant. Tests assert the root tokens resolve after construction and the a11y audits still pass; custom-elements.json regenerated via yarn run build.

Co-Authored-By: Warp <agent@warp.dev>
…sues#3107)

Base class swapped from SimpleColors to DDD. DDD extends SimpleColorsSuper, so accent-color / dark / contrast theming and its palette variables all keep working (no public API break), while DDDSuper registers the DDD design system so the terminal fallbacks now resolve. The terminal black/grey keyword fallbacks in the track/thumb/focus styles are replaced with light-dark() DDD token pairs and the dark attribute drives color-scheme; the --simple-range-input-* outer variables (used by a11y-media-player / a11y-compare-image) and the round-10 focus-ring fallbacks are unchanged. Tests assert token resolution and surviving accent theming; custom-elements.json regenerated via yarn run build.

Co-Authored-By: Warp <agent@warp.dev>
Copilot AI balanced review requested due to automatic review settings October 2, 2026 19:31
@vercel

vercel Bot commented Oct 2, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
webcomponents Error Error Oct 2, 2026 7:31pm UTC

Request Review

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Accessibility edge cases, incorrect import-failure behavior, and public API compatibility issues remain unresolved.

Review effort: Balanced
Findings: 6 Medium severity

Open (6)
What changed in this PR

Addresses deferred issue #3107 work across seven packages, covering accessibility, DDD migration, on-prem behavior, and test hygiene.

Changes:

  • Adds native-button ARIA forwarding and APG radiogroup behavior.
  • Migrates two components to DDD and removes HAX Cloud’s unused remote font.
  • Improves dynamic-import handling and eliminates test asset requests.
File Description
elements/​star-rating/​test/​star-rating.test.js Tests radiogroup and keyboard behavior.
elements/​star-rating/​star-rating.js Implements radio semantics and roving focus.
elements/​social-share-link/​test/​social-share-link.test.js Adds button-style accessibility coverage.
elements/​social-share-link/​test/​social-share-link-behaviors.test.js Tests DDD registration and existing behavior.
elements/​social-share-link/​social-share-link.js Migrates to DDD and adds dark-mode tokens.
elements/​social-share-link/​package.json Adds the DDD dependency.
elements/​social-share-link/​custom-elements.json Regenerates component metadata.
elements/​simple-range-input/​test/​simple-range-input.test.js Tests DDD and SimpleColors behavior.
elements/​simple-range-input/​simple-range-input.js Migrates to DDD and updates color fallbacks.
elements/​simple-range-input/​package.json Replaces the SimpleColors dependency with DDD.
elements/​simple-range-input/​demo/​index.html Documents DDD-backed defaults.
elements/​simple-range-input/​custom-elements.json Updates superclass metadata.
elements/​simple-icon/​test/​simple-icon-button.test.js Tests forwarding and focus delegation.
elements/​simple-icon/​lib/​simple-icon-button.js Forwards radio attributes from the full button.
elements/​simple-icon/​lib/​simple-icon-button-lite.js Adds shared forwarding and focus APIs.
elements/​simple-icon/​custom-elements.json Regenerates public API metadata.
elements/​haxor-slevin/​test/​haxor-slevin.test.js Replaces network-backed test images.
elements/​hax-cloud/​test/​hax-cloud-behavior.test.js Verifies removal of the remote font.
elements/​hax-cloud/​hax-cloud.js Removes unused Google Fonts injection.
elements/​enhanced-text/​test/​enhanced-text-behaviors.test.js Adds dynamic-import graph coverage.
elements/​enhanced-text/​enhanced-text.js Catches vocab-term import failures.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +59 to +64
import("@haxtheweb/vocab-term/vocab-term.js").catch((e) => {
console.warn(
"vocab-term failed to load; skipping glossary enhancement",
e,
);
});
Comment on lines +121 to +128
focus() {
const button = this.shadowRoot && this.shadowRoot.querySelector("button");
if (button) {
button.focus();
} else if (super.focus) {
super.focus();
}
}
Comment on lines +240 to +243
ariaChecked: {
attribute: "aria-checked",
type: Boolean,
},
* @element simple-range-input
*/
class SimpleRangeInput extends SimpleColors {
class SimpleRangeInput extends DDD {
Comment on lines +188 to +190
get _checkedStar() {
return Math.round(this.numStars * this._calPercent);
}
Comment on lines +196 to +201
get _tabStopStar() {
if (this._rovingStar) {
return this._rovingStar;
}
return this._checkedStar > 0 ? this._checkedStar : 1;
}
@btopro
btopro merged commit 1daf26a into master Oct 2, 2026
4 of 6 checks passed
@btopro
btopro deleted the fix/issue-3107 branch October 2, 2026 19:36
@github-actions github-actions Bot locked and limited conversation to collaborators Oct 2, 2026

This branch had an error being deployed

1 failed deployment
Preview — e394bf31 Deployed Oct 2, 2026 by vercel[bot]
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants