├── .env-example ├── .eslintrc ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── ----feature-request.md │ ├── ---bug-report-.md │ └── -question.md └── pull_request_template.md ├── .gitignore ├── .npmrc ├── .nvmrc ├── .stylelintignore ├── .stylelintrc ├── DOCS.md ├── LICENSE ├── README.md ├── babel.config.js ├── contributing.md ├── custom-rules └── hex-lowercase.js ├── jsdoc.json ├── manifest.json ├── package-lock.json ├── package.json ├── previews ├── import-manifest.png ├── include_logo.png ├── v10 │ └── include_banner.png ├── v11 │ └── include_banner.png ├── v12 │ └── include_banner.png ├── v14 │ └── include_banner.png ├── v15 │ └── include_banner.png ├── v16 │ └── include_banner.png ├── v8 │ └── include_banner.png └── v9 │ └── include_banner.png ├── src ├── code.js ├── components │ ├── Alert │ │ ├── index.js │ │ └── styles.scss │ ├── AltTextRow │ │ ├── index.js │ │ └── styles.scss │ ├── AnnotationStepPage.js │ ├── BannerAlert │ │ ├── index.js │ │ └── styles.scss │ ├── BannerSuccess.js │ ├── BannerTip.js │ ├── BannerTipText │ │ ├── index.js │ │ └── styles.scss │ ├── Checkbox │ │ ├── index.js │ │ └── styles.scss │ ├── ColorBlindnessFilter.js │ ├── ContrastScreenshot │ │ ├── index.js │ │ └── styles.scss │ ├── Dropdown │ │ ├── index.js │ │ └── styles.scss │ ├── EmptyStepSelection.js │ ├── ErrorBoundary.js │ ├── Footer.js │ ├── FooterActionButton.js │ ├── HeadingStep │ │ ├── index.js │ │ └── styles.scss │ ├── LoadingSpinner │ │ ├── index.js │ │ └── styles.scss │ ├── NavLeft │ │ ├── index.js │ │ └── styles.scss │ ├── ProgressLine.js │ ├── ProgressPieChart │ │ ├── index.js │ │ └── styles.scss │ ├── Toggle │ │ ├── index.js │ │ └── styles.scss │ └── index.js ├── constants │ ├── analytics.js │ ├── colors.js │ ├── contrast.js │ ├── figma-layer.js │ ├── index.js │ └── utilities.js ├── context │ ├── AppState.js │ └── index.js ├── data │ ├── color-blindness-types.js │ ├── dropdown-heading-types.json │ ├── dropdown-image-types.json │ ├── focus-order-types.js │ ├── gesture-types.js │ ├── heading-types-native.js │ ├── heading-types.js │ ├── landmark-types.js │ ├── reading-order-types.js │ ├── responsive-reflow-default-breakpoints.json │ ├── routes-native.json │ ├── routes.json │ ├── sample-structures.json │ ├── tips.json │ └── touch-target-types.js ├── figma-code │ ├── config.js │ ├── designer-checks.js │ ├── frame-helpers.js │ ├── index.js │ ├── initialize-page.js │ ├── on-selection-change.js │ ├── onload-plugin.js │ └── steps │ │ ├── alt-text.js │ │ ├── checkmark.js │ │ ├── color-blindness.js │ │ ├── color-contrast.js │ │ ├── complex-gestures.js │ │ ├── focus-grouping.js │ │ ├── headings.js │ │ ├── index.js │ │ ├── landmarks.js │ │ ├── reading-order.js │ │ ├── responsive-reflow.js │ │ ├── text-zoom.js │ │ └── touch-target.js ├── icons │ ├── SvgArrowRight.js │ ├── SvgArrowWidth.js │ ├── SvgCarrot.js │ ├── SvgCheck.js │ ├── SvgCheckSm.js │ ├── SvgChevronDown.js │ ├── SvgChevronLeft.js │ ├── SvgClose.js │ ├── SvgDownCarrot.js │ ├── SvgEmojiCelebrate.js │ ├── SvgEmojiMonocle.js │ ├── SvgEmojiStarEyes.js │ ├── SvgEyeClosed.js │ ├── SvgEyeOpened.js │ ├── SvgFocusGroup.js │ ├── SvgFrame.js │ ├── SvgImage.js │ ├── SvgImageSm.js │ ├── SvgInfo.js │ ├── SvgInfoFill.js │ ├── SvgLoadingSpinner.js │ ├── SvgMobile.js │ ├── SvgPlus.js │ ├── SvgReorder.js │ ├── SvgSettings.js │ ├── SvgSlashNone.js │ ├── SvgStepSlash.js │ ├── SvgText.js │ ├── SvgVector.js │ ├── SvgWarning.js │ ├── SvgWavy.js │ ├── SvgWeb.js │ ├── color-blindness │ │ ├── SvgAchromatomaly.js │ │ ├── SvgAchromatopsia.js │ │ ├── SvgDeuteranomaly.js │ │ ├── SvgDeuteranopia.js │ │ ├── SvgOriginal.js │ │ ├── SvgProtanopia.js │ │ ├── SvgProtonomaly.js │ │ ├── SvgTritanopia.js │ │ └── index.js │ ├── complex-gestures │ │ ├── SvgDragDrop.js │ │ ├── SvgMultiFingerTap.js │ │ ├── SvgPinchZoom.js │ │ ├── SvgRotate.js │ │ ├── SvgSwipe.js │ │ └── index.js │ ├── focus-grouping │ │ ├── SvgHelp1.js │ │ ├── SvgHelp2.js │ │ └── index.js │ ├── focus-order │ │ ├── SvgArrowKeys.js │ │ ├── SvgTabStops.js │ │ └── index.js │ ├── headings │ │ ├── SvgH.js │ │ ├── SvgH1.js │ │ ├── SvgH2.js │ │ ├── SvgH3.js │ │ ├── SvgH4.js │ │ ├── SvgH5.js │ │ ├── SvgH6.js │ │ └── index.js │ ├── index.js │ ├── landmarks │ │ ├── SvgBanner.js │ │ ├── SvgComplimentary.js │ │ ├── SvgContentInfo.js │ │ ├── SvgForm.js │ │ ├── SvgMain.js │ │ ├── SvgNavigation.js │ │ ├── SvgRegion.js │ │ ├── SvgSearch.js │ │ └── index.js │ ├── reading-order │ │ ├── SvgDown.js │ │ ├── SvgDownLeft.js │ │ ├── SvgDownRight.js │ │ ├── SvgHelp1.js │ │ ├── SvgHelp2.js │ │ ├── SvgLeft.js │ │ ├── SvgRight.js │ │ ├── SvgUp.js │ │ ├── SvgUpLeft.js │ │ ├── SvgUpRight.js │ │ └── index.js │ └── touch-target │ │ ├── SvgCustom.js │ │ ├── SvgHelp1.js │ │ ├── SvgHelp2.js │ │ ├── SvgMin48.js │ │ ├── SvgOverlap.js │ │ ├── SvgResize.js │ │ └── index.js ├── pages │ ├── AltText.js │ ├── ChooseYourOwnAdventure.js │ ├── ColorBlindness.js │ ├── ComplexGestures.js │ ├── Contrast.js │ ├── Dashboard.js │ ├── FocusGrouping.js │ ├── Headings.js │ ├── InteractiveElements.js │ ├── Landmarks.js │ ├── PageChange.js │ ├── ProgressLoading.js │ ├── ReadingOrder.js │ ├── ResponsiveReflow.js │ ├── SelectFrameToStart.js │ ├── Settings.js │ ├── TextZoom.js │ └── TouchTarget.js ├── styles │ ├── animations.scss │ ├── base.scss │ ├── mixins.scss │ ├── pages.scss │ ├── reset.scss │ ├── scaffolding.scss │ ├── shared.scss │ └── variables.scss ├── ui.html └── ui.js ├── webpack.config.js └── zip.js /.env-example: -------------------------------------------------------------------------------- 1 | ANALYTICS_URL= 2 | FEEDBACK_FORM_URL= -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["airbnb", "prettier"], 3 | "plugins": ["prettier", "react", "eslint-plugin-import-helpers"], 4 | "parserOptions": { 5 | "ecmaVersion": 2020 6 | }, 7 | "ignorePatterns": ["src/data/*.js"], 8 | "rules": { 9 | "global-require": 0, 10 | "prettier/prettier": ["error"], 11 | "no-case-declarations": 0, 12 | "no-param-reassign": 0, 13 | "no-promise-executor-return": 0, 14 | "no-restricted-globals": 0, 15 | "react/forbid-prop-types": 0, 16 | "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }], 17 | "react/jsx-fragments": 0, 18 | "react/jsx-no-constructed-context-values": 0, 19 | "react/jsx-props-no-spreading": 0, 20 | "react/no-danger": 0, 21 | "react/require-default-props": 0 22 | }, 23 | "globals": { 24 | "__html__": "readonly", 25 | "document": "readonly", 26 | "fetch": "readonly", 27 | "figma": "readonly", 28 | "parent": "writable", 29 | "window": "readonly", 30 | "Blob": "readonly", 31 | "Image": "readonly" 32 | }, 33 | "settings": { 34 | "import/resolver": { 35 | "webpack": { 36 | "config": "./webpack.config.js" 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/----feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F4BB Feature request" 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: calebnance 7 | 8 | --- 9 | 10 | ### Description 11 | 12 | 13 | 14 | ### Why 15 | 16 | 17 | 18 | 19 | 20 | ### Possible Implementation & Open Questions 21 | 22 | 23 | 24 | 25 | 26 | ### Is this something you're interested in working on? 27 | 28 | 29 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/---bug-report-.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F41B Bug report " 3 | about: Something isn't working right 4 | title: "[BUG]" 5 | labels: bug 6 | assignees: calebnance 7 | 8 | --- 9 | 10 | ### Details 11 | 12 | 13 | 14 | ### Expected Behavior 15 | 16 | 17 | 18 | ### Actual Behavior 19 | 20 | 21 | 22 | ### Possible Fix 23 | 24 | 25 | 26 |
Additional Info 27 | 28 | ### Your Environment 29 | 30 | 31 | 32 | - Operating System and version (desktop or mobile): 33 | - Link to your project and/or Figma file: 34 | 35 | ### Steps to Reproduce 36 | 37 | 38 | 39 | 40 | 41 | 1. first... 42 | 2. 43 | 3. 44 | 4. 45 | 46 | ### Stack Trace 47 | 48 | 49 | 50 |
51 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/-question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "❓Question" 3 | about: A support question that isn't a bug or feature request 4 | title: "[QUESTION]" 5 | labels: '' 6 | assignees: calebnance 7 | 8 | --- 9 | 10 | ### Description 11 | 12 | 13 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Description 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | ## Checklist: 12 | 13 | 14 | 15 | 16 | 17 | - [ ] I have read the **CONTRIBUTING** document and agree to the project's Code of Conduct 18 | - [ ] I have updated/added documentation affected by my changes (in DOCS.md). 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | dist_zips/ 4 | docs/ 5 | 6 | # macOS 7 | .DS_Store 8 | 9 | *.env 10 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | registry=https://registry.npmjs.org/ -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 20.18.1 -------------------------------------------------------------------------------- /.stylelintignore: -------------------------------------------------------------------------------- 1 | **/*.js -------------------------------------------------------------------------------- /.stylelintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["stylelint-config-standard-scss"], 3 | "plugins": [ 4 | "./custom-rules/hex-lowercase.js", 5 | "stylelint-order" 6 | ], 7 | "rules": { 8 | "custom-rules/hex-lowercase": true, 9 | "order/properties-alphabetical-order": true 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | include logo 3 | 4 | # Include 5 | 6 | an accessibility annotation Figma plugin 7 | 8 | [Docs](https://include.ebaydesign.tech) ∙ [Try in Figma](https://www.figma.com/community/plugin/1208180794570801545/Include%3A-an-accessibility-annotation-tool) ∙ [Roadmap](#roadmap) ∙ [Contribute](#contributing) 9 | 10 |
11 | 12 | ## Intro 13 | 14 | plugin version 16 15 | 16 | The eBay Include accessibility annotation Figma plugin is a tool to make annotating for accessibility (a11y) easier — easier for designers to spec and easier for developers to understand what is required. 17 | 18 | The plugin was developed by members of the accessibility and design teams at eBay and is released for public use on Figma. You can view and install the latest version of the plugin [here](https://www.figma.com/community/plugin/1208180794570801545/Include%3A-an-accessibility-annotation-tool). 19 | 20 | ## Roadmap 21 | 22 | **Near term bug fixes & improvements** 23 | 24 | - [ ] Scan for svg (alternative text) 25 | - [X] Add delete in multiple steps (v14) 26 | - [X] Add images manually in Alternative text step (v14) 27 | - [X] Add ability to edit landmarks (v12) 28 | - [X] Placing new arrow annotation below at end of previously placed arrow (v11) 29 | - [X] Touch target (v11) 30 | - [X] Updates for keyboard navigation (v10) 31 | - [X] Generate Responsive Designs from a single design (v10) 32 | - [X] Rename landmarks to use the HTML names (e.g. footer) and not aria roles (e.g. contentinfo). 33 | 34 | **Future explorations** 35 | 36 | - [X] Touch target revision (v15) 37 | - [X] Split between focus & reading order (v16) 38 | - [ ] Pointer gestures 39 | - [ ] Interactive elements step 40 | - [ ] Use of AI to generate labels 41 | - [ ] Cognitive step 42 | - [ ] Hearing step 43 | 44 | ## Installation 45 | 46 | ``` 47 | npm i 48 | ``` 49 | 50 | ## Development 51 | 52 | ``` 53 | npm run dev 54 | ``` 55 | 56 | To open **Inspect mode** 57 | 58 | ⌘ Command + ⌥ Option + I 59 | 60 | With the iframe of web app in a Figma plugin, hot-reloading doesn't really work, so to re-start the plugin quickly: 61 | 62 | ⌘ Command + ⌥ Option + P 63 | 64 | To open the plugin in development mode on Figma, map the manifest file at the root of this project. 65 | 66 | import manifest of Figma plugin 67 | 68 | See [docs](https://include.ebaydesign.tech) for more details on the project file structure and Figma layer methods used in this project. 69 | 70 | ## Contributing 71 | 72 | The main purpose of this repository is to provide a jumping-off point for developers and designers who want to expand upon or customize the plugin's accessibility annotation functionality. We welcome pull requests, feature ideas, and bug reports. 73 | 74 | - Pull requests are always welcome 75 | - Submit GitHub issues for any feature enhancements, bugs, or documentation problems 76 | - Read the [Contribution Tips and Guidelines](/contributing.md) 77 | - Participants in this project agree to abide by its [Code of Conduct](https://github.com/eBay/.github/blob/main/CODE_OF_CONDUCT.md) 78 | 79 | ## License 80 | 81 | Apache 2.0 - See [LICENSE](/LICENSE) for more information. 82 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | [ 4 | '@babel/preset-env', 5 | { 6 | modules: false 7 | } 8 | ], 9 | '@babel/preset-react' 10 | ], 11 | plugins: [ 12 | '@babel/plugin-transform-runtime', 13 | '@babel/plugin-syntax-dynamic-import', 14 | '@babel/plugin-proposal-class-properties' 15 | ], 16 | env: { 17 | production: { 18 | only: ['src'], 19 | plugins: [ 20 | [ 21 | 'transform-react-remove-prop-types', 22 | { 23 | removeImport: true 24 | } 25 | ], 26 | '@babel/plugin-transform-react-inline-elements', 27 | '@babel/plugin-transform-react-constant-elements' 28 | ] 29 | } 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /contributing.md: -------------------------------------------------------------------------------- 1 | # Contribution Tips and Guidelines 2 | 3 | The main purpose of this repository is to provide a jumping-off point for developers and designers who want to expand upon or customize the plugin's accessibility annotation functionality. We welcome pull requests, feature ideas, and bug reports. 4 | 5 | ## Pull requests are always welcome 6 | 7 | We are always thrilled to receive pull requests. We will do our best to process them quickly. 8 | 9 | ## Reporting Issues 10 | 11 | A great way to contribute to the project is to file a report when you encounter an issue. Check that our issue database doesn't already include that problem or suggestion before submitting an issue. If you find a match, you can use the "subscribe" button to get notified on updates. 12 | 13 | ## Code of Conduct 14 | 15 | Participants in this project agree to abide by its [Code of Conduct](https://github.com/eBay/.github/blob/main/CODE_OF_CONDUCT.md). 16 | -------------------------------------------------------------------------------- /custom-rules/hex-lowercase.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable-next-line */ 2 | const stylelint = require('stylelint'); 3 | 4 | // pulled from 5 | // https://medium.com/swlh/writing-your-first-custom-stylelint-rule-a9620bb2fb73 6 | const { report, ruleMessages, validateOptions } = stylelint.utils; 7 | 8 | const ruleName = 'custom-rules/hex-lowercase'; 9 | 10 | const messages = ruleMessages(ruleName, { 11 | expected: (unfixed, fixed) => `Expected "${unfixed}" to be "${fixed}"` 12 | }); 13 | 14 | module.exports = stylelint.createPlugin( 15 | ruleName, 16 | (primaryOption, secondaryOptionObject, context) => 17 | function lint(postcssRoot, postcssResult) { 18 | const validOptions = validateOptions(postcssResult, ruleName, { 19 | // no options for now... 20 | }); 21 | 22 | if (!validOptions) { 23 | return; 24 | } 25 | 26 | const isAutoFixing = Boolean(context.fix); 27 | postcssRoot.walkDecls((decl) => { 28 | const hasCapitalLetters = 29 | /^#([A-F0-9]{6}|[A-F0-9]{3})$/.test(decl.value) && 30 | /[A-Z]/.test(decl.value); 31 | 32 | if (!hasCapitalLetters) { 33 | return; 34 | } 35 | 36 | const { value } = decl; 37 | const newValue = value.toLowerCase(); 38 | 39 | if (isAutoFixing) { 40 | if (decl.raws.value) { 41 | decl.raws.value.raw = newValue; 42 | } else { 43 | decl.value = newValue; 44 | } 45 | } else { 46 | report({ 47 | ruleName, 48 | result: postcssResult, 49 | message: messages.expected(value, newValue), 50 | node: decl, 51 | word: value 52 | }); 53 | } 54 | }); 55 | } 56 | ); 57 | 58 | module.exports.ruleName = ruleName; 59 | module.exports.messages = messages; 60 | -------------------------------------------------------------------------------- /jsdoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "tags": { 3 | "allowUnknownTags": false 4 | }, 5 | "source": { 6 | "include": "./src", 7 | "includePattern": "\\.js$", 8 | "excludePattern": "(node_modules/|docs)" 9 | }, 10 | "plugins": ["plugins/markdown"], 11 | "opts": { 12 | "template": "node_modules/docdash", 13 | "encoding": "utf8", 14 | "destination": "docs/", 15 | "recurse": true, 16 | "verbose": true 17 | }, 18 | "templates": { 19 | "cleverLinks": false, 20 | "monospaceLinks": false 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Include – Accessibility Annotations", 3 | "id": "1208180794570801545", 4 | "api": "1.0.0", 5 | "main": "dist/code.js", 6 | "ui": "dist/ui.html", 7 | "editorType": ["figma"], 8 | "permissions": ["currentuser"], 9 | "documentAccess": "dynamic-page", 10 | "networkAccess": { 11 | "allowedDomains": ["https://include-analytics.ebaydesign.tech"], 12 | "reasoning": "No file data is collected at all. The only analytics we track are: who is using it (Figma user ID used for anonymized usage), when a new annotation is started, a step is completed, and dashboard is opened." 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "figma-include-accessibility-annotations", 3 | "version": "16", 4 | "description": "Include is a tool built to make annotating for accessibility (a11y) easier", 5 | "main": "code.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "webpack --mode=development --watch", 9 | "dev": "webpack --mode=development --watch", 10 | "serve": "webpack serve", 11 | "bundle": "webpack --mode=production && node zip.js", 12 | "lint": "eslint ./src", 13 | "lint-scss": "stylelint \"**/*.scss\"", 14 | "docs": "node_modules/.bin/jsdoc --readme DOCS.md -c jsdoc.json" 15 | }, 16 | "author": "eBay Design Technology", 17 | "devDependencies": { 18 | "@babel/core": "^7.27.1", 19 | "@babel/eslint-parser": "^7.27.1", 20 | "@babel/plugin-proposal-class-properties": "^7.18.6", 21 | "@babel/plugin-syntax-dynamic-import": "^7.8.3", 22 | "@babel/plugin-transform-react-constant-elements": "^7.27.1", 23 | "@babel/plugin-transform-react-inline-elements": "^7.27.1", 24 | "@babel/plugin-transform-runtime": "^7.27.1", 25 | "@babel/preset-env": "^7.27.2", 26 | "@babel/preset-react": "^7.27.1", 27 | "@babel/runtime": "^7.27.1", 28 | "adm-zip": "^0.5.16", 29 | "babel-loader": "^9.2.1", 30 | "babel-plugin-transform-react-remove-prop-types": "^0.4.24", 31 | "chalk": "^4.1.2", 32 | "css-loader": "^6.11.0", 33 | "docdash": "^1.2.0", 34 | "eslint": "^8.57.1", 35 | "eslint-config-airbnb": "^19.0.4", 36 | "eslint-config-prettier": "^9.1.0", 37 | "eslint-import-resolver-webpack": "^0.13.10", 38 | "eslint-plugin-import": "^2.31.0", 39 | "eslint-plugin-import-helpers": "^1.3.1", 40 | "eslint-plugin-jsx-a11y": "^6.10.2", 41 | "eslint-plugin-prettier": "^5.4.0", 42 | "eslint-plugin-react": "^7.37.5", 43 | "eslint-plugin-react-hooks": "^4.6.2", 44 | "html-webpack-inline-source-plugin": "^0.0.10", 45 | "html-webpack-plugin": "^5.6.3", 46 | "jsdoc": "~4.0.4", 47 | "prettier": "^3.5.3", 48 | "sass": "^1.87.0", 49 | "sass-loader": "^16.0.5", 50 | "style-loader": "^3.3.4", 51 | "stylelint": "^15.11.0", 52 | "stylelint-config-standard-scss": "^11.1.0", 53 | "stylelint-order": "^6.0.4", 54 | "stylelint-prettier": "^4.1.0", 55 | "url-loader": "^4.1.1", 56 | "webpack": "^5.99.8", 57 | "webpack-cli": "^5.1.4", 58 | "webpack-dev-server": "^4.15.2" 59 | }, 60 | "dependencies": { 61 | "dotenv": "^16.5.0", 62 | "prop-types": "^15.8.1", 63 | "react": "^18.3.1", 64 | "react-beautiful-dnd": "^13.1.1", 65 | "react-dev-utils": "^12.0.1", 66 | "react-dom": "^18.3.1", 67 | "react-router-dom": "^6.30.0" 68 | }, 69 | "prettier": { 70 | "singleQuote": true, 71 | "trailingComma": "none" 72 | }, 73 | "engines": { 74 | "node": ">=20.18.1" 75 | } 76 | } -------------------------------------------------------------------------------- /previews/import-manifest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eBay/figma-include-accessibility-annotations/4d03c8c824a928980e58f3aa0e83bf0765fce98d/previews/import-manifest.png -------------------------------------------------------------------------------- /previews/include_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eBay/figma-include-accessibility-annotations/4d03c8c824a928980e58f3aa0e83bf0765fce98d/previews/include_logo.png -------------------------------------------------------------------------------- /previews/v10/include_banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eBay/figma-include-accessibility-annotations/4d03c8c824a928980e58f3aa0e83bf0765fce98d/previews/v10/include_banner.png -------------------------------------------------------------------------------- /previews/v11/include_banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eBay/figma-include-accessibility-annotations/4d03c8c824a928980e58f3aa0e83bf0765fce98d/previews/v11/include_banner.png -------------------------------------------------------------------------------- /previews/v12/include_banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eBay/figma-include-accessibility-annotations/4d03c8c824a928980e58f3aa0e83bf0765fce98d/previews/v12/include_banner.png -------------------------------------------------------------------------------- /previews/v14/include_banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eBay/figma-include-accessibility-annotations/4d03c8c824a928980e58f3aa0e83bf0765fce98d/previews/v14/include_banner.png -------------------------------------------------------------------------------- /previews/v15/include_banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eBay/figma-include-accessibility-annotations/4d03c8c824a928980e58f3aa0e83bf0765fce98d/previews/v15/include_banner.png -------------------------------------------------------------------------------- /previews/v16/include_banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eBay/figma-include-accessibility-annotations/4d03c8c824a928980e58f3aa0e83bf0765fce98d/previews/v16/include_banner.png -------------------------------------------------------------------------------- /previews/v8/include_banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eBay/figma-include-accessibility-annotations/4d03c8c824a928980e58f3aa0e83bf0765fce98d/previews/v8/include_banner.png -------------------------------------------------------------------------------- /previews/v9/include_banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eBay/figma-include-accessibility-annotations/4d03c8c824a928980e58f3aa0e83bf0765fce98d/previews/v9/include_banner.png -------------------------------------------------------------------------------- /src/components/Alert/index.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | // styles 5 | import './styles.scss'; 6 | 7 | function Alert({ icon = null, style = {}, text, type = 'info' }) { 8 | return ( 9 |
10 | {icon &&
{icon}
} 11 | 12 |

{text}

13 |
14 | ); 15 | } 16 | 17 | Alert.propTypes = { 18 | // required 19 | text: PropTypes.string.isRequired, 20 | 21 | // optional 22 | icon: PropTypes.element, 23 | style: PropTypes.object, 24 | type: PropTypes.oneOf(['info', 'warning']) 25 | }; 26 | 27 | export default React.memo(Alert); 28 | -------------------------------------------------------------------------------- /src/components/Alert/styles.scss: -------------------------------------------------------------------------------- 1 | .alert { 2 | align-items: center; 3 | color: var(--figma-color-text); 4 | display: flex; 5 | padding: var(--spacing-sm); 6 | 7 | &.warning { 8 | color: var(--figma-color-bg-danger); 9 | } 10 | } -------------------------------------------------------------------------------- /src/components/AltTextRow/index.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { utils } from '@/constants'; 4 | 5 | // components 6 | import Dropdown from '@/components/Dropdown'; 7 | 8 | // data 9 | import imageTypesArray from '@/data/dropdown-image-types.json'; 10 | 11 | // app state 12 | import Context from '@/context'; 13 | 14 | // styles 15 | import './styles.scss'; 16 | 17 | function AltTextRow(props) { 18 | // main app state 19 | const { zoomTo } = React.useContext(Context); 20 | 21 | // props data 22 | const { base64 = null, displayType, index } = props; 23 | const { image, imageBuffer = null, isOpened, warnClass = '' } = props; 24 | 25 | // image data 26 | const { id, altText, name, type } = image; 27 | 28 | // on functions 29 | const { onChange, onFocus, onOpen, onSelect, onRemove } = props; 30 | 31 | const canEdit = type === 'informative'; 32 | 33 | return ( 34 |
35 |
zoomTo([id], true)} 38 | onKeyDown={({ key }) => { 39 | if (utils.isEnterKey(key)) zoomTo([id], true); 40 | }} 41 | role="button" 42 | tabIndex="0" 43 | > 44 | {displayType === 'scanned' && ( 45 | {name} 50 | )} 51 | 52 | {displayType === 'manual' && ( 53 |
60 | )} 61 | 62 |
scroll to
63 |
64 | 65 |
Alt text
66 | 67 | {canEdit === false &&
n/a
} 68 | 69 | {canEdit && ( 70 | 78 | )} 79 | 80 | 88 | 89 |
{ 94 | if (utils.isEnterKey(e.key)) onRemove(); 95 | }} 96 | role="button" 97 | tabIndex="0" 98 | > 99 |
100 |
101 |
102 | ); 103 | } 104 | 105 | AltTextRow.propTypes = { 106 | // required 107 | displayType: PropTypes.oneOf(['manual', 'scanned']).isRequired, 108 | image: PropTypes.shape({ 109 | id: PropTypes.string.isRequired, 110 | altText: PropTypes.string.isRequired, 111 | name: PropTypes.string.isRequired, 112 | type: PropTypes.string.isRequired 113 | }).isRequired, 114 | index: PropTypes.number.isRequired, 115 | isOpened: PropTypes.bool.isRequired, 116 | onChange: PropTypes.func.isRequired, 117 | onFocus: PropTypes.func.isRequired, 118 | onOpen: PropTypes.func.isRequired, 119 | onSelect: PropTypes.func.isRequired, 120 | onRemove: PropTypes.func.isRequired, 121 | 122 | // optional 123 | base64: PropTypes.string, 124 | imageBuffer: PropTypes.instanceOf(Uint8Array), 125 | warnClass: PropTypes.string 126 | }; 127 | 128 | export default React.memo(AltTextRow); 129 | -------------------------------------------------------------------------------- /src/components/AltTextRow/styles.scss: -------------------------------------------------------------------------------- 1 | .alt-text-row { 2 | align-items: center; 3 | column-gap: var(--spacing-xs); 4 | display: flex; 5 | margin-bottom: var(--spacing-xs); 6 | } 7 | 8 | .container-image-preview { 9 | position: relative; 10 | 11 | .scroll-to { 12 | background-color: var(--figma-color-bg-inverse); 13 | border-bottom-left-radius: 5px; 14 | border-bottom-right-radius: 5px; 15 | bottom: 0; 16 | color: var(--figma-color-text-oninverse); 17 | font-size: 10px; 18 | left: 0; 19 | opacity: 0; 20 | padding-bottom: 2px; 21 | position: absolute; 22 | text-align: center; 23 | transition: all 200ms ease; 24 | width: 100%; 25 | } 26 | 27 | &:hover .scroll-to { 28 | opacity: 1; 29 | } 30 | } 31 | 32 | .image-preview { 33 | background-color: var(--figma-color-bg-disabled); 34 | border-radius: 6px; 35 | height: 48px; 36 | min-width: 48px; 37 | object-fit: contain; 38 | width: 48px; 39 | } 40 | 41 | .image-preview-blob { 42 | background-color: var(--figma-color-bg-disabled); 43 | background-repeat: no-repeat; 44 | background-size: cover; 45 | border-radius: 6px; 46 | height: 48px; 47 | min-width: 48px; 48 | width: 48px; 49 | } 50 | 51 | .input { 52 | flex-grow: 1; 53 | } 54 | 55 | .input-na { 56 | flex-grow: 1; 57 | padding-left: 8px; 58 | } -------------------------------------------------------------------------------- /src/components/AnnotationStepPage.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { analytics } from '@/constants'; 4 | 5 | // components 6 | import BannerTip from '@/components/BannerTip'; 7 | import Footer from '@/components/Footer'; 8 | 9 | // app state 10 | import Context from '@/context'; 11 | 12 | function AnnotationStepPage({ 13 | children, 14 | bannerTipProps, 15 | footerProps = {}, 16 | title, 17 | routeName 18 | }) { 19 | const cnxt = React.useContext(Context); 20 | const { currentUser, sessionId, isProd } = cnxt; 21 | 22 | React.useEffect(() => { 23 | analytics.logEvent({ 24 | pageTitle: encodeURIComponent(routeName), 25 | sessionId, 26 | currentUser, 27 | isProd 28 | }); 29 | }, []); 30 | 31 | return ( 32 | 33 |
34 | 35 |
36 |

{title}

37 |
38 | {children} 39 |
40 |