diff --git a/src/components/FeatureList/index.tsx b/src/components/FeatureList/index.tsx index 570cf628df..ca07601f53 100644 --- a/src/components/FeatureList/index.tsx +++ b/src/components/FeatureList/index.tsx @@ -200,15 +200,49 @@ const FeatureList: React.FC = ({ {Object.entries(feature.frameworks) .filter(([, info]) => info.version !== 'n/a') .map(([frameworkName, frameworkInfo]) => ( - - {frameworkName} v{frameworkInfo.version} - + // The ELEMENT changes, not just the href. Guarding the + // href alone rendered the same DOM - withCurrentDocsPath + // returns undefined for undefined and React omits the + // attribute - so the chip stayed an with no href: + // not keyboard-focusable, navigating nowhere, still + // showing the link hover. 17 cells in features.json + // carry no apiUrl, of which 16 reach this branch - the + // 17th is Web / 7-Segment Display, filtered out earlier + // by version === "n/a". + // Latent only while every usage is compact mode, which + // skips this column. Same shape as the feature-name cell + // above, which swaps for

. + frameworkInfo.apiUrl ? ( + + {frameworkName} v{frameworkInfo.version} + + ) : ( + is not a control, and ARIA 1.2 does not allow the + attribute on generic elements. */ + title="No API reference" + > + {frameworkName} v{frameworkInfo.version} + {/* The dashed border and the dimmed token show sighted readers + that this chip has no link. Without this text the chip + announces exactly what a linked one announces - "iOS v1.2.3". + It says "no API reference", not "not available": every chip in + this column is a framework that DOES support the feature, so + "not available" would read as "this feature isn't on iOS". */} + (no API reference) + + ) ))} diff --git a/src/components/FeatureList/styles.module.css b/src/components/FeatureList/styles.module.css index 7e41c35f1b..1c29f473db 100644 --- a/src/components/FeatureList/styles.module.css +++ b/src/components/FeatureList/styles.module.css @@ -87,8 +87,18 @@ } +/* The chips carry padding and a border but no margin, and React renders the + .map() output with no whitespace between siblings, so without a container + layout they sit flush against one another. This rule was `display: none` + from the file's first commit - the column has never rendered, because all 50 + FeatureList usages pass displayMode="compact", which takes a different path. + Hiding the content while the component still emits its + Available Frameworks header was incoherent; this is the smallest + layout that makes the column legible if that view is ever used. */ .frameworkList { - display: none; + display: flex; + flex-wrap: wrap; + gap: 0.25rem; } .frameworkItem { @@ -112,14 +122,41 @@ text-decoration: none; } +/* Reachable by a screen reader, absent from the visual layout. Not + `display: none` or `visibility: hidden`, which remove it from the + accessibility tree as well and would defeat the point. */ +.visuallyHidden { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} + +/* No API reference for this framework yet. Dimmed through the border and a + colour token rather than `opacity`, which composited the label to 3.19:1 in + light mode - below AA - while looking merely faint. Measured against the + BUILT css rather than assumed token values: 5.29:1 light, 12.26:1 dark. + `border-style: dashed` carries the state without relying on colour. */ .frameworkItemUnavailable { - opacity: 0.5; - cursor: not-allowed; + color: var(--ifm-color-emphasis-700); + border-style: dashed; + cursor: default; } +/* Hold the dimmed colour on hover. This rule exists to cancel + .frameworkItem:hover, but it was left over from the opacity version and + restored --ifm-color-content - the full-contrast colour - so hovering an + unavailable chip made it look available, with only the dashed border + still carrying the state. The span is not interactive; cursor: default + already says so. */ .frameworkItemUnavailable:hover { background: var(--ifm-color-emphasis-100); - color: var(--ifm-color-content); + color: var(--ifm-color-emphasis-700); border-color: var(--ifm-color-emphasis-200); }