From 77d561071451c80490013567c1cd83d0baf1c32d Mon Sep 17 00:00:00 2001 From: TarunAdobe Date: Thu, 27 Nov 2025 16:28:52 +0530 Subject: [PATCH 1/5] chore: add storybook-screen-reader plugin --- 1st-gen/package.json | 1 + 1st-gen/storybook/main.js | 2 + 2nd-gen/packages/core/shared/base/version.ts | 1 - yarn.lock | 214 ++++++++++++++++++- 4 files changed, 208 insertions(+), 10 deletions(-) diff --git a/1st-gen/package.json b/1st-gen/package.json index a5dd157e761..4175e4cacda 100644 --- a/1st-gen/package.json +++ b/1st-gen/package.json @@ -186,6 +186,7 @@ "rollup": "4.52.2", "sinon": "17.0.2", "storybook": "8.6.14", + "storybook-screen-reader": "1.0.0", "stylelint": "16.24.0", "stylelint-config-standard": "38.0.0", "stylelint-header": "3.0.0", diff --git a/1st-gen/storybook/main.js b/1st-gen/storybook/main.js index 188ff25b55f..f667a37c9e9 100644 --- a/1st-gen/storybook/main.js +++ b/1st-gen/storybook/main.js @@ -30,6 +30,8 @@ export default { : []), // https://geometricpanda.github.io/storybook-addon-badges/ '@geometricpanda/storybook-addon-badges', + // Screen reader addon: https://www.npmjs.com/package/storybook-screen-reader + 'storybook-screen-reader', ], framework: { name: '@storybook/web-components-webpack5', diff --git a/2nd-gen/packages/core/shared/base/version.ts b/2nd-gen/packages/core/shared/base/version.ts index cb9e28ff658..2177cdd7401 100644 --- a/2nd-gen/packages/core/shared/base/version.ts +++ b/2nd-gen/packages/core/shared/base/version.ts @@ -9,6 +9,5 @@ * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ - // Generated by genversion. export const version = '1.10.0'; diff --git a/yarn.lock b/yarn.lock index 1013d66e8b6..32f57ff3492 100644 --- a/yarn.lock +++ b/yarn.lock @@ -758,7 +758,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-jsx@npm:^7.7.2": +"@babel/plugin-syntax-jsx@npm:^7.27.1, @babel/plugin-syntax-jsx@npm:^7.7.2": version: 7.27.1 resolution: "@babel/plugin-syntax-jsx@npm:7.27.1" dependencies: @@ -1344,6 +1344,55 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-react-display-name@npm:^7.28.0": + version: 7.28.0 + resolution: "@babel/plugin-transform-react-display-name@npm:7.28.0" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/f5f86d2ad92be3e962158f344c2e385e23e2dfae7c8c7dc32138fb2cc46f63f5e50386c9f6c6fc16dbf1792c7bb650ad92c18203d0c2c0bd875bc28b0b80ef30 + languageName: node + linkType: hard + +"@babel/plugin-transform-react-jsx-development@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-transform-react-jsx-development@npm:7.27.1" + dependencies: + "@babel/plugin-transform-react-jsx": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/eb8c4b6a79dc5c49b41e928e2037e1ee0bbfa722e4fd74c0b7c0d11103c82c2c25c434000e1b051d534c7261ab5c92b6d1e85313bf1b26e37db3f051ae217b58 + languageName: node + linkType: hard + +"@babel/plugin-transform-react-jsx@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-transform-react-jsx@npm:7.27.1" + dependencies: + "@babel/helper-annotate-as-pure": "npm:^7.27.1" + "@babel/helper-module-imports": "npm:^7.27.1" + "@babel/helper-plugin-utils": "npm:^7.27.1" + "@babel/plugin-syntax-jsx": "npm:^7.27.1" + "@babel/types": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/1a08637c39fc78c9760dd4a3ed363fdbc762994bf83ed7872ad5bda0232fcd0fc557332f2ce36b522c0226dfd9cc8faac6b88eddda535f24825198a689e571af + languageName: node + linkType: hard + +"@babel/plugin-transform-react-pure-annotations@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-transform-react-pure-annotations@npm:7.27.1" + dependencies: + "@babel/helper-annotate-as-pure": "npm:^7.27.1" + "@babel/helper-plugin-utils": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/34bc090f4a7e460d82a851971b4d0f32e4bb519bafb927154f4174506283fe02b0f471fc20655c6050a8bf7b748bfa31c7e8f7d688849476d8266623554fbb28 + languageName: node + linkType: hard + "@babel/plugin-transform-regenerator@npm:^7.28.4": version: 7.28.4 resolution: "@babel/plugin-transform-regenerator@npm:7.28.4" @@ -1497,7 +1546,7 @@ __metadata: languageName: node linkType: hard -"@babel/preset-env@npm:^7.11.0, @babel/preset-env@npm:^7.9.0": +"@babel/preset-env@npm:^7.11.0, @babel/preset-env@npm:^7.13.8, @babel/preset-env@npm:^7.9.0": version: 7.28.5 resolution: "@babel/preset-env@npm:7.28.5" dependencies: @@ -1590,6 +1639,22 @@ __metadata: languageName: node linkType: hard +"@babel/preset-react@npm:^7.12.13": + version: 7.28.5 + resolution: "@babel/preset-react@npm:7.28.5" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + "@babel/helper-validator-option": "npm:^7.27.1" + "@babel/plugin-transform-react-display-name": "npm:^7.28.0" + "@babel/plugin-transform-react-jsx": "npm:^7.27.1" + "@babel/plugin-transform-react-jsx-development": "npm:^7.27.1" + "@babel/plugin-transform-react-pure-annotations": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/0d785e708ff301f4102bd4738b77e550e32f981e54dfd3de1191b4d68306bbb934d2d465fc78a6bc22fff0a6b3ce3195a53984f52755c4349e7264c7e01e8c7c + languageName: node + linkType: hard + "@babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.17.8, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.5.5": version: 7.28.4 resolution: "@babel/runtime@npm:7.28.4" @@ -2771,6 +2836,29 @@ __metadata: languageName: node linkType: hard +"@emotion/is-prop-valid@npm:1.2.2": + version: 1.2.2 + resolution: "@emotion/is-prop-valid@npm:1.2.2" + dependencies: + "@emotion/memoize": "npm:^0.8.1" + checksum: 10c0/bb1530dcb4e0e5a4fabb219279f2d0bc35796baf66f6241f98b0d03db1985c890a8cafbea268e0edefd5eeda143dbd5c09a54b5fba74cee8c69b98b13194af50 + languageName: node + linkType: hard + +"@emotion/memoize@npm:^0.8.1": + version: 0.8.1 + resolution: "@emotion/memoize@npm:0.8.1" + checksum: 10c0/dffed372fc3b9fa2ba411e76af22b6bb686fb0cb07694fdfaa6dd2baeb0d5e4968c1a7caa472bfcf06a5997d5e7c7d16b90e993f9a6ffae79a2c3dbdc76dfe78 + languageName: node + linkType: hard + +"@emotion/unitless@npm:0.8.1": + version: 0.8.1 + resolution: "@emotion/unitless@npm:0.8.1" + checksum: 10c0/a1ed508628288f40bfe6dd17d431ed899c067a899fa293a13afe3aed1d70fac0412b8a215fafab0b42829360db687fecd763e5f01a64ddc4a4b58ec3112ff548 + languageName: node + linkType: hard + "@emotion/use-insertion-effect-with-fallbacks@npm:^1.0.0": version: 1.2.0 resolution: "@emotion/use-insertion-effect-with-fallbacks@npm:1.2.0" @@ -5413,6 +5501,7 @@ __metadata: rollup: "npm:4.52.2" sinon: "npm:17.0.2" storybook: "npm:8.6.14" + storybook-screen-reader: "npm:1.0.0" stylelint: "npm:16.24.0" stylelint-config-standard: "npm:38.0.0" stylelint-header: "npm:3.0.0" @@ -6860,7 +6949,7 @@ __metadata: languageName: node linkType: hard -"@storybook/components@npm:8.6.14": +"@storybook/components@npm:8.6.14, @storybook/components@npm:^8.0.0": version: 8.6.14 resolution: "@storybook/components@npm:8.6.14" peerDependencies: @@ -7082,7 +7171,7 @@ __metadata: languageName: node linkType: hard -"@storybook/manager-api@npm:8.6.14": +"@storybook/manager-api@npm:8.6.14, @storybook/manager-api@npm:^8.0.0": version: 8.6.14 resolution: "@storybook/manager-api@npm:8.6.14" peerDependencies: @@ -8618,6 +8707,13 @@ __metadata: languageName: node linkType: hard +"@types/stylis@npm:4.2.5": + version: 4.2.5 + resolution: "@types/stylis@npm:4.2.5" + checksum: 10c0/23f5b35a3a04f6bb31a29d404fa1bc8e0035fcaff2356b4047743a057e0c37b2eba7efe14d57dd2b95b398cea3bac294d9c6cd93ed307d8c0b7f5d282224b469 + languageName: node + linkType: hard + "@types/supports-color@npm:^8.0.0": version: 8.1.3 resolution: "@types/supports-color@npm:8.1.3" @@ -11550,6 +11646,13 @@ __metadata: languageName: node linkType: hard +"camelize@npm:^1.0.0": + version: 1.0.1 + resolution: "camelize@npm:1.0.1" + checksum: 10c0/4c9ac55efd356d37ac483bad3093758236ab686192751d1c9daa43188cc5a07b09bd431eb7458a4efd9ca22424bba23253e7b353feb35d7c749ba040de2385fb + languageName: node + linkType: hard + "caniuse-api@npm:^3.0.0": version: 3.0.0 resolution: "caniuse-api@npm:3.0.0" @@ -12726,6 +12829,13 @@ __metadata: languageName: node linkType: hard +"css-color-keywords@npm:^1.0.0": + version: 1.0.0 + resolution: "css-color-keywords@npm:1.0.0" + checksum: 10c0/af205a86c68e0051846ed91eb3e30b4517e1904aac040013ff1d742019b3f9369ba5658ba40901dbbc121186fc4bf0e75a814321cc3e3182fbb2feb81c6d9cb7 + languageName: node + linkType: hard + "css-declaration-sorter@npm:^6.3.1": version: 6.4.1 resolution: "css-declaration-sorter@npm:6.4.1" @@ -12823,6 +12933,17 @@ __metadata: languageName: node linkType: hard +"css-to-react-native@npm:3.2.0": + version: 3.2.0 + resolution: "css-to-react-native@npm:3.2.0" + dependencies: + camelize: "npm:^1.0.0" + css-color-keywords: "npm:^1.0.0" + postcss-value-parser: "npm:^4.0.2" + checksum: 10c0/fde850a511d5d3d7c55a1e9b8ed26b69a8ad4868b3487e36ebfbfc0b96fc34bc977d9cd1d61a289d0c74d3f9a662d8cee297da53d4433bf2e27d6acdff8e1003 + languageName: node + linkType: hard + "css-tree@npm:^1.1.2, css-tree@npm:^1.1.3": version: 1.1.3 resolution: "css-tree@npm:1.1.3" @@ -13023,7 +13144,7 @@ __metadata: languageName: node linkType: hard -"csstype@npm:^3.0.2": +"csstype@npm:3.1.3, csstype@npm:^3.0.2": version: 3.1.3 resolution: "csstype@npm:3.1.3" checksum: 10c0/80c089d6f7e0c5b2bd83cf0539ab41474198579584fa10d86d0cafe0642202343cbc119e076a0b1aece191989477081415d66c9fefbf3c957fc2fc4b7009f248 @@ -22663,7 +22784,7 @@ __metadata: languageName: node linkType: hard -"nanoid@npm:^3.1.25, nanoid@npm:^3.3.11, nanoid@npm:^3.3.6": +"nanoid@npm:^3.1.25, nanoid@npm:^3.3.11, nanoid@npm:^3.3.6, nanoid@npm:^3.3.7": version: 3.3.11 resolution: "nanoid@npm:3.3.11" bin: @@ -25435,7 +25556,7 @@ __metadata: languageName: node linkType: hard -"postcss-value-parser@npm:^4.1.0, postcss-value-parser@npm:^4.2.0": +"postcss-value-parser@npm:^4.0.2, postcss-value-parser@npm:^4.1.0, postcss-value-parser@npm:^4.2.0": version: 4.2.0 resolution: "postcss-value-parser@npm:4.2.0" checksum: 10c0/f4142a4f56565f77c1831168e04e3effd9ffcc5aebaf0f538eee4b2d465adfd4b85a44257bb48418202a63806a7da7fe9f56c330aebb3cac898e46b4cbf49161 @@ -25453,6 +25574,17 @@ __metadata: languageName: node linkType: hard +"postcss@npm:8.4.49": + version: 8.4.49 + resolution: "postcss@npm:8.4.49" + dependencies: + nanoid: "npm:^3.3.7" + picocolors: "npm:^1.1.1" + source-map-js: "npm:^1.2.1" + checksum: 10c0/f1b3f17aaf36d136f59ec373459f18129908235e65dbdc3aee5eef8eba0756106f52de5ec4682e29a2eab53eb25170e7e871b3e4b52a8f1de3d344a514306be3 + languageName: node + linkType: hard + "postcss@npm:8.5.6, postcss@npm:^8, postcss@npm:^8.4.33, postcss@npm:^8.4.5, postcss@npm:^8.5.6": version: 8.5.6 resolution: "postcss@npm:8.5.6" @@ -25902,6 +26034,13 @@ __metadata: languageName: node linkType: hard +"query-selector-shadow-dom@npm:^0.8.0": + version: 0.8.0 + resolution: "query-selector-shadow-dom@npm:0.8.0" + checksum: 10c0/4f5c3fe6e1075dfab65484e33bd4c48c040d422491c29902c3026e2aef3a130355d052823d798acb180fd7800c78342d3629443e870e8f8c56eacb4d1aa9e46b + languageName: node + linkType: hard + "query-string@npm:^7.1.0": version: 7.1.3 resolution: "query-string@npm:7.1.3" @@ -25998,7 +26137,7 @@ __metadata: languageName: node linkType: hard -"react-dom@npm:18.3.1": +"react-dom@npm:18.3.1, react-dom@npm:^18.2.0": version: 18.3.1 resolution: "react-dom@npm:18.3.1" dependencies: @@ -26046,7 +26185,7 @@ __metadata: languageName: node linkType: hard -"react@npm:18.3.1": +"react@npm:18.3.1, react@npm:^18.2.0": version: 18.3.1 resolution: "react@npm:18.3.1" dependencies: @@ -27649,6 +27788,13 @@ __metadata: languageName: node linkType: hard +"shallowequal@npm:1.1.0": + version: 1.1.0 + resolution: "shallowequal@npm:1.1.0" + checksum: 10c0/b926efb51cd0f47aa9bc061add788a4a650550bbe50647962113a4579b60af2abe7b62f9b02314acc6f97151d4cf87033a2b15fc20852fae306d1a095215396c + languageName: node + linkType: hard + "shebang-command@npm:^1.2.0": version: 1.2.0 resolution: "shebang-command@npm:1.2.0" @@ -28214,6 +28360,22 @@ __metadata: languageName: node linkType: hard +"storybook-screen-reader@npm:1.0.0": + version: 1.0.0 + resolution: "storybook-screen-reader@npm:1.0.0" + dependencies: + "@babel/preset-env": "npm:^7.13.8" + "@babel/preset-react": "npm:^7.12.13" + "@storybook/components": "npm:^8.0.0" + "@storybook/manager-api": "npm:^8.0.0" + query-selector-shadow-dom: "npm:^0.8.0" + react: "npm:^18.2.0" + react-dom: "npm:^18.2.0" + styled-components: "npm:^6.1.0" + checksum: 10c0/c08a2ac58c3e0f9ce736c49112b314e585975434246bedc25de57474f65d77e5635a088f1b1fa4a29386ecac00741c038badf3bfcadc4eaf1b76b6288aebcef6 + languageName: node + linkType: hard + "storybook@npm:10.0.3": version: 10.0.3 resolution: "storybook@npm:10.0.3" @@ -28625,6 +28787,26 @@ __metadata: languageName: node linkType: hard +"styled-components@npm:^6.1.0": + version: 6.1.19 + resolution: "styled-components@npm:6.1.19" + dependencies: + "@emotion/is-prop-valid": "npm:1.2.2" + "@emotion/unitless": "npm:0.8.1" + "@types/stylis": "npm:4.2.5" + css-to-react-native: "npm:3.2.0" + csstype: "npm:3.1.3" + postcss: "npm:8.4.49" + shallowequal: "npm:1.1.0" + stylis: "npm:4.3.2" + tslib: "npm:2.6.2" + peerDependencies: + react: ">= 16.8.0" + react-dom: ">= 16.8.0" + checksum: 10c0/8d20427a5debe54bfa3b55f79af2a3577551ed7f1d1cd34df986b73fd01ac519f9081b7737cc1f76e12fbc483fa50551e55be0bc984296e623cc6a2364697cd8 + languageName: node + linkType: hard + "styled-jsx@npm:5.1.1": version: 5.1.1 resolution: "styled-jsx@npm:5.1.1" @@ -28745,6 +28927,13 @@ __metadata: languageName: node linkType: hard +"stylis@npm:4.3.2": + version: 4.3.2 + resolution: "stylis@npm:4.3.2" + checksum: 10c0/0410e1404cbeee3388a9e17587875211ce2f014c8379af0d1e24ca55878867c9f1ccc7b0ce9a156ca53f5d6e301391a82b0645522a604674a378b3189a4a1994 + languageName: node + linkType: hard + "supports-color@npm:^5.3.0": version: 5.5.0 resolution: "supports-color@npm:5.5.0" @@ -29452,6 +29641,13 @@ __metadata: languageName: node linkType: hard +"tslib@npm:2.6.2": + version: 2.6.2 + resolution: "tslib@npm:2.6.2" + checksum: 10c0/e03a8a4271152c8b26604ed45535954c0a45296e32445b4b87f8a5abdb2421f40b59b4ca437c4346af0f28179780d604094eb64546bee2019d903d01c6c19bdb + languageName: node + linkType: hard + "tslib@npm:2.8.1, tslib@npm:^2.0.0, tslib@npm:^2.0.1, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.3.1, tslib@npm:^2.4.0, tslib@npm:^2.8.0": version: 2.8.1 resolution: "tslib@npm:2.8.1" From 736dcbb2cd9bd2bb8c78d7a1beaa5d4ba36332fd Mon Sep 17 00:00:00 2001 From: TarunAdobe Date: Tue, 2 Dec 2025 13:09:54 +0530 Subject: [PATCH 2/5] chore: update storybook-screen-reader plugin --- 1st-gen/package.json | 2 +- yarn.lock | 332 ++++++++++++++++++------------------------- 2 files changed, 136 insertions(+), 198 deletions(-) diff --git a/1st-gen/package.json b/1st-gen/package.json index 4175e4cacda..7ba674258e2 100644 --- a/1st-gen/package.json +++ b/1st-gen/package.json @@ -186,7 +186,7 @@ "rollup": "4.52.2", "sinon": "17.0.2", "storybook": "8.6.14", - "storybook-screen-reader": "1.0.0", + "storybook-screen-reader": "1.1.0", "stylelint": "16.24.0", "stylelint-config-standard": "38.0.0", "stylelint-header": "3.0.0", diff --git a/yarn.lock b/yarn.lock index 32f57ff3492..124cce09e10 100644 --- a/yarn.lock +++ b/yarn.lock @@ -758,7 +758,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-jsx@npm:^7.27.1, @babel/plugin-syntax-jsx@npm:^7.7.2": +"@babel/plugin-syntax-jsx@npm:^7.7.2": version: 7.27.1 resolution: "@babel/plugin-syntax-jsx@npm:7.27.1" dependencies: @@ -1344,55 +1344,6 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-react-display-name@npm:^7.28.0": - version: 7.28.0 - resolution: "@babel/plugin-transform-react-display-name@npm:7.28.0" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.27.1" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10c0/f5f86d2ad92be3e962158f344c2e385e23e2dfae7c8c7dc32138fb2cc46f63f5e50386c9f6c6fc16dbf1792c7bb650ad92c18203d0c2c0bd875bc28b0b80ef30 - languageName: node - linkType: hard - -"@babel/plugin-transform-react-jsx-development@npm:^7.27.1": - version: 7.27.1 - resolution: "@babel/plugin-transform-react-jsx-development@npm:7.27.1" - dependencies: - "@babel/plugin-transform-react-jsx": "npm:^7.27.1" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10c0/eb8c4b6a79dc5c49b41e928e2037e1ee0bbfa722e4fd74c0b7c0d11103c82c2c25c434000e1b051d534c7261ab5c92b6d1e85313bf1b26e37db3f051ae217b58 - languageName: node - linkType: hard - -"@babel/plugin-transform-react-jsx@npm:^7.27.1": - version: 7.27.1 - resolution: "@babel/plugin-transform-react-jsx@npm:7.27.1" - dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.27.1" - "@babel/helper-module-imports": "npm:^7.27.1" - "@babel/helper-plugin-utils": "npm:^7.27.1" - "@babel/plugin-syntax-jsx": "npm:^7.27.1" - "@babel/types": "npm:^7.27.1" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10c0/1a08637c39fc78c9760dd4a3ed363fdbc762994bf83ed7872ad5bda0232fcd0fc557332f2ce36b522c0226dfd9cc8faac6b88eddda535f24825198a689e571af - languageName: node - linkType: hard - -"@babel/plugin-transform-react-pure-annotations@npm:^7.27.1": - version: 7.27.1 - resolution: "@babel/plugin-transform-react-pure-annotations@npm:7.27.1" - dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.27.1" - "@babel/helper-plugin-utils": "npm:^7.27.1" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10c0/34bc090f4a7e460d82a851971b4d0f32e4bb519bafb927154f4174506283fe02b0f471fc20655c6050a8bf7b748bfa31c7e8f7d688849476d8266623554fbb28 - languageName: node - linkType: hard - "@babel/plugin-transform-regenerator@npm:^7.28.4": version: 7.28.4 resolution: "@babel/plugin-transform-regenerator@npm:7.28.4" @@ -1546,7 +1497,7 @@ __metadata: languageName: node linkType: hard -"@babel/preset-env@npm:^7.11.0, @babel/preset-env@npm:^7.13.8, @babel/preset-env@npm:^7.9.0": +"@babel/preset-env@npm:^7.11.0, @babel/preset-env@npm:^7.9.0": version: 7.28.5 resolution: "@babel/preset-env@npm:7.28.5" dependencies: @@ -1639,22 +1590,6 @@ __metadata: languageName: node linkType: hard -"@babel/preset-react@npm:^7.12.13": - version: 7.28.5 - resolution: "@babel/preset-react@npm:7.28.5" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.27.1" - "@babel/helper-validator-option": "npm:^7.27.1" - "@babel/plugin-transform-react-display-name": "npm:^7.28.0" - "@babel/plugin-transform-react-jsx": "npm:^7.27.1" - "@babel/plugin-transform-react-jsx-development": "npm:^7.27.1" - "@babel/plugin-transform-react-pure-annotations": "npm:^7.27.1" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10c0/0d785e708ff301f4102bd4738b77e550e32f981e54dfd3de1191b4d68306bbb934d2d465fc78a6bc22fff0a6b3ce3195a53984f52755c4349e7264c7e01e8c7c - languageName: node - linkType: hard - "@babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.17.8, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.5.5": version: 7.28.4 resolution: "@babel/runtime@npm:7.28.4" @@ -2836,29 +2771,6 @@ __metadata: languageName: node linkType: hard -"@emotion/is-prop-valid@npm:1.2.2": - version: 1.2.2 - resolution: "@emotion/is-prop-valid@npm:1.2.2" - dependencies: - "@emotion/memoize": "npm:^0.8.1" - checksum: 10c0/bb1530dcb4e0e5a4fabb219279f2d0bc35796baf66f6241f98b0d03db1985c890a8cafbea268e0edefd5eeda143dbd5c09a54b5fba74cee8c69b98b13194af50 - languageName: node - linkType: hard - -"@emotion/memoize@npm:^0.8.1": - version: 0.8.1 - resolution: "@emotion/memoize@npm:0.8.1" - checksum: 10c0/dffed372fc3b9fa2ba411e76af22b6bb686fb0cb07694fdfaa6dd2baeb0d5e4968c1a7caa472bfcf06a5997d5e7c7d16b90e993f9a6ffae79a2c3dbdc76dfe78 - languageName: node - linkType: hard - -"@emotion/unitless@npm:0.8.1": - version: 0.8.1 - resolution: "@emotion/unitless@npm:0.8.1" - checksum: 10c0/a1ed508628288f40bfe6dd17d431ed899c067a899fa293a13afe3aed1d70fac0412b8a215fafab0b42829360db687fecd763e5f01a64ddc4a4b58ec3112ff548 - languageName: node - linkType: hard - "@emotion/use-insertion-effect-with-fallbacks@npm:^1.0.0": version: 1.2.0 resolution: "@emotion/use-insertion-effect-with-fallbacks@npm:1.2.0" @@ -4102,6 +4014,16 @@ __metadata: languageName: node linkType: hard +"@lit-labs/observers@npm:^2.0.2": + version: 2.0.6 + resolution: "@lit-labs/observers@npm:2.0.6" + dependencies: + "@lit/reactive-element": "npm:^1.0.0 || ^2.0.0" + lit-html: "npm:^3.2.0" + checksum: 10c0/2e9559beb3b48af9ad6ac4593ec3a15cb8600cf9867ff7b07eb19cc543dc2b5d87aabdd072f007cb389c79bf3a0ef517cebc292e97d95f7153deb1166c66bef1 + languageName: node + linkType: hard + "@lit-labs/react@npm:^1.0.2": version: 1.2.1 resolution: "@lit-labs/react@npm:1.2.1" @@ -4126,7 +4048,7 @@ __metadata: languageName: node linkType: hard -"@lit/react@npm:1.0.8": +"@lit/react@npm:1.0.8, @lit/react@npm:^1.0.0": version: 1.0.8 resolution: "@lit/react@npm:1.0.8" peerDependencies: @@ -5501,7 +5423,7 @@ __metadata: rollup: "npm:4.52.2" sinon: "npm:17.0.2" storybook: "npm:8.6.14" - storybook-screen-reader: "npm:1.0.0" + storybook-screen-reader: "npm:1.1.0" stylelint: "npm:16.24.0" stylelint-config-standard: "npm:38.0.0" stylelint-header: "npm:3.0.0" @@ -5650,6 +5572,15 @@ __metadata: languageName: unknown linkType: soft +"@spectrum-web-components/base@npm:^0.42.5": + version: 0.42.5 + resolution: "@spectrum-web-components/base@npm:0.42.5" + dependencies: + lit: "npm:^2.5.0 || ^3.1.3" + checksum: 10c0/08a82ed97b2333333438494930fcb2da267f49cab94a7b0e2463d36b50603494db78c268093b7dc643ee016d569ceebe53f04a46ebf990117b1f483773205f6b + languageName: node + linkType: hard + "@spectrum-web-components/breadcrumbs@npm:1.10.0, @spectrum-web-components/breadcrumbs@workspace:1st-gen/packages/breadcrumbs": version: 0.0.0-use.local resolution: "@spectrum-web-components/breadcrumbs@workspace:1st-gen/packages/breadcrumbs" @@ -5796,6 +5727,18 @@ __metadata: languageName: unknown linkType: soft +"@spectrum-web-components/checkbox@npm:^0.42.5": + version: 0.42.5 + resolution: "@spectrum-web-components/checkbox@npm:0.42.5" + dependencies: + "@spectrum-web-components/base": "npm:^0.42.5" + "@spectrum-web-components/icon": "npm:^0.42.5" + "@spectrum-web-components/icons-ui": "npm:^0.42.5" + "@spectrum-web-components/shared": "npm:^0.42.5" + checksum: 10c0/a9d9b423b9ff18f790d79d63d50a4112fc5ecacf3d87ed53fc749a306b6bce20235cb21c483bc8f0a1fa68dfc99c1c1be410b297324ee7ab39df160ca5717c7f + languageName: node + linkType: hard + "@spectrum-web-components/clear-button@npm:1.10.0, @spectrum-web-components/clear-button@workspace:1st-gen/packages/clear-button": version: 0.0.0-use.local resolution: "@spectrum-web-components/clear-button@workspace:1st-gen/packages/clear-button" @@ -6076,6 +6019,16 @@ __metadata: languageName: unknown linkType: soft +"@spectrum-web-components/icon@npm:^0.42.5": + version: 0.42.5 + resolution: "@spectrum-web-components/icon@npm:0.42.5" + dependencies: + "@spectrum-web-components/base": "npm:^0.42.5" + "@spectrum-web-components/iconset": "npm:^0.42.5" + checksum: 10c0/6ed5122ee9118c6955cd035ebb27e13a841f62f438d0676ce9168eb396acc7a53a7fe223daebcd1b3a7095ad9c4010241553b415df814670e4c05be549f4f3ac + languageName: node + linkType: hard + "@spectrum-web-components/icons-ui@npm:1.10.0, @spectrum-web-components/icons-ui@workspace:1st-gen/packages/icons-ui": version: 0.0.0-use.local resolution: "@spectrum-web-components/icons-ui@workspace:1st-gen/packages/icons-ui" @@ -6092,6 +6045,17 @@ __metadata: languageName: unknown linkType: soft +"@spectrum-web-components/icons-ui@npm:^0.42.5": + version: 0.42.5 + resolution: "@spectrum-web-components/icons-ui@npm:0.42.5" + dependencies: + "@spectrum-web-components/base": "npm:^0.42.5" + "@spectrum-web-components/icon": "npm:^0.42.5" + "@spectrum-web-components/iconset": "npm:^0.42.5" + checksum: 10c0/0ae35daaeeefcb7635569e971d66b9e91d3c3e14dde135c9ab44f7f5963eca49f958a327599fc079543ac87bfffb4f6f6588182aa8c9ac9f176711aeb1502336 + languageName: node + linkType: hard + "@spectrum-web-components/icons-workflow@npm:1.10.0, @spectrum-web-components/icons-workflow@workspace:1st-gen/packages/icons-workflow": version: 0.0.0-use.local resolution: "@spectrum-web-components/icons-workflow@workspace:1st-gen/packages/icons-workflow" @@ -6124,6 +6088,15 @@ __metadata: languageName: unknown linkType: soft +"@spectrum-web-components/iconset@npm:^0.42.5": + version: 0.42.5 + resolution: "@spectrum-web-components/iconset@npm:0.42.5" + dependencies: + "@spectrum-web-components/base": "npm:^0.42.5" + checksum: 10c0/11a50d3e8f978c7a37e564ea0dc798555381f280a792b42ce5e5cab5fb3de241c1dd919356e0f25da7870709a11ac59df3b93bb2425ca72122cf52785cd42d27 + languageName: node + linkType: hard + "@spectrum-web-components/illustrated-message@npm:1.10.0, @spectrum-web-components/illustrated-message@workspace:1st-gen/packages/illustrated-message": version: 0.0.0-use.local resolution: "@spectrum-web-components/illustrated-message@workspace:1st-gen/packages/illustrated-message" @@ -6333,6 +6306,17 @@ __metadata: languageName: unknown linkType: soft +"@spectrum-web-components/shared@npm:^0.42.5": + version: 0.42.5 + resolution: "@spectrum-web-components/shared@npm:0.42.5" + dependencies: + "@lit-labs/observers": "npm:^2.0.2" + "@spectrum-web-components/base": "npm:^0.42.5" + focus-visible: "npm:^5.1.0" + checksum: 10c0/f363155ed97885875dcd415ee3dce4a6b0325978c492d9b12ad11412c4f9d421789de1e81bc9ea1dbde86f363bc841f184dd70df5aef62e2e9320d44a937448f + languageName: node + linkType: hard + "@spectrum-web-components/sidenav@npm:1.10.0, @spectrum-web-components/sidenav@workspace:1st-gen/packages/sidenav": version: 0.0.0-use.local resolution: "@spectrum-web-components/sidenav@workspace:1st-gen/packages/sidenav" @@ -6402,6 +6386,15 @@ __metadata: languageName: unknown linkType: soft +"@spectrum-web-components/styles@npm:^0.42.5": + version: 0.42.5 + resolution: "@spectrum-web-components/styles@npm:0.42.5" + dependencies: + "@spectrum-web-components/base": "npm:^0.42.5" + checksum: 10c0/caf5bbb0b8ee67da2f79c31883e17055e4d4cae828d588c5cf5c49efd5495ce558a3e6014077364e50327f291a6d909ec0e97926d731cb49756c83ed3d66a1c0 + languageName: node + linkType: hard + "@spectrum-web-components/swatch@npm:1.10.0, @spectrum-web-components/swatch@workspace:1st-gen/packages/swatch": version: 0.0.0-use.local resolution: "@spectrum-web-components/swatch@workspace:1st-gen/packages/swatch" @@ -6425,6 +6418,16 @@ __metadata: languageName: unknown linkType: soft +"@spectrum-web-components/switch@npm:^0.42.0": + version: 0.42.5 + resolution: "@spectrum-web-components/switch@npm:0.42.5" + dependencies: + "@spectrum-web-components/base": "npm:^0.42.5" + "@spectrum-web-components/checkbox": "npm:^0.42.5" + checksum: 10c0/cbb37673876f05d68d920bf457e2da08212bdccb90992a68b0690cb8667a3258e68028c33f8bf4770df519d8a28459fd72b43ccf8517e471a7e857b704131d7d + languageName: node + linkType: hard + "@spectrum-web-components/table@npm:1.10.0, @spectrum-web-components/table@workspace:1st-gen/packages/table": version: 0.0.0-use.local resolution: "@spectrum-web-components/table@workspace:1st-gen/packages/table" @@ -6486,6 +6489,16 @@ __metadata: languageName: unknown linkType: soft +"@spectrum-web-components/theme@npm:^0.42.0": + version: 0.42.5 + resolution: "@spectrum-web-components/theme@npm:0.42.5" + dependencies: + "@spectrum-web-components/base": "npm:^0.42.5" + "@spectrum-web-components/styles": "npm:^0.42.5" + checksum: 10c0/092099b7ccbf6f8a213e01fef18f7555024ceb16568c07de2e78ff5a5ea74bffff4fcfe552c90fbf7fe2ca497715a9de0a97372ea44cfbfb3e4f3ead0c44fa8b + languageName: node + linkType: hard + "@spectrum-web-components/thumbnail@npm:1.10.0, @spectrum-web-components/thumbnail@workspace:1st-gen/packages/thumbnail": version: 0.0.0-use.local resolution: "@spectrum-web-components/thumbnail@workspace:1st-gen/packages/thumbnail" @@ -6949,7 +6962,7 @@ __metadata: languageName: node linkType: hard -"@storybook/components@npm:8.6.14, @storybook/components@npm:^8.0.0": +"@storybook/components@npm:8.6.14": version: 8.6.14 resolution: "@storybook/components@npm:8.6.14" peerDependencies: @@ -7017,6 +7030,15 @@ __metadata: languageName: node linkType: hard +"@storybook/core-events@npm:^8.0.0": + version: 8.6.14 + resolution: "@storybook/core-events@npm:8.6.14" + peerDependencies: + storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 + checksum: 10c0/8fc9941e3ef9954ed82a845e29867ba4bcc2e0c1749c1ab6a916a24d3941d878cc509769b6c0c073e78ec91d22c7895787219bb6b5d3e787c8223963dbef6b3e + languageName: node + linkType: hard + "@storybook/core-webpack@npm:8.6.14": version: 8.6.14 resolution: "@storybook/core-webpack@npm:8.6.14" @@ -8707,13 +8729,6 @@ __metadata: languageName: node linkType: hard -"@types/stylis@npm:4.2.5": - version: 4.2.5 - resolution: "@types/stylis@npm:4.2.5" - checksum: 10c0/23f5b35a3a04f6bb31a29d404fa1bc8e0035fcaff2356b4047743a057e0c37b2eba7efe14d57dd2b95b398cea3bac294d9c6cd93ed307d8c0b7f5d282224b469 - languageName: node - linkType: hard - "@types/supports-color@npm:^8.0.0": version: 8.1.3 resolution: "@types/supports-color@npm:8.1.3" @@ -11646,13 +11661,6 @@ __metadata: languageName: node linkType: hard -"camelize@npm:^1.0.0": - version: 1.0.1 - resolution: "camelize@npm:1.0.1" - checksum: 10c0/4c9ac55efd356d37ac483bad3093758236ab686192751d1c9daa43188cc5a07b09bd431eb7458a4efd9ca22424bba23253e7b353feb35d7c749ba040de2385fb - languageName: node - linkType: hard - "caniuse-api@npm:^3.0.0": version: 3.0.0 resolution: "caniuse-api@npm:3.0.0" @@ -12829,13 +12837,6 @@ __metadata: languageName: node linkType: hard -"css-color-keywords@npm:^1.0.0": - version: 1.0.0 - resolution: "css-color-keywords@npm:1.0.0" - checksum: 10c0/af205a86c68e0051846ed91eb3e30b4517e1904aac040013ff1d742019b3f9369ba5658ba40901dbbc121186fc4bf0e75a814321cc3e3182fbb2feb81c6d9cb7 - languageName: node - linkType: hard - "css-declaration-sorter@npm:^6.3.1": version: 6.4.1 resolution: "css-declaration-sorter@npm:6.4.1" @@ -12933,17 +12934,6 @@ __metadata: languageName: node linkType: hard -"css-to-react-native@npm:3.2.0": - version: 3.2.0 - resolution: "css-to-react-native@npm:3.2.0" - dependencies: - camelize: "npm:^1.0.0" - css-color-keywords: "npm:^1.0.0" - postcss-value-parser: "npm:^4.0.2" - checksum: 10c0/fde850a511d5d3d7c55a1e9b8ed26b69a8ad4868b3487e36ebfbfc0b96fc34bc977d9cd1d61a289d0c74d3f9a662d8cee297da53d4433bf2e27d6acdff8e1003 - languageName: node - linkType: hard - "css-tree@npm:^1.1.2, css-tree@npm:^1.1.3": version: 1.1.3 resolution: "css-tree@npm:1.1.3" @@ -13144,7 +13134,7 @@ __metadata: languageName: node linkType: hard -"csstype@npm:3.1.3, csstype@npm:^3.0.2": +"csstype@npm:^3.0.2": version: 3.1.3 resolution: "csstype@npm:3.1.3" checksum: 10c0/80c089d6f7e0c5b2bd83cf0539ab41474198579584fa10d86d0cafe0642202343cbc119e076a0b1aece191989477081415d66c9fefbf3c957fc2fc4b7009f248 @@ -16031,7 +16021,7 @@ __metadata: languageName: node linkType: hard -"focus-visible@npm:5.2.1": +"focus-visible@npm:5.2.1, focus-visible@npm:^5.1.0": version: 5.2.1 resolution: "focus-visible@npm:5.2.1" checksum: 10c0/1c0e4e8b22be8684a664acc340efd6a41aafb560ce09979186a1c934de321ce8d6a3d7175c946aab1c87409b0e10f623274d7ce7d42ff16a0e4dc862fa151623 @@ -20432,7 +20422,7 @@ __metadata: languageName: node linkType: hard -"lit-html@npm:^2.0.0 || ^3.0.0, lit-html@npm:^2.4.0 || ^3.1.3, lit-html@npm:^3.3.0": +"lit-html@npm:^2.0.0 || ^3.0.0, lit-html@npm:^2.4.0 || ^3.1.3, lit-html@npm:^3.2.0, lit-html@npm:^3.3.0": version: 3.3.1 resolution: "lit-html@npm:3.3.1" dependencies: @@ -22784,7 +22774,7 @@ __metadata: languageName: node linkType: hard -"nanoid@npm:^3.1.25, nanoid@npm:^3.3.11, nanoid@npm:^3.3.6, nanoid@npm:^3.3.7": +"nanoid@npm:^3.1.25, nanoid@npm:^3.3.11, nanoid@npm:^3.3.6": version: 3.3.11 resolution: "nanoid@npm:3.3.11" bin: @@ -25556,7 +25546,7 @@ __metadata: languageName: node linkType: hard -"postcss-value-parser@npm:^4.0.2, postcss-value-parser@npm:^4.1.0, postcss-value-parser@npm:^4.2.0": +"postcss-value-parser@npm:^4.1.0, postcss-value-parser@npm:^4.2.0": version: 4.2.0 resolution: "postcss-value-parser@npm:4.2.0" checksum: 10c0/f4142a4f56565f77c1831168e04e3effd9ffcc5aebaf0f538eee4b2d465adfd4b85a44257bb48418202a63806a7da7fe9f56c330aebb3cac898e46b4cbf49161 @@ -25574,17 +25564,6 @@ __metadata: languageName: node linkType: hard -"postcss@npm:8.4.49": - version: 8.4.49 - resolution: "postcss@npm:8.4.49" - dependencies: - nanoid: "npm:^3.3.7" - picocolors: "npm:^1.1.1" - source-map-js: "npm:^1.2.1" - checksum: 10c0/f1b3f17aaf36d136f59ec373459f18129908235e65dbdc3aee5eef8eba0756106f52de5ec4682e29a2eab53eb25170e7e871b3e4b52a8f1de3d344a514306be3 - languageName: node - linkType: hard - "postcss@npm:8.5.6, postcss@npm:^8, postcss@npm:^8.4.33, postcss@npm:^8.4.5, postcss@npm:^8.5.6": version: 8.5.6 resolution: "postcss@npm:8.5.6" @@ -26034,10 +26013,10 @@ __metadata: languageName: node linkType: hard -"query-selector-shadow-dom@npm:^0.8.0": - version: 0.8.0 - resolution: "query-selector-shadow-dom@npm:0.8.0" - checksum: 10c0/4f5c3fe6e1075dfab65484e33bd4c48c040d422491c29902c3026e2aef3a130355d052823d798acb180fd7800c78342d3629443e870e8f8c56eacb4d1aa9e46b +"query-selector-shadow-dom@npm:^1.0.0": + version: 1.0.1 + resolution: "query-selector-shadow-dom@npm:1.0.1" + checksum: 10c0/f36de03f170ff1da69c3eecfa7f8b01e450a46dd266c921e17f36076ec59862eee00179489f30cb17c118bb56e868436578c01ea66f671fb358750d6ae474125 languageName: node linkType: hard @@ -26137,7 +26116,7 @@ __metadata: languageName: node linkType: hard -"react-dom@npm:18.3.1, react-dom@npm:^18.2.0": +"react-dom@npm:18.3.1": version: 18.3.1 resolution: "react-dom@npm:18.3.1" dependencies: @@ -27788,13 +27767,6 @@ __metadata: languageName: node linkType: hard -"shallowequal@npm:1.1.0": - version: 1.1.0 - resolution: "shallowequal@npm:1.1.0" - checksum: 10c0/b926efb51cd0f47aa9bc061add788a4a650550bbe50647962113a4579b60af2abe7b62f9b02314acc6f97151d4cf87033a2b15fc20852fae306d1a095215396c - languageName: node - linkType: hard - "shebang-command@npm:^1.2.0": version: 1.2.0 resolution: "shebang-command@npm:1.2.0" @@ -28360,19 +28332,19 @@ __metadata: languageName: node linkType: hard -"storybook-screen-reader@npm:1.0.0": - version: 1.0.0 - resolution: "storybook-screen-reader@npm:1.0.0" +"storybook-screen-reader@npm:1.1.0": + version: 1.1.0 + resolution: "storybook-screen-reader@npm:1.1.0" dependencies: - "@babel/preset-env": "npm:^7.13.8" - "@babel/preset-react": "npm:^7.12.13" - "@storybook/components": "npm:^8.0.0" + "@lit/react": "npm:^1.0.0" + "@spectrum-web-components/switch": "npm:^0.42.0" + "@spectrum-web-components/theme": "npm:^0.42.0" + "@storybook/core-events": "npm:^8.0.0" "@storybook/manager-api": "npm:^8.0.0" - query-selector-shadow-dom: "npm:^0.8.0" + lit: "npm:^3.1.0" + query-selector-shadow-dom: "npm:^1.0.0" react: "npm:^18.2.0" - react-dom: "npm:^18.2.0" - styled-components: "npm:^6.1.0" - checksum: 10c0/c08a2ac58c3e0f9ce736c49112b314e585975434246bedc25de57474f65d77e5635a088f1b1fa4a29386ecac00741c038badf3bfcadc4eaf1b76b6288aebcef6 + checksum: 10c0/1a39dab767e4c5a77642fbe7c27a17fcccf150d060c7d21c67127f5b53e6762b46a33a3f80b2466354905f7f30657debabfb9fab899aa6ecc6d5a77fe3c12634 languageName: node linkType: hard @@ -28787,26 +28759,6 @@ __metadata: languageName: node linkType: hard -"styled-components@npm:^6.1.0": - version: 6.1.19 - resolution: "styled-components@npm:6.1.19" - dependencies: - "@emotion/is-prop-valid": "npm:1.2.2" - "@emotion/unitless": "npm:0.8.1" - "@types/stylis": "npm:4.2.5" - css-to-react-native: "npm:3.2.0" - csstype: "npm:3.1.3" - postcss: "npm:8.4.49" - shallowequal: "npm:1.1.0" - stylis: "npm:4.3.2" - tslib: "npm:2.6.2" - peerDependencies: - react: ">= 16.8.0" - react-dom: ">= 16.8.0" - checksum: 10c0/8d20427a5debe54bfa3b55f79af2a3577551ed7f1d1cd34df986b73fd01ac519f9081b7737cc1f76e12fbc483fa50551e55be0bc984296e623cc6a2364697cd8 - languageName: node - linkType: hard - "styled-jsx@npm:5.1.1": version: 5.1.1 resolution: "styled-jsx@npm:5.1.1" @@ -28927,13 +28879,6 @@ __metadata: languageName: node linkType: hard -"stylis@npm:4.3.2": - version: 4.3.2 - resolution: "stylis@npm:4.3.2" - checksum: 10c0/0410e1404cbeee3388a9e17587875211ce2f014c8379af0d1e24ca55878867c9f1ccc7b0ce9a156ca53f5d6e301391a82b0645522a604674a378b3189a4a1994 - languageName: node - linkType: hard - "supports-color@npm:^5.3.0": version: 5.5.0 resolution: "supports-color@npm:5.5.0" @@ -29641,13 +29586,6 @@ __metadata: languageName: node linkType: hard -"tslib@npm:2.6.2": - version: 2.6.2 - resolution: "tslib@npm:2.6.2" - checksum: 10c0/e03a8a4271152c8b26604ed45535954c0a45296e32445b4b87f8a5abdb2421f40b59b4ca437c4346af0f28179780d604094eb64546bee2019d903d01c6c19bdb - languageName: node - linkType: hard - "tslib@npm:2.8.1, tslib@npm:^2.0.0, tslib@npm:^2.0.1, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.3.1, tslib@npm:^2.4.0, tslib@npm:^2.8.0": version: 2.8.1 resolution: "tslib@npm:2.8.1" From d9f1fdf5dea9049cc0731d1d2402d39f438bfcc5 Mon Sep 17 00:00:00 2001 From: TarunAdobe Date: Thu, 11 Dec 2025 11:57:37 +0530 Subject: [PATCH 3/5] feat: add local storybook screen reader addon --- .gitignore | 1 + 1st-gen/package.json | 19 +- .../projects/screen-reader-addon/manager.js | 14 + .../projects/screen-reader-addon/package.json | 68 ++ .../src/components/screen-reader-panel.ts | 255 +++++ .../screen-reader-addon/src/register.tsx | 39 + .../src/screen-reader/screenReader.ts | 970 ++++++++++++++++++ .../screen-reader-addon/tsconfig.json | 24 + 1st-gen/storybook/main.js | 4 +- 2nd-gen/packages/core/shared/base/version.ts | 11 - package.json | 6 +- yarn.lock | 167 +-- 12 files changed, 1427 insertions(+), 151 deletions(-) create mode 100644 1st-gen/projects/screen-reader-addon/manager.js create mode 100644 1st-gen/projects/screen-reader-addon/package.json create mode 100644 1st-gen/projects/screen-reader-addon/src/components/screen-reader-panel.ts create mode 100644 1st-gen/projects/screen-reader-addon/src/register.tsx create mode 100644 1st-gen/projects/screen-reader-addon/src/screen-reader/screenReader.ts create mode 100644 1st-gen/projects/screen-reader-addon/tsconfig.json diff --git a/.gitignore b/.gitignore index 379468a2d9c..4cc43a102e4 100644 --- a/.gitignore +++ b/.gitignore @@ -61,6 +61,7 @@ react !1st-gen/projects/example-project-webpack/src/index.js !1st-gen/projects/example-project-webpack/webpack.config.js !1st-gen/projects/templates/plopfile.js +!1st-gen/projects/screen-reader-addon/manager.js 1st-gen/tools/*/src/**/*.css.js 1st-gen/tools/*/src/**/*.css.js.map diff --git a/1st-gen/package.json b/1st-gen/package.json index 7ba674258e2..5a67e8099ce 100644 --- a/1st-gen/package.json +++ b/1st-gen/package.json @@ -186,7 +186,6 @@ "rollup": "4.52.2", "sinon": "17.0.2", "storybook": "8.6.14", - "storybook-screen-reader": "1.1.0", "stylelint": "16.24.0", "stylelint-config-standard": "38.0.0", "stylelint-header": "3.0.0", @@ -233,6 +232,19 @@ "command": "node ./scripts/watch-css.js", "service": true }, + "build:screen-reader-addon": { + "command": "yarn workspace @spectrum-web-components/screen-reader-addon build", + "files": [ + "projects/screen-reader-addon/src/**/*.ts", + "projects/screen-reader-addon/src/**/*.tsx", + "projects/screen-reader-addon/tsconfig.json", + "projects/screen-reader-addon/package.json", + "projects/screen-reader-addon/manager.js" + ], + "output": [ + "projects/screen-reader-addon/dist/**" + ] + }, "build:ts": { "clean": "if-file-deleted", "command": "node ./scripts/build-ts.js", @@ -270,6 +282,8 @@ "!projects/example-project-rollup", "!projects/example-project-webpack", "!projects/templates", + "!projects/screen-reader-addon/manager.js", + "!projects/screen-reader-addon/dist/**", "tools/**/*.js", "tools/**/*.js.map", "!**/build.js", @@ -382,7 +396,8 @@ "prestorybook": { "command": "cem analyze --outdir storybook/", "dependencies": [ - "build:ts" + "build:ts", + "build:screen-reader-addon" ], "files": [ "packages/**/*.ts", diff --git a/1st-gen/projects/screen-reader-addon/manager.js b/1st-gen/projects/screen-reader-addon/manager.js new file mode 100644 index 00000000000..458f2485bf5 --- /dev/null +++ b/1st-gen/projects/screen-reader-addon/manager.js @@ -0,0 +1,14 @@ +/** + * Copyright 2025 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +// Storybook manager addon entry point +import './dist/register.js'; diff --git a/1st-gen/projects/screen-reader-addon/package.json b/1st-gen/projects/screen-reader-addon/package.json new file mode 100644 index 00000000000..8c156a4853f --- /dev/null +++ b/1st-gen/projects/screen-reader-addon/package.json @@ -0,0 +1,68 @@ +{ + "author": "Adobe", + "bugs": { + "url": "https://github.com/adobe/spectrum-web-components/issues" + }, + "dependencies": { + "aria-query": "^5.3.0", + "dom-accessibility-api": "^0.7.0", + "query-selector-shadow-dom": "^1.0.0" + }, + "peerDependencies": { + "@lit/react": ">=1.0.0", + "@spectrum-web-components/switch": ">=1.0.0", + "@spectrum-web-components/theme": ">=1.0.0", + "@storybook/components": ">=8.0.0", + "@storybook/core-events": ">=8.0.0", + "@storybook/manager-api": ">=8.0.0", + "lit": "^2.5.0 || ^3.1.3", + "react": ">=18.0.0" + }, + "description": "A Screen Reader Storybook addon for accessibility testing", + "devDependencies": { + "esbuild": "0.21.5", + "typescript": "5.3.3" + }, + "files": [ + "dist/**/*" + ], + "homepage": "https://opensource.adobe.com/spectrum-web-components/", + "keywords": [ + "storybook", + "storybook-addons", + "addons", + "accessibility", + "a11y", + "screen-reader", + "wcag" + ], + "license": "Apache-2.0", + "main": "dist/register.js", + "module": "dist/register.js", + "name": "@spectrum-web-components/screen-reader-addon", + "private": true, + "repository": { + "directory": "1st-gen/projects/screen-reader-addon", + "type": "git", + "url": "https://github.com/adobe/spectrum-web-components.git" + }, + "scripts": { + "build": "esbuild src/register.tsx --bundle --outfile=dist/register.js --format=esm \"--external:@storybook/*\" \"--external:@spectrum-web-components/*\" \"--external:@lit/*\" --external:react --external:lit --platform=browser", + "typecheck": "tsc --noEmit" + }, + "version": "1.0.0", + "wireit": { + "build": { + "clean": "if-file-deleted", + "command": "esbuild src/register.tsx --bundle --outfile=dist/register.js --format=esm \"--external:@storybook/*\" \"--external:@spectrum-web-components/*\" \"--external:@lit/*\" --external:react --external:lit --platform=browser", + "files": [ + "src/**/*.ts", + "src/**/*.tsx", + "tsconfig.json" + ], + "output": [ + "dist/**" + ] + } + } +} diff --git a/1st-gen/projects/screen-reader-addon/src/components/screen-reader-panel.ts b/1st-gen/projects/screen-reader-addon/src/components/screen-reader-panel.ts new file mode 100644 index 00000000000..fa60224dcb3 --- /dev/null +++ b/1st-gen/projects/screen-reader-addon/src/components/screen-reader-panel.ts @@ -0,0 +1,255 @@ +/** + * Copyright 2025 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +import { css, html, LitElement } from 'lit'; +import { property } from 'lit/decorators.js'; +import { addons, type Channel } from '@storybook/manager-api'; +import { STORY_CHANGED } from '@storybook/core-events'; + +// Import Spectrum Web Components +import '@spectrum-web-components/switch/sp-switch.js'; +import '@spectrum-web-components/theme/sp-theme.js'; +import '@spectrum-web-components/theme/src/spectrum-two/themes-core-tokens.js'; + +import ScreenReader from '../screen-reader/screenReader.js'; + +interface ScreenReaderTextEvent extends CustomEvent { + detail: { + text: string; + }; +} + +export class ScreenReaderPanel extends LitElement { + @property({ type: Boolean }) + voice = false; + + @property({ type: Boolean }) + text = false; + + @property({ type: Boolean }) + isActive = false; + + @property({ type: String }) + screenReaderText = ''; + + private screenReader: ScreenReader | null = null; + private channel: Channel | null = null; + + static override styles = css` + :host { + display: block; + padding: 16px; + font-family: + -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, + sans-serif; + } + + .toggle-row { + display: flex; + align-items: center; + margin-bottom: 12px; + gap: 8px; + } + + .toggle-label { + font-size: 14px; + color: var(--spectrum-global-color-gray-800, #4b4b4b); + } + + .text-output { + font-size: 14px; + border-radius: 6px; + border: 1px solid var(--spectrum-global-color-gray-300, #e0e0e0); + padding: 12px; + margin-top: 12px; + background: var(--spectrum-global-color-gray-100, #f5f5f5); + min-height: 60px; + max-height: 200px; + overflow-y: auto; + } + + .status-text { + font-size: 12px; + color: var(--spectrum-global-color-gray-600, #6e6e6e); + margin: 12px 0 0 0; + font-style: italic; + } + + .placeholder { + color: var(--spectrum-global-color-gray-500, #959595); + } + `; + + constructor() { + super(); + this.handleTextChange = this.handleTextChange.bind(this); + this.handleStoryChange = this.handleStoryChange.bind(this); + } + + override connectedCallback(): void { + super.connectedCallback(); + + // Listen for text changes from the screen reader + window.addEventListener( + 'screen-reader-text-changed', + this.handleTextChange as EventListener + ); + + // Listen for story changes via Storybook API + this.channel = addons.getChannel(); + this.channel.on(STORY_CHANGED, this.handleStoryChange); + } + + override disconnectedCallback(): void { + super.disconnectedCallback(); + + window.removeEventListener( + 'screen-reader-text-changed', + this.handleTextChange as EventListener + ); + + if (this.channel) { + this.channel.off(STORY_CHANGED, this.handleStoryChange); + } + + this.stopScreenReader(); + } + + private handleTextChange(event: ScreenReaderTextEvent): void { + this.screenReaderText = event.detail.text; + } + + private handleStoryChange(): void { + if (this.isActive && this.screenReader) { + this.screenReader.stop(); + this.screenReader = null; + + // Wait for new story to load, then restart + setTimeout(() => { + if (this.voice || this.text) { + this.startScreenReader(); + } + }, 500); + } + } + + private handleVoiceToggle(event: Event): void { + this.voice = (event.target as HTMLInputElement).checked; + this.updateScreenReader(); + } + + private handleTextToggle(event: Event): void { + this.text = (event.target as HTMLInputElement).checked; + this.updateScreenReader(); + } + + private findStorybookIframe(): HTMLIFrameElement | null { + return ( + (document.getElementById( + 'storybook-preview-iframe' + ) as HTMLIFrameElement) || + (document.querySelector( + 'iframe[data-is-storybook="true"]' + ) as HTMLIFrameElement) || + (document.querySelector( + 'iframe[title*="storybook"]' + ) as HTMLIFrameElement) || + (document.querySelector('iframe') as HTMLIFrameElement) + ); + } + + private startScreenReader(): void { + const iframe = this.findStorybookIframe(); + + if (!iframe) { + // eslint-disable-next-line no-console + console.error('[Screen Reader Addon] Cannot find preview iframe'); + return; + } + + this.screenReader = new ScreenReader(); + this.screenReader.voiceEnabled = this.voice; + this.screenReader.textEnabled = this.text; + this.screenReader.start(iframe); + + this.isActive = true; + } + + private stopScreenReader(): void { + if (this.screenReader) { + this.screenReader.stop(); + this.screenReader = null; + } + this.isActive = false; + this.screenReaderText = ''; + } + + private updateScreenReader(): void { + const shouldBeActive = this.voice || this.text; + + if (shouldBeActive && !this.isActive) { + this.startScreenReader(); + } else if (!shouldBeActive && this.isActive) { + this.stopScreenReader(); + } else if (shouldBeActive && this.screenReader) { + this.screenReader.voiceEnabled = this.voice; + this.screenReader.textEnabled = this.text; + } + } + + override render() { + return html` + +
+ + Voice Reader + +
+ +
+ + Text Reader + +
+ + ${this.text + ? html` +
+ ${this.screenReaderText || + html` + + Navigate to hear announcements... + + `} +
+ ` + : ''} + ${this.isActive + ? html` +

+ Use Tab or arrow keys to navigate. Focus changes + will be announced. +

+ ` + : ''} +
+ `; + } +} + +customElements.define('screen-reader-panel', ScreenReaderPanel); diff --git a/1st-gen/projects/screen-reader-addon/src/register.tsx b/1st-gen/projects/screen-reader-addon/src/register.tsx new file mode 100644 index 00000000000..5bfc9bf8e61 --- /dev/null +++ b/1st-gen/projects/screen-reader-addon/src/register.tsx @@ -0,0 +1,39 @@ +/** + * Copyright 2025 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +import React from 'react'; +import { createComponent } from '@lit/react'; +import { addons, types } from '@storybook/manager-api'; +import { AddonPanel } from '@storybook/components'; +import { ScreenReaderPanel } from './components/screen-reader-panel.js'; + +// Create React wrapper for our Lit component +const ScreenReaderPanelReact = createComponent({ + tagName: 'screen-reader-panel', + elementClass: ScreenReaderPanel, + react: React, +}); + +const ADDON_ID = 'screenreader'; +const PANEL_ID = `${ADDON_ID}/panel`; + +addons.register(ADDON_ID, () => { + addons.add(PANEL_ID, { + type: types.PANEL, + title: 'Screen Reader', + render: ({ active }) => ( + + + + ), + }); +}); diff --git a/1st-gen/projects/screen-reader-addon/src/screen-reader/screenReader.ts b/1st-gen/projects/screen-reader-addon/src/screen-reader/screenReader.ts new file mode 100644 index 00000000000..809ce1b9062 --- /dev/null +++ b/1st-gen/projects/screen-reader-addon/src/screen-reader/screenReader.ts @@ -0,0 +1,970 @@ +/** + * Copyright 2025 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +import { querySelectorDeep } from 'query-selector-shadow-dom'; +import { + computeAccessibleDescription, + computeAccessibleName, +} from 'dom-accessibility-api'; +import { elementRoles } from 'aria-query'; + +type RoleAnnouncementFn = () => string; + +interface ElementRoleKey { + name: string; + attributes?: Array<{ name: string; value?: string }>; +} + +/** + * Dispatch text change event to the addon panel + */ +function dispatchTextChanged(text: string): void { + const customEvent = new CustomEvent('screen-reader-text-changed', { + detail: { text }, + }); + window.dispatchEvent(customEvent); +} + +/** + * Get the implicit ARIA role for an element using aria-query + */ +function getImplicitRole(element: Element): string | null { + if (!element || !element.tagName) { + return null; + } + + const tagName = element.tagName.toLowerCase(); + + // Check aria-query's elementRoles map + // elementRoles is a Map where keys are objects like { name: 'button' } + for (const [key, roleSet] of elementRoles) { + const roleKey = key as ElementRoleKey; + if (roleKey.name === tagName) { + // Check if attributes match (for elements like input with type) + if (roleKey.attributes) { + const matches = roleKey.attributes.every((attr) => { + if (attr.name === 'type') { + return element.getAttribute('type') === attr.value; + } + return ( + element.hasAttribute(attr.name) === + (attr.value !== undefined) + ); + }); + if (matches && roleSet.size > 0) { + return Array.from(roleSet)[0] as string; + } + } else if (roleSet.size > 0) { + return Array.from(roleSet)[0] as string; + } + } + } + + return null; +} + +/** + * Screen Reader class that simulates screen reader behavior + * Uses dom-accessibility-api for W3C-compliant accessible name computation + */ +export default class ScreenReader { + isRunning = false; + voiceEnabled = false; + textEnabled = false; + private storyDocument: Document | null = null; + private lastAnnouncedElement: Element | null = null; + + // Bound handlers for proper cleanup + private handleFocusIn: (event: FocusEvent) => void; + private handleKeyDown: (event: KeyboardEvent) => void; + private handleMutation: (mutations: MutationRecord[]) => void; + + private mutationObserver: MutationObserver | null = null; + private liveRegionObserver: MutationObserver | null = null; + + constructor() { + this.handleFocusIn = this.onFocusIn.bind(this); + this.handleKeyDown = this.onKeyDown.bind(this); + this.handleMutation = this.onMutation.bind(this); + } + + /** + * Compute the accessible role for an element + * Priority: explicit role > implicit role from aria-query > fallback mapping + */ + computeRole(element: Element | null): string { + if (!element) { + return 'element'; + } + + // 1. Check explicit ARIA role + const explicitRole = element.getAttribute('role'); + if (explicitRole) { + return explicitRole; + } + + // 2. Try to get implicit role from aria-query + const implicitRole = getImplicitRole(element); + if (implicitRole) { + return implicitRole; + } + + // 3. Fallback mapping for common elements + const tagName = element.tagName ? element.tagName.toLowerCase() : ''; + const fallbackMappings: Record = { + a: element.hasAttribute('href') ? 'link' : 'generic', + button: 'button', + input: this.getInputRole(element as HTMLInputElement), + select: 'combobox', + textarea: 'textbox', + h1: 'heading', + h2: 'heading', + h3: 'heading', + h4: 'heading', + h5: 'heading', + h6: 'heading', + p: 'paragraph', + img: 'img', + nav: 'navigation', + main: 'main', + aside: 'complementary', + header: 'banner', + footer: 'contentinfo', + li: 'listitem', + ul: 'list', + ol: 'list', + table: 'table', + details: 'group', + summary: 'button', + label: 'generic', + section: + element.hasAttribute('aria-label') || + element.hasAttribute('aria-labelledby') + ? 'region' + : 'generic', + article: 'article', + form: 'form', + dialog: 'dialog', + }; + + return fallbackMappings[tagName] || 'generic'; + } + + /** + * Get role for input elements based on type + */ + getInputRole(element: HTMLInputElement): string { + const type = (element.getAttribute('type') || 'text').toLowerCase(); + const inputRoles: Record = { + checkbox: 'checkbox', + radio: 'radio', + button: 'button', + submit: 'button', + reset: 'button', + image: 'button', + range: 'slider', + search: 'searchbox', + email: 'textbox', + tel: 'textbox', + url: 'textbox', + number: 'spinbutton', + password: 'textbox', + text: 'textbox', + }; + return inputRoles[type] || 'textbox'; + } + + /** + * Get accessible name using dom-accessibility-api (W3C AccName spec) + */ + getAccessibleName(element: Element | null): string { + if (!element) { + return ''; + } + + try { + return computeAccessibleName(element, { + // Compute name even for elements that normally wouldn't have one + computedStyleSupportsPseudoElements: true, + }); + } catch { + // Fallback for Shadow DOM elements that might not work with the library + if (element.getAttribute('aria-label')) { + return element.getAttribute('aria-label') || ''; + } + if ((element as Element & { shadowRoot: ShadowRoot }).shadowRoot) { + const slot = ( + element as Element & { shadowRoot: ShadowRoot } + ).shadowRoot.querySelector('slot'); + if (slot) { + const nodes = (slot as HTMLSlotElement).assignedNodes({ + flatten: true, + }); + return nodes + .map((n) => n.textContent || '') + .join('') + .trim(); + } + } + return (element.textContent || '').trim(); + } + } + + /** + * Get accessible description using dom-accessibility-api + */ + getAccessibleDescription(element: Element | null): string { + if (!element) { + return ''; + } + + try { + return computeAccessibleDescription(element); + } catch { + return ''; + } + } + + /** + * Generate announcement for an element based on its role and state + */ + announceElement(element: Element | null): void { + if (!element || element === this.lastAnnouncedElement) { + return; + } + + this.lastAnnouncedElement = element; + + const role = this.computeRole(element); + const name = this.getAccessibleName(element); + const description = this.getAccessibleDescription(element); + + // Build the announcement based on role + let announcement = this.buildRoleAnnouncement(element, role, name); + + // Add description if available + if (description) { + announcement += ` ${description}`; + } + + if (announcement) { + this.say(announcement); + } + } + + /** + * Build announcement string based on role + */ + buildRoleAnnouncement( + element: Element, + role: string, + name: string + ): string { + const announcements: Record = { + link: () => { + const visited = element.matches(':visited') ? 'visited ' : ''; + return `${visited}Link, ${name || 'unlabeled'}. Press Enter to follow.`; + }, + button: () => { + const pressed = element.getAttribute('aria-pressed'); + const expanded = element.getAttribute('aria-expanded'); + let state = ''; + if (pressed === 'true') { + state = ', pressed'; + } else if (pressed === 'false') { + state = ', not pressed'; + } + if (expanded === 'true') { + state += ', expanded'; + } else if (expanded === 'false') { + state += ', collapsed'; + } + return `Button, ${name || 'unlabeled'}${state}. Press Space or Enter to activate.`; + }, + checkbox: () => { + const inputElement = element as HTMLInputElement; + const checked = + inputElement.checked || + element.getAttribute('aria-checked') === 'true'; + const mixed = element.getAttribute('aria-checked') === 'mixed'; + const state = mixed + ? 'partially checked' + : checked + ? 'checked' + : 'not checked'; + return `Checkbox, ${name || 'unlabeled'}, ${state}. Press Space to toggle.`; + }, + radio: () => { + const inputElement = element as HTMLInputElement; + const checked = + inputElement.checked || + element.getAttribute('aria-checked') === 'true'; + return `Radio button, ${name || 'unlabeled'}, ${checked ? 'selected' : 'not selected'}.`; + }, + switch: () => { + const inputElement = element as HTMLInputElement; + const checked = + element.getAttribute('aria-checked') === 'true' || + inputElement.checked; + return `Switch, ${name || 'unlabeled'}, ${checked ? 'on' : 'off'}. Press Space to toggle.`; + }, + textbox: () => { + const inputElement = element as HTMLInputElement; + const value = inputElement.value || ''; + const required = + element.hasAttribute('required') || + element.getAttribute('aria-required') === 'true'; + const invalid = element.getAttribute('aria-invalid') === 'true'; + const readonly = + element.hasAttribute('readonly') || + element.getAttribute('aria-readonly') === 'true'; + let state = ''; + if (required) { + state += ', required'; + } + if (invalid) { + state += ', invalid entry'; + } + if (readonly) { + state += ', read only'; + } + return `Text field, ${name || 'unlabeled'}${state}. ${value ? `Contains: ${value}` : 'Empty.'}`; + }, + searchbox: () => { + const inputElement = element as HTMLInputElement; + const value = inputElement.value || ''; + return `Search field, ${name || 'unlabeled'}. ${value ? `Contains: ${value}` : 'Empty.'}`; + }, + combobox: () => { + const expanded = + element.getAttribute('aria-expanded') === 'true'; + const selectElement = element as HTMLSelectElement; + const value = + (element as HTMLInputElement).value || + selectElement.options?.[selectElement.selectedIndex] + ?.text || + ''; + return `Combo box, ${name || 'unlabeled'}, ${expanded ? 'expanded' : 'collapsed'}. ${value ? `Selected: ${value}` : ''} Press Space to open.`; + }, + listbox: () => { + const expanded = element.getAttribute('aria-expanded'); + let state = ''; + if (expanded === 'true') { + state = ', expanded'; + } else if (expanded === 'false') { + state = ', collapsed'; + } + return `List box, ${name || 'unlabeled'}${state}.`; + }, + slider: () => { + const inputElement = element as HTMLInputElement; + const value = + inputElement.value || + element.getAttribute('aria-valuenow') || + ''; + const min = + inputElement.min || + element.getAttribute('aria-valuemin') || + '0'; + const max = + inputElement.max || + element.getAttribute('aria-valuemax') || + '100'; + const valueText = + element.getAttribute('aria-valuetext') || value; + return `Slider, ${name || 'unlabeled'}. Value: ${valueText}. Range: ${min} to ${max}.`; + }, + spinbutton: () => { + const inputElement = element as HTMLInputElement; + const value = + inputElement.value || + element.getAttribute('aria-valuenow') || + ''; + return `Spin button, ${name || 'unlabeled'}. Value: ${value}. Use arrow keys to adjust.`; + }, + heading: () => { + const level = + element.getAttribute('aria-level') || + (element.tagName + ? element.tagName.match(/h(\d)/i)?.[1] + : null) || + '2'; + return `Heading level ${level}, ${name}`; + }, + img: () => { + if (!name && element.getAttribute('alt') === '') { + return ''; // Decorative image, don't announce + } + return `Image, ${name || 'no description'}`; + }, + figure: () => `Figure, ${name || ''}`, + listitem: () => { + const list = element.closest('ol, ul, [role="list"]'); + const items = list + ? list.querySelectorAll('li, [role="listitem"]') + : []; + const index = Array.from(items).indexOf(element) + 1; + const total = items.length; + return `${name}. List item ${index} of ${total}.`; + }, + option: () => { + const optionElement = element as HTMLOptionElement; + const selected = + element.getAttribute('aria-selected') === 'true' || + optionElement.selected; + const list = element.closest('[role="listbox"], select'); + const options = list + ? list.querySelectorAll('[role="option"], option') + : []; + const index = Array.from(options).indexOf(element) + 1; + return `${name}${selected ? ', selected' : ''}. Option ${index} of ${options.length}.`; + }, + menuitem: () => `Menu item, ${name}`, + menuitemcheckbox: () => { + const checked = element.getAttribute('aria-checked') === 'true'; + return `Menu item checkbox, ${name}, ${checked ? 'checked' : 'not checked'}`; + }, + menuitemradio: () => { + const checked = element.getAttribute('aria-checked') === 'true'; + return `Menu item radio, ${name}, ${checked ? 'selected' : 'not selected'}`; + }, + tab: () => { + const selected = + element.getAttribute('aria-selected') === 'true'; + const tablist = element.closest('[role="tablist"]'); + const tabs = tablist + ? tablist.querySelectorAll('[role="tab"]') + : []; + const index = Array.from(tabs).indexOf(element) + 1; + return `Tab, ${name}${selected ? ', selected' : ''}. ${index} of ${tabs.length}.`; + }, + tabpanel: () => `Tab panel, ${name}`, + navigation: () => `Navigation${name ? `, ${name}` : ''}`, + main: () => `Main content${name ? `, ${name}` : ''}`, + banner: () => `Banner${name ? `, ${name}` : ''}`, + contentinfo: () => `Content info${name ? `, ${name}` : ''}`, + complementary: () => `Complementary${name ? `, ${name}` : ''}`, + region: () => `Region, ${name}`, + article: () => `Article${name ? `, ${name}` : ''}`, + form: () => `Form${name ? `, ${name}` : ''}`, + search: () => `Search${name ? `, ${name}` : ''}`, + dialog: () => { + const modal = element.getAttribute('aria-modal') === 'true'; + return `${modal ? 'Modal ' : ''}Dialog, ${name || 'unlabeled'}`; + }, + alertdialog: () => `Alert dialog, ${name || 'unlabeled'}`, + alert: () => `Alert: ${name}`, + status: () => `Status: ${name}`, + log: () => `Log: ${name}`, + marquee: () => `Marquee: ${name}`, + timer: () => `Timer: ${name}`, + progressbar: () => { + const value = element.getAttribute('aria-valuenow'); + const valueText = element.getAttribute('aria-valuetext'); + if (valueText) { + return `Progress bar, ${name}. ${valueText}`; + } + if (value) { + return `Progress bar, ${name}. ${value} percent`; + } + return `Progress bar, ${name}. Loading...`; + }, + meter: () => { + const meterElement = element as HTMLMeterElement; + const value = + element.getAttribute('aria-valuenow') || meterElement.value; + return `Meter, ${name}. Value: ${value}`; + }, + tooltip: () => `Tooltip: ${name}`, + tree: () => `Tree, ${name}`, + treeitem: () => { + const expanded = element.getAttribute('aria-expanded'); + const selected = + element.getAttribute('aria-selected') === 'true'; + let state = selected ? ', selected' : ''; + if (expanded === 'true') { + state += ', expanded'; + } else if (expanded === 'false') { + state += ', collapsed'; + } + return `Tree item, ${name}${state}`; + }, + grid: () => `Grid, ${name}`, + gridcell: () => name, + row: () => { + const index = element.getAttribute('aria-rowindex'); + return index ? `Row ${index}, ${name}` : name; + }, + rowheader: () => `Row header, ${name}`, + columnheader: () => `Column header, ${name}`, + cell: () => name, + table: () => { + const rows = + element.querySelectorAll('tr, [role="row"]').length; + const cols = + element.querySelector('tr, [role="row"]')?.children + .length || 0; + return `Table, ${name || 'unlabeled'}. ${rows} rows, ${cols} columns.`; + }, + list: () => { + const items = element.querySelectorAll( + 'li, [role="listitem"]' + ).length; + return `List${name ? `, ${name}` : ''}. ${items} items.`; + }, + menu: () => `Menu, ${name}`, + menubar: () => `Menu bar, ${name}`, + toolbar: () => `Toolbar, ${name}`, + group: () => (name ? `Group, ${name}` : ''), + separator: () => 'Separator', + generic: () => name || '', + }; + + const announceFn = announcements[role]; + return announceFn ? announceFn() : name || `${role}`; + } + + /** + * Add visual focus indicator styles to the document + */ + addStyles(): void { + if (!this.storyDocument || !this.storyDocument.head) { + return; + } + + this.removeStyles(); + + const styleElement = this.storyDocument.createElement('style'); + styleElement.id = 'screen-reader-addon-styles'; + styleElement.textContent = ` + [data-sr-current] { + outline: 3px solid #005fcc !important; + outline-offset: 2px !important; + } + `; + this.storyDocument.head.appendChild(styleElement); + } + + /** + * Remove visual focus indicator styles + */ + removeStyles(): void { + if (!this.storyDocument) { + return; + } + const styles = this.storyDocument.getElementById( + 'screen-reader-addon-styles' + ); + if (styles) { + styles.remove(); + } + } + + /** + * Speak/display the announcement + */ + say(speech: string): void { + if (!speech) { + return; + } + + if (this.voiceEnabled) { + const utterance = new SpeechSynthesisUtterance(speech); + speechSynthesis.cancel(); + speechSynthesis.speak(utterance); + } + + if (this.textEnabled) { + dispatchTextChanged(speech); + } + } + + /** + * Update visual focus indicator + */ + updateFocusIndicator(element: Element | null): void { + if (!element) { + return; + } + + // Remove previous focus indicator + const prev = querySelectorDeep( + '[data-sr-current]', + this.storyDocument as Document + ); + if (prev) { + prev.removeAttribute('data-sr-current'); + } + + // Add focus indicator to current element + if (element.setAttribute) { + element.setAttribute('data-sr-current', 'true'); + } + } + + /** + * Find the deeply focused element, traversing into shadow DOMs + */ + getDeepActiveElement( + root: Document | ShadowRoot = this.storyDocument as Document + ): Element | null { + let active = root.activeElement; + + // Keep traversing into shadow roots to find the actual focused element + while (active && active.shadowRoot && active.shadowRoot.activeElement) { + active = active.shadowRoot.activeElement; + } + + return active; + } + + /** + * Handle focus changes - main way we track navigation + * + * Real screen readers announce the actual focused element (often inside shadow DOM). + * We traverse into shadow DOM to find the real focused element, just like browsers do. + */ + private onFocusIn(event: FocusEvent): void { + if (!this.isRunning) { + return; + } + + const target = event.target as Element | null; + if (!target) { + return; + } + + // Find the actual focused element (may be deep inside shadow DOM) + const deepActive = this.getDeepActiveElement(); + + // Use the deep active element if it has a name, otherwise use the event target + const deepName = deepActive ? this.getAccessibleName(deepActive) : ''; + const deepRole = deepActive ? this.computeRole(deepActive) : 'generic'; + + // Prefer the deep element if it has a meaningful name and role + const elementToAnnounce = + deepName && deepRole !== 'generic' ? deepActive : target; + + this.updateFocusIndicator(elementToAnnounce); + this.announceElement(elementToAnnounce); + } + + /** + * Handle keyboard events for additional navigation feedback + */ + private onKeyDown(event: KeyboardEvent): void { + if (!this.isRunning) { + return; + } + + // After arrow key navigation, check if aria-activedescendant changed + if ( + ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].indexOf( + event.key + ) !== -1 + ) { + setTimeout(() => { + this.checkActiveDescendant(event.target as Element); + }, 10); + } + } + + /** + * Check for aria-activedescendant changes (used by menus, listboxes, etc.) + */ + checkActiveDescendant(element: Element | null): void { + if (!element) { + return; + } + + const activeId = element.getAttribute('aria-activedescendant'); + if (activeId && this.storyDocument) { + const activeElement = this.storyDocument.getElementById(activeId); + if (activeElement) { + this.updateFocusIndicator(activeElement); + this.announceElement(activeElement); + return; + } + } + + // Also check shadow DOM for the active element + const elementWithShadow = element as Element & { + shadowRoot?: ShadowRoot; + }; + if (elementWithShadow.shadowRoot) { + const activeInShadow = elementWithShadow.shadowRoot.querySelector( + '[aria-selected="true"], [aria-current="true"], :focus' + ); + if (activeInShadow) { + this.updateFocusIndicator(activeInShadow); + this.announceElement(activeInShadow); + } + } + } + + /** + * Watch for DOM mutations to catch dynamic changes + */ + private onMutation(mutations: MutationRecord[]): void { + if (!this.isRunning) { + return; + } + + const watchedAttrs = [ + 'aria-selected', + 'aria-checked', + 'aria-expanded', + 'aria-activedescendant', + 'aria-pressed', + 'aria-invalid', + ]; + + mutations.forEach((mutation) => { + if (mutation.type === 'attributes') { + const target = mutation.target as Element; + + if ( + mutation.attributeName && + watchedAttrs.indexOf(mutation.attributeName) !== -1 + ) { + if (mutation.attributeName === 'aria-activedescendant') { + this.checkActiveDescendant(target); + } else if ( + target.getAttribute(mutation.attributeName) === + 'true' && + mutation.attributeName === 'aria-selected' + ) { + this.updateFocusIndicator(target); + this.announceElement(target); + } + } + } + }); + } + + /** + * Watch for live region updates (aria-live) + */ + private onLiveRegionMutation(mutations: MutationRecord[]): void { + if (!this.isRunning) { + return; + } + + mutations.forEach((mutation) => { + const target = mutation.target as Element; + + // Check if this is inside a live region + const liveRegion = ( + target.closest ? target : (target.parentElement as Element) + )?.closest( + '[aria-live], [role="alert"], [role="status"], [role="log"]' + ); + if (!liveRegion) { + return; + } + + const politeness = + liveRegion.getAttribute('aria-live') || + (liveRegion.getAttribute('role') === 'alert' + ? 'assertive' + : 'polite'); + + // Get the new content + let announcement = ''; + if (mutation.type === 'childList') { + mutation.addedNodes.forEach((node) => { + if (node.textContent) { + announcement += node.textContent.trim() + ' '; + } + }); + } else if (mutation.type === 'characterData') { + announcement = target.textContent || ''; + } + + if (announcement.trim()) { + // For assertive, interrupt current speech + if (politeness === 'assertive') { + speechSynthesis.cancel(); + } + this.say(announcement.trim()); + } + }); + } + + /** + * Set up mutation observer for aria attribute changes + */ + setupMutationObserver(): void { + if (!this.storyDocument || !this.storyDocument.body) { + return; + } + + this.mutationObserver = new MutationObserver(this.handleMutation); + this.mutationObserver.observe(this.storyDocument.body, { + attributes: true, + subtree: true, + attributeFilter: [ + 'aria-selected', + 'aria-checked', + 'aria-expanded', + 'aria-activedescendant', + 'aria-pressed', + 'aria-invalid', + ], + }); + } + + /** + * Set up observer for live regions + */ + setupLiveRegionObserver(): void { + if (!this.storyDocument || !this.storyDocument.body) { + return; + } + + this.liveRegionObserver = new MutationObserver( + this.onLiveRegionMutation.bind(this) + ); + this.liveRegionObserver.observe(this.storyDocument.body, { + childList: true, + subtree: true, + characterData: true, + }); + } + + /** + * Start the screen reader + */ + start(iframe?: HTMLIFrameElement | null): void { + let targetIframe = iframe; + if (!targetIframe) { + targetIframe = + (document.getElementById( + 'storybook-preview-iframe' + ) as HTMLIFrameElement) || + (document.querySelector( + 'iframe[data-is-storybook="true"]' + ) as HTMLIFrameElement) || + (document.querySelector('iframe') as HTMLIFrameElement); + } + + if ( + !targetIframe || + !targetIframe.contentWindow || + !targetIframe.contentWindow.document || + !targetIframe.contentWindow.document.body + ) { + // eslint-disable-next-line no-console + console.warn('[Screen Reader] Waiting for iframe...'); + setTimeout(() => { + this.start(targetIframe); + }, 200); + return; + } + + // Stop any existing instance first + this.stop(); + + this.storyDocument = targetIframe.contentWindow.document; + + // Wait for document to be ready + if (this.storyDocument.readyState === 'loading') { + this.storyDocument.addEventListener('DOMContentLoaded', () => { + this.start(targetIframe); + }); + return; + } + + this.addStyles(); + + // Listen for focus changes + this.storyDocument.addEventListener( + 'focusin', + this.handleFocusIn as EventListener, + true + ); + this.storyDocument.addEventListener( + 'keydown', + this.handleKeyDown as EventListener, + true + ); + + // Set up mutation observers + this.setupMutationObserver(); + this.setupLiveRegionObserver(); + + this.isRunning = true; + this.lastAnnouncedElement = null; + + this.say('Screen reader enabled. Use Tab or arrow keys to navigate.'); + + // Announce current focus if any + const currentFocus = this.storyDocument.activeElement; + if (currentFocus && currentFocus !== this.storyDocument.body) { + this.updateFocusIndicator(currentFocus); + this.announceElement(currentFocus); + } + } + + /** + * Stop the screen reader + */ + stop(): void { + if (!this.isRunning && !this.storyDocument) { + return; + } + + // Clean up event listeners + if (this.storyDocument) { + this.storyDocument.removeEventListener( + 'focusin', + this.handleFocusIn as EventListener, + true + ); + this.storyDocument.removeEventListener( + 'keydown', + this.handleKeyDown as EventListener, + true + ); + } + + // Clean up mutation observers + if (this.mutationObserver) { + this.mutationObserver.disconnect(); + this.mutationObserver = null; + } + + if (this.liveRegionObserver) { + this.liveRegionObserver.disconnect(); + this.liveRegionObserver = null; + } + + // Remove focus indicator + if (this.storyDocument) { + const current = querySelectorDeep( + '[data-sr-current]', + this.storyDocument + ); + if (current) { + current.removeAttribute('data-sr-current'); + } + this.removeStyles(); + } + + this.isRunning = false; + this.lastAnnouncedElement = null; + + if (this.voiceEnabled || this.textEnabled) { + this.say('Screen reader disabled'); + } + } +} diff --git a/1st-gen/projects/screen-reader-addon/tsconfig.json b/1st-gen/projects/screen-reader-addon/tsconfig.json new file mode 100644 index 00000000000..351e1b25732 --- /dev/null +++ b/1st-gen/projects/screen-reader-addon/tsconfig.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "moduleResolution": "node", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "declaration": false, + "strict": true, + "noImplicitAny": true, + "strictNullChecks": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "experimentalDecorators": true, + "useDefineForClassFields": false, + "jsx": "react", + "skipLibCheck": true, + "outDir": "./dist", + "rootDir": "./src" + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules", "dist"] +} diff --git a/1st-gen/storybook/main.js b/1st-gen/storybook/main.js index f667a37c9e9..2a307fe08f5 100644 --- a/1st-gen/storybook/main.js +++ b/1st-gen/storybook/main.js @@ -30,8 +30,8 @@ export default { : []), // https://geometricpanda.github.io/storybook-addon-badges/ '@geometricpanda/storybook-addon-badges', - // Screen reader addon: https://www.npmjs.com/package/storybook-screen-reader - 'storybook-screen-reader', + // Screen reader addon (local build) + '../projects/screen-reader-addon', ], framework: { name: '@storybook/web-components-webpack5', diff --git a/2nd-gen/packages/core/shared/base/version.ts b/2nd-gen/packages/core/shared/base/version.ts index 2177cdd7401..622cc87119d 100644 --- a/2nd-gen/packages/core/shared/base/version.ts +++ b/2nd-gen/packages/core/shared/base/version.ts @@ -1,13 +1,2 @@ -/** - * Copyright 2025 Adobe. All rights reserved. - * This file is licensed to you under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS - * OF ANY KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ // Generated by genversion. export const version = '1.10.0'; diff --git a/package.json b/package.json index f5cb45400c1..5acd99fdafa 100644 --- a/package.json +++ b/package.json @@ -27,13 +27,13 @@ "start:1st-gen": "yarn workspace @spectrum-web-components/1st-gen start", "start:2nd-gen": "yarn workspace @spectrum-web-components/2nd-gen start", "test": "run-p test:2nd-gen test:1st-gen", + "test:1st-gen": "yarn workspace @spectrum-web-components/1st-gen test", + "test:2nd-gen": "yarn workspace @spectrum-web-components/2nd-gen test", "test:a11y": "playwright test --config=playwright.a11y.config.ts", - "test:a11y:ui": "playwright test --config=playwright.a11y.config.ts --ui", "test:a11y:1st": "playwright test --config=playwright.a11y.config.ts --project=1st-gen", "test:a11y:2nd": "playwright test --config=playwright.a11y.config.ts --project=2nd-gen", "test:a11y:report": "playwright show-report 2nd-gen/test/playwright-a11y/report", - "test:1st-gen": "yarn workspace @spectrum-web-components/1st-gen test", - "test:2nd-gen": "yarn workspace @spectrum-web-components/2nd-gen test" + "test:a11y:ui": "playwright test --config=playwright.a11y.config.ts --ui" }, "workspaces": [ "1st-gen", diff --git a/yarn.lock b/yarn.lock index 124cce09e10..7fca01b83e8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4014,16 +4014,6 @@ __metadata: languageName: node linkType: hard -"@lit-labs/observers@npm:^2.0.2": - version: 2.0.6 - resolution: "@lit-labs/observers@npm:2.0.6" - dependencies: - "@lit/reactive-element": "npm:^1.0.0 || ^2.0.0" - lit-html: "npm:^3.2.0" - checksum: 10c0/2e9559beb3b48af9ad6ac4593ec3a15cb8600cf9867ff7b07eb19cc543dc2b5d87aabdd072f007cb389c79bf3a0ef517cebc292e97d95f7153deb1166c66bef1 - languageName: node - linkType: hard - "@lit-labs/react@npm:^1.0.2": version: 1.2.1 resolution: "@lit-labs/react@npm:1.2.1" @@ -4048,7 +4038,7 @@ __metadata: languageName: node linkType: hard -"@lit/react@npm:1.0.8, @lit/react@npm:^1.0.0": +"@lit/react@npm:1.0.8": version: 1.0.8 resolution: "@lit/react@npm:1.0.8" peerDependencies: @@ -5423,7 +5413,6 @@ __metadata: rollup: "npm:4.52.2" sinon: "npm:17.0.2" storybook: "npm:8.6.14" - storybook-screen-reader: "npm:1.1.0" stylelint: "npm:16.24.0" stylelint-config-standard: "npm:38.0.0" stylelint-header: "npm:3.0.0" @@ -5572,15 +5561,6 @@ __metadata: languageName: unknown linkType: soft -"@spectrum-web-components/base@npm:^0.42.5": - version: 0.42.5 - resolution: "@spectrum-web-components/base@npm:0.42.5" - dependencies: - lit: "npm:^2.5.0 || ^3.1.3" - checksum: 10c0/08a82ed97b2333333438494930fcb2da267f49cab94a7b0e2463d36b50603494db78c268093b7dc643ee016d569ceebe53f04a46ebf990117b1f483773205f6b - languageName: node - linkType: hard - "@spectrum-web-components/breadcrumbs@npm:1.10.0, @spectrum-web-components/breadcrumbs@workspace:1st-gen/packages/breadcrumbs": version: 0.0.0-use.local resolution: "@spectrum-web-components/breadcrumbs@workspace:1st-gen/packages/breadcrumbs" @@ -5727,18 +5707,6 @@ __metadata: languageName: unknown linkType: soft -"@spectrum-web-components/checkbox@npm:^0.42.5": - version: 0.42.5 - resolution: "@spectrum-web-components/checkbox@npm:0.42.5" - dependencies: - "@spectrum-web-components/base": "npm:^0.42.5" - "@spectrum-web-components/icon": "npm:^0.42.5" - "@spectrum-web-components/icons-ui": "npm:^0.42.5" - "@spectrum-web-components/shared": "npm:^0.42.5" - checksum: 10c0/a9d9b423b9ff18f790d79d63d50a4112fc5ecacf3d87ed53fc749a306b6bce20235cb21c483bc8f0a1fa68dfc99c1c1be410b297324ee7ab39df160ca5717c7f - languageName: node - linkType: hard - "@spectrum-web-components/clear-button@npm:1.10.0, @spectrum-web-components/clear-button@workspace:1st-gen/packages/clear-button": version: 0.0.0-use.local resolution: "@spectrum-web-components/clear-button@workspace:1st-gen/packages/clear-button" @@ -6019,16 +5987,6 @@ __metadata: languageName: unknown linkType: soft -"@spectrum-web-components/icon@npm:^0.42.5": - version: 0.42.5 - resolution: "@spectrum-web-components/icon@npm:0.42.5" - dependencies: - "@spectrum-web-components/base": "npm:^0.42.5" - "@spectrum-web-components/iconset": "npm:^0.42.5" - checksum: 10c0/6ed5122ee9118c6955cd035ebb27e13a841f62f438d0676ce9168eb396acc7a53a7fe223daebcd1b3a7095ad9c4010241553b415df814670e4c05be549f4f3ac - languageName: node - linkType: hard - "@spectrum-web-components/icons-ui@npm:1.10.0, @spectrum-web-components/icons-ui@workspace:1st-gen/packages/icons-ui": version: 0.0.0-use.local resolution: "@spectrum-web-components/icons-ui@workspace:1st-gen/packages/icons-ui" @@ -6045,17 +6003,6 @@ __metadata: languageName: unknown linkType: soft -"@spectrum-web-components/icons-ui@npm:^0.42.5": - version: 0.42.5 - resolution: "@spectrum-web-components/icons-ui@npm:0.42.5" - dependencies: - "@spectrum-web-components/base": "npm:^0.42.5" - "@spectrum-web-components/icon": "npm:^0.42.5" - "@spectrum-web-components/iconset": "npm:^0.42.5" - checksum: 10c0/0ae35daaeeefcb7635569e971d66b9e91d3c3e14dde135c9ab44f7f5963eca49f958a327599fc079543ac87bfffb4f6f6588182aa8c9ac9f176711aeb1502336 - languageName: node - linkType: hard - "@spectrum-web-components/icons-workflow@npm:1.10.0, @spectrum-web-components/icons-workflow@workspace:1st-gen/packages/icons-workflow": version: 0.0.0-use.local resolution: "@spectrum-web-components/icons-workflow@workspace:1st-gen/packages/icons-workflow" @@ -6088,15 +6035,6 @@ __metadata: languageName: unknown linkType: soft -"@spectrum-web-components/iconset@npm:^0.42.5": - version: 0.42.5 - resolution: "@spectrum-web-components/iconset@npm:0.42.5" - dependencies: - "@spectrum-web-components/base": "npm:^0.42.5" - checksum: 10c0/11a50d3e8f978c7a37e564ea0dc798555381f280a792b42ce5e5cab5fb3de241c1dd919356e0f25da7870709a11ac59df3b93bb2425ca72122cf52785cd42d27 - languageName: node - linkType: hard - "@spectrum-web-components/illustrated-message@npm:1.10.0, @spectrum-web-components/illustrated-message@workspace:1st-gen/packages/illustrated-message": version: 0.0.0-use.local resolution: "@spectrum-web-components/illustrated-message@workspace:1st-gen/packages/illustrated-message" @@ -6284,6 +6222,27 @@ __metadata: languageName: unknown linkType: soft +"@spectrum-web-components/screen-reader-addon@workspace:1st-gen/projects/screen-reader-addon": + version: 0.0.0-use.local + resolution: "@spectrum-web-components/screen-reader-addon@workspace:1st-gen/projects/screen-reader-addon" + dependencies: + aria-query: "npm:^5.3.0" + dom-accessibility-api: "npm:^0.7.0" + esbuild: "npm:0.21.5" + query-selector-shadow-dom: "npm:^1.0.0" + typescript: "npm:5.3.3" + peerDependencies: + "@lit/react": ">=1.0.0" + "@spectrum-web-components/switch": ">=1.0.0" + "@spectrum-web-components/theme": ">=1.0.0" + "@storybook/components": ">=8.0.0" + "@storybook/core-events": ">=8.0.0" + "@storybook/manager-api": ">=8.0.0" + lit: ^2.5.0 || ^3.1.3 + react: ">=18.0.0" + languageName: unknown + linkType: soft + "@spectrum-web-components/search@npm:1.10.0, @spectrum-web-components/search@workspace:1st-gen/packages/search": version: 0.0.0-use.local resolution: "@spectrum-web-components/search@workspace:1st-gen/packages/search" @@ -6306,17 +6265,6 @@ __metadata: languageName: unknown linkType: soft -"@spectrum-web-components/shared@npm:^0.42.5": - version: 0.42.5 - resolution: "@spectrum-web-components/shared@npm:0.42.5" - dependencies: - "@lit-labs/observers": "npm:^2.0.2" - "@spectrum-web-components/base": "npm:^0.42.5" - focus-visible: "npm:^5.1.0" - checksum: 10c0/f363155ed97885875dcd415ee3dce4a6b0325978c492d9b12ad11412c4f9d421789de1e81bc9ea1dbde86f363bc841f184dd70df5aef62e2e9320d44a937448f - languageName: node - linkType: hard - "@spectrum-web-components/sidenav@npm:1.10.0, @spectrum-web-components/sidenav@workspace:1st-gen/packages/sidenav": version: 0.0.0-use.local resolution: "@spectrum-web-components/sidenav@workspace:1st-gen/packages/sidenav" @@ -6386,15 +6334,6 @@ __metadata: languageName: unknown linkType: soft -"@spectrum-web-components/styles@npm:^0.42.5": - version: 0.42.5 - resolution: "@spectrum-web-components/styles@npm:0.42.5" - dependencies: - "@spectrum-web-components/base": "npm:^0.42.5" - checksum: 10c0/caf5bbb0b8ee67da2f79c31883e17055e4d4cae828d588c5cf5c49efd5495ce558a3e6014077364e50327f291a6d909ec0e97926d731cb49756c83ed3d66a1c0 - languageName: node - linkType: hard - "@spectrum-web-components/swatch@npm:1.10.0, @spectrum-web-components/swatch@workspace:1st-gen/packages/swatch": version: 0.0.0-use.local resolution: "@spectrum-web-components/swatch@workspace:1st-gen/packages/swatch" @@ -6418,16 +6357,6 @@ __metadata: languageName: unknown linkType: soft -"@spectrum-web-components/switch@npm:^0.42.0": - version: 0.42.5 - resolution: "@spectrum-web-components/switch@npm:0.42.5" - dependencies: - "@spectrum-web-components/base": "npm:^0.42.5" - "@spectrum-web-components/checkbox": "npm:^0.42.5" - checksum: 10c0/cbb37673876f05d68d920bf457e2da08212bdccb90992a68b0690cb8667a3258e68028c33f8bf4770df519d8a28459fd72b43ccf8517e471a7e857b704131d7d - languageName: node - linkType: hard - "@spectrum-web-components/table@npm:1.10.0, @spectrum-web-components/table@workspace:1st-gen/packages/table": version: 0.0.0-use.local resolution: "@spectrum-web-components/table@workspace:1st-gen/packages/table" @@ -6489,16 +6418,6 @@ __metadata: languageName: unknown linkType: soft -"@spectrum-web-components/theme@npm:^0.42.0": - version: 0.42.5 - resolution: "@spectrum-web-components/theme@npm:0.42.5" - dependencies: - "@spectrum-web-components/base": "npm:^0.42.5" - "@spectrum-web-components/styles": "npm:^0.42.5" - checksum: 10c0/092099b7ccbf6f8a213e01fef18f7555024ceb16568c07de2e78ff5a5ea74bffff4fcfe552c90fbf7fe2ca497715a9de0a97372ea44cfbfb3e4f3ead0c44fa8b - languageName: node - linkType: hard - "@spectrum-web-components/thumbnail@npm:1.10.0, @spectrum-web-components/thumbnail@workspace:1st-gen/packages/thumbnail": version: 0.0.0-use.local resolution: "@spectrum-web-components/thumbnail@workspace:1st-gen/packages/thumbnail" @@ -7030,15 +6949,6 @@ __metadata: languageName: node linkType: hard -"@storybook/core-events@npm:^8.0.0": - version: 8.6.14 - resolution: "@storybook/core-events@npm:8.6.14" - peerDependencies: - storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - checksum: 10c0/8fc9941e3ef9954ed82a845e29867ba4bcc2e0c1749c1ab6a916a24d3941d878cc509769b6c0c073e78ec91d22c7895787219bb6b5d3e787c8223963dbef6b3e - languageName: node - linkType: hard - "@storybook/core-webpack@npm:8.6.14": version: 8.6.14 resolution: "@storybook/core-webpack@npm:8.6.14" @@ -7193,7 +7103,7 @@ __metadata: languageName: node linkType: hard -"@storybook/manager-api@npm:8.6.14, @storybook/manager-api@npm:^8.0.0": +"@storybook/manager-api@npm:8.6.14": version: 8.6.14 resolution: "@storybook/manager-api@npm:8.6.14" peerDependencies: @@ -10528,7 +10438,7 @@ __metadata: languageName: node linkType: hard -"aria-query@npm:^5.0.0, aria-query@npm:^5.1.3": +"aria-query@npm:^5.0.0, aria-query@npm:^5.1.3, aria-query@npm:^5.3.0": version: 5.3.2 resolution: "aria-query@npm:5.3.2" checksum: 10c0/003c7e3e2cff5540bf7a7893775fc614de82b0c5dde8ae823d47b7a28a9d4da1f7ed85f340bdb93d5649caa927755f0e31ecc7ab63edfdfc00c8ef07e505e03e @@ -13767,6 +13677,13 @@ __metadata: languageName: node linkType: hard +"dom-accessibility-api@npm:^0.7.0": + version: 0.7.1 + resolution: "dom-accessibility-api@npm:0.7.1" + checksum: 10c0/1667710482e373913d610828c3eba062165bd747f7d7b5309d70a8ef02ebe14d3f26ec1b2a8edb6d9c9c045bd755426fdc87941e88d70c0e9907fd1ba762b277 + languageName: node + linkType: hard + "dom-converter@npm:^0.2.0": version: 0.2.0 resolution: "dom-converter@npm:0.2.0" @@ -16021,7 +15938,7 @@ __metadata: languageName: node linkType: hard -"focus-visible@npm:5.2.1, focus-visible@npm:^5.1.0": +"focus-visible@npm:5.2.1": version: 5.2.1 resolution: "focus-visible@npm:5.2.1" checksum: 10c0/1c0e4e8b22be8684a664acc340efd6a41aafb560ce09979186a1c934de321ce8d6a3d7175c946aab1c87409b0e10f623274d7ce7d42ff16a0e4dc862fa151623 @@ -20422,7 +20339,7 @@ __metadata: languageName: node linkType: hard -"lit-html@npm:^2.0.0 || ^3.0.0, lit-html@npm:^2.4.0 || ^3.1.3, lit-html@npm:^3.2.0, lit-html@npm:^3.3.0": +"lit-html@npm:^2.0.0 || ^3.0.0, lit-html@npm:^2.4.0 || ^3.1.3, lit-html@npm:^3.3.0": version: 3.3.1 resolution: "lit-html@npm:3.3.1" dependencies: @@ -26164,7 +26081,7 @@ __metadata: languageName: node linkType: hard -"react@npm:18.3.1, react@npm:^18.2.0": +"react@npm:18.3.1": version: 18.3.1 resolution: "react@npm:18.3.1" dependencies: @@ -28332,22 +28249,6 @@ __metadata: languageName: node linkType: hard -"storybook-screen-reader@npm:1.1.0": - version: 1.1.0 - resolution: "storybook-screen-reader@npm:1.1.0" - dependencies: - "@lit/react": "npm:^1.0.0" - "@spectrum-web-components/switch": "npm:^0.42.0" - "@spectrum-web-components/theme": "npm:^0.42.0" - "@storybook/core-events": "npm:^8.0.0" - "@storybook/manager-api": "npm:^8.0.0" - lit: "npm:^3.1.0" - query-selector-shadow-dom: "npm:^1.0.0" - react: "npm:^18.2.0" - checksum: 10c0/1a39dab767e4c5a77642fbe7c27a17fcccf150d060c7d21c67127f5b53e6762b46a33a3f80b2466354905f7f30657debabfb9fab899aa6ecc6d5a77fe3c12634 - languageName: node - linkType: hard - "storybook@npm:10.0.3": version: 10.0.3 resolution: "storybook@npm:10.0.3" From 01edbc78b9c4e7eb858d2bfce34a9c4901c28091 Mon Sep 17 00:00:00 2001 From: TarunAdobe Date: Thu, 11 Dec 2025 17:23:47 +0530 Subject: [PATCH 4/5] feat: let storybook build the addon --- 1st-gen/package.json | 19 +------ .../projects/screen-reader-addon/manager.js | 3 +- .../projects/screen-reader-addon/package.json | 49 +++++-------------- .../src/components/screen-reader-panel.ts | 30 +++++++----- .../screen-reader-addon/tsconfig.json | 24 --------- yarn.lock | 2 - 6 files changed, 34 insertions(+), 93 deletions(-) delete mode 100644 1st-gen/projects/screen-reader-addon/tsconfig.json diff --git a/1st-gen/package.json b/1st-gen/package.json index 5a67e8099ce..ed51613e68b 100644 --- a/1st-gen/package.json +++ b/1st-gen/package.json @@ -232,19 +232,6 @@ "command": "node ./scripts/watch-css.js", "service": true }, - "build:screen-reader-addon": { - "command": "yarn workspace @spectrum-web-components/screen-reader-addon build", - "files": [ - "projects/screen-reader-addon/src/**/*.ts", - "projects/screen-reader-addon/src/**/*.tsx", - "projects/screen-reader-addon/tsconfig.json", - "projects/screen-reader-addon/package.json", - "projects/screen-reader-addon/manager.js" - ], - "output": [ - "projects/screen-reader-addon/dist/**" - ] - }, "build:ts": { "clean": "if-file-deleted", "command": "node ./scripts/build-ts.js", @@ -282,8 +269,7 @@ "!projects/example-project-rollup", "!projects/example-project-webpack", "!projects/templates", - "!projects/screen-reader-addon/manager.js", - "!projects/screen-reader-addon/dist/**", + "!projects/screen-reader-addon/**", "tools/**/*.js", "tools/**/*.js.map", "!**/build.js", @@ -396,8 +382,7 @@ "prestorybook": { "command": "cem analyze --outdir storybook/", "dependencies": [ - "build:ts", - "build:screen-reader-addon" + "build:ts" ], "files": [ "packages/**/*.ts", diff --git a/1st-gen/projects/screen-reader-addon/manager.js b/1st-gen/projects/screen-reader-addon/manager.js index 458f2485bf5..509a2f28210 100644 --- a/1st-gen/projects/screen-reader-addon/manager.js +++ b/1st-gen/projects/screen-reader-addon/manager.js @@ -11,4 +11,5 @@ */ // Storybook manager addon entry point -import './dist/register.js'; +// Imports TypeScript source directly - Storybook's esbuild compiles on the fly +import './src/register.tsx'; diff --git a/1st-gen/projects/screen-reader-addon/package.json b/1st-gen/projects/screen-reader-addon/package.json index 8c156a4853f..7be3ce27199 100644 --- a/1st-gen/projects/screen-reader-addon/package.json +++ b/1st-gen/projects/screen-reader-addon/package.json @@ -8,24 +8,7 @@ "dom-accessibility-api": "^0.7.0", "query-selector-shadow-dom": "^1.0.0" }, - "peerDependencies": { - "@lit/react": ">=1.0.0", - "@spectrum-web-components/switch": ">=1.0.0", - "@spectrum-web-components/theme": ">=1.0.0", - "@storybook/components": ">=8.0.0", - "@storybook/core-events": ">=8.0.0", - "@storybook/manager-api": ">=8.0.0", - "lit": "^2.5.0 || ^3.1.3", - "react": ">=18.0.0" - }, "description": "A Screen Reader Storybook addon for accessibility testing", - "devDependencies": { - "esbuild": "0.21.5", - "typescript": "5.3.3" - }, - "files": [ - "dist/**/*" - ], "homepage": "https://opensource.adobe.com/spectrum-web-components/", "keywords": [ "storybook", @@ -37,32 +20,22 @@ "wcag" ], "license": "Apache-2.0", - "main": "dist/register.js", - "module": "dist/register.js", "name": "@spectrum-web-components/screen-reader-addon", + "peerDependencies": { + "@lit/react": ">=1.0.0", + "@spectrum-web-components/switch": ">=1.0.0", + "@spectrum-web-components/theme": ">=1.0.0", + "@storybook/components": ">=8.0.0", + "@storybook/core-events": ">=8.0.0", + "@storybook/manager-api": ">=8.0.0", + "lit": "^2.5.0 || ^3.1.3", + "react": ">=18.0.0" + }, "private": true, "repository": { "directory": "1st-gen/projects/screen-reader-addon", "type": "git", "url": "https://github.com/adobe/spectrum-web-components.git" }, - "scripts": { - "build": "esbuild src/register.tsx --bundle --outfile=dist/register.js --format=esm \"--external:@storybook/*\" \"--external:@spectrum-web-components/*\" \"--external:@lit/*\" --external:react --external:lit --platform=browser", - "typecheck": "tsc --noEmit" - }, - "version": "1.0.0", - "wireit": { - "build": { - "clean": "if-file-deleted", - "command": "esbuild src/register.tsx --bundle --outfile=dist/register.js --format=esm \"--external:@storybook/*\" \"--external:@spectrum-web-components/*\" \"--external:@lit/*\" --external:react --external:lit --platform=browser", - "files": [ - "src/**/*.ts", - "src/**/*.tsx", - "tsconfig.json" - ], - "output": [ - "dist/**" - ] - } - } + "version": "1.0.0" } diff --git a/1st-gen/projects/screen-reader-addon/src/components/screen-reader-panel.ts b/1st-gen/projects/screen-reader-addon/src/components/screen-reader-panel.ts index fa60224dcb3..54ab8361793 100644 --- a/1st-gen/projects/screen-reader-addon/src/components/screen-reader-panel.ts +++ b/1st-gen/projects/screen-reader-addon/src/components/screen-reader-panel.ts @@ -11,7 +11,6 @@ */ import { css, html, LitElement } from 'lit'; -import { property } from 'lit/decorators.js'; import { addons, type Channel } from '@storybook/manager-api'; import { STORY_CHANGED } from '@storybook/core-events'; @@ -29,17 +28,20 @@ interface ScreenReaderTextEvent extends CustomEvent { } export class ScreenReaderPanel extends LitElement { - @property({ type: Boolean }) - voice = false; - - @property({ type: Boolean }) - text = false; - - @property({ type: Boolean }) - isActive = false; + // Using static properties instead of decorators for compatibility + // with Storybook's internal esbuild (no decorator compilation needed) + static override properties = { + voice: { type: Boolean }, + text: { type: Boolean }, + isActive: { type: Boolean }, + screenReaderText: { type: String }, + }; - @property({ type: String }) - screenReaderText = ''; + // Use 'declare' to avoid class field definition overriding Lit's reactive properties + declare voice: boolean; + declare text: boolean; + declare isActive: boolean; + declare screenReaderText: string; private screenReader: ScreenReader | null = null; private channel: Channel | null = null; @@ -91,6 +93,12 @@ export class ScreenReaderPanel extends LitElement { constructor() { super(); + // Initialize reactive properties + this.voice = false; + this.text = false; + this.isActive = false; + this.screenReaderText = ''; + // Bind event handlers this.handleTextChange = this.handleTextChange.bind(this); this.handleStoryChange = this.handleStoryChange.bind(this); } diff --git a/1st-gen/projects/screen-reader-addon/tsconfig.json b/1st-gen/projects/screen-reader-addon/tsconfig.json deleted file mode 100644 index 351e1b25732..00000000000 --- a/1st-gen/projects/screen-reader-addon/tsconfig.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "module": "ESNext", - "moduleResolution": "node", - "lib": ["ES2020", "DOM", "DOM.Iterable"], - "declaration": false, - "strict": true, - "noImplicitAny": true, - "strictNullChecks": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "experimentalDecorators": true, - "useDefineForClassFields": false, - "jsx": "react", - "skipLibCheck": true, - "outDir": "./dist", - "rootDir": "./src" - }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules", "dist"] -} diff --git a/yarn.lock b/yarn.lock index 7fca01b83e8..d7627ef6a0c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6228,9 +6228,7 @@ __metadata: dependencies: aria-query: "npm:^5.3.0" dom-accessibility-api: "npm:^0.7.0" - esbuild: "npm:0.21.5" query-selector-shadow-dom: "npm:^1.0.0" - typescript: "npm:5.3.3" peerDependencies: "@lit/react": ">=1.0.0" "@spectrum-web-components/switch": ">=1.0.0" From 9c470bc53b5ef4fb2a4e36283347355512843df0 Mon Sep 17 00:00:00 2001 From: TarunAdobe Date: Thu, 11 Dec 2025 19:53:47 +0530 Subject: [PATCH 5/5] chore: move screen reader plugin to second-gen --- .gitignore | 1 - 1st-gen/package.json | 1 - 1st-gen/storybook/main.js | 4 +- 2nd-gen/packages/core/shared/base/version.ts | 11 ++ .../addons}/screen-reader-addon/manager.js | 0 .../addons}/screen-reader-addon/package.json | 5 +- .../src/components/screen-reader-panel.ts | 116 ++++++++++++------ .../screen-reader-addon/src/register.tsx | 0 .../src/screen-reader/screenReader.ts | 0 2nd-gen/packages/swc/.storybook/main.ts | 2 + 2nd-gen/packages/swc/package.json | 3 + yarn.lock | 22 +--- 12 files changed, 103 insertions(+), 62 deletions(-) rename {1st-gen/projects => 2nd-gen/packages/swc/.storybook/addons}/screen-reader-addon/manager.js (100%) rename {1st-gen/projects => 2nd-gen/packages/swc/.storybook/addons}/screen-reader-addon/package.json (82%) rename {1st-gen/projects => 2nd-gen/packages/swc/.storybook/addons}/screen-reader-addon/src/components/screen-reader-panel.ts (69%) rename {1st-gen/projects => 2nd-gen/packages/swc/.storybook/addons}/screen-reader-addon/src/register.tsx (100%) rename {1st-gen/projects => 2nd-gen/packages/swc/.storybook/addons}/screen-reader-addon/src/screen-reader/screenReader.ts (100%) diff --git a/.gitignore b/.gitignore index 4cc43a102e4..379468a2d9c 100644 --- a/.gitignore +++ b/.gitignore @@ -61,7 +61,6 @@ react !1st-gen/projects/example-project-webpack/src/index.js !1st-gen/projects/example-project-webpack/webpack.config.js !1st-gen/projects/templates/plopfile.js -!1st-gen/projects/screen-reader-addon/manager.js 1st-gen/tools/*/src/**/*.css.js 1st-gen/tools/*/src/**/*.css.js.map diff --git a/1st-gen/package.json b/1st-gen/package.json index ed51613e68b..a5dd157e761 100644 --- a/1st-gen/package.json +++ b/1st-gen/package.json @@ -269,7 +269,6 @@ "!projects/example-project-rollup", "!projects/example-project-webpack", "!projects/templates", - "!projects/screen-reader-addon/**", "tools/**/*.js", "tools/**/*.js.map", "!**/build.js", diff --git a/1st-gen/storybook/main.js b/1st-gen/storybook/main.js index 2a307fe08f5..cf3d269d6c5 100644 --- a/1st-gen/storybook/main.js +++ b/1st-gen/storybook/main.js @@ -30,8 +30,8 @@ export default { : []), // https://geometricpanda.github.io/storybook-addon-badges/ '@geometricpanda/storybook-addon-badges', - // Screen reader addon (local build) - '../projects/screen-reader-addon', + // Screen reader addon (shared from 2nd-gen) + '../../2nd-gen/packages/swc/.storybook/addons/screen-reader-addon', ], framework: { name: '@storybook/web-components-webpack5', diff --git a/2nd-gen/packages/core/shared/base/version.ts b/2nd-gen/packages/core/shared/base/version.ts index 622cc87119d..2177cdd7401 100644 --- a/2nd-gen/packages/core/shared/base/version.ts +++ b/2nd-gen/packages/core/shared/base/version.ts @@ -1,2 +1,13 @@ +/** + * Copyright 2025 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ // Generated by genversion. export const version = '1.10.0'; diff --git a/1st-gen/projects/screen-reader-addon/manager.js b/2nd-gen/packages/swc/.storybook/addons/screen-reader-addon/manager.js similarity index 100% rename from 1st-gen/projects/screen-reader-addon/manager.js rename to 2nd-gen/packages/swc/.storybook/addons/screen-reader-addon/manager.js diff --git a/1st-gen/projects/screen-reader-addon/package.json b/2nd-gen/packages/swc/.storybook/addons/screen-reader-addon/package.json similarity index 82% rename from 1st-gen/projects/screen-reader-addon/package.json rename to 2nd-gen/packages/swc/.storybook/addons/screen-reader-addon/package.json index 7be3ce27199..de15b06e808 100644 --- a/1st-gen/projects/screen-reader-addon/package.json +++ b/2nd-gen/packages/swc/.storybook/addons/screen-reader-addon/package.json @@ -23,7 +23,10 @@ "name": "@spectrum-web-components/screen-reader-addon", "peerDependencies": { "@lit/react": ">=1.0.0", + "@spectrum-web-components/field-label": ">=1.0.0", + "@spectrum-web-components/help-text": ">=1.0.0", "@spectrum-web-components/switch": ">=1.0.0", + "@spectrum-web-components/textfield": ">=1.0.0", "@spectrum-web-components/theme": ">=1.0.0", "@storybook/components": ">=8.0.0", "@storybook/core-events": ">=8.0.0", @@ -33,7 +36,7 @@ }, "private": true, "repository": { - "directory": "1st-gen/projects/screen-reader-addon", + "directory": "2nd-gen/packages/swc/.storybook/addons/screen-reader-addon", "type": "git", "url": "https://github.com/adobe/spectrum-web-components.git" }, diff --git a/1st-gen/projects/screen-reader-addon/src/components/screen-reader-panel.ts b/2nd-gen/packages/swc/.storybook/addons/screen-reader-addon/src/components/screen-reader-panel.ts similarity index 69% rename from 1st-gen/projects/screen-reader-addon/src/components/screen-reader-panel.ts rename to 2nd-gen/packages/swc/.storybook/addons/screen-reader-addon/src/components/screen-reader-panel.ts index 54ab8361793..78527bb9395 100644 --- a/1st-gen/projects/screen-reader-addon/src/components/screen-reader-panel.ts +++ b/2nd-gen/packages/swc/.storybook/addons/screen-reader-addon/src/components/screen-reader-panel.ts @@ -11,13 +11,16 @@ */ import { css, html, LitElement } from 'lit'; -import { addons, type Channel } from '@storybook/manager-api'; +import { addons } from '@storybook/manager-api'; import { STORY_CHANGED } from '@storybook/core-events'; // Import Spectrum Web Components import '@spectrum-web-components/switch/sp-switch.js'; import '@spectrum-web-components/theme/sp-theme.js'; import '@spectrum-web-components/theme/src/spectrum-two/themes-core-tokens.js'; +import '@spectrum-web-components/textfield/sp-textfield.js'; +import '@spectrum-web-components/help-text/sp-help-text.js'; +import '@spectrum-web-components/field-label/sp-field-label.js'; import ScreenReader from '../screen-reader/screenReader.js'; @@ -35,6 +38,7 @@ export class ScreenReaderPanel extends LitElement { text: { type: Boolean }, isActive: { type: Boolean }, screenReaderText: { type: String }, + themeColor: { type: String }, }; // Use 'declare' to avoid class field definition overriding Lit's reactive properties @@ -42,52 +46,34 @@ export class ScreenReaderPanel extends LitElement { declare text: boolean; declare isActive: boolean; declare screenReaderText: string; + declare themeColor: 'light' | 'dark'; private screenReader: ScreenReader | null = null; - private channel: Channel | null = null; + private channel: ReturnType | null = null; + private themeMediaQuery: MediaQueryList | null = null; static override styles = css` :host { display: block; padding: 16px; - font-family: - -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, - sans-serif; } .toggle-row { display: flex; align-items: center; margin-bottom: 12px; - gap: 8px; } - .toggle-label { - font-size: 14px; - color: var(--spectrum-global-color-gray-800, #4b4b4b); + .output-section { + margin-top: 16px; } - .text-output { - font-size: 14px; - border-radius: 6px; - border: 1px solid var(--spectrum-global-color-gray-300, #e0e0e0); - padding: 12px; - margin-top: 12px; - background: var(--spectrum-global-color-gray-100, #f5f5f5); - min-height: 60px; - max-height: 200px; - overflow-y: auto; - } - - .status-text { - font-size: 12px; - color: var(--spectrum-global-color-gray-600, #6e6e6e); - margin: 12px 0 0 0; - font-style: italic; + sp-textfield { + width: 100%; } - .placeholder { - color: var(--spectrum-global-color-gray-500, #959595); + sp-help-text { + margin-top: 12px; } `; @@ -98,9 +84,41 @@ export class ScreenReaderPanel extends LitElement { this.text = false; this.isActive = false; this.screenReaderText = ''; + this.themeColor = this.detectTheme(); // Bind event handlers this.handleTextChange = this.handleTextChange.bind(this); this.handleStoryChange = this.handleStoryChange.bind(this); + this.handleThemeChange = this.handleThemeChange.bind(this); + } + + private detectTheme(): 'light' | 'dark' { + // Detect theme by checking Storybook's actual background color + // This works for both explicit themes (1st-gen) and auto themes (2nd-gen) + const body = document.body; + const computedStyle = getComputedStyle(body); + const bgColor = computedStyle.backgroundColor; + + // Parse RGB values + const rgbMatch = bgColor.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/); + if (rgbMatch) { + const [, r, g, b] = rgbMatch.map(Number); + // Calculate relative luminance + const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255; + + // If background is dark (luminance < 0.5), use dark theme + return luminance < 0.5 ? 'dark' : 'light'; + } + + // Fallback to system preference + if (window.matchMedia('(prefers-color-scheme: dark)').matches) { + return 'dark'; + } + + return 'light'; + } + + private handleThemeChange(): void { + this.themeColor = this.detectTheme(); } override connectedCallback(): void { @@ -115,6 +133,12 @@ export class ScreenReaderPanel extends LitElement { // Listen for story changes via Storybook API this.channel = addons.getChannel(); this.channel.on(STORY_CHANGED, this.handleStoryChange); + + // Listen for system theme changes (for auto-theme Storybooks like 2nd-gen) + this.themeMediaQuery = window.matchMedia( + '(prefers-color-scheme: dark)' + ); + this.themeMediaQuery.addEventListener('change', this.handleThemeChange); } override disconnectedCallback(): void { @@ -129,6 +153,13 @@ export class ScreenReaderPanel extends LitElement { this.channel.off(STORY_CHANGED, this.handleStoryChange); } + if (this.themeMediaQuery) { + this.themeMediaQuery.removeEventListener( + 'change', + this.handleThemeChange + ); + } + this.stopScreenReader(); } @@ -216,7 +247,11 @@ export class ScreenReaderPanel extends LitElement { override render() { return html` - +
- ${this.screenReaderText || - html` - - Navigate to hear announcements... - - `} +
+ + Screen reader output + +
` : ''} ${this.isActive ? html` -

+ Use Tab or arrow keys to navigate. Focus changes will be announced. -

+ ` : ''} diff --git a/1st-gen/projects/screen-reader-addon/src/register.tsx b/2nd-gen/packages/swc/.storybook/addons/screen-reader-addon/src/register.tsx similarity index 100% rename from 1st-gen/projects/screen-reader-addon/src/register.tsx rename to 2nd-gen/packages/swc/.storybook/addons/screen-reader-addon/src/register.tsx diff --git a/1st-gen/projects/screen-reader-addon/src/screen-reader/screenReader.ts b/2nd-gen/packages/swc/.storybook/addons/screen-reader-addon/src/screen-reader/screenReader.ts similarity index 100% rename from 1st-gen/projects/screen-reader-addon/src/screen-reader/screenReader.ts rename to 2nd-gen/packages/swc/.storybook/addons/screen-reader-addon/src/screen-reader/screenReader.ts diff --git a/2nd-gen/packages/swc/.storybook/main.ts b/2nd-gen/packages/swc/.storybook/main.ts index 3f29c12473a..83e11926401 100644 --- a/2nd-gen/packages/swc/.storybook/main.ts +++ b/2nd-gen/packages/swc/.storybook/main.ts @@ -27,6 +27,8 @@ const config = { '@storybook/addon-a11y', '@storybook/addon-designs', '@storybook/addon-vitest', + // Screen reader addon (local) + resolve(__dirname, './addons/screen-reader-addon'), ], viteFinal: async (config) => { return mergeConfig(config, { diff --git a/2nd-gen/packages/swc/package.json b/2nd-gen/packages/swc/package.json index 40c49984cb6..4f3b70dec82 100644 --- a/2nd-gen/packages/swc/package.json +++ b/2nd-gen/packages/swc/package.json @@ -68,11 +68,14 @@ "@vitest/coverage-v8": "3.2.4", "@vitest/ui": "3.2.4", "@wc-toolkit/storybook-helpers": "10.0.0", + "aria-query": "^5.3.0", "autoprefixer": "10.4.21", + "dom-accessibility-api": "^0.7.0", "glob": "11.0.3", "playwright": "1.53.1", "postcss": "8.5.6", "postcss-preset-env": "10.4.0", + "query-selector-shadow-dom": "^1.0.0", "react": "19.1.1", "react-dom": "19.1.1", "rimraf": "6.0.1", diff --git a/yarn.lock b/yarn.lock index d7627ef6a0c..c704b96e2b8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -189,12 +189,15 @@ __metadata: "@vitest/coverage-v8": "npm:3.2.4" "@vitest/ui": "npm:3.2.4" "@wc-toolkit/storybook-helpers": "npm:10.0.0" + aria-query: "npm:^5.3.0" autoprefixer: "npm:10.4.21" + dom-accessibility-api: "npm:^0.7.0" glob: "npm:11.0.3" lit: "npm:^2.5.0 || ^3.1.3" playwright: "npm:1.53.1" postcss: "npm:8.5.6" postcss-preset-env: "npm:10.4.0" + query-selector-shadow-dom: "npm:^1.0.0" react: "npm:19.1.1" react-dom: "npm:19.1.1" rimraf: "npm:6.0.1" @@ -6222,25 +6225,6 @@ __metadata: languageName: unknown linkType: soft -"@spectrum-web-components/screen-reader-addon@workspace:1st-gen/projects/screen-reader-addon": - version: 0.0.0-use.local - resolution: "@spectrum-web-components/screen-reader-addon@workspace:1st-gen/projects/screen-reader-addon" - dependencies: - aria-query: "npm:^5.3.0" - dom-accessibility-api: "npm:^0.7.0" - query-selector-shadow-dom: "npm:^1.0.0" - peerDependencies: - "@lit/react": ">=1.0.0" - "@spectrum-web-components/switch": ">=1.0.0" - "@spectrum-web-components/theme": ">=1.0.0" - "@storybook/components": ">=8.0.0" - "@storybook/core-events": ">=8.0.0" - "@storybook/manager-api": ">=8.0.0" - lit: ^2.5.0 || ^3.1.3 - react: ">=18.0.0" - languageName: unknown - linkType: soft - "@spectrum-web-components/search@npm:1.10.0, @spectrum-web-components/search@workspace:1st-gen/packages/search": version: 0.0.0-use.local resolution: "@spectrum-web-components/search@workspace:1st-gen/packages/search"