From 8372e0b94c7de22ebfe467890c64e445bd84c3f3 Mon Sep 17 00:00:00 2001 From: Leo McArdle Date: Tue, 5 Dec 2023 12:33:33 +0000 Subject: [PATCH] feat(baseline): update widget to reflect new definition (#10128) See also: https://github.com/mdn/content/pull/30769 --- build/cli.ts | 45 ++++++++- build/index.ts | 15 +-- build/web-features.ts | 18 +--- client/src/app.scss | 12 +++ .../src/assets/icons/baseline/check-dark.svg | 1 - client/src/assets/icons/baseline/check.svg | 1 - .../src/assets/icons/baseline/cross-dark.svg | 1 - client/src/assets/icons/baseline/cross.svg | 1 - .../src/assets/icons/baseline/high-dark.svg | 1 + client/src/assets/icons/baseline/high.svg | 1 + .../assets/icons/baseline/limited-dark.svg | 1 + client/src/assets/icons/baseline/limited.svg | 1 + client/src/assets/icons/baseline/low-dark.svg | 1 + client/src/assets/icons/baseline/low.svg | 1 + client/src/assets/icons/feedback.svg | 1 + client/src/document/baseline-indicator.scss | 59 +++++++++--- client/src/document/baseline-indicator.tsx | 96 +++++++++++++++---- client/src/telemetry/constants.ts | 1 + client/src/telemetry/glean-context.tsx | 13 ++- client/src/telemetry/metrics.yaml | 3 +- client/src/ui/base/_themes.scss | 46 +++++---- libs/types/document.ts | 21 +--- libs/types/web-features.ts | 53 ++++++++++ package.json | 2 +- tsconfig.json | 3 +- type-fixes/web-features.ts | 5 + yarn.lock | 8 +- 27 files changed, 301 insertions(+), 110 deletions(-) delete mode 100644 client/src/assets/icons/baseline/check-dark.svg delete mode 100644 client/src/assets/icons/baseline/check.svg delete mode 100644 client/src/assets/icons/baseline/cross-dark.svg delete mode 100644 client/src/assets/icons/baseline/cross.svg create mode 100644 client/src/assets/icons/baseline/high-dark.svg create mode 100644 client/src/assets/icons/baseline/high.svg create mode 100644 client/src/assets/icons/baseline/limited-dark.svg create mode 100644 client/src/assets/icons/baseline/limited.svg create mode 100644 client/src/assets/icons/baseline/low-dark.svg create mode 100644 client/src/assets/icons/baseline/low.svg create mode 100644 client/src/assets/icons/feedback.svg create mode 100644 libs/types/web-features.ts create mode 100644 type-fixes/web-features.ts diff --git a/build/cli.ts b/build/cli.ts index d92c740a9149..9f9eb6e9cb4e 100644 --- a/build/cli.ts +++ b/build/cli.ts @@ -26,7 +26,7 @@ import { BuiltDocument, renderContributorsTxt, } from "./index.js"; -import { DocMetadata, Flaws } from "../libs/types/document.js"; +import { Doc, DocMetadata, Flaws } from "../libs/types/document.js"; import SearchIndex from "./search-index.js"; import { makeSitemapXML, makeSitemapIndexXML } from "./sitemaps.js"; import { humanFileSize } from "./utils.js"; @@ -52,6 +52,10 @@ interface GlobalMetadata { [locale: string]: Array; } +interface BuildMetadata { + [locale: string]: any; +} + async function buildDocumentInteractive( documentPath: string, interactive: boolean, @@ -132,6 +136,33 @@ async function buildDocuments( } const metadata: GlobalMetadata = {}; + const buildMetadata: BuildMetadata = {}; + + function updateBaselineBuildMetadata(doc: Doc) { + if (typeof doc.baseline?.baseline === "undefined") { + return; + } + + if (typeof buildMetadata[doc.locale] === "undefined") { + buildMetadata[doc.locale] = {}; + } + if (typeof buildMetadata[doc.locale].baseline === "undefined") { + buildMetadata[doc.locale].baseline = { + total: 0, + high: 0, + highPaths: [], + low: 0, + lowPaths: [], + not: 0, + notPaths: [], + }; + } + + buildMetadata[doc.locale].baseline.total++; + const key = doc.baseline.baseline || "not"; + buildMetadata[doc.locale].baseline[key]++; + buildMetadata[doc.locale].baseline[`${key}Paths`].push(doc.mdn_url); + } const documents = await Document.findAll(findAllOptions); const progressBar = new cliProgress.SingleBar( @@ -188,6 +219,10 @@ async function buildDocuments( appendTotalFlaws(builtDocument.flaws); } + if (builtDocument.baseline) { + updateBaselineBuildMetadata(builtDocument); + } + if (!noHTML) { fs.writeFileSync( path.join(outPath, "index.html"), @@ -330,6 +365,14 @@ async function buildDocuments( [...allBrowserCompat].sort().join(" ") ); + for (const [locale, meta] of Object.entries(buildMetadata)) { + // have to write per-locale because we build each locale concurrently + fs.writeFileSync( + path.join(BUILD_OUT_ROOT, locale.toLowerCase(), "build.json"), + JSON.stringify(meta) + ); + } + return { slugPerLocale: docPerLocale, peakHeapBytes, totalFlaws }; } diff --git a/build/index.ts b/build/index.ts index 41f3b51d0125..cdc99969f8ac 100644 --- a/build/index.ts +++ b/build/index.ts @@ -11,7 +11,7 @@ import { MacroRedirectedLinkError, } from "../kumascript/src/errors.js"; -import { Doc, WebFeatureStatus } from "../libs/types/document.js"; +import { Doc } from "../libs/types/document.js"; import { Document, execGit, slugToFolder } from "../content/index.js"; import { CONTENT_ROOT, REPOSITORY_URLS } from "../libs/env/index.js"; import * as kumascript from "../kumascript/index.js"; @@ -380,7 +380,7 @@ export async function buildDocument( browserCompat && (Array.isArray(browserCompat) ? browserCompat : [browserCompat]); - doc.baseline = await addBaseline(doc); + doc.baseline = addBaseline(doc); // If the document contains HTML, it will set `doc.hasMathML=true`. // The client ( component) needs to know this for loading polyfills. @@ -558,16 +558,9 @@ export async function buildDocument( return { doc: doc as Doc, liveSamples, fileAttachmentMap }; } -async function addBaseline( - doc: Partial -): Promise { +function addBaseline(doc: Partial) { if (doc.browserCompat) { - const filteredBrowserCompat = doc.browserCompat.filter( - (query) => - // temporary blocklist while we wait for an updated baseline definition/designs - !["css.properties.grid-template-columns.subgrid"].includes(query) - ); - return await getWebFeatureStatus(...filteredBrowserCompat); + return getWebFeatureStatus(...doc.browserCompat); } } diff --git a/build/web-features.ts b/build/web-features.ts index ec0363582e2d..2d07c244e679 100644 --- a/build/web-features.ts +++ b/build/web-features.ts @@ -1,24 +1,10 @@ -import { WebFeature, WebFeatureStatus } from "../libs/types/document.js"; -import { importJSON } from "./utils.js"; +import webFeatures from "web-features"; -let promise: Promise> | null = null; - -export async function getWebFeatures(): Promise> { - if (!promise) { - promise = importJSON>("web-features/index.json"); - } - - return promise; -} - -export async function getWebFeatureStatus( - ...features: string[] -): Promise { +export function getWebFeatureStatus(...features: string[]) { if (features.length === 0) { return; } - const webFeatures = await getWebFeatures(); for (const feature of Object.values(webFeatures)) { if ( feature.status && diff --git a/client/src/app.scss b/client/src/app.scss index 72f1a36aff69..ab22faaba672 100644 --- a/client/src/app.scss +++ b/client/src/app.scss @@ -352,3 +352,15 @@ sup.new { top: 0; z-index: var(--z-index-main-header); } + +.feedback-link::before { + background-color: var(--feedback-link-icon, var(--text-link)); + content: ""; + display: inline-flex; + height: 1em; + margin-right: 0.4em; + mask-image: url("./assets/icons/feedback.svg"); + mask-size: cover; + vertical-align: middle; + width: 1em; +} diff --git a/client/src/assets/icons/baseline/check-dark.svg b/client/src/assets/icons/baseline/check-dark.svg deleted file mode 100644 index e64c60aba194..000000000000 --- a/client/src/assets/icons/baseline/check-dark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/client/src/assets/icons/baseline/check.svg b/client/src/assets/icons/baseline/check.svg deleted file mode 100644 index a247a7445c53..000000000000 --- a/client/src/assets/icons/baseline/check.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/client/src/assets/icons/baseline/cross-dark.svg b/client/src/assets/icons/baseline/cross-dark.svg deleted file mode 100644 index 03ad46ed97c1..000000000000 --- a/client/src/assets/icons/baseline/cross-dark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/client/src/assets/icons/baseline/cross.svg b/client/src/assets/icons/baseline/cross.svg deleted file mode 100644 index 01d46e43abc5..000000000000 --- a/client/src/assets/icons/baseline/cross.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/client/src/assets/icons/baseline/high-dark.svg b/client/src/assets/icons/baseline/high-dark.svg new file mode 100644 index 000000000000..cf06ac9a8905 --- /dev/null +++ b/client/src/assets/icons/baseline/high-dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/assets/icons/baseline/high.svg b/client/src/assets/icons/baseline/high.svg new file mode 100644 index 000000000000..b72cacc383b3 --- /dev/null +++ b/client/src/assets/icons/baseline/high.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/assets/icons/baseline/limited-dark.svg b/client/src/assets/icons/baseline/limited-dark.svg new file mode 100644 index 000000000000..e5b19dda4cd6 --- /dev/null +++ b/client/src/assets/icons/baseline/limited-dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/assets/icons/baseline/limited.svg b/client/src/assets/icons/baseline/limited.svg new file mode 100644 index 000000000000..52081bb0b327 --- /dev/null +++ b/client/src/assets/icons/baseline/limited.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/assets/icons/baseline/low-dark.svg b/client/src/assets/icons/baseline/low-dark.svg new file mode 100644 index 000000000000..261502c44554 --- /dev/null +++ b/client/src/assets/icons/baseline/low-dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/assets/icons/baseline/low.svg b/client/src/assets/icons/baseline/low.svg new file mode 100644 index 000000000000..36912d2fb8b0 --- /dev/null +++ b/client/src/assets/icons/baseline/low.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/assets/icons/feedback.svg b/client/src/assets/icons/feedback.svg new file mode 100644 index 000000000000..cc09b3d58272 --- /dev/null +++ b/client/src/assets/icons/feedback.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/document/baseline-indicator.scss b/client/src/document/baseline-indicator.scss index 735ee76035c8..ace3f9042fd9 100644 --- a/client/src/document/baseline-indicator.scss +++ b/client/src/document/baseline-indicator.scss @@ -3,19 +3,32 @@ $browsers: "chrome", "edge", "firefox", "safari"; .baseline-indicator { - --baseline-bg: var(--baseline-unsupported-bg); - --baseline-engine-bg: var(--baseline-unsupported-engine-bg); - --baseline-img: var(--baseline-unsupported-img); + --baseline-bg: var(--baseline-limited-bg); + --baseline-engine-bg: var(--baseline-limited-engine-bg); + --baseline-img: var(--baseline-limited-img); + --baseline-check: var(--baseline-limited-check); + --baseline-cross: var(--baseline-limited-cross); + --feedback-link-icon: #666; background: var(--baseline-bg); border-radius: 0.25rem; margin: 1rem 0; padding-left: 3.8125rem; - &.supported { - --baseline-bg: var(--baseline-supported-bg); - --baseline-engine-bg: var(--baseline-supported-engine-bg); - --baseline-img: var(--baseline-supported-img); + &.high { + --baseline-bg: var(--baseline-high-bg); + --baseline-engine-bg: var(--baseline-high-engine-bg); + --baseline-img: var(--baseline-high-img); + --baseline-check: var(--baseline-high-check); + } + + &.low { + --baseline-bg: var(--baseline-low-bg); + --baseline-engine-bg: var(--baseline-low-engine-bg); + --baseline-img: var(--baseline-low-img); + --baseline-check: var(--baseline-low-check); + --baseline-pill-bg: var(--baseline-low-pill-bg); + --baseline-pill-color: var(--baseline-low-pill-color); } &[open] { @@ -34,6 +47,7 @@ $browsers: "chrome", "edge", "firefox", "safari"; display: flex; flex-wrap: wrap; gap: 0.5rem; + justify-content: space-between; padding: 1rem 0; padding-right: calc( var(--chevron-padding-left) + var(--chevron-size) + @@ -67,7 +81,6 @@ $browsers: "chrome", "edge", "firefox", "safari"; letter-spacing: 0; line-height: 1.5; margin: 0; - margin-right: auto; padding: 0.375rem 0; .not-bold { @@ -75,6 +88,17 @@ $browsers: "chrome", "edge", "firefox", "safari"; } } + .pill { + background: var(--baseline-pill-bg); + border-radius: 0.125rem; + color: var(--baseline-pill-color); + font-size: 0.75rem; + font-weight: 600; + margin-right: auto; + padding: 0 0.25rem; + text-transform: uppercase; + } + .browsers { display: flex; flex-wrap: wrap; @@ -107,7 +131,7 @@ $browsers: "chrome", "edge", "firefox", "safari"; } &::after { - background-color: var(--baseline-browser-unsupported-bg); + background-color: var(--baseline-cross); content: ""; display: block; height: 1.25rem; @@ -118,7 +142,7 @@ $browsers: "chrome", "edge", "firefox", "safari"; } &.supported::after { - background-color: var(--baseline-browser-supported-bg); + background-color: var(--baseline-check); mask-image: url("../assets/icons/baseline/browser-check.svg"); } } @@ -155,8 +179,21 @@ $browsers: "chrome", "edge", "firefox", "safari"; list-style: none; margin: 0; + &:first-child a { + &, + &:active, + &:visited { + background: none; + color: var(--text-link); + } + } + &:not(:first-child) a { - color: var(--text-primary); + &, + &:active { + background: none; + color: var(--text-primary); + } } } } diff --git a/client/src/document/baseline-indicator.tsx b/client/src/document/baseline-indicator.tsx index 5794f3b6aec9..db9ae287955a 100644 --- a/client/src/document/baseline-indicator.tsx +++ b/client/src/document/baseline-indicator.tsx @@ -1,11 +1,14 @@ import { DEFAULT_LOCALE } from "../../../libs/constants"; -import { WebFeatureStatus } from "../../../libs/types/document"; import { useLocale } from "../hooks"; import { BASELINE } from "../telemetry/constants"; import { useGleanClick } from "../telemetry/glean-context"; import { Icon } from "../ui/atoms/icon"; +import { useLocation } from "react-router"; + import "./baseline-indicator.scss"; +import type { SupportStatus } from "../../../libs/types/web-features"; + const ENGINES = [ { name: "Blink", browsers: ["Chrome", "Edge"] }, { name: "Gecko", browsers: ["Firefox"] }, @@ -24,20 +27,32 @@ const LOCALIZED_BCD_IDS = { "zh-TW": "瀏覽器相容性", }; -export function BaselineIndicator({ status }: { status: WebFeatureStatus }) { +const SURVEY_URL = + "https://survey.alchemer.com/s3/7634825/MDN-baseline-feedback"; + +export function BaselineIndicator({ status }: { status: SupportStatus }) { const gleanClick = useGleanClick(); const locale = useLocale(); + const { pathname } = useLocation(); const bcdLink = `#${ LOCALIZED_BCD_IDS[locale] || LOCALIZED_BCD_IDS[DEFAULT_LOCALE] }`; + const low_date = status.baseline_low_date + ? new Date(status.baseline_low_date) + : undefined; + const level = status.baseline + ? status.baseline + : status.baseline === false + ? "not" + : undefined; + + const feedbackLink = `${SURVEY_URL}?page=${pathname}&level=${level}`; + const supported = (browser: string) => { - const version: string | boolean | undefined = - status.support?.[browser.toLowerCase()]; - return Boolean( - status.is_baseline || typeof version === "string" || version - ); + const version: string | undefined = status.support?.[browser.toLowerCase()]; + return Boolean(status.baseline || version); }; const engineTitle = (browsers: string[]) => @@ -57,23 +72,32 @@ export function BaselineIndicator({ status }: { status: WebFeatureStatus }) { }) .join(""); - return typeof status.is_baseline !== "undefined" ? ( + return level ? (
e.currentTarget.open && gleanClick(BASELINE.TOGGLE_OPEN)} >

- Baseline:{" "} - - {status.is_baseline ? "Widely supported" : "Not widely supported"} - + {level !== "not" ? ( + <> + Baseline{" "} + + {level === "high" + ? "Widely available" + : low_date?.getFullYear()} + + + ) : ( + Limited availability + )}

+ {level === "low" &&
Newly available
}
{ENGINES.map(({ name, browsers }) => ( @@ -95,15 +119,38 @@ export function BaselineIndicator({ status }: { status: WebFeatureStatus }) {
-

- Baseline is determined by this web feature being supported on the - current and the previous major versions of major browsers. -

+ {level === "high" ? ( +

+ This feature is well established and works across many devices and + browser versions. It’s been available across browsers since{" "} + {low_date?.toLocaleDateString("en-US", { + year: "numeric", + month: "long", + })} + . +

+ ) : level === "low" ? ( +

+ Since{" "} + {low_date?.toLocaleDateString("en-US", { + year: "numeric", + month: "long", + })} + , this feature works across the latest devices and browser versions. + This feature might not work in older devices or browsers. +

+ ) : ( +

+ This feature is not Baseline because it does not work in some of the + most widely-used browsers. +

+ )}
  • Learn more @@ -113,6 +160,17 @@ export function BaselineIndicator({ status }: { status: WebFeatureStatus }) { See full compatibility
  • +
  • + + Feedback + +
diff --git a/client/src/telemetry/constants.ts b/client/src/telemetry/constants.ts index 505463538c96..5c10be730c5b 100644 --- a/client/src/telemetry/constants.ts +++ b/client/src/telemetry/constants.ts @@ -64,4 +64,5 @@ export const BASELINE = Object.freeze({ TOGGLE_OPEN: "baseline_toggle_open", LINK_LEARN_MORE: "baseline_link_learn_more", LINK_BCD_TABLE: "baseline_link_bcd_table", + LINK_FEEDBACK: "baseline_link_feedback", }); diff --git a/client/src/telemetry/glean-context.tsx b/client/src/telemetry/glean-context.tsx index f69803d35f68..55c5988cad8e 100644 --- a/client/src/telemetry/glean-context.tsx +++ b/client/src/telemetry/glean-context.tsx @@ -217,19 +217,18 @@ export function useGleanPage(pageNotFound: boolean, doc?: Doc) { viewportHorizontalCoverage: Math.round( (100 * window.innerWidth) / window.screen.width ), - isBaseline: - doc?.baseline?.is_baseline === undefined - ? undefined - : doc.baseline.is_baseline - ? "baseline" - : "not_baseline", + isBaseline: doc?.baseline?.baseline + ? `baseline_${doc.baseline.baseline}` + : doc?.baseline?.baseline === false + ? "not_baseline" + : undefined, utm: getUTMParameters(), }); if (typeof userData !== "undefined" && path.current !== loc.pathname) { path.current = loc.pathname; submit(); } - }, [loc.pathname, userData, pageNotFound, doc?.baseline?.is_baseline]); + }, [loc.pathname, userData, pageNotFound, doc?.baseline?.baseline]); } export function useGleanClick() { diff --git a/client/src/telemetry/metrics.yaml b/client/src/telemetry/metrics.yaml index 75bee79369ca..6dea208f59c1 100644 --- a/client/src/telemetry/metrics.yaml +++ b/client/src/telemetry/metrics.yaml @@ -87,7 +87,8 @@ page: description: | The Baseline status of the page: null: the page has no baseline status - "baseline": the page is baseline + "baseline_high": the page is baseline high + "baseline_low": the page is baseline low "not_baseline" the page is not baseline lifetime: application send_in_pings: diff --git a/client/src/ui/base/_themes.scss b/client/src/ui/base/_themes.scss index 223831842e37..1c1c46a5f613 100644 --- a/client/src/ui/base/_themes.scss +++ b/client/src/ui/base/_themes.scss @@ -190,14 +190,21 @@ --form-invalid-focus-color: #{$mdn-color-light-theme-red-50}; --form-invalid-focus-effect-color: #{rgba($mdn-color-light-theme-red-50, 0.2)}; - --baseline-supported-bg: #e6f4ea; - --baseline-supported-engine-bg: #ceead6; - --baseline-supported-img: url("../../assets/icons/baseline/check.svg"); - --baseline-unsupported-bg: #f1f3f4; - --baseline-unsupported-engine-bg: #e3e6e8; - --baseline-unsupported-img: url("../../assets/icons/baseline/cross.svg"); - --baseline-browser-supported-bg: #1e8e3e; - --baseline-browser-unsupported-bg: #666; + --baseline-high-bg: #e6f4ea; + --baseline-high-engine-bg: #ceead6; + --baseline-high-img: url("../../assets/icons/baseline/high.svg"); + --baseline-high-check: #099949; + --baseline-low-bg: #e8f0fe; + --baseline-low-engine-bg: #d2e3fc; + --baseline-low-check: #1a73e8; + --baseline-low-img: url("../../assets/icons/baseline/low.svg"); + --baseline-low-pill-bg: #3367d6; + --baseline-low-pill-color: #f1f3f4; + --baseline-limited-bg: #f1f3f4; + --baseline-limited-engine-bg: #e3e6e8; + --baseline-limited-img: url("../../assets/icons/baseline/limited.svg"); + --baseline-limited-check: #1e8e3e; + --baseline-limited-cross: #ea8600; color-scheme: light; } @@ -389,14 +396,21 @@ --form-invalid-focus-color: #{$mdn-color-light-theme-red-40}; --form-invalid-focus-effect-color: #{rgba($mdn-color-light-theme-red-40, 0.2)}; - --baseline-supported-bg: #0e2a10; - --baseline-supported-engine-bg: #031b05; - --baseline-supported-img: url("../../assets/icons/baseline/check-dark.svg"); - --baseline-unsupported-bg: #282a2c; - --baseline-unsupported-engine-bg: #1d1e1f; - --baseline-unsupported-img: url("../../assets/icons/baseline/cross-dark.svg"); - --baseline-browser-supported-bg: #5bb974; - --baseline-browser-unsupported-bg: #9aa0a6; + --baseline-high-bg: #0e2a10; + --baseline-high-engine-bg: #031b05; + --baseline-high-img: url("../../assets/icons/baseline/high-dark.svg"); + --baseline-high-check: #099949; + --baseline-low-bg: #041e49; + --baseline-low-engine-bg: #020d20; + --baseline-low-check: #1a73e8; + --baseline-low-img: url("../../assets/icons/baseline/low-dark.svg"); + --baseline-low-pill-bg: #3367d6; + --baseline-low-pill-color: #f1f3f4; + --baseline-limited-bg: #282a2c; + --baseline-limited-engine-bg: #1d1e1f; + --baseline-limited-img: url("../../assets/icons/baseline/limited-dark.svg"); + --baseline-limited-check: #1e8e3e; + --baseline-limited-cross: #ea8600; color-scheme: dark; } diff --git a/libs/types/document.ts b/libs/types/document.ts index a946283df52f..4aca45f50064 100644 --- a/libs/types/document.ts +++ b/libs/types/document.ts @@ -1,3 +1,5 @@ +import type { SupportStatus } from "./web-features.js"; + export interface Source { folder: string; github_url: string; @@ -146,7 +148,7 @@ export interface DocMetadata { popularity?: number; // Used for search. noIndexing?: boolean; browserCompat?: string[]; - baseline?: WebFeatureStatus; + baseline?: SupportStatus; hash?: string; } @@ -218,20 +220,3 @@ export interface NewsItem { }; published_at: string; } - -export interface WebFeature { - compat_features?: string[]; - status?: WebFeatureStatus; - spec?: unknown; -} - -export interface WebFeatureStatus { - is_baseline?: boolean; - since?: string; - support?: { - chrome?: string | boolean; - edge?: string | boolean; - firefox?: string | boolean; - safari?: string | boolean; - }; -} diff --git a/libs/types/web-features.ts b/libs/types/web-features.ts new file mode 100644 index 000000000000..7b5d0834da1f --- /dev/null +++ b/libs/types/web-features.ts @@ -0,0 +1,53 @@ +export type Features = { [key: string]: FeatureData }; + +// Types below copied from web-platform-dx/web-features GitHub repo: +// https://github.com/web-platform-dx/web-features/blob/5ad19b0dec722eaf6484b7d569e62e64ad7bfef0/index.ts#L8-L44 + +export interface FeatureData { + /** Alias identifier */ + alias?: string | [string, string, ...string[]]; + /** Specification */ + spec: + | specification_url + | [specification_url, specification_url, ...specification_url[]]; + /** caniuse.com identifier */ + caniuse?: string | [string, string, ...string[]]; + /** Whether a feature is considered a "baseline" web platform feature and when it achieved that status */ + status?: SupportStatus; + /** Sources of support data for this feature */ + compat_features?: string[]; + /** Usage stats */ + usage_stats?: + | usage_stats_url + | [usage_stats_url, usage_stats_url, ...usage_stats_url[]]; // A single URL or an array of two or more +} + +type browserIdentifier = + | "chrome" + | "chrome_android" + | "edge" + | "firefox" + | "firefox_android" + | "safari" + | "safari_ios"; + +type BaselineHighLow = "high" | "low"; + +export interface SupportStatus { + /** Whether the feature is Baseline (low substatus), Baseline (high substatus), or not (false) */ + baseline?: BaselineHighLow | false; + /** Date the feature achieved Baseline low status */ + baseline_low_date?: string; + /** Browser versions that most-recently introduced the feature */ + support?: { [K in browserIdentifier]?: string }; +} + +/** Specification URL + * @format uri + */ +type specification_url = string; + +/** Usage stats URL + * @format uri + */ +type usage_stats_url = string; diff --git a/package.json b/package.json index 1e81b5189089..78752a4a9927 100644 --- a/package.json +++ b/package.json @@ -137,7 +137,7 @@ "unified": "^11.0.4", "unist-builder": "^4.0.0", "unist-util-visit": "^5.0.0", - "web-features": "0.4.1", + "web-features": "0.5.0-alpha.1", "web-specs": "^2.75.1" }, "devDependencies": { diff --git a/tsconfig.json b/tsconfig.json index b04b539ef81b..1e145d71f752 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,7 +12,8 @@ "front-matter": ["./type-fixes/front-matter.js"], "@mdn/browser-compat-data/types": [ "./node_modules/@mdn/browser-compat-data/types.d.ts" - ] + ], + "web-features": ["./type-fixes/web-features.js"] }, "preserveWatchOutput": true, "resolveJsonModule": true, diff --git a/type-fixes/web-features.ts b/type-fixes/web-features.ts new file mode 100644 index 000000000000..393ea95e32bb --- /dev/null +++ b/type-fixes/web-features.ts @@ -0,0 +1,5 @@ +import features from "../node_modules/web-features/index.js"; + +import type { Features } from "../libs/types/web-features.js"; + +export default features as Features; diff --git a/yarn.lock b/yarn.lock index 173546d1bb2c..904380c6f7b1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15296,10 +15296,10 @@ wcwidth@^1.0.1: dependencies: defaults "^1.0.3" -web-features@0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/web-features/-/web-features-0.4.1.tgz#8dc4c1bf169e67bc2f67c4e0152e2bd178a07e97" - integrity sha512-L+sP/1snkijvsef57Pn6+BILxDykeZQhlqS2JaYSqe+auajKbVgGzqJjknPpeGGDZVRz6Lfl88o0Mu3ZpD+luQ== +web-features@0.5.0-alpha.1: + version "0.5.0-alpha.1" + resolved "https://registry.yarnpkg.com/web-features/-/web-features-0.5.0-alpha.1.tgz#672577016c8741f325b40849170c594b48378408" + integrity sha512-8ZcitZ3YCrZMwCajqRCOE81cUNutGuRKwRh6pVSxDC4YFG/2Yl0lToqyBjs0p7y4EpU6BOXjMmofcTI2tUve7Q== web-namespaces@^2.0.0: version "2.0.1"