├── test-app ├── app │ ├── models │ │ └── .gitkeep │ ├── routes │ │ └── .gitkeep │ ├── components │ │ ├── .gitkeep │ │ ├── glint-typecheck.js │ │ └── glint-typecheck.hbs │ ├── controllers │ │ └── .gitkeep │ ├── helpers │ │ └── .gitkeep │ ├── templates │ │ ├── components │ │ │ └── .gitkeep │ │ └── application.hbs │ ├── styles │ │ └── app.css │ ├── router.ts │ ├── config │ │ └── environment.d.ts │ ├── app.ts │ └── index.html ├── tests │ ├── unit │ │ └── .gitkeep │ ├── integration │ │ ├── .gitkeep │ │ └── modifiers │ │ │ └── click-outside-test.js │ ├── test-helper.ts │ ├── index.html │ └── helpers │ │ ├── index.js │ │ └── index.ts ├── .watchmanconfig ├── types │ └── global.d.ts ├── public │ └── robots.txt ├── .template-lintrc.js ├── .stylelintrc.js ├── .stylelintignore ├── config │ ├── optional-features.json │ ├── targets.js │ ├── ember-cli-update.json │ ├── environment.js │ └── ember-try.js ├── .prettierignore ├── .gitignore ├── .prettierrc.cjs ├── .editorconfig ├── ember-cli-build.js ├── .ember-cli ├── .npmignore ├── testem.js ├── tsconfig.json ├── README.md ├── eslint.config.mjs └── package.json ├── ember-click-outside-modifier ├── src │ ├── index.js │ └── modifiers │ │ └── click-outside.js ├── types │ ├── index.d.ts │ ├── template-registry.d.ts │ └── modifiers │ │ └── click-outside.d.ts ├── .template-lintrc.cjs ├── addon-main.cjs ├── .prettierignore ├── .gitignore ├── .prettierrc.cjs ├── babel.config.json ├── unpublished-development-types │ └── index.d.ts ├── tsconfig.json ├── rollup.config.mjs ├── eslint.config.mjs └── package.json ├── pnpm-workspace.yaml ├── .prettierrc.cjs ├── .prettierignore ├── .npmrc ├── .gitignore ├── .editorconfig ├── config └── ember-cli-update.json ├── CONTRIBUTING.md ├── LICENSE.md ├── .github └── workflows │ ├── push-dist.yml │ └── ci.yml ├── package.json ├── README.md ├── RELEASE.md └── CHANGELOG.md /test-app/app/models/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test-app/app/routes/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test-app/tests/unit/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test-app/app/components/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test-app/app/controllers/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test-app/app/helpers/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test-app/tests/integration/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test-app/app/templates/components/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test-app/.watchmanconfig: -------------------------------------------------------------------------------- 1 | { 2 | "ignore_dirs": ["dist"] 3 | } 4 | -------------------------------------------------------------------------------- /test-app/types/global.d.ts: -------------------------------------------------------------------------------- 1 | import '@glint/environment-ember-loose'; 2 | -------------------------------------------------------------------------------- /test-app/public/robots.txt: -------------------------------------------------------------------------------- 1 | # http://www.robotstxt.org 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /test-app/app/templates/application.hbs: -------------------------------------------------------------------------------- 1 |

Welcome to Ember

2 | 3 | {{outlet}} -------------------------------------------------------------------------------- /test-app/.template-lintrc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | extends: 'recommended', 5 | }; 6 | -------------------------------------------------------------------------------- /ember-click-outside-modifier/src/index.js: -------------------------------------------------------------------------------- 1 | export { default as clickOutside } from './modifiers/click-outside.js'; 2 | -------------------------------------------------------------------------------- /ember-click-outside-modifier/types/index.d.ts: -------------------------------------------------------------------------------- 1 | export { default as clickOutside } from './modifiers/click-outside'; 2 | -------------------------------------------------------------------------------- /ember-click-outside-modifier/.template-lintrc.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | extends: 'recommended', 5 | }; 6 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - 'ember-click-outside-modifier' 3 | - 'test-app' 4 | onlyBuiltDependencies: 5 | - 'core-js' 6 | -------------------------------------------------------------------------------- /.prettierrc.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | plugins: ['prettier-plugin-ember-template-tag'], 5 | singleQuote: true, 6 | }; 7 | -------------------------------------------------------------------------------- /test-app/app/styles/app.css: -------------------------------------------------------------------------------- 1 | /* Ember supports plain CSS out of the box. More info: https://cli.emberjs.com/release/advanced-use/stylesheets/ */ 2 | -------------------------------------------------------------------------------- /ember-click-outside-modifier/addon-main.cjs: -------------------------------------------------------------------------------- 1 | const { addonV1Shim } = require('@embroider/addon-shim'); 2 | module.exports = addonV1Shim(__dirname); 3 | -------------------------------------------------------------------------------- /test-app/.stylelintrc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | extends: ['stylelint-config-standard', 'stylelint-prettier/recommended'], 5 | }; 6 | -------------------------------------------------------------------------------- /test-app/.stylelintignore: -------------------------------------------------------------------------------- 1 | # unconventional files 2 | /blueprints/*/files/ 3 | 4 | # compiled output 5 | /dist/ 6 | 7 | # addons 8 | /.node_modules.ember-try/ 9 | -------------------------------------------------------------------------------- /ember-click-outside-modifier/.prettierignore: -------------------------------------------------------------------------------- 1 | # unconventional js 2 | /blueprints/*/files/ 3 | 4 | # compiled output 5 | /dist/ 6 | /declarations/ 7 | 8 | # misc 9 | /coverage/ 10 | -------------------------------------------------------------------------------- /test-app/app/components/glint-typecheck.js: -------------------------------------------------------------------------------- 1 | import Component from '@glimmer/component'; 2 | 3 | export default class extends Component { 4 | noop() { 5 | // do nothing 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /test-app/config/optional-features.json: -------------------------------------------------------------------------------- 1 | { 2 | "application-template-wrapper": false, 3 | "default-async-observers": true, 4 | "jquery-integration": false, 5 | "template-only-glimmer-components": true 6 | } 7 | -------------------------------------------------------------------------------- /test-app/.prettierignore: -------------------------------------------------------------------------------- 1 | # unconventional js 2 | /blueprints/*/files/ 3 | 4 | # compiled output 5 | /dist/ 6 | 7 | # misc 8 | /coverage/ 9 | !.* 10 | .*/ 11 | 12 | # ember-try 13 | /.node_modules.ember-try/ 14 | -------------------------------------------------------------------------------- /test-app/config/targets.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const browsers = [ 4 | 'last 1 Chrome versions', 5 | 'last 1 Firefox versions', 6 | 'last 1 Safari versions', 7 | ]; 8 | 9 | module.exports = { 10 | browsers, 11 | }; 12 | -------------------------------------------------------------------------------- /ember-click-outside-modifier/types/template-registry.d.ts: -------------------------------------------------------------------------------- 1 | import type ClickOutsideModifier from './modifiers/click-outside'; 2 | 3 | export default interface EmberClickOutsideRegistry { 4 | 'click-outside': typeof ClickOutsideModifier; 5 | } 6 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Prettier is also run from each package, so the ignores here 2 | # protect against files that may not be within a package 3 | 4 | # misc 5 | !.* 6 | .lint-todo/ 7 | 8 | # ember-try 9 | /.node_modules.ember-try/ 10 | /pnpm-lock.ember-try.yaml 11 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | # Docs: https://pnpm.io/npmrc 2 | # https://github.com/emberjs/rfcs/pull/907 3 | 4 | # we don't want addons to be bad citizens of the ecosystem 5 | auto-install-peers=false 6 | 7 | # we want true isolation, 8 | # if a dependency is not declared, we want an error 9 | resolve-peers-from-workspace-root=false 10 | -------------------------------------------------------------------------------- /test-app/app/router.ts: -------------------------------------------------------------------------------- 1 | import EmberRouter from '@ember/routing/router'; 2 | import config from 'test-app/config/environment'; 3 | 4 | export default class Router extends EmberRouter { 5 | location = config.locationType; 6 | rootURL = config.rootURL; 7 | } 8 | 9 | Router.map(function () { 10 | // Add route declarations here 11 | }); 12 | -------------------------------------------------------------------------------- /test-app/tests/test-helper.ts: -------------------------------------------------------------------------------- 1 | import Application from 'test-app/app'; 2 | import config from 'test-app/config/environment'; 3 | import * as QUnit from 'qunit'; 4 | import { setApplication } from '@ember/test-helpers'; 5 | import { setup } from 'qunit-dom'; 6 | import { start } from 'ember-qunit'; 7 | 8 | setApplication(Application.create(config.APP)); 9 | 10 | setup(QUnit.assert); 11 | 12 | start(); 13 | -------------------------------------------------------------------------------- /test-app/app/config/environment.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Type declarations for 3 | * import config from 'test-app/config/environment' 4 | */ 5 | declare const config: { 6 | environment: string; 7 | modulePrefix: string; 8 | podModulePrefix: string; 9 | locationType: 'history' | 'hash' | 'none' | 'auto'; 10 | rootURL: string; 11 | APP: Record; 12 | }; 13 | 14 | export default config; 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules/ 5 | 6 | # misc 7 | .env* 8 | .pnp* 9 | .pnpm-debug.log 10 | .sass-cache 11 | .eslintcache 12 | coverage/ 13 | npm-debug.log* 14 | yarn-error.log 15 | 16 | # ember-try 17 | /.node_modules.ember-try/ 18 | /package.json.ember-try 19 | /package-lock.json.ember-try 20 | /yarn.lock.ember-try 21 | /pnpm-lock.ember-try.yaml 22 | -------------------------------------------------------------------------------- /test-app/app/app.ts: -------------------------------------------------------------------------------- 1 | import Application from '@ember/application'; 2 | import Resolver from 'ember-resolver'; 3 | import loadInitializers from 'ember-load-initializers'; 4 | import config from 'test-app/config/environment'; 5 | 6 | export default class App extends Application { 7 | modulePrefix = config.modulePrefix; 8 | podModulePrefix = config.podModulePrefix; 9 | Resolver = Resolver; 10 | } 11 | 12 | loadInitializers(App, config.modulePrefix); 13 | -------------------------------------------------------------------------------- /test-app/app/components/glint-typecheck.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | end_of_line = lf 9 | charset = utf-8 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | indent_style = space 13 | indent_size = 2 14 | 15 | [*.hbs] 16 | insert_final_newline = false 17 | 18 | [*.{diff,md}] 19 | trim_trailing_whitespace = false 20 | -------------------------------------------------------------------------------- /test-app/.gitignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist/ 3 | /declarations/ 4 | 5 | # dependencies 6 | /node_modules/ 7 | 8 | # misc 9 | /.env* 10 | /.pnp* 11 | /.eslintcache 12 | /coverage/ 13 | /npm-debug.log* 14 | /testem.log 15 | /yarn-error.log 16 | 17 | # ember-try 18 | /.node_modules.ember-try/ 19 | /npm-shrinkwrap.json.ember-try 20 | /package.json.ember-try 21 | /package-lock.json.ember-try 22 | /yarn.lock.ember-try 23 | 24 | # broccoli-debug 25 | /DEBUG/ 26 | -------------------------------------------------------------------------------- /test-app/.prettierrc.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | plugins: ['prettier-plugin-ember-template-tag'], 5 | overrides: [ 6 | { 7 | files: '*.{js,gjs,ts,gts,mjs,mts,cjs,cts}', 8 | options: { 9 | singleQuote: true, 10 | }, 11 | }, 12 | { 13 | files: '*.{gjs,gts}', 14 | options: { 15 | singleQuote: true, 16 | templateSingleQuote: false, 17 | }, 18 | }, 19 | ], 20 | }; 21 | -------------------------------------------------------------------------------- /ember-click-outside-modifier/.gitignore: -------------------------------------------------------------------------------- 1 | # The authoritative copies of these live in the monorepo root (because they're 2 | # more useful on github that way), but the build copies them into here so they 3 | # will also appear in published NPM packages. 4 | /README.md 5 | /LICENSE.md 6 | 7 | # compiled output 8 | dist/ 9 | declarations/ 10 | 11 | # npm/pnpm/yarn pack output 12 | *.tgz 13 | 14 | # deps & caches 15 | node_modules/ 16 | .eslintcache 17 | .prettiercache 18 | -------------------------------------------------------------------------------- /test-app/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | end_of_line = lf 9 | charset = utf-8 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | indent_style = space 13 | indent_size = 2 14 | 15 | [*.hbs] 16 | insert_final_newline = false 17 | 18 | [*.{diff,md}] 19 | trim_trailing_whitespace = false 20 | -------------------------------------------------------------------------------- /ember-click-outside-modifier/.prettierrc.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | plugins: ['prettier-plugin-ember-template-tag'], 5 | overrides: [ 6 | { 7 | files: '*.{js,gjs,ts,gts,mjs,mts,cjs,cts}', 8 | options: { 9 | singleQuote: true, 10 | }, 11 | }, 12 | { 13 | files: '*.{gjs,gts}', 14 | options: { 15 | singleQuote: true, 16 | templateSingleQuote: false, 17 | }, 18 | }, 19 | ], 20 | }; 21 | -------------------------------------------------------------------------------- /test-app/ember-cli-build.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const EmberApp = require('ember-cli/lib/broccoli/ember-app'); 4 | 5 | module.exports = function (defaults) { 6 | let app = new EmberApp(defaults, { 7 | 'ember-cli-babel': { enableTypeScriptTransform: true }, 8 | autoImport: { 9 | watchDependencies: ['ember-click-outside-modifier'], 10 | }, 11 | }); 12 | 13 | const { maybeEmbroider } = require('@embroider/test-setup'); 14 | return maybeEmbroider(app); 15 | }; 16 | -------------------------------------------------------------------------------- /ember-click-outside-modifier/babel.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | [ 4 | "@babel/plugin-transform-typescript", 5 | { 6 | "allExtensions": true, 7 | "onlyRemoveTypeImports": true, 8 | "allowDeclareFields": true 9 | } 10 | ], 11 | "@embroider/addon-dev/template-colocation-plugin", 12 | [ 13 | "babel-plugin-ember-template-compilation", 14 | { 15 | "targetFormat": "hbs", 16 | "transforms": [] 17 | } 18 | ] 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /ember-click-outside-modifier/types/modifiers/click-outside.d.ts: -------------------------------------------------------------------------------- 1 | import Modifier from 'ember-modifier'; 2 | 3 | export interface ClickOutsideSignature { 4 | Element?: HTMLElement; 5 | Args: { 6 | Positional: [handlerValue: (event: Event) => unknown, useCapture?: boolean]; 7 | Named?: 8 | | { 9 | events?: string[]; 10 | } 11 | | { 12 | event?: string; 13 | }; 14 | }; 15 | } 16 | 17 | export default class ClickOutsideModifier extends Modifier {} 18 | -------------------------------------------------------------------------------- /test-app/.ember-cli: -------------------------------------------------------------------------------- 1 | { 2 | /** 3 | Ember CLI sends analytics information by default. The data is completely 4 | anonymous, but there are times when you might want to disable this behavior. 5 | 6 | Setting `disableAnalytics` to true will prevent any data from being sent. 7 | */ 8 | "disableAnalytics": false, 9 | 10 | /** 11 | Setting `isTypeScriptProject` to true will force the blueprint generators to generate TypeScript 12 | rather than JavaScript by default, when a TypeScript version of a given blueprint is available. 13 | */ 14 | "isTypeScriptProject": true 15 | } 16 | -------------------------------------------------------------------------------- /config/ember-cli-update.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": "1.0.0", 3 | "packages": [ 4 | { 5 | "name": "@embroider/addon-blueprint", 6 | "version": "4.1.1", 7 | "blueprints": [ 8 | { 9 | "name": "@embroider/addon-blueprint", 10 | "isBaseBlueprint": true, 11 | "options": [ 12 | "--addon-location=ember-click-outside-modifier", 13 | "--ci-provider=github", 14 | "--pnpm", 15 | "--test-app-location=test-app", 16 | "--typescript" 17 | ] 18 | } 19 | ] 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /test-app/.npmignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist/ 3 | /tmp/ 4 | 5 | # dependencies 6 | /bower_components/ 7 | 8 | # misc 9 | /.bowerrc 10 | /.editorconfig 11 | /.ember-cli.js 12 | /.env* 13 | /.eslintcache 14 | /.eslintignore 15 | /.eslintrc.js 16 | /.git/ 17 | /.gitignore 18 | /.prettierignore 19 | /.prettierrc.js 20 | /.template-lintrc.js 21 | /.travis.yml 22 | /.watchmanconfig 23 | /bower.json 24 | /config/ember-try.js 25 | /CONTRIBUTING.md 26 | /ember-cli-build.js 27 | /testem.js 28 | /tests/ 29 | /yarn.lock 30 | .gitkeep 31 | 32 | # ember-try 33 | /.node_modules.ember-try/ 34 | /bower.json.ember-try 35 | /package.json.ember-try 36 | -------------------------------------------------------------------------------- /test-app/config/ember-cli-update.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": "1.0.0", 3 | "packages": [ 4 | { 5 | "name": "ember-cli", 6 | "version": "5.2.0-beta.0", 7 | "blueprints": [ 8 | { 9 | "name": "app", 10 | "outputRepo": "https://github.com/ember-cli/ember-new-output", 11 | "codemodsSource": "ember-app-codemods-manifest@1", 12 | "isBaseBlueprint": true, 13 | "options": [ 14 | "--no-welcome", 15 | "--pnpm", 16 | "--ci-provider=github", 17 | "--typescript" 18 | ] 19 | } 20 | ] 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /test-app/testem.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | test_page: 'tests/index.html?hidepassed', 5 | disable_watching: true, 6 | launch_in_ci: ['Chrome'], 7 | launch_in_dev: ['Chrome'], 8 | browser_start_timeout: 120, 9 | browser_args: { 10 | Chrome: { 11 | ci: [ 12 | // --no-sandbox is needed when running Chrome inside a container 13 | process.env.CI ? '--no-sandbox' : null, 14 | '--headless', 15 | '--disable-dev-shm-usage', 16 | '--disable-software-rasterizer', 17 | '--mute-audio', 18 | '--remote-debugging-port=0', 19 | '--window-size=1440,900', 20 | ].filter(Boolean), 21 | }, 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /test-app/app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | TestApp 6 | 7 | 8 | 9 | {{content-for "head"}} 10 | 11 | 12 | 13 | 14 | {{content-for "head-footer"}} 15 | 16 | 17 | {{content-for "body"}} 18 | 19 | 20 | 21 | 22 | {{content-for "body-footer"}} 23 | 24 | 25 | -------------------------------------------------------------------------------- /ember-click-outside-modifier/unpublished-development-types/index.d.ts: -------------------------------------------------------------------------------- 1 | // Add any types here that you need for local development only. 2 | // These will *not* be published as part of your addon, so be careful that your published code does not rely on them! 3 | 4 | import '@glint/environment-ember-loose'; 5 | import '@glint/environment-ember-template-imports'; 6 | 7 | // Uncomment if you need to support consuming projects in loose mode 8 | // 9 | // declare module '@glint/environment-ember-loose/registry' { 10 | // export default interface Registry { 11 | // // Add any registry entries from other addons here that your addon itself uses (in non-strict mode templates) 12 | // // See https://typed-ember.gitbook.io/glint/using-glint/ember/using-addons 13 | // } 14 | // } 15 | -------------------------------------------------------------------------------- /test-app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@tsconfig/ember/tsconfig.json", 3 | "glint": { 4 | "environment": ["ember-loose", "ember-template-imports"] 5 | }, 6 | "compilerOptions": { 7 | "skipLibCheck": true, 8 | "noEmit": true, 9 | "noEmitOnError": false, 10 | "declaration": false, 11 | "declarationMap": false, 12 | // The combination of `baseUrl` with `paths` allows Ember's classic package 13 | // layout, which is not resolvable with the Node resolution algorithm, to 14 | // work with TypeScript. 15 | "baseUrl": ".", 16 | "paths": { 17 | "test-app/tests/*": ["tests/*"], 18 | "test-app/*": ["app/*"], 19 | "*": ["types/*"] 20 | }, 21 | "types": [ 22 | "ember-source/types", 23 | ] 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How To Contribute 2 | 3 | ## Installation 4 | 5 | - `git clone https://github.com/lifeart/ember-click-outside-modifier.git` 6 | - `cd ember-click-outside-modifier` 7 | - `pnpm install` 8 | 9 | ## Linting 10 | 11 | - `pnpm lint` 12 | - `pnpm lint:fix` 13 | 14 | ## Building the addon 15 | 16 | - `cd ember-click-outside-modifier` 17 | - `pnpm build` 18 | 19 | ## Running tests 20 | 21 | - `cd test-app` 22 | - `pnpm test` – Runs the test suite on the current Ember version 23 | - `pnpm test:watch` – Runs the test suite in "watch mode" 24 | 25 | ## Running the test application 26 | 27 | - `cd test-app` 28 | - `pnpm start` 29 | - Visit the test application at [http://localhost:4200](http://localhost:4200). 30 | 31 | For more information on using ember-cli, visit [https://cli.emberjs.com/release/](https://cli.emberjs.com/release/). 32 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 4 | 5 | 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: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | 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. 10 | -------------------------------------------------------------------------------- /.github/workflows/push-dist.yml: -------------------------------------------------------------------------------- 1 | # Because this library needs to be built, 2 | # we can't easily point package.json files at the git repo for easy cross-repo testing. 3 | # 4 | # This workflow brings back that capability by placing the compiled assets on a "dist" branch 5 | # (configurable via the "branch" option below) 6 | name: Push dist 7 | 8 | on: 9 | push: 10 | branches: 11 | - main 12 | - master 13 | 14 | jobs: 15 | push-dist: 16 | name: Push dist 17 | runs-on: ubuntu-latest 18 | timeout-minutes: 10 19 | 20 | steps: 21 | - uses: actions/checkout@v4 22 | - name: Install pnpm 23 | uses: pnpm/action-setup@v4 24 | 25 | - name: Install Node 26 | uses: actions/setup-node@v4 27 | with: 28 | node-version: 20.x 29 | cache: 'pnpm' 30 | 31 | - name: Install Dependencies 32 | run: pnpm install --frozen-lockfile 33 | - uses: kategengler/put-built-npm-package-contents-on-branch@v2.0.0 34 | with: 35 | branch: dist 36 | token: ${{ secrets.GITHUB_TOKEN }} 37 | working-directory: 'ember-click-outside-modifier' 38 | -------------------------------------------------------------------------------- /test-app/tests/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | TestApp Tests 6 | 7 | 8 | 9 | {{content-for "head"}} 10 | {{content-for "test-head"}} 11 | 12 | 13 | 14 | 15 | 16 | {{content-for "head-footer"}} 17 | {{content-for "test-head-footer"}} 18 | 19 | 20 | {{content-for "body"}} 21 | {{content-for "test-body"}} 22 | 23 |
24 |
25 |
26 |
27 |
28 |
29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | {{content-for "body-footer"}} 37 | {{content-for "test-body-footer"}} 38 | 39 | 40 | -------------------------------------------------------------------------------- /test-app/config/environment.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (environment) { 4 | const ENV = { 5 | modulePrefix: 'test-app', 6 | environment, 7 | rootURL: '/', 8 | locationType: 'history', 9 | EmberENV: { 10 | EXTEND_PROTOTYPES: false, 11 | FEATURES: { 12 | // Here you can enable experimental features on an ember canary build 13 | // e.g. EMBER_NATIVE_DECORATOR_SUPPORT: true 14 | }, 15 | }, 16 | 17 | APP: { 18 | // Here you can pass flags/options to your application instance 19 | // when it is created 20 | }, 21 | }; 22 | 23 | if (environment === 'development') { 24 | // ENV.APP.LOG_RESOLVER = true; 25 | // ENV.APP.LOG_ACTIVE_GENERATION = true; 26 | // ENV.APP.LOG_TRANSITIONS = true; 27 | // ENV.APP.LOG_TRANSITIONS_INTERNAL = true; 28 | // ENV.APP.LOG_VIEW_LOOKUPS = true; 29 | } 30 | 31 | if (environment === 'test') { 32 | // Testem prefers this... 33 | ENV.locationType = 'none'; 34 | 35 | // keep test console output quieter 36 | ENV.APP.LOG_ACTIVE_GENERATION = false; 37 | ENV.APP.LOG_VIEW_LOOKUPS = false; 38 | 39 | ENV.APP.rootElement = '#ember-testing'; 40 | ENV.APP.autoboot = false; 41 | } 42 | 43 | if (environment === 'production') { 44 | // here you can enable a production-specific feature 45 | } 46 | 47 | return ENV; 48 | }; 49 | -------------------------------------------------------------------------------- /test-app/tests/helpers/index.js: -------------------------------------------------------------------------------- 1 | import { 2 | setupApplicationTest as upstreamSetupApplicationTest, 3 | setupRenderingTest as upstreamSetupRenderingTest, 4 | setupTest as upstreamSetupTest, 5 | } from 'ember-qunit'; 6 | 7 | // This file exists to provide wrappers around ember-qunit's / ember-mocha's 8 | // test setup functions. This way, you can easily extend the setup that is 9 | // needed per test type. 10 | 11 | function setupApplicationTest(hooks, options) { 12 | upstreamSetupApplicationTest(hooks, options); 13 | 14 | // Additional setup for application tests can be done here. 15 | // 16 | // For example, if you need an authenticated session for each 17 | // application test, you could do: 18 | // 19 | // hooks.beforeEach(async function () { 20 | // await authenticateSession(); // ember-simple-auth 21 | // }); 22 | // 23 | // This is also a good place to call test setup functions coming 24 | // from other addons: 25 | // 26 | // setupIntl(hooks); // ember-intl 27 | // setupMirage(hooks); // ember-cli-mirage 28 | } 29 | 30 | function setupRenderingTest(hooks, options) { 31 | upstreamSetupRenderingTest(hooks, options); 32 | 33 | // Additional setup for rendering tests can be done here. 34 | } 35 | 36 | function setupTest(hooks, options) { 37 | upstreamSetupTest(hooks, options); 38 | 39 | // Additional setup for unit tests can be done here. 40 | } 41 | 42 | export { setupApplicationTest, setupRenderingTest, setupTest }; 43 | -------------------------------------------------------------------------------- /test-app/tests/helpers/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | setupApplicationTest as upstreamSetupApplicationTest, 3 | setupRenderingTest as upstreamSetupRenderingTest, 4 | setupTest as upstreamSetupTest, 5 | type SetupTestOptions, 6 | } from 'ember-qunit'; 7 | 8 | // This file exists to provide wrappers around ember-qunit's / ember-mocha's 9 | // test setup functions. This way, you can easily extend the setup that is 10 | // needed per test type. 11 | 12 | function setupApplicationTest(hooks: NestedHooks, options?: SetupTestOptions) { 13 | upstreamSetupApplicationTest(hooks, options); 14 | 15 | // Additional setup for application tests can be done here. 16 | // 17 | // For example, if you need an authenticated session for each 18 | // application test, you could do: 19 | // 20 | // hooks.beforeEach(async function () { 21 | // await authenticateSession(); // ember-simple-auth 22 | // }); 23 | // 24 | // This is also a good place to call test setup functions coming 25 | // from other addons: 26 | // 27 | // setupIntl(hooks); // ember-intl 28 | // setupMirage(hooks); // ember-cli-mirage 29 | } 30 | 31 | function setupRenderingTest(hooks: NestedHooks, options?: SetupTestOptions) { 32 | upstreamSetupRenderingTest(hooks, options); 33 | 34 | // Additional setup for rendering tests can be done here. 35 | } 36 | 37 | function setupTest(hooks: NestedHooks, options?: SetupTestOptions) { 38 | upstreamSetupTest(hooks, options); 39 | 40 | // Additional setup for unit tests can be done here. 41 | } 42 | 43 | export { setupApplicationTest, setupRenderingTest, setupTest }; 44 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "repository": { 4 | "type": "git", 5 | "url": "git@github.com:lifeart/ember-click-outside-modifier.git" 6 | }, 7 | "scripts": { 8 | "build": "pnpm --filter ember-click-outside-modifier build", 9 | "prepare": "pnpm build", 10 | "lint": "pnpm --filter '*' lint", 11 | "test": "pnpm --filter '*' test", 12 | "test:ember": "pnpm --filter '*' test:ember" 13 | }, 14 | "packageManager": "pnpm@10.0.0", 15 | "devDependencies": { 16 | "@glint/core": "^1.2.1", 17 | "@release-it-plugins/lerna-changelog": "^7.0.0", 18 | "@release-it-plugins/workspaces": "^4.2.0", 19 | "concurrently": "^9.1.2", 20 | "prettier-plugin-ember-template-tag": "^2.0.2", 21 | "release-it": "^17.11.0" 22 | }, 23 | "publishConfig": { 24 | "registry": "https://registry.npmjs.org" 25 | }, 26 | "release-it": { 27 | "hooks": { 28 | "before:init": "cp README.md LICENSE.md ember-click-outside-modifier/" 29 | }, 30 | "plugins": { 31 | "@release-it-plugins/lerna-changelog": { 32 | "infile": "CHANGELOG.md", 33 | "launchEditor": true 34 | }, 35 | "@release-it-plugins/workspaces": { 36 | "workspaces": [ 37 | "ember-click-outside-modifier" 38 | ] 39 | } 40 | }, 41 | "git": { 42 | "tagName": "v${version}" 43 | }, 44 | "github": { 45 | "release": true, 46 | "tokenRef": "GITHUB_AUTH" 47 | }, 48 | "npm": false 49 | }, 50 | "volta": { 51 | "node": "20.19.0", 52 | "pnpm": "10.6.5" 53 | }, 54 | "version": "4.1.2" 55 | } 56 | -------------------------------------------------------------------------------- /test-app/README.md: -------------------------------------------------------------------------------- 1 | # test-app 2 | 3 | This README outlines the details of collaborating on this Ember application. 4 | A short introduction of this app could easily go here. 5 | 6 | ## Prerequisites 7 | 8 | You will need the following things properly installed on your computer. 9 | 10 | - [Git](https://git-scm.com/) 11 | - [Node.js](https://nodejs.org/) 12 | - [pnpm](https://pnpm.io/) 13 | - [Ember CLI](https://cli.emberjs.com/release/) 14 | - [Google Chrome](https://google.com/chrome/) 15 | 16 | ## Installation 17 | 18 | - `git clone https://github.com/lifeart/ember-click-outside-modifier.git` this repository 19 | - `cd ember-click-outside-modifier/test-app` 20 | - `pnpm install` 21 | 22 | ## Running / Development 23 | 24 | - `pnpm start` 25 | - Visit your app at [http://localhost:4200](http://localhost:4200). 26 | - Visit your tests at [http://localhost:4200/tests](http://localhost:4200/tests). 27 | 28 | ### Code Generators 29 | 30 | Make use of the many generators for code, try `ember help generate` for more details 31 | 32 | ### Running Tests 33 | 34 | - `pnpm test` 35 | - `pnpm test:ember --server` 36 | 37 | ### Linting 38 | 39 | - `pnpm lint` 40 | - `pnpm lint:fix` 41 | 42 | ### Building 43 | 44 | - `pnpm ember build` (development) 45 | - `pnpm build` (production) 46 | 47 | ### Deploying 48 | 49 | Specify what it takes to deploy your app. 50 | 51 | ## Further Reading / Useful Links 52 | 53 | - [ember.js](https://emberjs.com/) 54 | - [ember-cli](https://cli.emberjs.com/release/) 55 | - Development Browser Extensions 56 | - [ember inspector for chrome](https://chrome.google.com/webstore/detail/ember-inspector/bmdblncegkenkacieihfhpjfppoconhi) 57 | - [ember inspector for firefox](https://addons.mozilla.org/en-US/firefox/addon/ember-inspector/) 58 | -------------------------------------------------------------------------------- /ember-click-outside-modifier/src/modifiers/click-outside.js: -------------------------------------------------------------------------------- 1 | const HAS_WINDOWS = typeof window !== 'undefined'; 2 | const HAS_NAVIGATOR = typeof navigator !== 'undefined'; 3 | const IS_TOUCH = 4 | HAS_WINDOWS && 5 | ('ontouchstart' in window || 6 | (HAS_NAVIGATOR && navigator.msMaxTouchPoints > 0)); 7 | const EVENTS = IS_TOUCH ? ['touchstart'] : ['click']; 8 | 9 | import { modifier } from 'ember-modifier'; 10 | 11 | function getEventNames({ event, events }) { 12 | if (events) { 13 | return events; 14 | } 15 | 16 | if (event) { 17 | return [event]; 18 | } 19 | 20 | return EVENTS; 21 | } 22 | 23 | export default modifier( 24 | function clickOutside( 25 | element, 26 | [handlerValue, useCapture] = [undefined, false], 27 | hashParams = {}, 28 | ) { 29 | const refEvent = new Event('clickReference'); 30 | const events = getEventNames(hashParams); 31 | const isFunction = typeof handlerValue === 'function'; 32 | if (!isFunction) { 33 | throw new Error('{{click-outside}}: Handler value must be a function.'); 34 | } 35 | const handlers = []; 36 | events.forEach((eventName) => { 37 | const handler = (event) => { 38 | if (refEvent.timeStamp > event.timeStamp) { 39 | return; 40 | } 41 | const isClickOutside = 42 | event.target !== element && !element.contains(event.target); 43 | if (!isClickOutside) { 44 | return; 45 | } 46 | handlerValue(event); 47 | }; 48 | handlers.push([eventName, handler]); 49 | document.documentElement.addEventListener(eventName, handler, useCapture); 50 | }); 51 | return () => { 52 | handlers.forEach(([eventName, handler]) => { 53 | document.documentElement.removeEventListener( 54 | eventName, 55 | handler, 56 | useCapture, 57 | ); 58 | }); 59 | }; 60 | }, 61 | { eager: false }, 62 | ); 63 | -------------------------------------------------------------------------------- /ember-click-outside-modifier/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@tsconfig/ember/tsconfig.json", 3 | "include": ["src/**/*", "types/**/*", "unpublished-development-types/**/*"], 4 | "glint": { 5 | "environment": ["ember-loose", "ember-template-imports"] 6 | }, 7 | "compilerOptions": { 8 | "allowJs": true, 9 | "declarationDir": "declarations", 10 | /** 11 | https://www.typescriptlang.org/tsconfig#noEmit 12 | 13 | We want to emit declarations, so this option must be set to `false`. 14 | @tsconfig/ember sets this to `true`, which is incompatible with our need to set `emitDeclarationOnly`. 15 | @tsconfig/ember is more optimized for apps, which wouldn't emit anything, only type check. 16 | */ 17 | "noEmit": false, 18 | /** 19 | https://www.typescriptlang.org/tsconfig#emitDeclarationOnly 20 | We want to only emit declarations as we use Rollup to emit JavaScript. 21 | */ 22 | "emitDeclarationOnly": true, 23 | 24 | /** 25 | https://www.typescriptlang.org/tsconfig#noEmitOnError 26 | Do not block emit on TS errors. 27 | */ 28 | "noEmitOnError": false, 29 | 30 | /** 31 | https://www.typescriptlang.org/tsconfig#rootDir 32 | "Default: The longest common path of all non-declaration input files." 33 | 34 | Because we want our declarations' structure to match our rollup output, 35 | we need this "rootDir" to match the "srcDir" in the rollup.config.mjs. 36 | 37 | This way, we can have simpler `package.json#exports` that matches 38 | imports to files on disk 39 | */ 40 | "rootDir": "./src", 41 | 42 | /** 43 | https://www.typescriptlang.org/tsconfig#allowImportingTsExtensions 44 | 45 | We want our tooling to know how to resolve our custom files so the appropriate plugins 46 | can do the proper transformations on those files. 47 | */ 48 | "allowImportingTsExtensions": true, 49 | 50 | "types": ["ember-source/types"] 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ember-click-outside-modifier 2 | 3 | Ember modifier to react on clicks outside an element without stopping the event propagation. Great for closing dialogues, menus among other things. 4 | 5 | If you need more control on click outside - take a look at [ember-click-outside](https://github.com/zeppelin/ember-click-outside) 6 | 7 | Inspired by [v-click-outside](https://github.com/ndelvalle/v-click-outside) 8 | 9 | ## Compatibility 10 | 11 | * Ember.js v3.20 or above 12 | - Embroider or ember-auto-import v2 (this is [v2 addon](https://emberjs.github.io/rfcs/0507-embroider-v2-package-format.html)) 13 | 14 | ## Installation 15 | 16 | ``` 17 | ember install ember-click-outside-modifier 18 | ``` 19 | 20 | ## Usage 21 | 22 | ```hbs 23 |
24 | ``` 25 | 26 | You can also provide specific events that you want to bind to with the `event` or `events` named arguments. 27 | 28 | ```hbs 29 |
30 |
31 | ``` 32 | 33 | ## Usage with Glint 34 | 35 | `ember-click-outside-modifier` is a glint enabled addon. Add this to your 36 | `types/global.d.ts` file: 37 | 38 | ```ts 39 | import '@glint/environment-ember-loose'; 40 | 41 | import type EmberClickOutsideRegistry from 'ember-click-outside-modifier/template-registry'; 42 | 43 | declare module '@glint/environment-ember-loose/registry' { 44 | export default interface Registry extends EmberClickOutsideRegistry, /* other addon registries */ { 45 | // local entries 46 | } 47 | } 48 | ``` 49 | 50 | For the entire guide, please refer to [Using 51 | Addons](https://typed-ember.gitbook.io/glint/environments/ember/using-addons#using-glint-enabled-addons) 52 | section on the glint handbook. 53 | 54 | Types are made available through package.json `exports` field. 55 | 56 | ## Usage with `