@expressivecss/mcp-server 0.3.1 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "expressivecss-mcp",
3
3
  "displayName": "ExpressiveCSS MCP",
4
- "version": "0.3.1",
4
+ "version": "0.4.1",
5
5
  "description": "ExpressiveCSS workflow server with Setup Expert, Rules Enforcer, Creative Director, Page Arcjitect, Component Syntax Expert, and Quality Inspector.",
6
6
  "author": {
7
7
  "name": "BaezFJ",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "expressivecss-mcp",
3
3
  "displayName": "ExpressiveCSS MCP",
4
- "version": "0.3.1",
4
+ "version": "0.4.1",
5
5
  "description": "ExpressiveCSS workflow server with Setup Expert, Rules Enforcer, Creative Director, Page Arcjitect, Component Syntax Expert, and Quality Inspector.",
6
6
  "author": {
7
7
  "name": "BaezFJ",
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.1 - 2026-10-14
4
+
5
+ - The catalogue, guides and rules cover keypad and keyboard.
6
+ - Bundled framework guidance: ExpressiveCSS 0.15.0.
7
+
8
+ ## 0.4.0 - 2026-10-11
9
+
10
+ - Command-output redaction no longer stalls the server on long token runs.
11
+ 160K characters of hex output took 6 s to redact; it now takes milliseconds.
12
+ - New `EXPRESSIVECSS_MCP_ALLOWED_PROJECT_ROOTS` setting limits which
13
+ directories a caller can pass as `projectRoot`. It is unset by default, which
14
+ keeps the current behavior.
15
+ - Calls with a `projectRoot` are 3 to 5 times faster. The server resolves the
16
+ ExpressiveCSS version once per call and sizes file buffers to the file
17
+ instead of the read limit.
18
+ - Tool results use compact JSON text, which is about a third smaller.
19
+ - The catalogue, guides and rules cover map, confetti and particles.
20
+ - Bundled framework guidance: ExpressiveCSS 0.14.1.
21
+
3
22
  ## 0.3.1 - 2026-10-08
4
23
 
5
24
  - Fix `npx @expressivecss/mcp-server`, which failed with "could not determine
package/README.md CHANGED
@@ -619,6 +619,7 @@ network limits, evidence handling, and bounded repair workflow.
619
619
  - `EXPRESSIVECSS_MCP_QA_MAX_TOTAL_MB`
620
620
  - `EXPRESSIVECSS_MCP_COMMAND_TIMEOUT_MS`
621
621
  - `EXPRESSIVECSS_MCP_ALLOWED_COMMAND_ROOTS`
622
+ - `EXPRESSIVECSS_MCP_ALLOWED_PROJECT_ROOTS`
622
623
  - `SKIP_SETUP_EXPERT`
623
624
  - `SKIP_RULES_ENFORCER`
624
625
  - `SKIP_CREATIVE_DIRECTOR`
@@ -642,6 +643,8 @@ EXPRESSIVECSS_MCP_ALLOWED_COMMAND_ROOTS=["/srv/projects/site-a","/srv/projects/s
642
643
 
643
644
  The real `projectRoot` must equal or be contained by one of those roots. A tool caller cannot expand this policy. Allowed commands receive only the executable path, system/temp/locale variables, `CI=1`, `NO_COLOR=1`, and `HOME`/`USERPROFILE` reset to the project root. API keys, tokens, passwords, cloud credentials, SSH agent variables, and other MCP-process environment values are not forwarded.
644
645
 
646
+ Any tool accepts a `projectRoot` by default, and `quality_inspector` reports the existence, size and SHA-256 of files under it. To limit which directories a caller can name, set `EXPRESSIVECSS_MCP_ALLOWED_PROJECT_ROOTS` in the same format. A `projectRoot` whose real path is outside every listed root fails with a tool error. An empty or invalid value denies every caller-supplied root. The default root, from `--project-root` or the working directory, is not checked.
647
+
645
648
  ## Sample client configuration
646
649
 
647
650
  ### `mcp/expressivecss/mcp.json`
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "frameworkVersion": "0.13.1",
4
- "sourceRevision": "3ed93f73a1e5a5ab9d201993b132fd64d81478ca",
3
+ "frameworkVersion": "0.15.0",
4
+ "sourceRevision": "5cd5bde4379bebb7873249bd8948879ae76634d9",
5
5
  "basis": "Reviewed checkout snapshot, not proof of published package contents or target-browser conformance. Implemented means only the named scope. Full Material parity remains unassessed.",
6
6
  "browserRun": {
7
- "recordedOn": "2026-10-08",
7
+ "recordedOn": "2026-10-10",
8
8
  "engine": "chromium",
9
9
  "engineVersion": "153.0.8010.12",
10
10
  "nodeVersion": "v24.21.0",
11
11
  "status": "passed",
12
12
  "inputsCurrent": false,
13
- "reportSha256": "b2f7a499810474b2448e87bde25fa13c969ab79a096d7281b84990803d624c47",
13
+ "reportSha256": "901697c1476a6369682ffc54fd0de71c0eed9db9a738b7f16d2c1780956ea287",
14
14
  "collector": "scripts/record-capability-evidence.mjs"
15
15
  },
16
16
  "entries": [
@@ -487,9 +487,9 @@
487
487
  "slug": "stepper",
488
488
  "title": "Stepper",
489
489
  "kind": "component",
490
- "support": "implemented",
490
+ "support": "unassessed",
491
491
  "lastReviewedSupport": "implemented",
492
- "sourceReview": "source-reviewed",
492
+ "sourceReview": "needs-review",
493
493
  "reviewedOn": "2026-10-06",
494
494
  "scope": "Horizontal and vertical ordered lists with current, complete and invalid steps, supporting text, links back to finished steps and a content panel in vertical steps.",
495
495
  "adaptation": "An <ol> with aria-current=\"step\"; CSS alt text speaks the complete and invalid states from translatable tokens.",
@@ -1432,22 +1432,22 @@
1432
1432
  "file": "tests/message-scroller-browser.test.js",
1433
1433
  "name": "chromium: message scroller follows output, keeps its place on prepend and anchors new turns",
1434
1434
  "scope": "Opening at the end, following streamed text, release on a wheel scroll up, the inert button and resuming from it, following kept through a click on a message, scrollToMessage with a peek and with a missing id, prepend preservation, an appended anchor at the peek with a spacer that clears as the reply grows, and destroy. No spoken-output assertion.",
1435
- "state": "not-recorded"
1435
+ "state": "stale"
1436
1436
  },
1437
1437
  {
1438
1438
  "file": "tests/message-scroller-browser.test.js",
1439
1439
  "name": "chromium: message scroller opens saved transcripts at the requested position",
1440
1440
  "scope": "last-anchor on a long last turn, last-anchor falling back to the end, and start.",
1441
- "state": "not-recorded"
1441
+ "state": "stale"
1442
1442
  },
1443
1443
  {
1444
1444
  "file": "tests/message-scroller-browser.test.js",
1445
1445
  "name": "chromium: message scroller jumps to a message inside a shadow root",
1446
1446
  "scope": "scrollToMessage called right after init finds a message in a shadow root and scrolls it one peek below the top; pressing the button from the keyboard there moves focus to the viewport as the button goes inert.",
1447
- "state": "not-recorded"
1447
+ "state": "stale"
1448
1448
  }
1449
1449
  ],
1450
- "browserEvidence": "incomplete",
1450
+ "browserEvidence": "needs-rerun",
1451
1451
  "recheckWhen": [
1452
1452
  "A reviewed source changes",
1453
1453
  "A mapped test or its recorded inputs change",
@@ -1508,9 +1508,9 @@
1508
1508
  "slug": "data-table",
1509
1509
  "title": "Data table",
1510
1510
  "kind": "component",
1511
- "support": "implemented",
1511
+ "support": "unassessed",
1512
1512
  "lastReviewedSupport": "implemented",
1513
- "sourceReview": "source-reviewed",
1513
+ "sourceReview": "needs-review",
1514
1514
  "reviewedOn": "2026-10-06",
1515
1515
  "scope": "Scrolling wrapper with an outline, sticky header row, numeric columns, dense rows, a sort arrow drawn from aria-sort and checkbox row selection.",
1516
1516
  "adaptation": "A plain div wraps a native <table>, so the table keeps its role; the page owns sorting, select-all and the scroll region name.",
@@ -1708,9 +1708,9 @@
1708
1708
  "slug": "line-chart",
1709
1709
  "title": "Line chart",
1710
1710
  "kind": "component",
1711
- "support": "implemented",
1711
+ "support": "unassessed",
1712
1712
  "lastReviewedSupport": "implemented",
1713
- "sourceReview": "source-reviewed",
1713
+ "sourceReview": "needs-review",
1714
1714
  "reviewedOn": "2026-10-06",
1715
1715
  "scope": "Smooth monotone lines drawn from a figure's data table, with area, stacked, fade and sparkline modifiers, dashed series, gaps, a fixed y range, x labels, a legend, and a pointer and keyboard tooltip.",
1716
1716
  "adaptation": "The <table> stays in the page as the text alternative and the no-JavaScript fallback; the SVG is aria-hidden and the plot is one Tab stop with a polite live tooltip.",
@@ -1783,9 +1783,9 @@
1783
1783
  "slug": "column-chart",
1784
1784
  "title": "Column chart",
1785
1785
  "kind": "component",
1786
- "support": "implemented",
1786
+ "support": "unassessed",
1787
1787
  "lastReviewedSupport": "implemented",
1788
- "sourceReview": "source-reviewed",
1788
+ "sourceReview": "needs-review",
1789
1789
  "reviewedOn": "2026-10-07",
1790
1790
  "scope": "Columns drawn from zero from a figure's data table, grouped by row or stacked, with fade, track and sparkline modifiers, negative values, gaps, a fixed y range, x labels, a legend, and a pointer and keyboard tooltip with a highlight band.",
1791
1791
  "adaptation": "The <table> stays in the page as the text alternative and the no-JavaScript fallback; the columns are aria-hidden and the plot is one Tab stop with a polite live tooltip.",
@@ -1856,9 +1856,9 @@
1856
1856
  "slug": "bar-chart",
1857
1857
  "title": "Bar chart",
1858
1858
  "kind": "component",
1859
- "support": "implemented",
1859
+ "support": "unassessed",
1860
1860
  "lastReviewedSupport": "implemented",
1861
- "sourceReview": "source-reviewed",
1861
+ "sourceReview": "needs-review",
1862
1862
  "reviewedOn": "2026-10-07",
1863
1863
  "scope": "Horizontal bars drawn from zero from a figure's data table, grouped by row or stacked, with split, track, values and sparkline modifiers, negative values, gaps, a fixed value range, row labels, a legend, and a pointer and keyboard tooltip with a highlight band.",
1864
1864
  "adaptation": "The <table> stays in the page as the text alternative and the no-JavaScript fallback; the bars and their values are aria-hidden and the plot is one Tab stop with a polite live tooltip.",
@@ -1933,9 +1933,9 @@
1933
1933
  "slug": "pie-chart",
1934
1934
  "title": "Pie chart",
1935
1935
  "kind": "component",
1936
- "support": "implemented",
1936
+ "support": "unassessed",
1937
1937
  "lastReviewedSupport": "implemented",
1938
- "sourceReview": "source-reviewed",
1938
+ "sourceReview": "needs-review",
1939
1939
  "reviewedOn": "2026-10-07",
1940
1940
  "scope": "Slices drawn clockwise from the top from a figure's data table, with a legend of each row's cell and share, donut, values and sparkline modifiers, a <tfoot> total in the donut hole, further columns in the tooltip, and a pointer and keyboard tooltip that highlights the slice.",
1941
1941
  "adaptation": "The <table> stays in the page as the text alternative and the no-JavaScript fallback; the slices, values, total and legend are aria-hidden and the plot is one Tab stop with a polite live tooltip.",
@@ -2006,9 +2006,9 @@
2006
2006
  "slug": "heatmap-chart",
2007
2007
  "title": "Heatmap chart",
2008
2008
  "kind": "component",
2009
- "support": "implemented",
2009
+ "support": "unassessed",
2010
2010
  "lastReviewedSupport": "implemented",
2011
- "sourceReview": "source-reviewed",
2011
+ "sourceReview": "needs-review",
2012
2012
  "reviewedOn": "2026-10-07",
2013
2013
  "scope": "Every body cell of a figure's data table drawn as a shaded grid cell, with row headers beside the grid, column headers below, a scale naming the lowest and highest cells, values, data-label short or hidden labels, data-min and data-max, gaps, and a pointer and keyboard tooltip that moves cell by cell.",
2014
2014
  "adaptation": "The <table> stays in the page as the text alternative and the no-JavaScript fallback; the grid, labels and scale are aria-hidden and the plot is one Tab stop with a polite live tooltip.",
@@ -2079,9 +2079,9 @@
2079
2079
  "slug": "radar-chart",
2080
2080
  "title": "Radar chart",
2081
2081
  "kind": "component",
2082
- "support": "implemented",
2082
+ "support": "unassessed",
2083
2083
  "lastReviewedSupport": "implemented",
2084
- "sourceReview": "source-reviewed",
2084
+ "sourceReview": "needs-review",
2085
2085
  "reviewedOn": "2026-10-07",
2086
2086
  "scope": "Spokes drawn clockwise from the top from a figure's data table, one shape per series from zero in the middle to the scale's top at the rim, row labels past each spoke, a legend for several series, area, points, dashed and sparkline modifiers, data-min and data-max, and a pointer and keyboard tooltip with a cursor spoke.",
2087
2087
  "adaptation": "The <table> stays in the page as the text alternative and the no-JavaScript fallback; the grid, shapes, labels and legend are aria-hidden and the plot is one Tab stop with a polite live tooltip.",
@@ -2152,9 +2152,9 @@
2152
2152
  "slug": "radial-chart",
2153
2153
  "title": "Radial chart",
2154
2154
  "kind": "component",
2155
- "support": "implemented",
2155
+ "support": "unassessed",
2156
2156
  "lastReviewedSupport": "implemented",
2157
- "sourceReview": "source-reviewed",
2157
+ "sourceReview": "needs-review",
2158
2158
  "reviewedOn": "2026-10-07",
2159
2159
  "scope": "Rings drawn clockwise from the top from a figure's data table as a share of data-max, with tracks, a legend of each row's cell for more than one row, gauge and sparkline modifiers, a <tfoot> total in the middle, further columns in the tooltip, and a pointer and keyboard tooltip that highlights the ring.",
2160
2160
  "adaptation": "The <table> stays in the page as the text alternative and the no-JavaScript fallback; the rings, total and legend are aria-hidden and the plot is one Tab stop with a polite live tooltip.",
@@ -2225,9 +2225,9 @@
2225
2225
  "slug": "mixed-chart",
2226
2226
  "title": "Mixed chart",
2227
2227
  "kind": "component",
2228
- "support": "implemented",
2228
+ "support": "unassessed",
2229
2229
  "lastReviewedSupport": "implemented",
2230
- "sourceReview": "source-reviewed",
2230
+ "sourceReview": "needs-review",
2231
2231
  "reviewedOn": "2026-10-07",
2232
2232
  "scope": "Columns, smooth lines and areas drawn per series from a figure's data table by header class, with dashed lines, a second scale for end series with its own fixed range, x labels, a legend, a sparkline modifier, and a pointer and keyboard tooltip with points on the lines.",
2233
2233
  "adaptation": "The <table> stays in the page as the text alternative and the no-JavaScript fallback; the columns and SVG are aria-hidden and the plot is one Tab stop with a polite live tooltip.",
@@ -3242,10 +3242,118 @@
3242
3242
  "file": "tests/marquee-browser.test.js",
3243
3243
  "name": "chromium: marquee loops its two groups, pauses, follows direction and stops under reduced motion",
3244
3244
  "scope": "A short group filling the strip, the copy one gap after it, the half-cycle position horizontally, in RTL and vertically, reverse, pausing on hover, focus and .paused, one link per item in the accessibility tree and the reduced-motion stop with the copy hidden. No spoken-output assertion.",
3245
- "state": "not-recorded"
3245
+ "state": "stale"
3246
3246
  }
3247
3247
  ],
3248
- "browserEvidence": "incomplete",
3248
+ "browserEvidence": "needs-rerun",
3249
+ "recheckWhen": [
3250
+ "A reviewed source changes",
3251
+ "A mapped test or its recorded inputs change",
3252
+ "Google revises the linked guidance or before claiming a new release matches it"
3253
+ ]
3254
+ },
3255
+ {
3256
+ "slug": "confetti",
3257
+ "title": "Confetti",
3258
+ "kind": "component",
3259
+ "support": "implemented",
3260
+ "lastReviewedSupport": "implemented",
3261
+ "sourceReview": "source-reviewed",
3262
+ "reviewedOn": "2026-10-09",
3263
+ "scope": "Bursts from a button's center over the page, inside an authored canvas, or from script, with count, angle, spread, speed, decay, gravity, drift, lifetime, origin, colors, square, circle and star shapes, and size options, theme colors by default and a promise that resolves when the burst ends.",
3264
+ "adaptation": "A canvas drawn with requestAnimationFrame. The page canvas is an aria-hidden manual popover with pointer events off, so it draws above modal dialogs without blocking clicks. Reduced motion draws nothing.",
3265
+ "upstream": {
3266
+ "source": "https://m3.material.io/components",
3267
+ "reviewedOn": "2026-10-09",
3268
+ "scope": "web-extension-inventory-reviewed",
3269
+ "note": "Requirements and boundaries: design reference web-extensions-review. The inventory page renders client-side, so this review relies on the 2026-09-13 inventory review. Full visual parity and spoken output unverified.",
3270
+ "sections": [
3271
+ "No standalone Material component"
3272
+ ],
3273
+ "sources": [],
3274
+ "requirements": "Keep the effect decorative and out of the accessibility tree, never block input, state the outcome in text and draw nothing when reduced motion is requested."
3275
+ },
3276
+ "relationship": "none",
3277
+ "sources": [
3278
+ {
3279
+ "path": "src/sass/components/_confetti.scss",
3280
+ "sha256": "0dc01d28e2bf26877ab57e5d5504b6dbd734b3ef64f593bf67e34753922a3d63"
3281
+ },
3282
+ {
3283
+ "path": "src/ts/components/confetti.ts",
3284
+ "sha256": "c5f6f8782548d71bce17e1f701b7f7c1376c2a88252fc3e07238699125c6503e"
3285
+ }
3286
+ ],
3287
+ "gaps": [
3288
+ {
3289
+ "kind": "verification",
3290
+ "description": "The burst origin on a button and on a canvas, theme colors, manualStart, the page canvas in the top layer above a modal dialog with pointer events off and aria-hidden, its removal when the burst ends, destroy and the reduced-motion skip are checked in a browser; frame rate on low-end devices and forced colors remain unverified.",
3291
+ "nextStep": "Watch a burst on a low-end phone and in forced colors, and confirm a screen reader announces nothing for it."
3292
+ }
3293
+ ],
3294
+ "browserChecks": [
3295
+ {
3296
+ "file": "tests/confetti-browser.test.js",
3297
+ "name": "chromium: confetti bursts from its trigger in theme colors, on its own canvas, above a modal dialog and not under reduced motion",
3298
+ "scope": "A canvas bursting at its center on init, manualStart waiting for fire(), a button bursting from its center in the theme primary color, the page canvas covering the viewport in the top layer with aria-hidden and no pointer events, fire() resolving after it is removed, a burst over an open modal dialog, destroy and the reduced-motion skip. No spoken-output assertion.",
3299
+ "state": "stale"
3300
+ }
3301
+ ],
3302
+ "browserEvidence": "needs-rerun",
3303
+ "recheckWhen": [
3304
+ "A reviewed source changes",
3305
+ "A mapped test or its recorded inputs change",
3306
+ "Google revises the linked guidance or before claiming a new release matches it"
3307
+ ]
3308
+ },
3309
+ {
3310
+ "slug": "particles",
3311
+ "title": "Particles",
3312
+ "kind": "component",
3313
+ "support": "unassessed",
3314
+ "lastReviewedSupport": "implemented",
3315
+ "sourceReview": "needs-review",
3316
+ "reviewedOn": "2026-10-09",
3317
+ "scope": "A canvas that covers its positioned ancestor with drifting dots that fade near the edges and lean toward the pointer, with quantity, staticity, ease, size, color and drift options and the theme on-surface color by default.",
3318
+ "adaptation": "A canvas drawn with requestAnimationFrame, aria-hidden with pointer events off. The dot color comes from the canvas's CSS color, read each frame so theme changes apply. Reduced motion draws the dots once without motion.",
3319
+ "upstream": {
3320
+ "source": "https://m3.material.io/components",
3321
+ "reviewedOn": "2026-10-09",
3322
+ "scope": "web-extension-inventory-reviewed",
3323
+ "note": "Requirements and boundaries: design reference web-extensions-review. The inventory page renders client-side, so this review relies on the 2026-09-13 inventory review. Full visual parity and spoken output unverified.",
3324
+ "sections": [
3325
+ "No standalone Material component"
3326
+ ],
3327
+ "sources": [],
3328
+ "requirements": "Keep the effect decorative and out of the accessibility tree, never block input, keep text over it readable and stop motion when reduced motion is requested."
3329
+ },
3330
+ "relationship": "none",
3331
+ "sources": [
3332
+ {
3333
+ "path": "src/sass/components/_particles.scss",
3334
+ "sha256": "5d2d67515f7152d5b86d506e7fe42d9c66f058bd7b9e30a06a7b8fedc4738cc3"
3335
+ },
3336
+ {
3337
+ "path": "src/ts/components/particles.ts",
3338
+ "sha256": "7a22a1f580deb76e59bdeef75e8cfe432ee00743106a3348f5ad3c7f05e1f43b"
3339
+ }
3340
+ ],
3341
+ "gaps": [
3342
+ {
3343
+ "kind": "verification",
3344
+ "description": "The canvas covering its box, the on-surface default and the color option, following the pointer only while it is over the canvas, drift, refitting on resize, destroy and the still drawing under reduced motion are checked in a browser; frame rate on low-end devices, forced colors and contrast of text over the dots remain unverified.",
3345
+ "nextStep": "Watch a full-width hero of particles on a low-end phone and in forced colors, and check text contrast over the densest area."
3346
+ }
3347
+ ],
3348
+ "browserChecks": [
3349
+ {
3350
+ "file": "tests/particles-browser.test.js",
3351
+ "name": "chromium: particles fill their box in the theme color, follow the pointer, drift, refit on resize and stay still under reduced motion",
3352
+ "scope": "The canvas covering its positioned ancestor, a dot fading in where it was placed in the theme on-surface color, following the pointer inside the canvas and holding when it leaves, destroy clearing the canvas, vx drift, the color option, the pixel buffer after a resize and still dots under reduced motion. No spoken-output assertion.",
3353
+ "state": "stale"
3354
+ }
3355
+ ],
3356
+ "browserEvidence": "needs-rerun",
3249
3357
  "recheckWhen": [
3250
3358
  "A reviewed source changes",
3251
3359
  "A mapped test or its recorded inputs change",
@@ -3360,6 +3468,66 @@
3360
3468
  "Google revises the linked guidance or before claiming a new release matches it"
3361
3469
  ]
3362
3470
  },
3471
+ {
3472
+ "slug": "map",
3473
+ "title": "Map",
3474
+ "kind": "component",
3475
+ "support": "unassessed",
3476
+ "lastReviewedSupport": "implemented",
3477
+ "sourceReview": "needs-review",
3478
+ "reviewedOn": "2026-10-09",
3479
+ "scope": "MapLibre map with themed OpenFreeMap styles, markers with labels, tooltips, popups and dragging, routes, arcs, clusters, and zoom, compass, locate and full screen controls.",
3480
+ "adaptation": "The page passes in the maplibre-gl module. Markers, popups and controls are authored HTML moved into MapLibre; routes, arcs and clusters are GeoJSON layers whose colors are read from theme tokens and redrawn when the theme changes.",
3481
+ "upstream": {
3482
+ "source": "https://m3.material.io/components",
3483
+ "reviewedOn": "2026-10-09",
3484
+ "scope": "web-extension-inventory-reviewed",
3485
+ "note": "Requirements and boundaries: design reference web-extensions-review. The inventory page renders client-side, so this review relies on the 2026-09-13 inventory review. Full visual parity and spoken output unverified.",
3486
+ "sections": [
3487
+ "No standalone Material component"
3488
+ ],
3489
+ "sources": [],
3490
+ "requirements": "Name the map region, make interactive markers named buttons, return focus when a popup closes, keep tile attribution visible and give the same information in text."
3491
+ },
3492
+ "relationship": "none",
3493
+ "sources": [
3494
+ {
3495
+ "path": "src/sass/components/_map.scss",
3496
+ "sha256": "3bc9d7ba4dcf2c8d632701d4a6d127dd0e83662b994591260a58581bc2f3d5de"
3497
+ },
3498
+ {
3499
+ "path": "src/ts/components/mapView.ts",
3500
+ "sha256": "eb0804b2b9368c8af1c9e6d6827c8bde42ceb4e01bdd9b3666d13a867bc67b03"
3501
+ }
3502
+ ],
3503
+ "gaps": [
3504
+ {
3505
+ "kind": "verification",
3506
+ "description": "Marker placement, the popup opened from its marker with aria-expanded, Escape and map-click closing with focus back on the marker, zoom limits, the compass bearing, theme-colored routes, arcs and clusters redrawn after a theme swap, removeOverlay and destroy are checked in a browser; the locate and full screen controls, marker dragging, spoken output, touch gestures and forced colors remain unverified.",
3507
+ "nextStep": "Use the map with a screen reader and on a touch device, try locate and full screen with real permissions, drag a marker with the keyboard, and check forced colors."
3508
+ }
3509
+ ],
3510
+ "browserChecks": [
3511
+ {
3512
+ "file": "tests/map-browser.test.js",
3513
+ "name": "chromium: map places markers and popups, runs controls, themes overlays and restores its markup",
3514
+ "scope": "Markers placed with the default dot, the popup without a marker open at init, a marker button opening its popup with aria-expanded, Escape and a map click closing it with focus back on the marker, zoom out disabled at the minimum zoom, zoom in, the compass bearing and reset, route, arcs and clusters in the theme primary color, no count layer without glyphs, all redrawn in the dark primary after a theme change, removeOverlay, destroy restoring the markup and controls, and a location arriving after destroy being ignored. No spoken-output assertion.",
3515
+ "state": "stale"
3516
+ },
3517
+ {
3518
+ "file": "tests/map-browser.test.js",
3519
+ "name": "chromium: a map in a shadow root opens its marker popup",
3520
+ "scope": "A marker button inside a shadow root finding its popup by id, then opening it with aria-expanded. No spoken-output assertion.",
3521
+ "state": "stale"
3522
+ }
3523
+ ],
3524
+ "browserEvidence": "needs-rerun",
3525
+ "recheckWhen": [
3526
+ "A reviewed source changes",
3527
+ "A mapped test or its recorded inputs change",
3528
+ "Google revises the linked guidance or before claiming a new release matches it"
3529
+ ]
3530
+ },
3363
3531
  {
3364
3532
  "slug": "toolbars",
3365
3533
  "title": "Toolbars",
@@ -3660,16 +3828,16 @@
3660
3828
  "file": "tests/rich-text-editor-browser.test.js",
3661
3829
  "name": "chromium: rich text editor formats text, reflects state and keeps the textarea in sync",
3662
3830
  "scope": "Hidden textarea, textbox role and name from the label, starting HTML, label click focus, bold and heading commands with aria-pressed and .active, undo disabled state, textarea value and input event, empty value, and destroy. No spoken-output assertion.",
3663
- "state": "not-recorded"
3831
+ "state": "stale"
3664
3832
  },
3665
3833
  {
3666
3834
  "file": "tests/rich-text-editor-browser.test.js",
3667
3835
  "name": "chromium: rich text editor follows a disabled textarea",
3668
3836
  "scope": "A disabled textarea makes the editor read-only and disables every toolbar button.",
3669
- "state": "not-recorded"
3837
+ "state": "stale"
3670
3838
  }
3671
3839
  ],
3672
- "browserEvidence": "incomplete",
3840
+ "browserEvidence": "needs-rerun",
3673
3841
  "recheckWhen": [
3674
3842
  "A reviewed source changes",
3675
3843
  "A mapped test or its recorded inputs change",
@@ -3680,9 +3848,9 @@
3680
3848
  "slug": "drop-zone",
3681
3849
  "title": "Drop zone",
3682
3850
  "kind": "component",
3683
- "support": "implemented",
3851
+ "support": "unassessed",
3684
3852
  "lastReviewedSupport": "implemented",
3685
- "sourceReview": "source-reviewed",
3853
+ "sourceReview": "needs-review",
3686
3854
  "reviewedOn": "2026-10-06",
3687
3855
  "scope": "A label-sized native file input with a dragover state and a list of chosen file names and locale-formatted sizes.",
3688
3856
  "adaptation": "The native input covers the label, so clicks, keys and drops are the browser's; the shared Forms behavior marks the drag and fills the list.",
@@ -4512,6 +4680,65 @@
4512
4680
  "Google revises the linked guidance or before claiming a new release matches it"
4513
4681
  ]
4514
4682
  },
4683
+ {
4684
+ "slug": "keypad",
4685
+ "title": "Keypad and Keyboard",
4686
+ "kind": "component",
4687
+ "support": "unassessed",
4688
+ "lastReviewedSupport": "implemented",
4689
+ "sourceReview": "needs-review",
4690
+ "reviewedOn": "2026-10-11",
4691
+ "scope": "A three-column keypad of round keys with two-cell wide keys and a keyboard of rows sized from a column count with an optional number row, typing into the field named by aria-controls with value keys, Backspace, Enter, a one-shot Shift, data-key keys inside the field's wrapper, dial-pad letters, styled call keys, an onKey callback and a pressed shape morph.",
4692
+ "adaptation": "Keys are native buttons in a named group; edits go through the field's value and fire a composed input event, Enter uses requestSubmit() so validation runs, and inputmode=\"none\" on the field keeps the device keyboard closed. Browsers check minlength only on what a person types, so a minimum length is written as pattern.",
4693
+ "upstream": {
4694
+ "source": "https://m3.material.io/components",
4695
+ "reviewedOn": "2026-10-11",
4696
+ "scope": "web-extension-inventory-reviewed",
4697
+ "note": "Requirements and boundaries: design reference web-extensions-review. The inventory page renders client-side, so this review relies on the 2026-09-13 inventory review. Full visual parity and spoken output unverified.",
4698
+ "sections": [
4699
+ "No standalone Material component"
4700
+ ],
4701
+ "sources": [],
4702
+ "requirements": "Name the group and every icon key, keep keys from submitting the form, keep the field labelled and usable from a hardware keyboard, and keep keys at a usable target size."
4703
+ },
4704
+ "relationship": "none",
4705
+ "sources": [
4706
+ {
4707
+ "path": "src/sass/components/_keypad.scss",
4708
+ "sha256": "b530b6c62630f0bb86f146db24d4d7b363491355b2f2d3302a34b2274b42bf13"
4709
+ },
4710
+ {
4711
+ "path": "src/ts/components/keypad.ts",
4712
+ "sha256": "074900c8486ebcb978cb33bff7d51c47e1721e738eb593651768c3d17e768752"
4713
+ }
4714
+ ],
4715
+ "gaps": [
4716
+ {
4717
+ "kind": "verification",
4718
+ "description": "Typing at the caret, maxlength, pattern validation on Enter, Backspace including emoji, Enter submitting a form and adding a new line in a textarea, a one-shot Shift with capitals shown, number inputs, disabled fieldsets, in-field keys, shadow roots, focus staying in the field, the keypad grid and wide keys, keyboard key widths and the number row, the pressed shape and destroy are checked in a browser; screen reader output, forced colors, enlarged text and touch devices remain unverified.",
4719
+ "nextStep": "Type a PIN and a message with a screen reader and on a touch device in each engine, and check forced colors and enlarged text."
4720
+ },
4721
+ {
4722
+ "kind": "feature",
4723
+ "description": "There is no caps lock, no symbol layer switching and no highlight of the key a hardware keyboard presses, and minlength does not apply to keypad edits.",
4724
+ "nextStep": "Swap rows from onKey for a symbols key, add caps lock when a page needs it, and write a minimum length as pattern."
4725
+ }
4726
+ ],
4727
+ "browserChecks": [
4728
+ {
4729
+ "file": "tests/keypad-browser.test.js",
4730
+ "name": "chromium: keypad and keyboard type at the caret, edit, submit, shift and lay out their keys",
4731
+ "scope": "Digits typed at the caret, maxlength, focus kept in the field on a pointer press, Backspace including emoji, Enter submitting once, a pattern mismatch blocking Enter, onKey values, composed input events from a shadow root, number, decimal and signed input, a disabled fieldset and its legend, a trailing Backspace in the field that runs once for two keypads, for a field inside its keyboard and for a field rendered after init, a password toggle that is not a key, a prefilled untouched field typed at the end, a caret placed at the start kept for keys activated from the keyboard, Shift showing capitals and releasing after one character, space and a textarea new line, three 72px round keypad columns, a two-cell wide key, a tenth-of-row letter key, the half-key indent, a one-and-a-half-key Shift, the space bar filling its row, a 40px number row that types and that hidden drops, the pressed corner, destroy, and the shared listeners leaving with the last keypad. No spoken-output assertion.",
4732
+ "state": "not-recorded"
4733
+ }
4734
+ ],
4735
+ "browserEvidence": "incomplete",
4736
+ "recheckWhen": [
4737
+ "A reviewed source changes",
4738
+ "A mapped test or its recorded inputs change",
4739
+ "Google revises the linked guidance or before claiming a new release matches it"
4740
+ ]
4741
+ },
4515
4742
  {
4516
4743
  "slug": "questionnaire",
4517
4744
  "title": "Questionnaire",