diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..206a292 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,17 @@ +{ + "name": "Primer Live Region Element", + "image": "mcr.microsoft.com/vscode/devcontainers/typescript-node:20", + "forwardPorts": [], + "onCreateCommand": ["/bin/bash", "-c", "npm i"], + "remoteUser": "node", + "features": { + "ghcr.io/devcontainers/features/sshd:1": { + "version": "latest" + } + }, + "hostRequirements": { + "cpus": 4, + "memory": "8gb", + "storage": "32gb" + } +} diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..1ed453a --- /dev/null +++ b/.editorconfig @@ -0,0 +1,10 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true + +[*.{js,json,yml}] +charset = utf-8 +indent_style = space +indent_size = 2 diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..1521c8b --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +dist diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 0000000..71fa19d --- /dev/null +++ b/.eslintrc.cjs @@ -0,0 +1,39 @@ +'use strict' + +/** + * @type {import('eslint').Linter.Config} + */ +const config = { + root: true, + parser: '@typescript-eslint/parser', + parserOptions: { + ecmaVersion: 2022, + ecmaFeatures: { + jsx: true, + }, + sourceType: 'module', + }, + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:github/recommended', + 'plugin:github/browser', + 'plugin:github/typescript', + ], + settings: {}, + env: { + browser: true, + node: true, + es6: true, + }, + rules: { + 'no-unused-vars': [ + 'error', + { + argsIgnorePattern: '^_', + }, + ], + }, +} + +module.exports = config diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..95d6901 --- /dev/null +++ b/.github/CODE_OF_CONDUCT.md @@ -0,0 +1,76 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +- The use of sexualized language or imagery and unwelcome sexual attention or + advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic + address, without explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at design-systems@github.com. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 0000000..1231c64 --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,9 @@ +# Contributing + +## Code of conduct + +We value all of our community members, and thus want to foster a positive +contributing environment. Please take a look at our +[code of conduct](./CODE_OF_CONDUCT.md) before engaging in our workspaces. + +## Getting started diff --git a/.github/SECURITY.md b/.github/SECURITY.md new file mode 100644 index 0000000..a66a41c --- /dev/null +++ b/.github/SECURITY.md @@ -0,0 +1,31 @@ +Thanks for helping make GitHub safe for everyone. + +## Security + +GitHub takes the security of our software products and services seriously, including all of the open source code repositories managed through our GitHub organizations, such as [GitHub](https://github.com/GitHub). + +Even though [open source repositories are outside of the scope of our bug bounty program](https://bounty.github.com/index.html#scope) and therefore not eligible for bounty rewards, we will ensure that your finding gets passed along to the appropriate maintainers for remediation. + +## Reporting Security Issues + +If you believe you have found a security vulnerability in any GitHub-owned repository, please report it to us through coordinated disclosure. + +**Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.** + +Instead, please send an email to opensource-security[@]github.com. + +Please include as much of the information listed below as you can to help us better understand and resolve the issue: + +- The type of issue (e.g., buffer overflow, SQL injection, or cross-site scripting) +- Full paths of source file(s) related to the manifestation of the issue +- The location of the affected source code (tag/branch/commit or direct URL) +- Any special configuration required to reproduce the issue +- Step-by-step instructions to reproduce the issue +- Proof-of-concept or exploit code (if possible) +- Impact of the issue, including how an attacker might exploit the issue + +This information will help us triage your report more quickly. + +## Policy + +See [GitHub's Safe Harbor Policy](https://docs.github.com/en/github/site-policy/github-bug-bounty-program-legal-safe-harbor#1-safe-harbor-terms) diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..c078c93 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,22 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: 'npm' + directory: '/' + schedule: + interval: 'weekly' + labels: + - 'dependencies' + - 'skip changeset' + + - package-ecosystem: 'github-actions' + directory: '/' + schedule: + interval: 'weekly' + labels: + - 'dependencies' + - 'skip changeset' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..c4abec5 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,77 @@ +name: CI +on: + push: + branches: + - main + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + format: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'npm' + - name: Install dependencies + run: npm ci + - name: Check file formatting + run: npm run format:diff + + lint: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'npm' + - name: Install dependencies + run: npm ci + - name: Lint project using eslint + run: npm run lint + - name: Lint package using publint + run: npx publint --strict + + test: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'npm' + - name: Install dependencies + run: npm ci + - name: Build project + run: npm run build + - name: Run tests + run: npm test + + type-check: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'npm' + - name: Install dependencies + run: npm ci + - name: Build project + run: npm run build + - name: Run TypeScript + run: npm run type-check diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..afae652 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +# Dependency folders +node_modules + +# Package build folders +dist + +# custom-elements-manifest +custome-elements.json + +# TypeScript +*.tsbuildinfo diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..9a2a0e2 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +v20 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..441d955 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 GitHub, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..09c26d3 --- /dev/null +++ b/README.md @@ -0,0 +1,115 @@ +# live-region-element + +> A custom element for making announcements with live regions + +## Getting started + +To install `@primer/live-region-element` in your project, you will need to run the +following command using [npm](https://www.npmjs.com/): + +```bash +npm install -S @primer/live-region-element +``` + +## Usage + +The `@primer/live-region-element` package provides a custom element to assist in making +announcements with live regions. You can make announcements with this custom +element by calling the `announce()` and `announceFromElement` methods: + +```ts +const liveRegion = document.querySelector('live-region') + +liveRegion.announce('Example message') +``` + +The package also provides `announce()` and `announceFromElement` so that you +can directly call them, as well. + +```ts +import {announce, announceFromElement} from '@primer/live-region-element' + +announce('Example message') +``` + +Each method also supports specifying the politeness level of the announcement +through the `politeness` option. + +```ts +const liveRegion = document.querySelector('live-region') + +liveRegion.announce('Example polite message', { + politeness: 'polite', +}) + +liveRegion.announce('Example assertive message', { + politeness: 'assertive', +}) +``` + +It is **essential** that the `live-region` element exists in the initial HTML +payload of your application. To do so, include `` in +your HTML and make sure that [the custom element has been +defined](#defining-live-region-as-a-custom-element). Follow the [Declarative +shadow DOM](#declarative-shadow-dom) section below if you would like to include +this in your HTML. + +### Defining `live-region` as a custom element + +The `@primer/live-region-element` package provides an entrypoint that you can +use to define the `live-region` custom element. + +```ts +import '@primer/live-region-element/define` +``` + +If you prefer to define the custom element directly, import `LiveRegionElement` +directly from the package and use that to define the `live-region` element. For +example: + +```ts +import {LiveRegionElement} from '@primer/live-region-element' + +if (!customElements.get('live-region')) { + customElements.define('live-region', LiveRegionElement) +} +``` + +### Declarative Shadow DOM + +The `live-region` custom element includes support for [Declarative Shadow +DOM](https://developer.chrome.com/docs/css-ui/declarative-shadow-dom) and you +can leverage this feature by using the following snippet: + +```html + + + +``` + +In addition, a `templateContent` export is available through the package which +can be used alongside `