├── .editorconfig ├── .gitignore ├── .prettierrc ├── .releaserc ├── .stylelintrc ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── angular.json ├── commitlint.config.js ├── docs ├── app │ ├── app.component.html │ ├── app.component.spec.ts │ ├── app.component.ts │ ├── app.module.ts │ ├── codes.ts │ ├── examples │ │ ├── control-example │ │ │ ├── control-example.component.html │ │ │ ├── control-example.component.scss │ │ │ └── control-example.component.ts │ │ ├── drag-example │ │ │ ├── drag-example.component.html │ │ │ └── drag-example.component.ts │ │ ├── dropdown-example │ │ │ ├── dropdown-example.component.html │ │ │ ├── dropdown-example.component.scss │ │ │ └── dropdown-example.component.ts │ │ ├── dynamic-text-example │ │ │ ├── dynamic-text-example.component.html │ │ │ └── dynamic-text-example.component.ts │ │ ├── fullscreen-position-example │ │ │ ├── fullscreen-position-example.component.html │ │ │ └── fullscreen-position-example.component.ts │ │ ├── global-position-example │ │ │ ├── global-position-example.component.html │ │ │ └── global-position-example.component.ts │ │ ├── modal-example │ │ │ ├── modal-example.component.html │ │ │ ├── modal-example.component.scss │ │ │ └── modal-example.component.ts │ │ ├── relative-position-example │ │ │ ├── relative-position-example.component.html │ │ │ └── relative-position-example.component.ts │ │ ├── ribbon-example │ │ │ ├── ribbon-example.component.html │ │ │ ├── ribbon-example.component.scss │ │ │ └── ribbon-example.component.ts │ │ └── slide-position-example │ │ │ ├── slide-position-example.component.html │ │ │ └── slide-position-example.component.ts │ ├── host-components │ │ ├── hero-screen │ │ │ ├── hero-screen.component.html │ │ │ └── hero-screen.component.ts │ │ ├── simple-list │ │ │ ├── simple-list.component.html │ │ │ └── simple-list.component.ts │ │ ├── simple-modal │ │ │ ├── simple-modal.component.html │ │ │ └── simple-modal.component.ts │ │ └── tooltip │ │ │ ├── tooltip.component.html │ │ │ └── tooltip.component.ts │ ├── test │ │ ├── test.component.html │ │ ├── test.component.scss │ │ ├── test.component.spec.ts │ │ └── test.component.ts │ └── utils │ │ ├── content │ │ ├── content.component.html │ │ ├── content.component.scss │ │ └── content.component.ts │ │ ├── scollspy.directive.ts │ │ ├── section │ │ ├── section.component.html │ │ └── section.component.ts │ │ └── sub-section │ │ ├── sub-section.component.html │ │ └── sub-section.component.ts ├── assets │ ├── .gitkeep │ ├── archived-versions.json │ ├── favicon.png │ ├── favicon │ │ ├── android-chrome-192x192.png │ │ ├── android-chrome-256x256.png │ │ ├── apple-touch-icon.png │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── favicon.ico │ │ ├── mstile-150x150.png │ │ ├── og-image.jpg │ │ └── safari-pinned-tab.svg │ ├── icons │ │ ├── icons8-beer-50.png │ │ ├── icons8-cafe-50.png │ │ ├── icons8-cocktail-50.png │ │ ├── icons8-cola-50.png │ │ ├── icons8-comments-50.png │ │ ├── icons8-confetti-50.png │ │ ├── icons8-dynamite-50.png │ │ ├── icons8-explosive-50.png │ │ ├── icons8-firework-explosion-100.png │ │ ├── icons8-french-fries-50.png │ │ ├── icons8-fried-chicken-50.png │ │ ├── icons8-hamburger-50.png │ │ ├── icons8-orange-50.png │ │ ├── icons8-pears-50.png │ │ ├── icons8-pizza-50.png │ │ ├── icons8-sandwich-50.png │ │ ├── icons8-scooter-50.png │ │ ├── icons8-sweet-banana-50.png │ │ ├── icons8-tequila-shot-50.png │ │ ├── icons8-watch-50.png │ │ ├── icons8-watermelon-50.png │ │ └── icons8-whiskey-50.png │ ├── illus │ │ ├── congrats.svg │ │ └── undraw_content_vbqo.svg │ ├── img │ │ ├── blast.png │ │ ├── bomb.png │ │ ├── clock.png │ │ ├── cow.png │ │ ├── five.png │ │ ├── fly.png │ │ ├── four.png │ │ ├── goat.png │ │ ├── mail.png │ │ ├── one.png │ │ ├── snake.png │ │ ├── three.png │ │ └── two.png │ ├── lo-logo.png │ ├── toppy-favicon.png │ ├── toppy-logo-white.png │ └── toppy-logo.png ├── browserslist ├── environments │ ├── environment.prod.ts │ ├── environment.ts │ └── version.ts ├── favicon.ico ├── index.html ├── karma.conf.js ├── main.ts ├── markdown │ └── main.md ├── polyfills.ts ├── styles │ ├── _common.scss │ ├── _config.scss │ ├── _temp.scss │ ├── animations │ │ ├── __index.scss │ │ └── _slide_in.scss │ ├── base │ │ ├── __index.scss │ │ ├── _buttons.scss │ │ ├── _fonts.scss │ │ ├── _icons.scss │ │ ├── _input.scss │ │ ├── _pre.scss │ │ ├── _reset.scss │ │ ├── _typography.scss │ │ └── _utility.scss │ ├── browsers │ │ ├── __index.scss │ │ ├── _chrome.scss │ │ ├── _firefox.scss │ │ └── _ie11.scss │ ├── components │ │ ├── __index.scss │ │ ├── _blade.scss │ │ ├── _controls.scss │ │ ├── _hero.scss │ │ ├── _menu.scss │ │ ├── _modal.scss │ │ ├── _table.scss │ │ └── _target-element-container.scss │ ├── elements │ │ ├── __index.scss │ │ ├── _btn.scss │ │ ├── _hr.scss │ │ ├── _toast.scss │ │ └── _tooltip.scss │ ├── helpers │ │ ├── __index.scss │ │ ├── _debug.scss │ │ ├── functions │ │ │ ├── __index.scss │ │ │ ├── _clr.scss │ │ │ ├── _fs.scss │ │ │ ├── _rem.scss │ │ │ └── _z.scss │ │ └── mixins │ │ │ ├── __index.scss │ │ │ ├── _acceleration.scss │ │ │ ├── _ellipsis.scss │ │ │ ├── _gradient.scss │ │ │ ├── _placeholder.scss │ │ │ └── _smooth-font.scss │ ├── icons │ │ ├── toppy.svg │ │ ├── toppy.ttf │ │ └── toppy.woff │ ├── layouts │ │ └── __index.scss │ ├── pages │ │ └── __index.scss │ ├── responsive │ │ ├── __index.scss │ │ ├── _lg.scss │ │ ├── _md.scss │ │ └── _xl.scss │ ├── root.scss │ └── vendors │ │ ├── __index.scss │ │ ├── _bootstrap.scss │ │ ├── _pretty-checkbox.scss │ │ └── _prism.scss ├── test.ts ├── tsconfig.app.json ├── tsconfig.spec.json └── tslint.json ├── e2e ├── protractor.conf.js ├── src │ ├── app.e2e-spec.ts │ └── app.po.ts └── tsconfig.e2e.json ├── package-lock.json ├── package.json ├── projects └── toppy │ ├── karma.conf.js │ ├── ng-package.json │ ├── package.json │ ├── src │ ├── lib │ │ ├── config.ts │ │ ├── models.ts │ │ ├── position │ │ │ ├── fullscreen-position.ts │ │ │ ├── global-position.ts │ │ │ ├── index.ts │ │ │ ├── position.ts │ │ │ ├── relative-position.ts │ │ │ └── slide-position.ts │ │ ├── styles.scss │ │ ├── template.html │ │ ├── toppy-control.ts │ │ ├── toppy.component.ts │ │ ├── toppy.module.ts │ │ ├── toppy.ts │ │ └── utils.ts │ ├── public_api.ts │ ├── test.ts │ └── tests │ │ ├── positions │ │ ├── fullscreen-position.spec.ts │ │ ├── global-position.spec.ts │ │ ├── relative-position.spec.ts │ │ └── slide-position.spec.ts │ │ ├── toppy-control.spec.ts │ │ ├── toppy.component.spec.ts │ │ ├── toppy.spec.ts │ │ └── utils.spec.ts │ ├── tsconfig.lib.json │ ├── tsconfig.spec.json │ └── tslint.json ├── scripts ├── archive.js ├── build-md.js ├── gh-pages.js └── version.sh ├── tsconfig.json └── tslint.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | .history/* 23 | !.vscode/settings.json 24 | !.vscode/tasks.json 25 | !.vscode/launch.json 26 | !.vscode/extensions.json 27 | 28 | # misc 29 | /.sass-cache 30 | /connect.lock 31 | /coverage 32 | /documentation 33 | /libpeerconnection.log 34 | npm-debug.log 35 | yarn-error.log 36 | testem.log 37 | /typings 38 | 39 | # System Files 40 | .DS_Store 41 | Thumbs.db 42 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120, 3 | "singleQuote": true, 4 | "useTabs": false, 5 | "tabWidth": 2, 6 | "semi": true, 7 | "bracketSpacing": true 8 | } 9 | -------------------------------------------------------------------------------- /.releaserc: -------------------------------------------------------------------------------- 1 | { 2 | "branch": "master", 3 | "plugins": [ 4 | [ 5 | "@semantic-release/exec", 6 | { 7 | "prepareCmd": "npm run archive:app -- ${nextRelease.version} && chmod a+x ./scripts/version.sh && ./scripts/version.sh ${nextRelease.version} && cp -r ./README.md ./dist/toppy && npx json -I -f package.json -e 'this.version=\"${nextRelease.version}\"'", 8 | "successCmd": "npm run postpublish -- ${nextRelease.version}" 9 | } 10 | ], 11 | [ 12 | "@semantic-release/commit-analyzer", 13 | { 14 | "releaseRules": [ 15 | { "type": "feat", "release": "minor" }, 16 | { "type": "fix", "release": "patch" }, 17 | { "type": "perf", "release": "patch" }, 18 | { "breaking": true, "release": "major" }, 19 | { "revert": true, "release": "patch" }, 20 | { "type": "docs", "release": "patch" }, 21 | { "type": "refactor", "release": "patch" }, 22 | { "type": "style", "release": "patch" } 23 | ], 24 | "parserOpts": { 25 | "noteKeywords": ["BREAKING CHANGE", "BREAKING CHANGES", "BREAKING"] 26 | } 27 | } 28 | ], 29 | "@semantic-release/changelog", 30 | "@semantic-release/release-notes-generator", 31 | [ 32 | "@semantic-release/npm", 33 | { 34 | "npmPublish": true, 35 | "tarballDir": "dist/toppy", 36 | "pkgRoot": "dist/toppy" 37 | } 38 | ], 39 | "@semantic-release/github", 40 | [ 41 | "@semantic-release/git", 42 | { 43 | "assets": [ 44 | "projects/toppy/package.json", 45 | "package.json", 46 | "package-lock.json", 47 | "CHANGELOG.md", 48 | "docs/environments/version.ts", 49 | "docs/assets/archived-versions.json" 50 | ], 51 | "message": ":fire: chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" 52 | } 53 | ] 54 | ], 55 | "preset": "angular" 56 | } 57 | -------------------------------------------------------------------------------- /.stylelintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "stylelint-config-recommended-scss", 3 | "rules": { 4 | "selector-type-no-unknown": [true, { "ignoreTypes": ["/choosy-/"] }] 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | cache: 3 | directories: 4 | - '~/.npm' 5 | - node_modules 6 | notifications: 7 | email: false 8 | slack: 9 | secure: E3zMq5rOujXNqci/8aKxtDDFYNb3QqEi8O9n2enTpLzuK5qVPnaVDzXre7MxLN13LYsRMzT3hpzngOu09Zj1Gt49MCXBDjseF6tVddEE2hURVCVSF87Of4pMUbxxC8zmIwMk33UBGGkS2F5fvkKiX1KL2LdqoJ+2GwD6xq0swPXC+LvbbT0bMif0jFzyJKYyqvT13UzMg+6m4obrfKbaXUdrG7woFs1UMhwkSY4i167w/l3+hYGY4TsOENhoqdUahP3CGu1v6zesLacwGk8A8H00A8dS5oXu0XuWZ+AdFOBpNBHj0JOWkFmMdDTtwOzKIYrGnPHbE1U0/ROdqguT6EBVqnOIHnGsjvBkqUN9mVrR+9iLcdODnsv9MkDEKnxrcpUcCITfTdsaCktIC17Xoe14WsIAB+doxq9fYGvBqqTj7GzMA+8a36ae2AaQDNrAJ+YojbqkisWc/BkkFFHd2EISges/nYmDqDcdk0UpfNuAeheynEiIFKISoxGjd5w/VI9oopY250u2qAwEPdvV8tn31WOxLlx00oe928bY4yPzMv/CkRInXzhmddCZidBGKh7nKTDut4VST/nwawkey5G1xYzHOzxSX1z7X8RQkMocWZ5etGv9bCxiOV/RSkhjzu8eLHKqUd5xs/+PYDxmG3iFzmVXEf4mELm7Bw2JuxE= 10 | node_js: 11 | - 9.3.0 12 | install: 13 | - npm install 14 | - npm install -g codecov 15 | before_script: 16 | - export CHROME_BIN=/usr/bin/google-chrome 17 | - export DISPLAY=:99.0 18 | - sh -e /etc/init.d/xvfb start 19 | - sudo apt-get update 20 | - sudo apt-get install -y libappindicator1 fonts-liberation 21 | - wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb 22 | - sudo dpkg -i google-chrome*.deb 23 | script: 24 | - npm run test:lib -- --watch=false 25 | - codecov 26 | - npm run build:lib 27 | - npm run build:app 28 | after_success: 29 | - npm run travis-deploy-once "npm run release" 30 | branches: 31 | except: 32 | - "/^v\\d+\\.\\d+\\.\\d+$/" 33 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [2.3.4](https://github.com/lokesh-coder/toppy/compare/v2.3.3...v2.3.4) (2019-07-31) 2 | 3 | 4 | ### Bug Fixes 5 | 6 | * backdrop custom class not added ([#35](https://github.com/lokesh-coder/toppy/issues/35)) ([23752b9](https://github.com/lokesh-coder/toppy/commit/23752b9)) 7 | 8 | ## [2.3.3](https://github.com/lokesh-coder/toppy/compare/v2.3.2...v2.3.3) (2019-03-13) 9 | 10 | 11 | ### Bug Fixes 12 | 13 | * relative positon incorrect placement on `autoUpdate` ([f3c0106](https://github.com/lokesh-coder/toppy/commit/f3c0106)) 14 | 15 | ## [2.3.2](https://github.com/lokesh-coder/toppy/compare/v2.3.1...v2.3.2) (2019-02-12) 16 | 17 | ## [2.3.1](https://github.com/lokesh-coder/toppy/compare/v2.3.0...v2.3.1) (2019-02-10) 18 | 19 | # [2.3.0](https://github.com/lokesh-coder/toppy/compare/v2.2.0...v2.3.0) (2019-01-05) 20 | 21 | 22 | ### Features 23 | 24 | * add support to access host component instance ([6cf180a](https://github.com/lokesh-coder/toppy/commit/6cf180a)) 25 | 26 | # [2.2.0](https://github.com/lokesh-coder/toppy/compare/v2.1.0...v2.2.0) (2018-12-31) 27 | 28 | 29 | ### Features 30 | 31 | * attach component custom props on initialize without ToppyOverlay ([e96a5f4](https://github.com/lokesh-coder/toppy/commit/e96a5f4)) 32 | 33 | # [2.1.0](https://github.com/lokesh-coder/toppy/compare/v2.0.5...v2.1.0) (2018-12-25) 34 | 35 | 36 | ### Bug Fixes 37 | 38 | * re-render when nested dynamic component ([68f5844](https://github.com/lokesh-coder/toppy/commit/68f5844)) 39 | 40 | 41 | ### Features 42 | 43 | * add position classes to warpper element ([79fc1a5](https://github.com/lokesh-coder/toppy/commit/79fc1a5)) 44 | * add position classes to warpper element ([b8ffb44](https://github.com/lokesh-coder/toppy/commit/b8ffb44)) 45 | 46 | ## [2.0.5](https://github.com/lokesh-coder/toppy/compare/v2.0.4...v2.0.5) (2018-12-24) 47 | 48 | ## [2.0.4](https://github.com/lokesh-coder/toppy/compare/v2.0.3...v2.0.4) (2018-12-20) 49 | 50 | 51 | ### Bug Fixes 52 | 53 | * allow custom props to be accessed in host component ([9d8e4ba](https://github.com/lokesh-coder/toppy/commit/9d8e4ba)) 54 | 55 | ## [2.0.3](https://github.com/lokesh-coder/toppy/compare/v2.0.2...v2.0.3) (2018-12-15) 56 | 57 | ## [2.0.2](https://github.com/lokesh-coder/toppy/compare/v2.0.1...v2.0.2) (2018-12-15) 58 | 59 | 60 | ### Bug Fixes 61 | 62 | * incorrect signature in API ([c80658e](https://github.com/lokesh-coder/toppy/commit/c80658e)) 63 | 64 | ## [2.0.1](https://github.com/lokesh-coder/toppy/compare/v2.0.0...v2.0.1) (2018-12-14) 65 | 66 | # [2.0.0](https://github.com/lokesh-coder/toppy/compare/v1.3.1...v2.0.0) (2018-12-14) 67 | 68 | 69 | ### Bug Fixes 70 | 71 | * remove unused components ([10a3fd8](https://github.com/lokesh-coder/toppy/commit/10a3fd8)) 72 | * ss class method [skip ci] ([521c2d1](https://github.com/lokesh-coder/toppy/commit/521c2d1)) 73 | 74 | 75 | ### Features 76 | 77 | * access custom props in Component, Template and Plain text contents ([b8550c8](https://github.com/lokesh-coder/toppy/commit/b8550c8)) 78 | * add template ref context ([e3e4ff1](https://github.com/lokesh-coder/toppy/commit/e3e4ff1)), closes [#19](https://github.com/lokesh-coder/toppy/issues/19) 79 | * added support for custom key to reference later ([3901878](https://github.com/lokesh-coder/toppy/commit/3901878)) 80 | * include context data in templateref ([a865929](https://github.com/lokesh-coder/toppy/commit/a865929)) 81 | 82 | 83 | ### BREAKING CHANGES 84 | 85 | * API has been changed. `.overlay()` to `.position()` , `.host()` to `.content()` , `updateHost()` to `updateContent()` , `ToppyRef` to `ToppyControl`. Introduced `.config()`. Performance improvement. 86 | 87 | ## [1.3.1](https://github.com/lokesh-coder/toppy/compare/v1.3.0...v1.3.1) (2018-12-05) 88 | 89 | 90 | ### Bug Fixes 91 | 92 | * **global position:** calculate proper left and top co-ordinates when `hostWidth` and `hostHeight` in percentage ([59dd68b](https://github.com/lokesh-coder/toppy/commit/59dd68b)) 93 | 94 | # [1.3.0](https://github.com/lokesh-coder/toppy/compare/v1.2.4...v1.3.0) (2018-12-04) 95 | 96 | 97 | ### Features 98 | 99 | * **relative position:** added support for content sticking with target element when `autoUpdate` is set to true ([6fa37e7](https://github.com/lokesh-coder/toppy/commit/6fa37e7)) 100 | 101 | ## [1.2.4](https://github.com/lokesh-coder/toppy/compare/v1.2.3...v1.2.4) (2018-11-28) 102 | 103 | 104 | ### Bug Fixes 105 | 106 | * replace codeclimate with codecov config in travis ([af9d16f](https://github.com/lokesh-coder/toppy/commit/af9d16f)) 107 | 108 | ## [1.2.3](https://github.com/lokesh-coder/toppy/compare/v1.2.2...v1.2.3) (2018-11-28) 109 | 110 | 111 | ### Bug Fixes 112 | 113 | * **docs:** update font path ([29834a5](https://github.com/lokesh-coder/toppy/commit/29834a5)) 114 | * move artifacts after build ([d7ff131](https://github.com/lokesh-coder/toppy/commit/d7ff131)) 115 | 116 | ## [1.2.2](https://github.com/lokesh-coder/toppy/compare/v1.2.1...v1.2.2) (2018-11-28) 117 | 118 | 119 | ### Bug Fixes 120 | 121 | * updated vulnerable dependencies ([ace393d](https://github.com/lokesh-coder/toppy/commit/ace393d)) 122 | * **docs:** update icon fonts path ([eedca4c](https://github.com/lokesh-coder/toppy/commit/eedca4c)) 123 | 124 | ## [1.2.1](https://github.com/lokesh-coder/toppy/compare/v1.2.0...v1.2.1) (2018-11-26) 125 | 126 | 127 | ### Bug Fixes 128 | 129 | * **docs:** set font icons path properly ([1d26809](https://github.com/lokesh-coder/toppy/commit/1d26809)) 130 | * **docs:** set font icons path properly ([0ae8424](https://github.com/lokesh-coder/toppy/commit/0ae8424)) 131 | 132 | # [1.2.0](https://github.com/lokesh-coder/toppy/compare/v1.1.1...v1.2.0) (2018-11-24) 133 | 134 | 135 | ### Features 136 | 137 | * added new config prop 'bodyClassNameOnOpen' ([0e047bf](https://github.com/lokesh-coder/toppy/commit/0e047bf)) 138 | * add new config 'closeOnEsc' ([fc1577e](https://github.com/lokesh-coder/toppy/commit/fc1577e)) 139 | * added support to change content after create ([02182b3](https://github.com/lokesh-coder/toppy/commit/02182b3)) 140 | * added version selector in doc ([7554f7b](https://github.com/lokesh-coder/toppy/commit/7554f7b)) 141 | * minor improvements and fixes ([8152b1c](https://github.com/lokesh-coder/toppy/commit/8152b1c)) 142 | 143 | ## [1.1.1](https://github.com/lokesh-coder/toppy/compare/v1.1.0...v1.1.1) (2018-11-22) 144 | 145 | 146 | ### Bug Fixes 147 | 148 | * multiple toppy config override ([#8](https://github.com/lokesh-coder/toppy/issues/8)) ([ca0ce7e](https://github.com/lokesh-coder/toppy/commit/ca0ce7e)) 149 | 150 | # [1.1.0](https://github.com/lokesh-coder/toppy/compare/v1.0.18...v1.1.0) (2018-11-18) 151 | 152 | 153 | ### Features 154 | 155 | * fade in content once position is updated ([3520ef6](https://github.com/lokesh-coder/toppy/commit/3520ef6)) 156 | * fade in content only after final position is updated ([abbfc8f](https://github.com/lokesh-coder/toppy/commit/abbfc8f)) 157 | 158 | ## [1.0.18](https://github.com/lokesh-coder/toppy/compare/v1.0.17...v1.0.18) (2018-11-16) 159 | 160 | ## [1.0.17](https://github.com/lokesh-coder/toppy/compare/v1.0.16...v1.0.17) (2018-11-13) 161 | 162 | ## [1.0.16](https://github.com/lokesh-coder/toppy/compare/v1.0.15...v1.0.16) (2018-11-09) 163 | 164 | ## [1.0.15](https://github.com/lokesh-coder/toppy/compare/v1.0.14...v1.0.15) (2018-11-06) 165 | 166 | ## [1.0.14](https://github.com/lokesh-coder/toppy/compare/v1.0.13...v1.0.14) (2018-11-03) 167 | 168 | ## [1.0.13](https://github.com/lokesh-coder/toppy/compare/v1.0.12...v1.0.13) (2018-11-02) 169 | 170 | 171 | ### Bug Fixes 172 | 173 | * override files on ghpages instead of replace ([d282266](https://github.com/lokesh-coder/toppy/commit/d282266)) 174 | 175 | ## [1.0.12](https://github.com/lokesh-coder/toppy/compare/v1.0.11...v1.0.12) (2018-11-02) 176 | 177 | 178 | ### Bug Fixes 179 | 180 | * add and sort details in package file ([6db7797](https://github.com/lokesh-coder/toppy/commit/6db7797)) 181 | * merge conflict resolve ([a412259](https://github.com/lokesh-coder/toppy/commit/a412259)) 182 | 183 | ## [1.0.11](https://github.com/lokesh-coder/toppy/compare/v1.0.10...v1.0.11) (2018-11-01) 184 | 185 | 186 | ### Bug Fixes 187 | 188 | * move archive logic to verfiyRelease stage ([cdce3c1](https://github.com/lokesh-coder/toppy/commit/cdce3c1)) 189 | 190 | ## [1.0.10](https://github.com/lokesh-coder/toppy/compare/v1.0.9...v1.0.10) (2018-11-01) 191 | 192 | 193 | ### Bug Fixes 194 | 195 | * archive version before publishing ([6dd714a](https://github.com/lokesh-coder/toppy/commit/6dd714a)) 196 | 197 | ## [1.0.9](https://github.com/lokesh-coder/toppy/compare/v1.0.8...v1.0.9) (2018-11-01) 198 | 199 | 200 | ### Bug Fixes 201 | 202 | * publish gh-pages with achived versions ([19a34c2](https://github.com/lokesh-coder/toppy/commit/19a34c2)) 203 | 204 | ## [1.0.8](https://github.com/lokesh-coder/toppy/compare/v1.0.7...v1.0.8) (2018-11-01) 205 | 206 | 207 | ### Bug Fixes 208 | 209 | * ghpages publish path ([f5d2f47](https://github.com/lokesh-coder/toppy/commit/f5d2f47)) 210 | 211 | ## [1.0.7](https://github.com/lokesh-coder/toppy/compare/v1.0.6...v1.0.7) (2018-11-01) 212 | 213 | 214 | ### Bug Fixes 215 | 216 | * set archive version properly ([b01d0ab](https://github.com/lokesh-coder/toppy/commit/b01d0ab)) 217 | 218 | ## [1.0.6](https://github.com/lokesh-coder/toppy/compare/v1.0.5...v1.0.6) (2018-11-01) 219 | 220 | 221 | ### Bug Fixes 222 | 223 | * archive doc build versions ([06226c4](https://github.com/lokesh-coder/toppy/commit/06226c4)) 224 | 225 | ## [1.0.5](https://github.com/lokesh-coder/toppy/compare/v1.0.4...v1.0.5) (2018-11-01) 226 | 227 | 228 | ### Bug Fixes 229 | 230 | * change gh pages publish package ([a5ef149](https://github.com/lokesh-coder/toppy/commit/a5ef149)) 231 | 232 | ## [1.0.4](https://github.com/lokesh-coder/toppy/compare/v1.0.3...v1.0.4) (2018-11-01) 233 | 234 | 235 | ### Bug Fixes 236 | 237 | * update build command in package json ([0ed8a10](https://github.com/lokesh-coder/toppy/commit/0ed8a10)) 238 | 239 | ## [1.0.3](https://github.com/lokesh-coder/toppy/compare/v1.0.2...v1.0.3) (2018-11-01) 240 | 241 | 242 | ### Bug Fixes 243 | 244 | * remove assets release in github ([8fb1ec8](https://github.com/lokesh-coder/toppy/commit/8fb1ec8)) 245 | 246 | ## [1.0.2](https://github.com/lokesh-coder/toppy/compare/v1.0.1...v1.0.2) (2018-11-01) 247 | 248 | 249 | ### Bug Fixes 250 | 251 | * release doc assets to github pages ([87b460b](https://github.com/lokesh-coder/toppy/commit/87b460b)) 252 | 253 | ## [1.0.1](https://github.com/lokesh-coder/toppy.git/compare/v1.0.0...v1.0.1) (2018-11-01) 254 | 255 | # 1.0.0 (2018-11-01) 256 | 257 | 258 | ### Bug Fixes 259 | 260 | * package json scripts and travis ([bc4f996](https://github.com/lokesh-coder/toppy.git/commit/bc4f996)) 261 | 262 | 263 | ### Features 264 | 265 | * add support for ghpages auto publish ([a8c8b7c](https://github.com/lokesh-coder/toppy.git/commit/a8c8b7c)) 266 | * initial commit ([6464f1a](https://github.com/lokesh-coder/toppy.git/commit/6464f1a)) 267 | * **docs:** installation API update ([a80fab0](https://github.com/lokesh-coder/toppy.git/commit/a80fab0)) 268 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Lokesh Rajendran ( mexican.dirtyfellow@gmail.com ) 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 | -------------------------------------------------------------------------------- /angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "toppy-app": { 7 | "root": "", 8 | "sourceRoot": "docs", 9 | "projectType": "application", 10 | "prefix": "app", 11 | "schematics": { 12 | "@schematics/angular:component": { 13 | "styleext": "scss", 14 | "spec": false 15 | }, 16 | "@schematics/angular:class": { 17 | "spec": false 18 | }, 19 | "@schematics/angular:directive": { 20 | "spec": false 21 | }, 22 | "@schematics/angular:guard": { 23 | "spec": false 24 | }, 25 | "@schematics/angular:module": { 26 | "spec": false 27 | }, 28 | "@schematics/angular:pipe": { 29 | "spec": false 30 | }, 31 | "@schematics/angular:service": { 32 | "spec": false 33 | } 34 | }, 35 | "architect": { 36 | "build": { 37 | "builder": "@angular-devkit/build-angular:browser", 38 | "options": { 39 | "outputPath": "dist/toppy-app", 40 | "index": "docs/index.html", 41 | "main": "docs/main.ts", 42 | "polyfills": "docs/polyfills.ts", 43 | "tsConfig": "docs/tsconfig.app.json", 44 | "assets": ["docs/favicon.ico", "docs/assets"], 45 | "styles": ["docs/styles/root.scss", "node_modules/prismjs/themes/prism.css"], 46 | "scripts": [ 47 | "node_modules/marked/lib/marked.js", 48 | "node_modules/prismjs/prism.js", 49 | "node_modules/prismjs/components/prism-css.min.js", 50 | "node_modules/prismjs/components/prism-typescript.min.js", 51 | "node_modules/prismjs/components/prism-powershell.min.js", 52 | "node_modules/prismjs/components/prism-javascript.min.js" 53 | ] 54 | }, 55 | "configurations": { 56 | "production": { 57 | "fileReplacements": [ 58 | { 59 | "replace": "docs/environments/environment.ts", 60 | "with": "docs/environments/environment.prod.ts" 61 | } 62 | ], 63 | "optimization": true, 64 | "outputHashing": "all", 65 | "sourceMap": false, 66 | "extractCss": true, 67 | "namedChunks": false, 68 | "aot": true, 69 | "extractLicenses": true, 70 | "vendorChunk": false, 71 | "buildOptimizer": true, 72 | "budgets": [ 73 | { 74 | "type": "initial", 75 | "maximumWarning": "2mb", 76 | "maximumError": "5mb" 77 | } 78 | ] 79 | } 80 | } 81 | }, 82 | "serve": { 83 | "builder": "@angular-devkit/build-angular:dev-server", 84 | "options": { 85 | "browserTarget": "toppy-app:build" 86 | }, 87 | "configurations": { 88 | "production": { 89 | "browserTarget": "toppy-app:build:production" 90 | } 91 | } 92 | }, 93 | "extract-i18n": { 94 | "builder": "@angular-devkit/build-angular:extract-i18n", 95 | "options": { 96 | "browserTarget": "toppy-app:build" 97 | } 98 | }, 99 | "test": { 100 | "builder": "@angular-devkit/build-angular:karma", 101 | "options": { 102 | "main": "docs/test.ts", 103 | "polyfills": "docs/polyfills.ts", 104 | "tsConfig": "docs/tsconfig.spec.json", 105 | "karmaConfig": "docs/karma.conf.js", 106 | "styles": ["docs/styles/root.scss"], 107 | "scripts": [], 108 | "assets": ["docs/favicon.ico", "docs/assets"] 109 | } 110 | }, 111 | "lint": { 112 | "builder": "@angular-devkit/build-angular:tslint", 113 | "options": { 114 | "tsConfig": ["docs/tsconfig.app.json", "docs/tsconfig.spec.json"], 115 | "exclude": ["**/node_modules/**"] 116 | } 117 | } 118 | } 119 | }, 120 | "toppy-app-e2e": { 121 | "root": "e2e/", 122 | "projectType": "application", 123 | "prefix": "", 124 | "architect": { 125 | "e2e": { 126 | "builder": "@angular-devkit/build-angular:protractor", 127 | "options": { 128 | "protractorConfig": "e2e/protractor.conf.js", 129 | "devServerTarget": "toppy-app:serve" 130 | }, 131 | "configurations": { 132 | "production": { 133 | "devServerTarget": "toppy-app:serve:production" 134 | } 135 | } 136 | }, 137 | "lint": { 138 | "builder": "@angular-devkit/build-angular:tslint", 139 | "options": { 140 | "tsConfig": "e2e/tsconfig.e2e.json", 141 | "exclude": ["**/node_modules/**"] 142 | } 143 | } 144 | } 145 | }, 146 | "toppy": { 147 | "root": "projects/toppy", 148 | "sourceRoot": "projects/toppy/src", 149 | "projectType": "library", 150 | "prefix": "lib", 151 | "architect": { 152 | "build": { 153 | "builder": "@angular-devkit/build-ng-packagr:build", 154 | "options": { 155 | "tsConfig": "projects/toppy/tsconfig.lib.json", 156 | "project": "projects/toppy/ng-package.json" 157 | } 158 | }, 159 | "test": { 160 | "builder": "@angular-devkit/build-angular:karma", 161 | "options": { 162 | "main": "projects/toppy/src/test.ts", 163 | "tsConfig": "projects/toppy/tsconfig.spec.json", 164 | "karmaConfig": "projects/toppy/karma.conf.js", 165 | "codeCoverage": true 166 | } 167 | }, 168 | "lint": { 169 | "builder": "@angular-devkit/build-angular:tslint", 170 | "options": { 171 | "tsConfig": ["projects/toppy/tsconfig.lib.json", "projects/toppy/tsconfig.spec.json"], 172 | "exclude": ["**/node_modules/**"] 173 | } 174 | } 175 | } 176 | } 177 | }, 178 | "defaultProject": "toppy-app" 179 | } 180 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { extends: ['@commitlint/config-conventional'] }; 2 | -------------------------------------------------------------------------------- /docs/app/app.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |
7 | Toppy 8 |
9 |
Tiny Overlay library for Angular apps. Easy and simple API
10 |
11 | tooltip modal sidemenu dropdowns 12 | popup menu toaster alerts datepicker 13 | popovers 14 |
15 |
16 |
17 |
18 | 19 |
20 | 21 | 25 |
26 |
27 | 28 | 32 | 33 |
34 |
35 | 36 | 40 | 41 |
42 |
43 | 44 | 48 | 49 |
50 |
51 | 56 |
57 | 71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | 122 |
123 |
124 |
125 |
126 | 127 |
128 |
129 |
130 |
131 | 134 | -------------------------------------------------------------------------------- /docs/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from "@angular/core/testing"; 2 | import { AppComponent } from "./app.component"; 3 | describe("AppComponent", () => { 4 | beforeEach(async(() => { 5 | TestBed.configureTestingModule({ 6 | declarations: [AppComponent] 7 | }).compileComponents(); 8 | })); 9 | it("should create the app", async(() => { 10 | const fixture = TestBed.createComponent(AppComponent); 11 | const app = fixture.debugElement.componentInstance; 12 | expect(app).toBeTruthy(); 13 | })); 14 | it(`should have as title 'toppy app'`, async(() => { 15 | const fixture = TestBed.createComponent(AppComponent); 16 | const app = fixture.debugElement.componentInstance; 17 | expect(app.title).toEqual("toppy-app"); 18 | })); 19 | it("should render title in a h1 tag", async(() => { 20 | const fixture = TestBed.createComponent(AppComponent); 21 | fixture.detectChanges(); 22 | const compiled = fixture.debugElement.nativeElement; 23 | expect(compiled.querySelector("h1").textContent).toContain("Welcome to toppy App!"); 24 | })); 25 | }); 26 | -------------------------------------------------------------------------------- /docs/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Component, ElementRef, ViewChild } from '@angular/core'; 3 | import { fromEvent } from 'rxjs'; 4 | import { TOPPY_VERSION } from '../environments/version'; 5 | // import { Toppy } from 'toppy'; 6 | import { code } from './codes'; 7 | 8 | @Component({ 9 | selector: 'app-root', 10 | templateUrl: './app.component.html' 11 | }) 12 | export class AppComponent { 13 | latestVersion = ''; 14 | versions = []; 15 | title = 'toppy-app'; 16 | selectedVersion = ''; 17 | currentVersion = TOPPY_VERSION; 18 | @ViewChild('el', { read: ElementRef }) 19 | el: ElementRef; 20 | ins; 21 | code = code; 22 | constructor(private http: HttpClient) { 23 | this.http.get('./assets/archived-versions.json').subscribe(data => { 24 | this.versions = Object.keys(data) 25 | .filter(a => a !== 'undefined') 26 | .sort((a, b) => ('' + b).localeCompare(a)); 27 | this.latestVersion = this.versions[0]; 28 | this.getCurrentVerison(); 29 | }); 30 | } 31 | currentSection = ''; 32 | 33 | onSectionChange(sectionId: string) { 34 | this.currentSection = sectionId; 35 | } 36 | 37 | scrollTo(section) { 38 | this.currentSection = section; 39 | document.querySelector('#' + section).scrollIntoView(); 40 | } 41 | 42 | ngOnInit() { 43 | this.onScroll(); 44 | } 45 | 46 | ngafterViewInit() { 47 | this.getCurrentVerison(); 48 | } 49 | 50 | getCurrentVerison() { 51 | const parts = window.location.pathname.split('/').filter(a => a.length > 0); 52 | if (parts.length === 2) { 53 | this.selectedVersion = parts[1]; 54 | } else { 55 | this.selectedVersion = this.latestVersion; 56 | } 57 | } 58 | 59 | onVersionChange(version) { 60 | (window as any).location = `https://lokesh-coder.github.io/toppy/${version}`; 61 | } 62 | 63 | onScroll() { 64 | fromEvent(window, 'scroll') 65 | .pipe() 66 | .subscribe(res => { 67 | const heroHeight = document.querySelector('.hero').getBoundingClientRect().height; 68 | const scrolledTo = document.documentElement.scrollTop; 69 | if (scrolledTo >= heroHeight) { 70 | document.querySelector('body').classList.add('sidebar-fixed'); 71 | } else { 72 | document.querySelector('body').classList.remove('sidebar-fixed'); 73 | } 74 | }); 75 | } 76 | 77 | tweet(e) { 78 | const getWindowOptions = function() { 79 | const width = 500; 80 | const height = 350; 81 | const left = window.innerWidth / 2 - width / 2; 82 | const top = window.innerHeight / 2 - height / 2; 83 | 84 | return ['resizable,scrollbars,status', 'height=' + height, 'width=' + width, 'left=' + left, 'top=' + top].join(); 85 | }; 86 | // const text = encodeURIComponent('Hey everyone, come & see how good I look!'); 87 | const shareUrl = `https://twitter.com/intent/tweet?hashtags=angular&original_referer=http%3A%2F%2Flocalhost%3A4200%2F&ref_src=twsrc%5Etfw&text=Cute%20overlay%20library%20for%20Angular%20-%20tooltips%2C%20modals%2C%20toastr%2C%20menu%2C%20dropdowns%2C%20alerts%2C%20popovers%2C%20sidebar%20and%20more...%20&tw_p=tweetbutton&url=https%3A%2F%2Flokesh-coder.github.io%2Ftoppy%2F&via=lokesh_coder`; 88 | 89 | e.preventDefault(); 90 | const win = window.open(shareUrl, 'ShareOnTwitter', getWindowOptions()); 91 | win.opener = null; // 2 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /docs/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { HttpClientModule } from '@angular/common/http'; 2 | import { NgModule } from '@angular/core'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { BrowserModule } from '@angular/platform-browser'; 5 | import { ToppyModule } from 'toppy'; 6 | import { AppComponent } from './app.component'; 7 | import { ControlExampleComponent } from './examples/control-example/control-example.component'; 8 | import { DragExampleComponent } from './examples/drag-example/drag-example.component'; 9 | import { DropdownExampleComponent } from './examples/dropdown-example/dropdown-example.component'; 10 | import { DynamicTextExampleComponent } from './examples/dynamic-text-example/dynamic-text-example.component'; 11 | import { FullscreenPositionExampleComponent } from './examples/fullscreen-position-example/fullscreen-position-example.component'; 12 | import { GlobalPositionExampleComponent } from './examples/global-position-example/global-position-example.component'; 13 | import { ModalExampleComponent } from './examples/modal-example/modal-example.component'; 14 | import { RelativePositionExampleComponent } from './examples/relative-position-example/relative-position-example.component'; 15 | import { RibbonExampleComponent } from './examples/ribbon-example/ribbon-example.component'; 16 | import { SlidePositionExampleComponent } from './examples/slide-position-example/slide-position-example.component'; 17 | import { HeroScreenComponent } from './host-components/hero-screen/hero-screen.component'; 18 | import { SimpleListComponent } from './host-components/simple-list/simple-list.component'; 19 | import { SimpleModalComponent } from './host-components/simple-modal/simple-modal.component'; 20 | import { TooltipComponent } from './host-components/tooltip/tooltip.component'; 21 | import { TestComponent } from './test/test.component'; 22 | import { ContentComponent } from './utils/content/content.component'; 23 | import { ScrollSpyDirective } from './utils/scollspy.directive'; 24 | import { SectionComponent } from './utils/section/section.component'; 25 | import { SubSectionComponent } from './utils/sub-section/sub-section.component'; 26 | 27 | @NgModule({ 28 | declarations: [ 29 | AppComponent, 30 | TestComponent, 31 | SectionComponent, 32 | SubSectionComponent, 33 | RelativePositionExampleComponent, 34 | TooltipComponent, 35 | SimpleModalComponent, 36 | SimpleListComponent, 37 | GlobalPositionExampleComponent, 38 | SlidePositionExampleComponent, 39 | FullscreenPositionExampleComponent, 40 | DragExampleComponent, 41 | HeroScreenComponent, 42 | ModalExampleComponent, 43 | ContentComponent, 44 | DynamicTextExampleComponent, 45 | DropdownExampleComponent, 46 | RibbonExampleComponent, 47 | ControlExampleComponent, 48 | ScrollSpyDirective 49 | ], 50 | imports: [BrowserModule, FormsModule, HttpClientModule, ToppyModule], 51 | providers: [], 52 | entryComponents: [TestComponent, TooltipComponent, SimpleModalComponent, SimpleListComponent, HeroScreenComponent], 53 | bootstrap: [AppComponent], 54 | exports: [] 55 | }) 56 | export class AppModule {} 57 | -------------------------------------------------------------------------------- /docs/app/codes.ts: -------------------------------------------------------------------------------- 1 | const code: any = {}; 2 | 3 | code.NPM_INSTALL = `> npm install toppy --save //or 4 | > yarn add toppy 5 | `; 6 | 7 | code.INSTALL = `const position = new GlobalPosition(); 8 | const ref = this.toppy.overlay(position).host().create(); 9 | ref.open(); // use it anywhere`; 10 | 11 | export { code }; 12 | -------------------------------------------------------------------------------- /docs/app/examples/control-example/control-example.component.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/app/examples/control-example/control-example.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/app/examples/control-example/control-example.component.scss -------------------------------------------------------------------------------- /docs/app/examples/control-example/control-example.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { Toppy } from '../../../../projects/toppy/src/lib/toppy'; 3 | 4 | @Component({ 5 | selector: 'app-control-example', 6 | templateUrl: './control-example.component.html', 7 | styleUrls: ['./control-example.component.scss'] 8 | }) 9 | export class ControlExampleComponent implements OnInit { 10 | constructor(private toppy: Toppy) {} 11 | 12 | ngOnInit() {} 13 | open() { 14 | this.toppy.getCtrl('sonia').open(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /docs/app/examples/drag-example/drag-example.component.html: -------------------------------------------------------------------------------- 1 | 8 |
9 | 17 |
18 | 19 |
20 | Reset 21 |
22 | -------------------------------------------------------------------------------- /docs/app/examples/drag-example/drag-example.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'; 2 | import { Subject } from 'rxjs'; 3 | import { OutsidePlacement } from '../../../../projects/toppy/src/lib/models'; 4 | import { RelativePosition, Toppy, ToppyControl } from '../../../../projects/toppy/src/public_api'; 5 | 6 | @Component({ 7 | selector: 'app-drag-example', 8 | templateUrl: './drag-example.component.html' 9 | }) 10 | export class DragExampleComponent implements OnInit { 11 | pos1 = 0; 12 | pos2 = 0; 13 | pos3 = 0; 14 | pos4 = 0; 15 | @ViewChild('el') el: ElementRef; 16 | private _toppyControl: ToppyControl; 17 | pauser = new Subject(); 18 | constructor(private toppy: Toppy) {} 19 | 20 | ngOnInit() { 21 | this._toppyControl = this.toppy 22 | .position( 23 | new RelativePosition({ 24 | placement: OutsidePlacement.TOP, 25 | src: this.el.nativeElement, 26 | width: 'auto', 27 | autoUpdate: true 28 | }) 29 | ) 30 | .content('Drag me', { class: 'tooltip' }) 31 | .create(); 32 | } 33 | 34 | ngAfterViewInit() { 35 | this.dragElement(); 36 | } 37 | reset() { 38 | this.el.nativeElement.style.left = '0px'; 39 | this.el.nativeElement.style.top = '0px'; 40 | } 41 | onMouseOver() { 42 | this._toppyControl.open(); 43 | } 44 | onMouseLeave() { 45 | this._toppyControl.close(); 46 | } 47 | dragMouseDown(e) { 48 | e = e || window.event; 49 | e.preventDefault(); 50 | // get the mouse cursor position at startup: 51 | this.pos3 = e.clientX; 52 | this.pos4 = e.clientY; 53 | document.onmouseup = this.closeDragElement.bind(this); 54 | // call a function whenever the cursor moves: 55 | document.onmousemove = this.elementDrag.bind(this); 56 | } 57 | 58 | elementDrag(e) { 59 | e = e || window.event; 60 | e.preventDefault(); 61 | // calculate the new cursor position: 62 | this.pos1 = this.pos3 - e.clientX; 63 | this.pos2 = this.pos4 - e.clientY; 64 | this.pos3 = e.clientX; 65 | this.pos4 = e.clientY; 66 | this.el.nativeElement.style.top = this.el.nativeElement.offsetTop - this.pos2 + 'px'; 67 | this.el.nativeElement.style.left = this.el.nativeElement.offsetLeft - this.pos1 + 'px'; 68 | } 69 | 70 | closeDragElement() { 71 | document.onmouseup = null; 72 | document.onmousemove = null; 73 | } 74 | 75 | dragElement() { 76 | this.el.nativeElement.onmousedown = this.dragMouseDown.bind(this); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /docs/app/examples/dropdown-example/dropdown-example.component.html: -------------------------------------------------------------------------------- 1 | 4 | 5 |
6 | I like {{ selectedEatable.name }} 7 |
8 | 9 | 10 | 15 | 16 | 17 | 18 | 27 | 28 | -------------------------------------------------------------------------------- /docs/app/examples/dropdown-example/dropdown-example.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/app/examples/dropdown-example/dropdown-example.component.scss -------------------------------------------------------------------------------- /docs/app/examples/dropdown-example/dropdown-example.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, ElementRef, OnInit, TemplateRef, ViewChild } from '@angular/core'; 2 | import { OutsidePlacement } from '../../../../projects/toppy/src/lib/models'; 3 | import { RelativePosition, Toppy, ToppyControl } from '../../../../projects/toppy/src/public_api'; 4 | 5 | @Component({ 6 | selector: 'app-dropdown-example', 7 | templateUrl: './dropdown-example.component.html', 8 | styleUrls: ['./dropdown-example.component.scss'] 9 | }) 10 | export class DropdownExampleComponent implements OnInit { 11 | @ViewChild('el') el: ElementRef; 12 | @ViewChild('el2') el2: ElementRef; 13 | private _toppyControl: ToppyControl; 14 | private _toppyControl2: ToppyControl; 15 | @ViewChild('tpl', { read: TemplateRef }) tpl: TemplateRef; 16 | @ViewChild('tpl2', { read: TemplateRef }) tpl2: TemplateRef; 17 | items = [ 18 | { name: 'Beer', icon: 'icons8-beer-50' }, 19 | { name: 'Coffee', icon: 'icons8-cafe-50' }, 20 | { name: 'Cocktail', icon: 'icons8-cocktail-50' }, 21 | { name: 'Cola', icon: 'icons8-cola-50' }, 22 | { name: 'Tequila', icon: 'icons8-tequila-shot-50' }, 23 | { name: 'Whiskey', icon: 'icons8-whiskey-50' } 24 | ]; 25 | eatables = [ 26 | { name: 'French fries', icon: 'icons8-french-fries-50' }, 27 | { name: 'Fried chicken', icon: 'icons8-fried-chicken-50' }, 28 | { name: 'Hamburger', icon: 'icons8-hamburger-50' }, 29 | { name: 'Pizza', icon: 'icons8-pizza-50' }, 30 | { name: 'Sandwich', icon: 'icons8-sandwich-50' } 31 | ]; 32 | selectedData; 33 | selectedEatable; 34 | isOpen = false; 35 | constructor(private toppy: Toppy) { 36 | this.selectedData = this.items[0]; 37 | this.selectedEatable = this.eatables[0]; 38 | } 39 | 40 | ngOnInit() { 41 | this._toppyControl = this.toppy 42 | .position( 43 | new RelativePosition({ 44 | placement: OutsidePlacement.BOTTOM, 45 | src: this.el.nativeElement, 46 | width: '100%', 47 | autoUpdate: true 48 | }) 49 | ) 50 | .config({ 51 | closeOnDocClick: true, 52 | docClickCallback: () => { 53 | this.isOpen = false; 54 | } 55 | }) 56 | .content(this.tpl) 57 | .create('sonia'); 58 | 59 | this._toppyControl2 = this.toppy 60 | .position( 61 | new RelativePosition({ 62 | placement: OutsidePlacement.TOP, 63 | src: this.el2.nativeElement, 64 | width: 'auto', 65 | autoUpdate: true 66 | }) 67 | ) 68 | .config({ 69 | docClickCallback: () => { 70 | this.isOpen = false; 71 | } 72 | }) 73 | .content(this.tpl2) 74 | .create(); 75 | } 76 | 77 | open() { 78 | this.isOpen = true; 79 | this._toppyControl.open(); 80 | } 81 | open2() { 82 | this._toppyControl2.open(); 83 | } 84 | close() { 85 | this.isOpen = false; 86 | this._toppyControl.close(); 87 | } 88 | close2() { 89 | this._toppyControl2.close(); 90 | } 91 | select(item) { 92 | this.selectedData = item; 93 | this.close(); 94 | } 95 | selectEatable(item) { 96 | this.selectedEatable = item; 97 | this.close2(); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /docs/app/examples/dynamic-text-example/dynamic-text-example.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | -------------------------------------------------------------------------------- /docs/app/examples/dynamic-text-example/dynamic-text-example.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'; 2 | import * as format from 'date-fns/format'; 3 | import { never, Observable, Subject, timer } from 'rxjs'; 4 | import { map, switchMap, timeInterval } from 'rxjs/operators'; 5 | import { OutsidePlacement } from '../../../../projects/toppy/src/lib/models'; 6 | import { RelativePosition, Toppy, ToppyControl } from '../../../../projects/toppy/src/public_api'; 7 | 8 | @Component({ 9 | selector: 'app-dynamic-text-example', 10 | templateUrl: './dynamic-text-example.component.html' 11 | }) 12 | export class DynamicTextExampleComponent implements OnInit { 13 | @ViewChild('el') el: ElementRef; 14 | private _toppyControl: ToppyControl; 15 | pauser = new Subject(); 16 | constructor(private toppy: Toppy) { 17 | this.pauser.pipe(switchMap(paused => (paused ? never() : this.source()))).subscribe(x => console.log(x)); 18 | } 19 | 20 | source(): Observable { 21 | return new Observable(observer => { 22 | timer(0, 100) 23 | .pipe( 24 | timeInterval(), 25 | map(() => this._toppyControl.updateTextContent.next(this.formatedTime())) 26 | ) 27 | .subscribe(); 28 | }); 29 | } 30 | 31 | formatedTime() { 32 | return format(new Date(), 'HH:mm:ss A'); 33 | } 34 | 35 | ngOnInit() { 36 | this._toppyControl = this.toppy 37 | .position( 38 | new RelativePosition({ 39 | placement: OutsidePlacement.RIGHT, 40 | src: this.el.nativeElement, 41 | width: 'auto', 42 | autoUpdate: true 43 | }) 44 | ) 45 | .content(this.formatedTime(), { class: 'tooltip' }) 46 | .create(); 47 | } 48 | 49 | onMouseOver() { 50 | this._toppyControl.open(); 51 | this.pauser.next(false); 52 | } 53 | onMouseLeave() { 54 | this._toppyControl.close(); 55 | this.pauser.next(true); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /docs/app/examples/fullscreen-position-example/fullscreen-position-example.component.html: -------------------------------------------------------------------------------- 1 |
2 |
Open fullscreen demo
3 |
4 | -------------------------------------------------------------------------------- /docs/app/examples/fullscreen-position-example/fullscreen-position-example.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { FullscreenPosition, Toppy, ToppyControl } from 'toppy'; 3 | import { HeroScreenComponent } from '../../host-components/hero-screen/hero-screen.component'; 4 | 5 | @Component({ 6 | selector: 'app-fullscreen-position-example', 7 | templateUrl: './fullscreen-position-example.component.html' 8 | }) 9 | export class FullscreenPositionExampleComponent implements OnInit { 10 | private _toppyControl: ToppyControl; 11 | constructor(private toppy: Toppy) {} 12 | 13 | ngOnInit() { 14 | this._toppyControl = this.toppy 15 | .position(new FullscreenPosition()) 16 | .config({ 17 | closeOnEsc: true 18 | }) 19 | .content(HeroScreenComponent) 20 | .create(); 21 | this._toppyControl.listen('t_compins').subscribe(d => { 22 | console.log('HeroScreenComponent initiated', d); 23 | }); 24 | } 25 | 26 | open() { 27 | this._toppyControl.open(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /docs/app/examples/global-position-example/global-position-example.component.html: -------------------------------------------------------------------------------- 1 |
2 |
click me
3 |
4 |
5 |
    6 |
  • 7 |
    11 | 18 |
    19 | 20 |
    21 |
    22 |
  • 23 |
24 |
25 | -------------------------------------------------------------------------------- /docs/app/examples/global-position-example/global-position-example.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, ViewEncapsulation } from '@angular/core'; 2 | import { GlobalPosition, InsidePlacement, Toppy, ToppyControl } from 'toppy'; 3 | import { SimpleModalComponent } from '../../host-components/simple-modal/simple-modal.component'; 4 | 5 | @Component({ 6 | selector: 'app-global-position-example', 7 | templateUrl: './global-position-example.component.html', 8 | encapsulation: ViewEncapsulation.None, 9 | styles: [ 10 | ` 11 | .global-content-wrapper { 12 | background: #e91e63; 13 | padding: 1rem 2rem; 14 | border: 2px solid #cc1a57; 15 | border-radius: 3px; 16 | color: #fff; 17 | font-weight: 500; 18 | } 19 | ` 20 | ] 21 | }) 22 | export class GlobalPositionExampleComponent implements OnInit { 23 | placements: { name: string; value: InsidePlacement }[] = [ 24 | { name: 'Bottom', value: InsidePlacement.BOTTOM }, 25 | { name: 'Bottom left', value: InsidePlacement.BOTTOM_LEFT }, 26 | { name: 'Bottom right', value: InsidePlacement.BOTTOM_RIGHT }, 27 | { name: 'Left', value: InsidePlacement.LEFT }, 28 | { name: 'Right', value: InsidePlacement.RIGHT }, 29 | { name: 'Top', value: InsidePlacement.TOP }, 30 | { name: 'Top left', value: InsidePlacement.TOP_LEFT }, 31 | { name: 'Top right', value: InsidePlacement.TOP_RIGHT }, 32 | { name: 'Center', value: InsidePlacement.CENTER } 33 | ]; 34 | selectedPlacement = this.placements[8].value; 35 | private _toppyControl: ToppyControl; 36 | constructor(private toppy: Toppy) {} 37 | 38 | ngOnInit() { 39 | this._toppyControl = this.toppy 40 | .position(new GlobalPosition({ placement: this.selectedPlacement, height: 'auto', width: 'auto', offset: 10 })) 41 | .config({ 42 | docClickCallback: () => { 43 | console.log('doc click callback'); 44 | }, 45 | closeOnDocClick: true, 46 | wrapperClass: 'global-content-wrapper', 47 | backdrop: true, 48 | bodyClass: 'global-toastr' 49 | }) 50 | .content(SimpleModalComponent) 51 | .create(); 52 | } 53 | 54 | open() { 55 | const content = this.placements.find(a => a.value === this.selectedPlacement).name; 56 | this._toppyControl.updateContent(content); 57 | this._toppyControl.open(); 58 | } 59 | 60 | onOptionChange() { 61 | this._toppyControl.updatePosition({ 62 | placement: this.selectedPlacement 63 | }); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /docs/app/examples/modal-example/modal-example.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 |
6 | 7 |
8 | 9 | 10 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /docs/app/examples/modal-example/modal-example.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/app/examples/modal-example/modal-example.component.scss -------------------------------------------------------------------------------- /docs/app/examples/modal-example/modal-example.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core'; 2 | import { GlobalPosition, InsidePlacement, Toppy, ToppyControl } from 'toppy'; 3 | 4 | @Component({ 5 | selector: 'app-modal-example', 6 | templateUrl: './modal-example.component.html', 7 | styleUrls: ['./modal-example.component.scss'] 8 | }) 9 | export class ModalExampleComponent implements OnInit { 10 | _toppyControl: ToppyControl; 11 | _toppyControl2: ToppyControl; 12 | @ViewChild('modalTpl', { read: TemplateRef }) modalTpl: TemplateRef; 13 | 14 | constructor(private toppy: Toppy) {} 15 | 16 | ngOnInit() { 17 | this._toppyControl = this.toppy 18 | .position( 19 | new GlobalPosition({ 20 | placement: InsidePlacement.CENTER, 21 | width: 300, 22 | height: 'auto' 23 | }) 24 | ) 25 | .config({ 26 | backdrop: true, 27 | closeOnDocClick: false, 28 | closeOnEsc: true 29 | }) 30 | .content(this.modalTpl) 31 | .create(); 32 | 33 | this._toppyControl2 = this.toppy 34 | .position( 35 | new GlobalPosition({ 36 | placement: InsidePlacement.CENTER, 37 | width: 'auto', 38 | height: 'auto' 39 | }) 40 | ) 41 | .config({ 42 | closeOnEsc: true, 43 | closeOnDocClick: true 44 | }) 45 | .content('', { hasHTML: true }) 46 | .create(); 47 | } 48 | open() { 49 | this._toppyControl.open(); 50 | } 51 | openImage() { 52 | this._toppyControl2.open(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /docs/app/examples/relative-position-example/relative-position-example.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | I am a target element
4 | Hover me 5 |
6 |
7 |
8 |
    9 |
  • 10 |
    14 | 22 | 23 |
    24 | 25 |
    26 |
    27 |
  • 28 |
29 |
30 | -------------------------------------------------------------------------------- /docs/app/examples/relative-position-example/relative-position-example.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'; 2 | import { Subject } from 'rxjs'; 3 | import { OutsidePlacement, RelativePosition, Toppy } from 'toppy'; 4 | import { ToppyControl } from '../../../../projects/toppy/src/lib/toppy-control'; 5 | 6 | @Component({ 7 | selector: 'app-relative-position-example', 8 | templateUrl: './relative-position-example.component.html', 9 | styles: [], 10 | providers: [Toppy] 11 | }) 12 | export class RelativePositionExampleComponent implements OnInit { 13 | @ViewChild('targetEl', { read: ElementRef }) 14 | targetEl: ElementRef; 15 | 16 | placements: { name: string; value: OutsidePlacement }[] = [ 17 | { name: 'Bottom', value: OutsidePlacement.BOTTOM }, 18 | { name: 'Bottom left', value: OutsidePlacement.BOTTOM_LEFT }, 19 | { name: 'Bottom right', value: OutsidePlacement.BOTTOM_RIGHT }, 20 | { name: 'Left', value: OutsidePlacement.LEFT }, 21 | { name: 'Left bottom', value: OutsidePlacement.LEFT_BOTTOM }, 22 | { name: 'Left top', value: OutsidePlacement.LEFT_TOP }, 23 | { name: 'Right', value: OutsidePlacement.RIGHT }, 24 | { name: 'Right bottom', value: OutsidePlacement.RIGHT_BOTTOM }, 25 | { name: 'Right top', value: OutsidePlacement.RIGHT_TOP }, 26 | { name: 'Top', value: OutsidePlacement.TOP }, 27 | { name: 'Top left', value: OutsidePlacement.TOP_LEFT }, 28 | { name: 'Top right', value: OutsidePlacement.TOP_RIGHT } 29 | ]; 30 | selectedPlacement = this.placements[0].value; 31 | private _toppyControl: ToppyControl; 32 | destroy$ = new Subject(); 33 | constructor(private toppy: Toppy) {} 34 | 35 | ngOnInit() { 36 | this._toppyControl = this.toppy 37 | .position( 38 | new RelativePosition({ 39 | placement: this.selectedPlacement, 40 | src: this.targetEl.nativeElement, 41 | autoUpdate: true 42 | }) 43 | ) 44 | .content('hello') 45 | .create(); 46 | } 47 | 48 | onOptionChange() { 49 | this._toppyControl.updatePosition({ 50 | placement: this.selectedPlacement 51 | }); 52 | } 53 | onMouseOver() { 54 | const content = this.placements.find(a => a.value === this.selectedPlacement).name; 55 | this._toppyControl.updateContent(content, { class: 'tooltip' }); 56 | this._toppyControl.open(); 57 | } 58 | onMouseLeave() { 59 | this._toppyControl.close(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /docs/app/examples/ribbon-example/ribbon-example.component.html: -------------------------------------------------------------------------------- 1 |
Open ribbon
2 | 3 | 4 |
5 |
6 |
7 |

8 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Consectetur natus, esse amet nisi laboriosam omnis 9 | tenetur accusantium vero at totam ducimus itaque soluta adipisci mollitia expedita dolores quaerat ratione 10 | iure? 11 |

12 | 13 |
14 |
15 |
16 |
17 | -------------------------------------------------------------------------------- /docs/app/examples/ribbon-example/ribbon-example.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/app/examples/ribbon-example/ribbon-example.component.scss -------------------------------------------------------------------------------- /docs/app/examples/ribbon-example/ribbon-example.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core'; 2 | import { InsidePlacement } from '../../../../projects/toppy/src/lib/models'; 3 | import { GlobalPosition, Toppy, ToppyControl } from '../../../../projects/toppy/src/public_api'; 4 | 5 | @Component({ 6 | selector: 'app-ribbon-example', 7 | templateUrl: './ribbon-example.component.html', 8 | styleUrls: ['./ribbon-example.component.scss'] 9 | }) 10 | export class RibbonExampleComponent implements OnInit { 11 | private _toppyControl: ToppyControl; 12 | @ViewChild('tpl', { read: TemplateRef }) tpl: TemplateRef; 13 | constructor(private toppy: Toppy) {} 14 | 15 | ngOnInit() { 16 | this._toppyControl = this.toppy 17 | .position( 18 | new GlobalPosition({ 19 | placement: InsidePlacement.BOTTOM, 20 | width: '100%', 21 | height: 'auto' 22 | }) 23 | ) 24 | .config({ 25 | closeOnDocClick: false 26 | }) 27 | .content(this.tpl) 28 | .create(); 29 | } 30 | open() { 31 | this._toppyControl.open(); 32 | } 33 | close() { 34 | this._toppyControl.close(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /docs/app/examples/slide-position-example/slide-position-example.component.html: -------------------------------------------------------------------------------- 1 |
2 |
Open sidebar
3 |
4 |
5 |
    6 |
  • 7 |
    11 | 18 |
    19 | 20 |
    21 |
    22 |
  • 23 |
24 |
25 | -------------------------------------------------------------------------------- /docs/app/examples/slide-position-example/slide-position-example.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { SlidePlacement, SlidePosition, Toppy, ToppyControl } from 'toppy'; 3 | import { SimpleListComponent } from '../../host-components/simple-list/simple-list.component'; 4 | 5 | @Component({ 6 | selector: 'app-slide-position-example', 7 | templateUrl: './slide-position-example.component.html', 8 | styles: [] 9 | }) 10 | export class SlidePositionExampleComponent implements OnInit { 11 | placements: { name: string; value: SlidePlacement }[] = [ 12 | { name: 'Left', value: SlidePlacement.LEFT }, 13 | { name: 'Right', value: SlidePlacement.RIGHT } 14 | ]; 15 | selectedPlacement = this.placements[0].value; 16 | private _toppyControl: ToppyControl; 17 | constructor(private toppy: Toppy) {} 18 | 19 | ngOnInit() {} 20 | 21 | open() { 22 | if (this._toppyControl) { 23 | this._toppyControl.close(); 24 | } 25 | this._toppyControl = this.toppy 26 | .position(new SlidePosition({ placement: this.selectedPlacement })) 27 | .config({ 28 | closeOnDocClick: true 29 | }) 30 | .content(SimpleListComponent) 31 | .create(); 32 | this._toppyControl.open(); 33 | } 34 | 35 | onOptionChange() { 36 | console.log('option changed'); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /docs/app/host-components/hero-screen/hero-screen.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Hello, Its fullscreen overlay

4 |

5 | It occupies complete screen width and height. Please click ESCAPE key or click close button to close the overlay 6 |

7 | 10 |
11 |
12 | -------------------------------------------------------------------------------- /docs/app/host-components/hero-screen/hero-screen.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-hero-screen', 5 | templateUrl: './hero-screen.component.html', 6 | styles: [] 7 | }) 8 | export class HeroScreenComponent { 9 | close; 10 | dispose() { 11 | this.close(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /docs/app/host-components/simple-list/simple-list.component.html: -------------------------------------------------------------------------------- 1 |

Slide example

2 | -------------------------------------------------------------------------------- /docs/app/host-components/simple-list/simple-list.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-simple-list', 5 | templateUrl: './simple-list.component.html', 6 | styles: [] 7 | }) 8 | export class SimpleListComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit() { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /docs/app/host-components/simple-modal/simple-modal.component.html: -------------------------------------------------------------------------------- 1 |
2 | Globally positioned! 3 |
-------------------------------------------------------------------------------- /docs/app/host-components/simple-modal/simple-modal.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-simple-modal', 5 | templateUrl: './simple-modal.component.html', 6 | styles: [] 7 | }) 8 | export class SimpleModalComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit() { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /docs/app/host-components/tooltip/tooltip.component.html: -------------------------------------------------------------------------------- 1 |

2 | tooltip works! 3 |

-------------------------------------------------------------------------------- /docs/app/host-components/tooltip/tooltip.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-tooltip', 5 | templateUrl: './tooltip.component.html', 6 | styles: [] 7 | }) 8 | export class TooltipComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit() { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /docs/app/test/test.component.html: -------------------------------------------------------------------------------- 1 |
2 |

Hello Everyone!

3 | close 4 |
5 | -------------------------------------------------------------------------------- /docs/app/test/test.component.scss: -------------------------------------------------------------------------------- 1 | .box { 2 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 3 | 'Segoe UI Emoji', 'Segoe UI Symbol'; 4 | background: #e91e63; 5 | padding: 5px; 6 | border-radius: 3px; 7 | font-size: 14px; 8 | margin-top: 0.2rem; 9 | color: #fff; 10 | } 11 | 12 | p { 13 | margin: 0; 14 | font-weight: 500; 15 | margin-bottom: 10px; 16 | } 17 | -------------------------------------------------------------------------------- /docs/app/test/test.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { TestComponent } from './test.component'; 4 | 5 | describe('TestComponent', () => { 6 | let component: TestComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ TestComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(TestComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /docs/app/test/test.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-test', 5 | templateUrl: './test.component.html', 6 | styleUrls: ['./test.component.scss'] 7 | }) 8 | export class TestComponent implements OnInit { 9 | close; 10 | constructor() {} 11 | 12 | ngOnInit() {} 13 | dismiss() { 14 | this.close(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /docs/app/utils/content/content.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/app/utils/content/content.component.scss -------------------------------------------------------------------------------- /docs/app/utils/content/content.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-content', 5 | templateUrl: './content.component.html' 6 | }) 7 | export class ContentComponent implements OnInit { 8 | constructor() {} 9 | 10 | ngOnInit() {} 11 | } 12 | -------------------------------------------------------------------------------- /docs/app/utils/scollspy.directive.ts: -------------------------------------------------------------------------------- 1 | import { Directive, ElementRef, EventEmitter, HostListener, Input, Output } from '@angular/core'; 2 | 3 | @Directive({ 4 | selector: '[scrollSpy]' 5 | }) 6 | export class ScrollSpyDirective { 7 | @Input() public spiedTags = []; 8 | @Output() public sectionChange = new EventEmitter(); 9 | private currentSection: string; 10 | 11 | constructor(private _el: ElementRef) {} 12 | 13 | @HostListener('window:scroll', ['$event']) 14 | onScroll(event: any) { 15 | let currentSection: string; 16 | const children = document.querySelectorAll('h3'); 17 | const scrollTop = document.documentElement.scrollTop; 18 | const parentOffset = document.documentElement.offsetTop; 19 | for (let i = 0; i < children.length; i++) { 20 | const element = children[i]; 21 | if (this.spiedTags.some(spiedTag => spiedTag === element.tagName)) { 22 | if (element.offsetTop - parentOffset <= scrollTop) { 23 | currentSection = element.id; 24 | } 25 | } 26 | } 27 | if (currentSection !== this.currentSection) { 28 | this.currentSection = currentSection; 29 | this.sectionChange.emit(this.currentSection); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /docs/app/utils/section/section.component.html: -------------------------------------------------------------------------------- 1 |
2 |

{{ heading }}

3 | 4 |
5 | -------------------------------------------------------------------------------- /docs/app/utils/section/section.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-section', 5 | templateUrl: './section.component.html' 6 | }) 7 | export class SectionComponent implements OnInit { 8 | @Input() 9 | heading = ''; 10 | @Input() 11 | icon = ''; 12 | constructor() {} 13 | 14 | ngOnInit() {} 15 | } 16 | -------------------------------------------------------------------------------- /docs/app/utils/sub-section/sub-section.component.html: -------------------------------------------------------------------------------- 1 |
2 |
{{ heading }}
3 | 4 |
5 | -------------------------------------------------------------------------------- /docs/app/utils/sub-section/sub-section.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-sub-section', 5 | templateUrl: './sub-section.component.html', 6 | styles: [] 7 | }) 8 | export class SubSectionComponent implements OnInit { 9 | @Input() 10 | heading; 11 | constructor() {} 12 | 13 | ngOnInit() {} 14 | } 15 | -------------------------------------------------------------------------------- /docs/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/.gitkeep -------------------------------------------------------------------------------- /docs/assets/archived-versions.json: -------------------------------------------------------------------------------- 1 | {"undefined":1541115139547,"1.0.11":1541115874348,"1.0.12":1541117479211,"1.0.13":1541118084059,"1.0.14":1541236752420,"1.0.15":1541524275096,"1.0.16":1541786515110,"1.0.17":1542127897095,"1.0.18":1542339601683,"1.1.0":1542548397540,"1.1.1":1542860347098,"1.2.0":1543048207817,"1.2.2":1543389399932,"1.2.3":1543405671424,"1.2.4":1543409608479,"1.3.0":1543944610263,"1.3.1":1543996147918,"2.0.0":1544793410445,"2.0.1":1544794243418,"2.0.2":1544841561628,"2.0.3":1544845267568,"2.0.4":1545292006287,"2.0.5":1545654967450,"2.1.0":1545763951127,"2.2.0":1546233019376,"2.3.0":1546714578991,"2.3.1":1549813301631,"2.3.2":1549952769013,"2.3.3":1552500395017,"2.3.4":1564588293511} 2 | -------------------------------------------------------------------------------- /docs/assets/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/favicon.png -------------------------------------------------------------------------------- /docs/assets/favicon/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/favicon/android-chrome-192x192.png -------------------------------------------------------------------------------- /docs/assets/favicon/android-chrome-256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/favicon/android-chrome-256x256.png -------------------------------------------------------------------------------- /docs/assets/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /docs/assets/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /docs/assets/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /docs/assets/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/favicon/favicon.ico -------------------------------------------------------------------------------- /docs/assets/favicon/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/favicon/mstile-150x150.png -------------------------------------------------------------------------------- /docs/assets/favicon/og-image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/favicon/og-image.jpg -------------------------------------------------------------------------------- /docs/assets/favicon/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.11, written by Peter Selinger 2001-2013 9 | 10 | 12 | 17 | 21 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /docs/assets/icons/icons8-beer-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/icons/icons8-beer-50.png -------------------------------------------------------------------------------- /docs/assets/icons/icons8-cafe-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/icons/icons8-cafe-50.png -------------------------------------------------------------------------------- /docs/assets/icons/icons8-cocktail-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/icons/icons8-cocktail-50.png -------------------------------------------------------------------------------- /docs/assets/icons/icons8-cola-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/icons/icons8-cola-50.png -------------------------------------------------------------------------------- /docs/assets/icons/icons8-comments-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/icons/icons8-comments-50.png -------------------------------------------------------------------------------- /docs/assets/icons/icons8-confetti-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/icons/icons8-confetti-50.png -------------------------------------------------------------------------------- /docs/assets/icons/icons8-dynamite-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/icons/icons8-dynamite-50.png -------------------------------------------------------------------------------- /docs/assets/icons/icons8-explosive-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/icons/icons8-explosive-50.png -------------------------------------------------------------------------------- /docs/assets/icons/icons8-firework-explosion-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/icons/icons8-firework-explosion-100.png -------------------------------------------------------------------------------- /docs/assets/icons/icons8-french-fries-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/icons/icons8-french-fries-50.png -------------------------------------------------------------------------------- /docs/assets/icons/icons8-fried-chicken-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/icons/icons8-fried-chicken-50.png -------------------------------------------------------------------------------- /docs/assets/icons/icons8-hamburger-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/icons/icons8-hamburger-50.png -------------------------------------------------------------------------------- /docs/assets/icons/icons8-orange-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/icons/icons8-orange-50.png -------------------------------------------------------------------------------- /docs/assets/icons/icons8-pears-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/icons/icons8-pears-50.png -------------------------------------------------------------------------------- /docs/assets/icons/icons8-pizza-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/icons/icons8-pizza-50.png -------------------------------------------------------------------------------- /docs/assets/icons/icons8-sandwich-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/icons/icons8-sandwich-50.png -------------------------------------------------------------------------------- /docs/assets/icons/icons8-scooter-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/icons/icons8-scooter-50.png -------------------------------------------------------------------------------- /docs/assets/icons/icons8-sweet-banana-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/icons/icons8-sweet-banana-50.png -------------------------------------------------------------------------------- /docs/assets/icons/icons8-tequila-shot-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/icons/icons8-tequila-shot-50.png -------------------------------------------------------------------------------- /docs/assets/icons/icons8-watch-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/icons/icons8-watch-50.png -------------------------------------------------------------------------------- /docs/assets/icons/icons8-watermelon-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/icons/icons8-watermelon-50.png -------------------------------------------------------------------------------- /docs/assets/icons/icons8-whiskey-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/icons/icons8-whiskey-50.png -------------------------------------------------------------------------------- /docs/assets/img/blast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/img/blast.png -------------------------------------------------------------------------------- /docs/assets/img/bomb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/img/bomb.png -------------------------------------------------------------------------------- /docs/assets/img/clock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/img/clock.png -------------------------------------------------------------------------------- /docs/assets/img/cow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/img/cow.png -------------------------------------------------------------------------------- /docs/assets/img/five.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/img/five.png -------------------------------------------------------------------------------- /docs/assets/img/fly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/img/fly.png -------------------------------------------------------------------------------- /docs/assets/img/four.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/img/four.png -------------------------------------------------------------------------------- /docs/assets/img/goat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/img/goat.png -------------------------------------------------------------------------------- /docs/assets/img/mail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/img/mail.png -------------------------------------------------------------------------------- /docs/assets/img/one.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/img/one.png -------------------------------------------------------------------------------- /docs/assets/img/snake.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/img/snake.png -------------------------------------------------------------------------------- /docs/assets/img/three.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/img/three.png -------------------------------------------------------------------------------- /docs/assets/img/two.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/img/two.png -------------------------------------------------------------------------------- /docs/assets/lo-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/lo-logo.png -------------------------------------------------------------------------------- /docs/assets/toppy-favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/toppy-favicon.png -------------------------------------------------------------------------------- /docs/assets/toppy-logo-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/toppy-logo-white.png -------------------------------------------------------------------------------- /docs/assets/toppy-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/assets/toppy-logo.png -------------------------------------------------------------------------------- /docs/browserslist: -------------------------------------------------------------------------------- 1 | # This file is currently used by autoprefixer to adjust CSS to support the below specified browsers 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | # 5 | # For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed 6 | 7 | > 0.5% 8 | last 2 versions 9 | Firefox ESR 10 | not dead 11 | not IE 9-11 -------------------------------------------------------------------------------- /docs/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /docs/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /docs/environments/version.ts: -------------------------------------------------------------------------------- 1 | export const TOPPY_VERSION='2.3.4' 2 | -------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/favicon.ico -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Toppy - Overlay library for Angular 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 25 | 26 | 27 | 28 | 29 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /docs/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, '../coverage'), 20 | reports: ['html', 'lcovonly'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false 30 | }); 31 | }; -------------------------------------------------------------------------------- /docs/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.error(err)); 13 | 14 | -------------------------------------------------------------------------------- /docs/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE9, IE10 and IE11 requires all of the following polyfills. **/ 22 | // import 'core-js/es6/symbol'; 23 | // import 'core-js/es6/object'; 24 | // import 'core-js/es6/function'; 25 | // import 'core-js/es6/parse-int'; 26 | // import 'core-js/es6/parse-float'; 27 | // import 'core-js/es6/number'; 28 | // import 'core-js/es6/math'; 29 | // import 'core-js/es6/string'; 30 | // import 'core-js/es6/date'; 31 | // import 'core-js/es6/array'; 32 | // import 'core-js/es6/regexp'; 33 | // import 'core-js/es6/map'; 34 | // import 'core-js/es6/weak-map'; 35 | // import 'core-js/es6/set'; 36 | 37 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 38 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 39 | 40 | /** IE10 and IE11 requires the following for the Reflect API. */ 41 | // import 'core-js/es6/reflect'; 42 | 43 | 44 | /** Evergreen browsers require these. **/ 45 | // Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove. 46 | 47 | 48 | 49 | /** 50 | * Web Animations `@angular/platform-browser/animations` 51 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. 52 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). 53 | **/ 54 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 55 | 56 | /** 57 | * By default, zone.js will patch all possible macroTask and DomEvents 58 | * user can disable parts of macroTask/DomEvents patch by setting following flags 59 | */ 60 | 61 | // (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 62 | // (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 63 | // (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 64 | 65 | /* 66 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 67 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 68 | */ 69 | // (window as any).__Zone_enable_cross_context_check = true; 70 | 71 | /*************************************************************************************************** 72 | * Zone JS is required by default for Angular itself. 73 | */ 74 | import 'zone.js/dist/zone'; // Included with Angular CLI. 75 | 76 | 77 | 78 | /*************************************************************************************************** 79 | * APPLICATION IMPORTS 80 | */ 81 | -------------------------------------------------------------------------------- /docs/styles/_common.scss: -------------------------------------------------------------------------------- 1 | /* stylelint-disable scss/at-import-no-partial-leading-underscore */ 2 | @import './config'; 3 | @import './helpers/_index'; 4 | @import './themes/_index'; 5 | -------------------------------------------------------------------------------- /docs/styles/_config.scss: -------------------------------------------------------------------------------- 1 | $toppy--base-font-size: 13px; 2 | $toppy--base-font-size-xl: 16px; 3 | $toppy--app-name: 'TOPPY'; 4 | $toppy--debug: false; 5 | $toppy--font-family: 'Rubik', acumin-pro, 'Inconsolata', 'Inter UI', 'Nunito Sans'; 6 | $toppy--font-family-headings: 'acumin-pro'; 7 | $toppy--font-family-monospace: 'Roboto mono', 'calling-code', 'Courier New', 'Lucida Console', Monaco, Courier, 8 | monospace; 9 | 10 | $toppy--colors: ( 11 | 'bg': #fafafa, 12 | 'text': #88889a, 13 | 'heading': #9590d4, 14 | 'border': #e9edff, 15 | 'dark': #585c6d, 16 | 'shadow': #dddde9, 17 | 'primary': #3F51B5, 18 | 'secondary': #ef8fb7, 19 | 'success': #3fc782, 20 | 'warning': #f78f1e, 21 | 'danger': #e3505a, 22 | 'info': #03a9f4, 23 | 'yellow': #cabcb1, 24 | 'alt': #3F51B5 25 | ); 26 | 27 | $toppy--font-sizes: ( 28 | 'sm': 0.9rem, 29 | 'md': 1rem, 30 | 'lg': 1.4rem, 31 | 'xl': 4rem, 32 | 'h1': 3.2rem, 33 | 'h2': 2rem, 34 | 'h3': 1.75rem, 35 | 'h4': 1.5rem, 36 | 'h5': 1.25rem, 37 | 'h6': 1rem 38 | ); 39 | 40 | $toppy--border-rad: 3px; 41 | $toppy--icons-font: 'toppy'; 42 | $toppy--icon-font-path: './icons'; 43 | 44 | $toppy--grid-breakpoints: ( 45 | xs: 0, 46 | sm: 576px, 47 | md: 768px, 48 | lg: 992px, 49 | xl: 1600px 50 | ); 51 | -------------------------------------------------------------------------------- /docs/styles/animations/__index.scss: -------------------------------------------------------------------------------- 1 | @import './slide_in'; 2 | -------------------------------------------------------------------------------- /docs/styles/animations/_slide_in.scss: -------------------------------------------------------------------------------- 1 | /* ---------------------------------------------- 2 | .slide-in-left { 3 | animation: slide-in-left 0.5s cubic-bezier(0.250, 0.460, 0.450, 0.940) both; 4 | } 5 | ---------------------------------------------- */ 6 | 7 | @keyframes slide-in-left { 8 | 0% { 9 | opacity: 0; 10 | transform: translateX(-10px); 11 | } 12 | 13 | 100% { 14 | opacity: 1; 15 | transform: translateX(0); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /docs/styles/base/__index.scss: -------------------------------------------------------------------------------- 1 | @import './fonts'; 2 | @import './icons'; 3 | @import './reset'; 4 | @import './typography'; 5 | @import './utility'; 6 | @import './input'; 7 | @import './buttons'; 8 | @import './pre'; 9 | -------------------------------------------------------------------------------- /docs/styles/base/_buttons.scss: -------------------------------------------------------------------------------- 1 | button.btn.-is-plain { 2 | background-color: transparent; 3 | border-color: transparent; 4 | } 5 | 6 | button.btn.-is-compact { 7 | padding: 0; 8 | } 9 | -------------------------------------------------------------------------------- /docs/styles/base/_fonts.scss: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css?family=Roboto+Mono:400,500,700'); 2 | @import url('https://use.typekit.net/uur7gsm.css'); 3 | @import url('https://fonts.googleapis.com/css?family=Rubik:300,400,500,700'); 4 | -------------------------------------------------------------------------------- /docs/styles/base/_icons.scss: -------------------------------------------------------------------------------- 1 | $icons: ( 2 | alert-circle: '\e902', 3 | alert-triangle: '\e904', 4 | arrow-left: '\e910', 5 | arrow-right: '\e912', 6 | check-circle: '\e92c', 7 | copy: '\e944', 8 | edit: '\e958', 9 | external-link: '\e95b', 10 | file: '\e964', 11 | filter: '\e966', 12 | github: '\e970', 13 | hash: '\e975', 14 | heart: '\e977', 15 | help: '\e978', 16 | home: '\e979', 17 | link: '\e982', 18 | loader: '\e986', 19 | maximize-2: '\e98e', 20 | menu: '\e98f', 21 | minimize-2: '\e995', 22 | more-horizontal: '\e99b', 23 | navigation: '\e9a0', 24 | plus-circle: '\e9b2', 25 | radio: '\e9b7', 26 | repeat: '\e9ba', 27 | rss: '\e9be', 28 | settings: '\e9c4', 29 | share-2: '\e9c6', 30 | sliders: '\e9d1', 31 | tag: '\e9db', 32 | terminal: '\e9dd', 33 | twitter: '\e9ea', 34 | users: '\e9f6', 35 | x: '\ea02', 36 | x-circle: '\ea03', 37 | zap: '\ea06' 38 | ); 39 | 40 | @font-face { 41 | font-family: 'toppy'; 42 | font-style: normal; 43 | font-weight: normal; 44 | src: url('#{$toppy--icon-font-path}/toppy.ttf?olqd7c') format('truetype'), 45 | url('#{$toppy--icon-font-path}/toppy.woff?olqd7c') format('woff'), 46 | url('#{$toppy--icon-font-path}/toppy.svg?olqd7c#choosy') format('svg'); 47 | } 48 | 49 | .toppy-icon { 50 | /* use !important to prevent issues with browser extensions that change fonts */ 51 | font-family: $toppy--icons-font !important; 52 | 53 | /* Better Font Rendering =========== */ 54 | -webkit-font-smoothing: antialiased; 55 | font-style: normal; 56 | font-variant: normal; 57 | font-weight: normal; 58 | line-height: 1; 59 | -moz-osx-font-smoothing: grayscale; 60 | speak: none; 61 | text-transform: none; 62 | font-size: 80%; 63 | } 64 | @each $icon in $icons { 65 | .icon-#{nth($icon, 1)} { 66 | &:before { 67 | content: nth($icon, 2); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /docs/styles/base/_input.scss: -------------------------------------------------------------------------------- 1 | input.form-control { 2 | font-weight: 500; 3 | font-size: 1.25rem; 4 | border: 0; 5 | padding: 0.75rem 1rem; 6 | line-height: 1; 7 | background: clr('bg2'); 8 | } 9 | 10 | input.form-control.-is-inline { 11 | padding: 0.4rem 1rem; 12 | color: clr('heading'); 13 | } 14 | -------------------------------------------------------------------------------- /docs/styles/base/_pre.scss: -------------------------------------------------------------------------------- 1 | markdown .inline-code { 2 | padding: 1rem; 3 | pre[class*='language-'] { 4 | display: inline-block; 5 | line-height: 1; 6 | padding: 0; 7 | margin: 0; 8 | background: transparent; 9 | code { 10 | font-size: 1rem; 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /docs/styles/base/_reset.scss: -------------------------------------------------------------------------------- 1 | html { 2 | @include smooth-font(); 3 | font-size: $toppy--base-font-size; 4 | } 5 | 6 | .custom-select { 7 | -moz-appearance: none; 8 | -webkit-appearance: none; 9 | } 10 | 11 | .btn.btn-link { 12 | color: clr('link-alt'); 13 | font-weight: 500; 14 | &:hover { 15 | text-decoration: none; 16 | } 17 | } 18 | 19 | .btn.btn-lg { 20 | font-size: 1rem; 21 | } 22 | 23 | button.btn, 24 | a.btn { 25 | line-height: 1; 26 | padding: 0.5rem 1rem; 27 | } 28 | 29 | .btn.btn-success, 30 | .btn.btn-danger, 31 | .btn.btn-primary { 32 | color: #fff; 33 | } 34 | a:not([href]):not([tabindex]) { 35 | color: none !important; 36 | } 37 | -------------------------------------------------------------------------------- /docs/styles/base/_typography.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/styles/base/_typography.scss -------------------------------------------------------------------------------- /docs/styles/base/_utility.scss: -------------------------------------------------------------------------------- 1 | .doc-util-flex-2 { 2 | flex: 2 !important; 3 | } 4 | 5 | .doc-util-valign-middle { 6 | display: flex; 7 | flex-direction: column; 8 | justify-content: center; 9 | } 10 | 11 | .doc-util-tt-lowercase { 12 | text-transform: lowercase; 13 | } 14 | 15 | .doc-util-cover-span { 16 | display: flex; 17 | flex-direction: column; 18 | } 19 | 20 | .doc-util-cursor-pointer { 21 | cursor: pointer; 22 | } 23 | 24 | .doc-util-pos-right { 25 | right: 0; 26 | left: auto !important; 27 | } 28 | 29 | .ff-asap { 30 | } 31 | 32 | .--only-on-parent-hover { 33 | display: none !important; 34 | } 35 | -------------------------------------------------------------------------------- /docs/styles/browsers/__index.scss: -------------------------------------------------------------------------------- 1 | @import './ie11'; 2 | @import './chrome'; 3 | @import './firefox'; 4 | -------------------------------------------------------------------------------- /docs/styles/browsers/_chrome.scss: -------------------------------------------------------------------------------- 1 | /* stylelint-disable media-feature-name-no-vendor-prefix */ 2 | @media all and (-webkit-min-device-pixel-ratio: 1) { 3 | } 4 | 5 | 6 | /* Change the white to any color ;) */ 7 | 8 | @-webkit-keyframes autofill { 9 | to { 10 | color: #666; 11 | background: transparent; 12 | } 13 | } 14 | 15 | input:-webkit-autofill { 16 | -webkit-animation-name: autofill; 17 | -webkit-animation-fill-mode: both; 18 | } -------------------------------------------------------------------------------- /docs/styles/browsers/_firefox.scss: -------------------------------------------------------------------------------- 1 | /* stylelint-disable function-url-quotes*/ 2 | @-moz-document url-prefix() { 3 | /* empty */ 4 | } 5 | -------------------------------------------------------------------------------- /docs/styles/browsers/_ie11.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/styles/browsers/_ie11.scss -------------------------------------------------------------------------------- /docs/styles/components/__index.scss: -------------------------------------------------------------------------------- 1 | @import 'target-element-container'; 2 | @import 'controls'; 3 | @import 'blade'; 4 | @import 'hero'; 5 | @import 'menu'; 6 | @import 'modal'; 7 | @import 'table'; 8 | -------------------------------------------------------------------------------- /docs/styles/components/_blade.scss: -------------------------------------------------------------------------------- 1 | .comp.blade { 2 | background: #3a3d40; 3 | height: 100%; 4 | color: #fff; 5 | h3 { 6 | font-weight: 300; 7 | text-align: center; 8 | display: flex; 9 | align-items: center; 10 | justify-content: center; 11 | flex: 1; 12 | height: 100%; 13 | opacity: 0.9; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /docs/styles/components/_controls.scss: -------------------------------------------------------------------------------- 1 | .comp.controls { 2 | display: flex; 3 | flex-wrap: wrap; 4 | align-items: center; 5 | justify-content: start; 6 | line-height: 3; 7 | // background: #f4f4f9; 8 | padding: 1rem; 9 | li { 10 | display: flex; 11 | flex: 0 0 9rem; 12 | margin: 0.5rem; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /docs/styles/components/_hero.scss: -------------------------------------------------------------------------------- 1 | .comp.hero { 2 | background: #24283c; 3 | height: 100%; 4 | display: flex; 5 | align-items: center; 6 | flex-direction: column; 7 | justify-content: center; 8 | h1 { 9 | font-weight: 300; 10 | color: #fff; 11 | } 12 | p { 13 | color: #aaa; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /docs/styles/components/_menu.scss: -------------------------------------------------------------------------------- 1 | ul.comp.menu { 2 | li { 3 | background-color: transparent; 4 | border: none; 5 | color: clr('heading'); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /docs/styles/components/_modal.scss: -------------------------------------------------------------------------------- 1 | .modal-container { 2 | background: #fff; 3 | border-radius: 4px; 4 | box-shadow: 4px 5px 19px #62616b; 5 | overflow: hidden; 6 | color: clr('dark'); 7 | } 8 | 9 | .modal-header { 10 | padding: 20px; 11 | font-weight: 400; 12 | background: #f0f0ff; 13 | text-align: center; 14 | font-size: 1.4rem; 15 | } 16 | .modal-body { 17 | padding: 20px; 18 | .illus { 19 | min-height: 192px; 20 | } 21 | } 22 | .modal-footer { 23 | text-align: right; 24 | padding: 20px; 25 | } 26 | -------------------------------------------------------------------------------- /docs/styles/components/_table.scss: -------------------------------------------------------------------------------- 1 | table { 2 | // @include .table; 3 | width: 100%; 4 | } 5 | -------------------------------------------------------------------------------- /docs/styles/components/_target-element-container.scss: -------------------------------------------------------------------------------- 1 | .comp.target-element-container { 2 | padding: 2rem; 3 | display: flex; 4 | align-items: center; 5 | justify-content: center; 6 | .target-element { 7 | background: clr('primary'); 8 | padding: 1rem; 9 | border-radius: 2px; 10 | color: #fff; 11 | font-weight: 500; 12 | box-shadow: 0px 3px 6px #c6c6d8; 13 | cursor: pointer; 14 | } 15 | 16 | .target-element-basic { 17 | padding: 1rem 2rem; 18 | border: 1px dashed #d8d8e3; 19 | cursor: pointer; 20 | } 21 | 22 | .target-element-basic:hover { 23 | border-color: #cfd2de; 24 | color: clr('dark'); 25 | background-color: #fff; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /docs/styles/elements/__index.scss: -------------------------------------------------------------------------------- 1 | @import './btn'; 2 | @import './hr'; 3 | @import './tooltip'; 4 | @import './toast'; 5 | -------------------------------------------------------------------------------- /docs/styles/elements/_btn.scss: -------------------------------------------------------------------------------- 1 | .btn.btn-transparent { 2 | background-color: transparent; 3 | border-color: transparent; 4 | } 5 | -------------------------------------------------------------------------------- /docs/styles/elements/_hr.scss: -------------------------------------------------------------------------------- 1 | .doc-el-hr { 2 | background-color: transparentize(#fff, 0.8); 3 | // height: 0.1rem; 4 | height: 1px; 5 | &.hr-dark{ 6 | background-color: transparentize(#000, 0.9); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /docs/styles/elements/_toast.scss: -------------------------------------------------------------------------------- 1 | .el.toast { 2 | background: #76cc7a; 3 | padding: 1rem; 4 | border: 1px solid #7dbf81; 5 | border-radius: 3px; 6 | color: #fff; 7 | } 8 | -------------------------------------------------------------------------------- /docs/styles/elements/_tooltip.scss: -------------------------------------------------------------------------------- 1 | .el.tooltip { 2 | background: #e75676bd; 3 | padding: 0.3rem 0.5rem; 4 | border-radius: 3px; 5 | font-size: 11px; 6 | color: #fff; 7 | text-shadow: 1px 1px 1px #a55b6b; 8 | margin: 0; 9 | } 10 | -------------------------------------------------------------------------------- /docs/styles/helpers/__index.scss: -------------------------------------------------------------------------------- 1 | /* stylelint-disable scss/at-import-no-partial-leading-underscore */ 2 | @import './functions/_index'; 3 | @import './mixins/_index'; 4 | @import './debug'; 5 | -------------------------------------------------------------------------------- /docs/styles/helpers/_debug.scss: -------------------------------------------------------------------------------- 1 | @if ($toppy--debug) { 2 | div, 3 | ul { 4 | box-shadow: 0px 0px 1px 0px #e3505a; 5 | } 6 | section { 7 | box-shadow: 0px 0px 1px 1px #187fe5; 8 | } 9 | 10 | span, 11 | li { 12 | box-shadow: 0px 0px 1px 0px #212529; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /docs/styles/helpers/functions/__index.scss: -------------------------------------------------------------------------------- 1 | @import './clr'; 2 | @import './fs'; 3 | @import './rem'; 4 | @import './z'; 5 | -------------------------------------------------------------------------------- /docs/styles/helpers/functions/_clr.scss: -------------------------------------------------------------------------------- 1 | @function clr($key: 'primary') { 2 | @return map-get($toppy--colors, $key); 3 | } 4 | -------------------------------------------------------------------------------- /docs/styles/helpers/functions/_fs.scss: -------------------------------------------------------------------------------- 1 | @function fs($key: 'md') { 2 | @return map-get($toppy--font-sizes, $key); 3 | } 4 | -------------------------------------------------------------------------------- /docs/styles/helpers/functions/_rem.scss: -------------------------------------------------------------------------------- 1 | @function rem($pixels, $context: $toppy--base-font-size) { 2 | @if (unitless($pixels)) { 3 | $pixels: $pixels * 1px; 4 | } 5 | @if (unitless($context)) { 6 | $context: $context * 1px; 7 | } 8 | @return $pixels / $context * 1rem; 9 | } 10 | -------------------------------------------------------------------------------- /docs/styles/helpers/functions/_z.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/styles/helpers/functions/_z.scss -------------------------------------------------------------------------------- /docs/styles/helpers/mixins/__index.scss: -------------------------------------------------------------------------------- 1 | @import './acceleration'; 2 | @import './ellipsis'; 3 | @import './placeholder'; 4 | @import './smooth-font'; 5 | @import './gradient'; 6 | -------------------------------------------------------------------------------- /docs/styles/helpers/mixins/_acceleration.scss: -------------------------------------------------------------------------------- 1 | @mixin hardware($backface: true, $perspective: 1000) { 2 | @if $backface { 3 | backface-visibility: hidden; 4 | } 5 | perspective: $perspective; 6 | } 7 | -------------------------------------------------------------------------------- /docs/styles/helpers/mixins/_ellipsis.scss: -------------------------------------------------------------------------------- 1 | /// div { 2 | /// @include ellipsis; 3 | /// } 4 | /// 5 | /// .box { 6 | /// @include ellipsis(3); 7 | /// } 8 | 9 | /* stylelint-disable */ 10 | 11 | @mixin ellipsis($lines: 1, $substract: 0) { 12 | @if $lines == 1 { 13 | overflow: hidden; 14 | text-overflow: ellipsis; 15 | white-space: nowrap; 16 | width: 100% - $substract; 17 | } @else { 18 | -webkit-box-orient: vertical; 19 | box-orient: vertical; 20 | display: -webkit-box; 21 | display: box; 22 | -webkit-line-clamp: $lines; 23 | line-clamp: $lines; 24 | overflow: hidden; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /docs/styles/helpers/mixins/_gradient.scss: -------------------------------------------------------------------------------- 1 | @function is-direction($value) { 2 | $is-keyword: index( 3 | 4 | ( 5 | to top, 6 | to top right, 7 | to right top, 8 | to right, 9 | to bottom right, 10 | to right bottom, 11 | to bottom, 12 | to bottom left, 13 | to left bottom, 14 | to left, 15 | to left top, 16 | to top left 17 | ), 18 | $value 19 | ); 20 | $is-angle: type-of($value)=='number' and index('deg' 'grad' 'turn' 'rad', unit($value)); 21 | @return $is-keyword or $is-angle; 22 | } 23 | @mixin linear-gradient($direction, $color-stops...) { 24 | @if is-direction($direction) ==false { 25 | $color-stops: $direction, $color-stops; 26 | $direction: 180deg; 27 | } 28 | background: nth(nth($color-stops, 1), 1); 29 | background: -webkit-linear-gradient(legacy-direction($direction), $color-stops); 30 | background: linear-gradient($direction, $color-stops); 31 | } 32 | -------------------------------------------------------------------------------- /docs/styles/helpers/mixins/_placeholder.scss: -------------------------------------------------------------------------------- 1 | /* stylelint-disable selector-no-vendor-prefix */ 2 | @mixin input-placeholder { 3 | &.placeholder { 4 | @content; 5 | } 6 | &:-moz-placeholder { 7 | @content; 8 | } 9 | &::-moz-placeholder { 10 | @content; 11 | } 12 | &:-ms-input-placeholder { 13 | @content; 14 | } 15 | &::-webkit-input-placeholder { 16 | @content; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /docs/styles/helpers/mixins/_smooth-font.scss: -------------------------------------------------------------------------------- 1 | /* stylelint-disable */ 2 | 3 | @mixin smooth-font($lines: 1, $substract: 0) { 4 | font-size: 100%; 5 | -webkit-text-size-adjust: 100%; 6 | font-variant-ligatures: none; 7 | -webkit-font-variant-ligatures: none; 8 | text-rendering: optimizeLegibility; 9 | -moz-osx-font-smoothing: grayscale; 10 | font-smoothing: antialiased; 11 | -webkit-font-smoothing: antialiased; 12 | text-shadow: rgba(0, 0, 0, 0.01) 0 0 1px; 13 | } 14 | -------------------------------------------------------------------------------- /docs/styles/icons/toppy.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/styles/icons/toppy.ttf -------------------------------------------------------------------------------- /docs/styles/icons/toppy.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/styles/icons/toppy.woff -------------------------------------------------------------------------------- /docs/styles/layouts/__index.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/styles/layouts/__index.scss -------------------------------------------------------------------------------- /docs/styles/pages/__index.scss: -------------------------------------------------------------------------------- 1 | // @import "./playground"; 2 | -------------------------------------------------------------------------------- /docs/styles/responsive/__index.scss: -------------------------------------------------------------------------------- 1 | @import './lg'; 2 | @import './xl'; 3 | @import './md'; 4 | -------------------------------------------------------------------------------- /docs/styles/responsive/_lg.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/styles/responsive/_lg.scss -------------------------------------------------------------------------------- /docs/styles/responsive/_md.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lokesh-coder/toppy/3129723f99f430b0448eb52b433250a4816d558a/docs/styles/responsive/_md.scss -------------------------------------------------------------------------------- /docs/styles/responsive/_xl.scss: -------------------------------------------------------------------------------- 1 | @include media-breakpoint-up(xl) { 2 | html { 3 | // font-size: $toppy--base-font-size-xl; 4 | } 5 | } -------------------------------------------------------------------------------- /docs/styles/root.scss: -------------------------------------------------------------------------------- 1 | /* stylelint-disable scss/at-import-no-partial-leading-underscore */ 2 | 3 | @import './config'; 4 | @import './helpers/_index'; 5 | @import './base/_index'; 6 | @import './vendors/_index'; 7 | @import './pages/_index'; 8 | @import './animations/_index'; 9 | @import './components/_index'; 10 | @import './layouts/_index'; 11 | @import './elements/_index'; 12 | @import './browsers/_index'; 13 | @import './responsive/_index'; 14 | @import './temp'; 15 | -------------------------------------------------------------------------------- /docs/styles/vendors/__index.scss: -------------------------------------------------------------------------------- 1 | @import './bootstrap'; 2 | @import './pretty-checkbox'; 3 | @import './prism'; 4 | -------------------------------------------------------------------------------- /docs/styles/vendors/_bootstrap.scss: -------------------------------------------------------------------------------- 1 | /* Bootstrap config */ 2 | $body-bg: clr('bg'); 3 | $body-color: clr('text'); 4 | $link-color: clr('primary'); 5 | $link-hover-color: clr('primary-o'); 6 | $headings-color: clr('dark'); 7 | 8 | $theme-colors: ( 9 | primary: clr('primary'), 10 | secondary: clr('secondary'), 11 | success: clr('success'), 12 | warning: clr('warning'), 13 | danger: clr('danger'), 14 | info: clr('info'), 15 | dark: clr('dark'), 16 | alt: clr('alt'), 17 | ); 18 | $border-radius: $toppy--border-rad; 19 | $font-family-base: $toppy--font-family; 20 | $headings-font-family: $toppy--font-family-headings; 21 | $breadcrumb-margin-bottom: 0; 22 | 23 | $h1-font-size: fs('h1'); 24 | $h2-font-size: fs('h2'); 25 | $h3-font-size: fs('h3'); 26 | $h4-font-size: fs('h4'); 27 | $h5-font-size: fs('h5'); 28 | $h6-font-size: fs('h6'); 29 | $input-btn-padding-y-lg: 0.8rem; 30 | $input-btn-padding-x-lg: 1.5rem; 31 | 32 | $grid-breakpoints: $toppy--grid-breakpoints; 33 | 34 | @import '~bootstrap/scss/functions'; 35 | @import '~bootstrap/scss/variables'; 36 | @import '~bootstrap/scss/mixins'; 37 | // @import '~bootstrap/scss/print'; 38 | @import '~bootstrap/scss/reboot'; 39 | @import '~bootstrap/scss/type'; 40 | @import '~bootstrap/scss/images'; 41 | @import '~bootstrap/scss/code'; 42 | @import '~bootstrap/scss/grid'; 43 | @import '~bootstrap/scss/tables'; 44 | @import '~bootstrap/scss/forms'; 45 | @import '~bootstrap/scss/buttons'; 46 | @import '~bootstrap/scss/transitions'; 47 | //@import '~bootstrap/scss/dropdown'; 48 | //@import '~bootstrap/scss/button-group'; 49 | @import '~bootstrap/scss/input-group'; 50 | @import '~bootstrap/scss/custom-forms'; 51 | @import '~bootstrap/scss/nav'; 52 | @import '~bootstrap/scss/navbar'; 53 | @import '~bootstrap/scss/card'; 54 | //@import '~bootstrap/scss/breadcrumb'; 55 | // @import '~bootstrap/scss/pagination'; 56 | @import '~bootstrap/scss/badge'; 57 | // @import '~bootstrap/scss/jumbotron'; 58 | @import '~bootstrap/scss/alert'; 59 | //@import '~bootstrap/scss/progress'; 60 | // @import '~bootstrap/scss/media'; 61 | @import '~bootstrap/scss/list-group'; 62 | @import '~bootstrap/scss/close'; 63 | //@import '~bootstrap/scss/modal'; 64 | //@import '~bootstrap/scss/tooltip'; 65 | //@import '~bootstrap/scss/popover'; 66 | // @import '~bootstrap/scss/carousel'; 67 | @import '~bootstrap/scss/utilities'; 68 | -------------------------------------------------------------------------------- /docs/styles/vendors/_pretty-checkbox.scss: -------------------------------------------------------------------------------- 1 | $pretty--color-success: clr('success'); 2 | @import '~pretty-checkbox/src/pretty-checkbox'; 3 | 4 | .pretty.pretty-check { 5 | .state label:before, 6 | .pretty.p-round .state label:after { 7 | border-width: 0.15rem; 8 | } 9 | .icon { 10 | transform: scale(0.8); 11 | } 12 | } 13 | 14 | .pretty.p-switch .state label:before, 15 | .pretty.p-switch .state label:after { 16 | top: calc((0% - (100% - 1em)) - 12%); 17 | } 18 | -------------------------------------------------------------------------------- /docs/styles/vendors/_prism.scss: -------------------------------------------------------------------------------- 1 | app-content pre[class*='language-'] { 2 | background: #fff; 3 | border: 1px solid clr('border'); 4 | border-radius: $toppy--border-rad; 5 | code { 6 | font-size: 12px; 7 | font-family: $toppy--font-family-monospace; 8 | } 9 | } 10 | app-content .inline-code { 11 | display: flex; 12 | align-items: center; 13 | flex-wrap: wrap; 14 | pre[class*='language-'] { 15 | font-size: 13px !important; 16 | background-color: #f0f0f3; 17 | border: 0; 18 | margin: 6px; 19 | padding: 2px 8px; 20 | code{ 21 | 22 | font-size: 10px !important; 23 | } 24 | } 25 | } 26 | 27 | app-content code[class*='language-'], 28 | app-content pre[class*='language-'] { 29 | color: #51585d; 30 | } 31 | -------------------------------------------------------------------------------- /docs/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: any; 11 | 12 | // First, initialize the Angular testing environment. 13 | getTestBed().initTestEnvironment( 14 | BrowserDynamicTestingModule, 15 | platformBrowserDynamicTesting() 16 | ); 17 | // Then we find all the tests. 18 | const context = require.context('./', true, /\.spec\.ts$/); 19 | // And load the modules. 20 | context.keys().map(context); 21 | -------------------------------------------------------------------------------- /docs/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "types": [] 6 | }, 7 | "exclude": [ 8 | "test.ts", 9 | "**/*.spec.ts" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /docs/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "test.ts", 12 | "polyfills.ts" 13 | ], 14 | "include": [ 15 | "**/*.spec.ts", 16 | "**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /docs/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tslint.json", 3 | "rules": { 4 | "directive-selector": [ 5 | true, 6 | "attribute", 7 | "app", 8 | "camelCase" 9 | ], 10 | "component-selector": [ 11 | true, 12 | "element", 13 | "app", 14 | "kebab-case" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './src/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | onPrepare() { 23 | require('ts-node').register({ 24 | project: require('path').join(__dirname, './tsconfig.e2e.json') 25 | }); 26 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 27 | } 28 | }; -------------------------------------------------------------------------------- /e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | 3 | describe('workspace-project App', () => { 4 | let page: AppPage; 5 | 6 | beforeEach(() => { 7 | page = new AppPage(); 8 | }); 9 | 10 | it('should display welcome message', () => { 11 | page.navigateTo(); 12 | expect(page.getParagraphText()).toEqual('Welcome to toppy-app!'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | getParagraphText() { 9 | return element(by.css('app-root h1')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types": [ 8 | "jasmine", 9 | "jasminewd2", 10 | "node" 11 | ] 12 | } 13 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "toppy-app", 3 | "version": "2.3.4", 4 | "description": "Overlay library for Angular 7+", 5 | "keywords": [ 6 | "angular", 7 | "dropdown", 8 | "modal", 9 | "overlay", 10 | "popover", 11 | "popup", 12 | "sidebar", 13 | "tooltip" 14 | ], 15 | "homepage": "https://github.com/lokesh-coder/toppy", 16 | "bugs": { 17 | "url": "https://github.com/lokesh-coder/toppy/issues" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "https://github.com/lokesh-coder/toppy" 22 | }, 23 | "license": "MIT", 24 | "author": { 25 | "name": "Lokesh Rajendran", 26 | "email": "mexican.dirtyfellow@gmail.com", 27 | "url": "https://github.com/lokesh-coder" 28 | }, 29 | "scripts": { 30 | "archive:app": "node ./scripts/archive.js", 31 | "build:app": "ng build --prod --baseHref=/toppy/", 32 | "build:lib": "ng build toppy", 33 | "e2e": "ng e2e", 34 | "lint": "ng lint", 35 | "ng": "ng", 36 | "postpublish": "node ./scripts/gh-pages.js", 37 | "release": "semantic-release", 38 | "start": "ng serve", 39 | "test": "npm run test:lib", 40 | "test:app": "ng test --project toppy-app", 41 | "test:lib": "ng test --project toppy", 42 | "travis-deploy-once": "travis-deploy-once" 43 | }, 44 | "dependencies": { 45 | "@angular/animations": "~7.1.0", 46 | "@angular/common": "~7.1.0", 47 | "@angular/compiler": "~7.1.0", 48 | "@angular/core": "~7.1.0", 49 | "@angular/forms": "~7.1.0", 50 | "@angular/http": "~7.1.0", 51 | "@angular/platform-browser": "~7.1.0", 52 | "@angular/platform-browser-dynamic": "~7.1.0", 53 | "@angular/router": "~7.1.0", 54 | "@ngx-prism/core": "^2.0.1", 55 | "@types/prismjs": "^1.9.0", 56 | "bootstrap": "^4.1.3", 57 | "core-js": "^2.5.7", 58 | "date-fns": "^1.29.0", 59 | "listr": "^0.14.3", 60 | "lodash-es": "^4.17.11", 61 | "npm-registry-client": "^8.6.0", 62 | "pretty-checkbox": "^3.0.3", 63 | "prismjs": "^1.15.0", 64 | "remark-bracketed-spans": "^3.0.0", 65 | "remark-custom-blocks": "^2.3.1", 66 | "rxjs": "~6.3.3", 67 | "zone.js": "~0.8.26" 68 | }, 69 | "devDependencies": { 70 | "@angular-devkit/build-angular": "~0.11.0", 71 | "@angular-devkit/build-ng-packagr": "~0.11.0", 72 | "@angular/cli": "~7.1.0", 73 | "@angular/compiler-cli": "~7.1.0", 74 | "@angular/language-service": "~7.1.0", 75 | "@commitlint/cli": "7.2.1", 76 | "@commitlint/config-conventional": "7.1.2", 77 | "@commitlint/travis-cli": "7.2.1", 78 | "@semantic-release/changelog": "3.0.1", 79 | "@semantic-release/exec": "3.3.0", 80 | "@semantic-release/git": "7.0.5", 81 | "@semantic-release/github": "^5.2.5", 82 | "@semantic-release/release-notes-generator": "^7.1.4", 83 | "@types/jasmine": "~3.3.0", 84 | "@types/jasminewd2": "~2.0.6", 85 | "@types/node": "~10.12.10", 86 | "angular-cli-ghpages": "^0.5.3", 87 | "codelyzer": "~4.5.0", 88 | "conventional-changelog": "3.0.5", 89 | "fs-extra": "^7.0.1", 90 | "gh-pages": "^2.0.1", 91 | "github-release-notes": "0.17.0", 92 | "husky": "^1.2.0", 93 | "jasmine-core": "~3.3.0", 94 | "jasmine-spec-reporter": "~4.2.1", 95 | "json": "^9.0.6", 96 | "karma": "~3.1.1", 97 | "karma-chrome-launcher": "~2.2.0", 98 | "karma-coverage-istanbul-reporter": "~2.0.4", 99 | "karma-helpful-reporter": "^0.3.4", 100 | "karma-jasmine": "~2.0.1", 101 | "karma-jasmine-html-reporter": "^1.4.0", 102 | "karma-viewport": "^1.0.2", 103 | "ng-packagr": "^4.4.0", 104 | "nodemon": "^1.18.7", 105 | "protractor": "~5.4.1", 106 | "rehype-format": "^2.3.1", 107 | "rehype-highlight": "^2.2.1", 108 | "rehype-raw": "^4.0.0", 109 | "rehype-stringify": "^5.0.0", 110 | "remark-attr": "^0.8.0", 111 | "remark-autolink-headings": "^5.1.0", 112 | "remark-highlight.js": "^5.0.0", 113 | "remark-html": "^9.0.0", 114 | "remark-rehype": "^4.0.0", 115 | "remark-slug": "^5.1.1", 116 | "replace-in-file": "^3.4.2", 117 | "sane": "^4.0.2", 118 | "semantic-release": "^15.12.2", 119 | "stylelint": "^9.9.0", 120 | "stylelint-config-recommended-scss": "^3.2.0", 121 | "stylelint-scss": "^3.4.0", 122 | "travis-deploy-once": "5.0.9", 123 | "ts-node": "~7.0.1", 124 | "tsickle": "0.34.0", 125 | "tslib": "^1.9.3", 126 | "tslint": "~5.11.0", 127 | "typescript": "~3.1.6" 128 | }, 129 | "husky": { 130 | "hooks": { 131 | "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /projects/toppy/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular', 'viewport'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-viewport'), 11 | require('karma-chrome-launcher'), 12 | require('karma-jasmine-html-reporter'), 13 | require('karma-coverage-istanbul-reporter'), 14 | require('@angular-devkit/build-angular/plugins/karma') 15 | ], 16 | client: { 17 | clearContext: false // leave Jasmine Spec Runner output visible in browser 18 | }, 19 | coverageIstanbulReporter: { 20 | dir: require('path').join(__dirname, '../../coverage'), 21 | reports: ['html', 'lcovonly', 'json'], 22 | fixWebpackSourcePaths: true 23 | }, 24 | reporters: ['progress', 'kjhtml'], 25 | port: 9876, 26 | colors: true, 27 | logLevel: config.LOG_INFO, 28 | autoWatch: true, 29 | browsers: ['Chrome'], 30 | singleRun: false 31 | }); 32 | }; 33 | -------------------------------------------------------------------------------- /projects/toppy/ng-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", 3 | "dest": "../../dist/toppy", 4 | "lib": { 5 | "entryFile": "src/public_api.ts" 6 | } 7 | } -------------------------------------------------------------------------------- /projects/toppy/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "toppy", 3 | "version": "0.0.0-development", 4 | "description": "Overlay library for Angular 7+", 5 | "keywords": [ 6 | "angular", 7 | "dropdown", 8 | "modal", 9 | "overlay", 10 | "popover", 11 | "popup", 12 | "sidebar", 13 | "tooltip" 14 | ], 15 | "homepage": "https://github.com/lokesh-coder/toppy", 16 | "bugs": { 17 | "url": "https://github.com/lokesh-coder/toppy/issues" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "https://github.com/lokesh-coder/toppy" 22 | }, 23 | "license": "MIT", 24 | "author": { 25 | "name": "Lokesh Rajendran", 26 | "email": "mexican.dirtyfellow@gmail.com", 27 | "url": "https://github.com/lokesh-coder" 28 | }, 29 | "peerDependencies": { 30 | "@angular/common": "^7.0.0", 31 | "@angular/core": "^7.0.0" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /projects/toppy/src/lib/config.ts: -------------------------------------------------------------------------------- 1 | import { ToppyConfig } from './models'; 2 | 3 | export const DefaultConfig: ToppyConfig = { 4 | containerClass: 't-overlay', 5 | bodyClass: 't-open', 6 | wrapperClass: '', 7 | backdropClass: '', 8 | backdrop: false, 9 | closeOnDocClick: false, 10 | listenWindowEvents: true, 11 | closeOnEsc: false, 12 | windowResizeCallback: () => {}, 13 | docClickCallback: () => {} 14 | }; 15 | -------------------------------------------------------------------------------- /projects/toppy/src/lib/models.ts: -------------------------------------------------------------------------------- 1 | import { TemplateRef } from '@angular/core'; 2 | import { ToppyPosition } from './position/position'; 3 | 4 | export interface PositionMeta { 5 | top?: number; 6 | left?: number; 7 | bottom?: number; 8 | right?: number; 9 | height?: number | string; 10 | width?: number | string; 11 | position?: string; 12 | extra?: string; 13 | } 14 | 15 | enum p { 16 | TOP = 't', 17 | LEFT = 'l', 18 | RIGHT = 'r', 19 | BOTTOM = 'b', 20 | TOP_LEFT = 'tl', 21 | TOP_RIGHT = 'tr', 22 | BOTTOM_LEFT = 'bl', 23 | BOTTOM_RIGHT = 'br' 24 | } 25 | 26 | enum o { 27 | LEFT_TOP = 'lt', 28 | RIGHT_TOP = 'rt', 29 | LEFT_BOTTOM = 'lb', 30 | RIGHT_BOTTOM = 'rb' 31 | } 32 | 33 | enum i { 34 | CENTER = 'c' 35 | } 36 | export const OutsidePlacement = { 37 | ...p, 38 | ...o 39 | }; 40 | export const InsidePlacement = { 41 | ...p, 42 | ...i 43 | }; 44 | export type OutsidePlacement = p | o; 45 | export type InsidePlacement = p | i; 46 | 47 | export enum SlidePlacement { 48 | LEFT = 'l', 49 | RIGHT = 'r' 50 | } 51 | 52 | export interface ContainerSize { 53 | width: string | number; 54 | height: string | number; 55 | } 56 | 57 | export interface ToppyConfig { 58 | backdrop: boolean; 59 | containerClass: string; 60 | wrapperClass: string; 61 | backdropClass: string; 62 | listenWindowEvents: boolean; 63 | closeOnDocClick: boolean; 64 | bodyClass: string; 65 | closeOnEsc: boolean; 66 | windowResizeCallback: () => void; 67 | docClickCallback: () => void; 68 | } 69 | 70 | export interface ComponentType { 71 | new (...args: any[]): T; 72 | } 73 | 74 | export type TID = string; 75 | 76 | export type ToppyEventName = 't_open' | 't_close' | 't_dynpos' | 't_detach' | 't_posupdate' | 't_compins'; 77 | 78 | export interface ToppyEvent { 79 | from: TID; 80 | name: ToppyEventName; 81 | data?: any; 82 | } 83 | 84 | export const enum ContentType { 85 | STRING = 's', 86 | HTML = 'h', 87 | TEMPLATE = 't', 88 | COMPONENT = 'c' 89 | } 90 | export type ContentData = string | TemplateRef | ComponentType; 91 | export type ContentProps = { [x: string]: any } | any; 92 | 93 | export interface Content { 94 | type?: ContentType; 95 | data: ContentData; 96 | props?: ContentProps; 97 | } 98 | 99 | export interface Inputs { 100 | position: ToppyPosition | null; 101 | config: ToppyConfig; 102 | content: Content; 103 | tid: TID; 104 | } 105 | -------------------------------------------------------------------------------- /projects/toppy/src/lib/position/fullscreen-position.ts: -------------------------------------------------------------------------------- 1 | import { PositionMeta } from '../models'; 2 | import { ToppyPosition } from './position'; 3 | 4 | export class FullscreenPosition extends ToppyPosition { 5 | getPositions(): PositionMeta { 6 | return { top: 0, left: 0, width: '100%', height: '100%', position: 'fixed' }; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /projects/toppy/src/lib/position/global-position.ts: -------------------------------------------------------------------------------- 1 | import { InsidePlacement } from '../models'; 2 | import { setWH } from '../utils'; 3 | import { ToppyPosition } from './position'; 4 | 5 | interface GlobalPositionConfig { 6 | placement?: InsidePlacement; 7 | offset?: number; 8 | width?: string | number; 9 | height?: string | number; 10 | } 11 | 12 | export class GlobalPosition extends ToppyPosition { 13 | protected config: GlobalPositionConfig = { placement: InsidePlacement.CENTER, width: 100, height: 100, offset: 0 }; 14 | 15 | constructor(config: GlobalPositionConfig) { 16 | super(); 17 | this.updateConfig(config); 18 | } 19 | getPositions(hostEl?: HTMLElement) { 20 | const host = hostEl.getBoundingClientRect() as any; 21 | const src = { 22 | width: window['innerWidth'], 23 | height: window['innerHeight'] 24 | }; 25 | let { width: w, height: h } = this.config; 26 | 27 | w = setWH(src, host, 'width', w); 28 | h = setWH(src, host, 'height', h); 29 | 30 | const props = this.calc(this.config.placement, src, host); 31 | return { 32 | ...props, 33 | width: w, 34 | height: h, 35 | position: 'fixed', 36 | extra: this.config.placement 37 | }; 38 | } 39 | 40 | private calc(placement: InsidePlacement, src, host) { 41 | const [main, sub] = placement.split(''); 42 | const p: any = {}; 43 | 44 | if (main === 't') { 45 | p.top = this.config.offset; 46 | } 47 | if (main === 'b') { 48 | p.bottom = this.config.offset; 49 | } 50 | if ((main === 'l' || main === 'r' || main === 'c') && !sub) { 51 | p.top = (src.height - host.height) / 2; 52 | } 53 | 54 | if ((main === 't' || main === 'b' || main === 'c') && !sub) { 55 | p.left = (src.width - host.width) / 2; 56 | } 57 | if ((main === 'l' && !sub) || sub === 'l') { 58 | p.left = this.config.offset; 59 | } 60 | if ((main === 'r' && !sub) || sub === 'r') { 61 | p.right = this.config.offset; 62 | } 63 | 64 | return p; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /projects/toppy/src/lib/position/index.ts: -------------------------------------------------------------------------------- 1 | export { FullscreenPosition } from './fullscreen-position'; 2 | export { GlobalPosition } from './global-position'; 3 | export { RelativePosition } from './relative-position'; 4 | export { SlidePosition } from './slide-position'; 5 | -------------------------------------------------------------------------------- /projects/toppy/src/lib/position/position.ts: -------------------------------------------------------------------------------- 1 | export abstract class ToppyPosition { 2 | protected config = {}; 3 | abstract getPositions(host: HTMLElement): any; 4 | 5 | getClassName(): string { 6 | return this.constructor.name.replace('Pos', '-pos').toLowerCase(); 7 | } 8 | 9 | updateConfig(config) { 10 | this.config = { ...this.config, ...config }; 11 | } 12 | 13 | init(tid: string) {} 14 | } 15 | -------------------------------------------------------------------------------- /projects/toppy/src/lib/position/relative-position.ts: -------------------------------------------------------------------------------- 1 | import { OutsidePlacement, PositionMeta } from '../models'; 2 | import { Bus, setWH } from '../utils'; 3 | import { ToppyPosition } from './position'; 4 | 5 | interface RelativePositionConfig { 6 | src: HTMLElement; 7 | placement?: OutsidePlacement; 8 | autoUpdate?: boolean; 9 | width?: string | number; 10 | height?: string | number; 11 | } 12 | 13 | export class RelativePosition extends ToppyPosition { 14 | protected config: RelativePositionConfig = { 15 | src: null, 16 | placement: OutsidePlacement.TOP, 17 | autoUpdate: false, 18 | width: 'auto', 19 | height: 'auto' 20 | }; 21 | obs: MutationObserver; 22 | constructor(config: RelativePositionConfig) { 23 | super(); 24 | this.updateConfig(config); 25 | } 26 | init(tid: string): void { 27 | if (this.config.autoUpdate) this.listenDrag(tid); 28 | } 29 | 30 | getPositions(targetEl: HTMLElement): Pick { 31 | const s = this.getCoords(this.config.src); 32 | const h = this.getCoords(targetEl); 33 | let { width: w, height: ht } = this.config; 34 | 35 | w = setWH(s, h, 'width', w); 36 | ht = setWH(s, h, 'height', ht); 37 | 38 | const { pos, props } = this.calculatePos(this.config.placement, s, h); 39 | return { ...this.round(props), width: w, height: ht, extra: pos }; 40 | } 41 | 42 | private getCoords(elem: HTMLElement): PositionMeta { 43 | return elem.getBoundingClientRect(); 44 | } 45 | 46 | private calc(placement: OutsidePlacement, src, host): object { 47 | const [main, sub] = placement.split(''); 48 | const p = { left: 0, top: 0 }; 49 | if ((main === 't' || main === 'b') && !sub) { 50 | p.left = src.left + (src.width - host.width) / 2; 51 | } 52 | 53 | if ((main === 't' || main === 'b') && sub) { 54 | p.left = src.left; 55 | } 56 | if ((main === 't' || main === 'b') && sub === 'r') { 57 | p.left = src.left + src.width - host.width; 58 | } 59 | if (main === 'l') { 60 | p.left = src.left - host.width; 61 | } 62 | if (main === 'r') { 63 | p.left = src.right; 64 | } 65 | 66 | if (main === 't') { 67 | p.top = src.top - host.height; 68 | } 69 | if (main === 'b') { 70 | p.top = src.top + src.height; 71 | } 72 | if (main === 'l' || main === 'r') { 73 | p.top = src.top + (src.height - host.height) / 2; 74 | } 75 | if (sub === 't' && (main === 'l' || main === 'r')) { 76 | p.top = src.top; 77 | } 78 | if (sub === 'b' && (main === 'l' || main === 'r')) { 79 | p.top = src.top + src.height - host.height; 80 | } 81 | return p; 82 | } 83 | 84 | private calculatePos(pos, s, h, c = true): { [x: string]: any } { 85 | const props = this.calc(pos, s, h); 86 | 87 | if (c && this.config.autoUpdate && this.isOverflowed({ ...props, width: h.width, height: h.height })) { 88 | return this.calculatePos(this.nextPosition(pos), s, h, false); 89 | } 90 | 91 | return { pos, props }; 92 | } 93 | 94 | private isOverflowed(props: { [x: string]: any }): boolean { 95 | const { innerHeight, innerWidth } = window; 96 | props.bottom = props.top + props.height; 97 | props.right = props.left + props.width; 98 | return props.bottom > innerHeight || props.top <= 0 || props.left <= 0 || props.right > innerWidth; 99 | } 100 | 101 | private nextPosition(current: OutsidePlacement): string { 102 | const placements = ['t', 'b', 'l', 'r', 'tl', 'bl', 'tr', 'br', 'lt', 'rt', 'lb', 'rb']; 103 | 104 | const index = placements.indexOf(current); 105 | const even = index % 2 === 0; 106 | return even ? placements[index + 1] : placements[index - 1]; 107 | } 108 | 109 | private round(props: object): object { 110 | Object.keys(props).forEach(x => (props[x] = Math.round(props[x]))); 111 | return props; 112 | } 113 | 114 | private listenDrag(tid: string): void { 115 | if (this.obs) this.obs.disconnect(); 116 | this.obs = new MutationObserver(mutationsList => { 117 | for (const mutation of mutationsList) { 118 | if (mutation.type === 'attributes') Bus.send(tid, 't_dynpos'); 119 | } 120 | }); 121 | 122 | this.obs.observe(this.config.src, { 123 | attributeFilter: ['style'] 124 | }); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /projects/toppy/src/lib/position/slide-position.ts: -------------------------------------------------------------------------------- 1 | import { PositionMeta, SlidePlacement } from '../models'; 2 | import { ToppyPosition } from './position'; 3 | 4 | interface SlidePlacementConfig { 5 | placement?: SlidePlacement; 6 | width?: string; 7 | } 8 | 9 | export class SlidePosition extends ToppyPosition { 10 | protected config: SlidePlacementConfig = { placement: SlidePlacement.LEFT, width: '30%' }; 11 | 12 | constructor(config: SlidePlacementConfig) { 13 | super(); 14 | this.config = { ...this.config, ...config }; 15 | } 16 | getPositions(): PositionMeta { 17 | const props = this.config.placement === SlidePlacement.LEFT ? { left: 0 } : { right: 0 }; 18 | return { 19 | ...props, 20 | top: 0, 21 | width: this.config.width, 22 | height: '100%', 23 | position: 'fixed', 24 | extra: this.config.placement 25 | }; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /projects/toppy/src/lib/styles.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | left: 0; 3 | position: fixed; 4 | top: 0; 5 | width: 100%; 6 | height: 100%; 7 | pointer-events: none; 8 | &.no-pointers { 9 | pointer-events: all; 10 | } 11 | .t-backdrop { 12 | left: 0; 13 | position: fixed; 14 | top: 0; 15 | width: 100%; 16 | height: 100%; 17 | background: rgba(0, 0, 0, 0.5); 18 | // pointer-events: none; 19 | } 20 | > div.t-wrapper { 21 | position: absolute; 22 | visibility: hidden; 23 | opacity: 0; 24 | transition: opacity 0.2s ease; 25 | overflow: hidden; 26 | pointer-events: all; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /projects/toppy/src/lib/template.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 5 |
{{ content.data }}
6 |
7 |
8 | 9 | 10 | 11 | 12 |
13 |
14 | -------------------------------------------------------------------------------- /projects/toppy/src/lib/toppy-control.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ApplicationRef, 3 | ComponentFactory, 4 | ComponentFactoryResolver, 5 | ComponentRef, 6 | Injector, 7 | ViewRef 8 | } from '@angular/core'; 9 | import { animationFrameScheduler, fromEvent, merge as mergeObs, Observable, Subject } from 'rxjs'; 10 | import { debounceTime, distinctUntilChanged, filter, map, observeOn, skipWhile, takeUntil, tap } from 'rxjs/operators'; 11 | import { Content, ContentData, ContentProps, TID, ToppyConfig, ToppyEventName } from './models'; 12 | import { ToppyPosition } from './position/position'; 13 | import { ToppyComponent } from './toppy.component'; 14 | import { BodyEl, Bus, getContent } from './utils'; 15 | 16 | export class ToppyControl { 17 | position: ToppyPosition; 18 | config: ToppyConfig; 19 | content: Content; 20 | tid: TID; 21 | comp: ToppyComponent; 22 | updateTextContent: Subject = new Subject(); 23 | hostView: ViewRef; 24 | compRef: ComponentRef; 25 | 26 | private viewEl: HTMLElement; 27 | private isOpen = false; 28 | private compFac: ComponentFactory; 29 | private die: Subject<1> = new Subject(); 30 | 31 | constructor( 32 | private appRef: ApplicationRef, 33 | private compResolver: ComponentFactoryResolver, 34 | private injector: Injector 35 | ) { 36 | this.updateTextContent.subscribe(content => { 37 | if (this.isOpen) this.comp.updateTextContent(content); 38 | }); 39 | } 40 | 41 | open(): void { 42 | if (this.isOpen) return; 43 | 44 | this.attach(); 45 | if (this.viewEl) { 46 | mergeObs(this.onDocumentClick(), this.onWindowResize(), this.onEscClick()).subscribe(); 47 | setTimeout(() => Bus.send(this.tid, 't_dynpos'), 1); 48 | } 49 | 50 | Bus.send(this.tid, 't_open'); 51 | this.isOpen = true; 52 | } 53 | 54 | close(): void { 55 | if (!this.isOpen) return; 56 | 57 | this.dettach(); 58 | this.die.next(1); 59 | Bus.send(this.tid, 't_close'); 60 | this.isOpen = false; 61 | } 62 | 63 | toggle(): void { 64 | return this.isOpen ? this.close() : this.open(); 65 | } 66 | 67 | onEscClick(): Observable { 68 | return fromEvent(BodyEl, 'keydown').pipe( 69 | takeUntil(this.die), 70 | skipWhile(() => !this.config.closeOnEsc), 71 | filter((e: any) => (e.key === 'Escape' || e.key === 'Esc' || e.keyCode === 27) && e.target.nodeName === 'BODY'), 72 | tap(e => e.preventDefault()), 73 | map(e => e.target), 74 | tap(() => this.close()) 75 | ); 76 | } 77 | 78 | onDocumentClick(): Observable { 79 | return fromEvent(this.viewEl, 'click').pipe( 80 | takeUntil(this.die), 81 | map((e: any) => e.target), 82 | skipWhile(() => !this.config.closeOnDocClick), 83 | filter(this.isNotHostElement.bind(this)), 84 | tap(() => { 85 | this.config.docClickCallback(); 86 | this.close(); 87 | }) 88 | ); 89 | } 90 | 91 | onWindowResize(): Observable { 92 | const onResize = fromEvent(window, 'resize'); 93 | const onScroll = fromEvent(window, 'scroll', { passive: true }); 94 | return mergeObs(onResize, onScroll).pipe( 95 | skipWhile(() => !this.config.listenWindowEvents), 96 | takeUntil(this.die), 97 | debounceTime(5), 98 | observeOn(animationFrameScheduler), 99 | distinctUntilChanged(), 100 | tap(() => { 101 | Bus.send(this.tid, 't_dynpos'); 102 | this.config.windowResizeCallback(); 103 | }) 104 | ); 105 | } 106 | 107 | changePosition(newPosition: ToppyPosition): void { 108 | this.position = newPosition; 109 | } 110 | 111 | updatePosition(positionConfig: any): void { 112 | this.position.updateConfig(positionConfig); 113 | } 114 | 115 | updateContent(content: ContentData, props: ContentProps = {}): void { 116 | this.content = getContent(content, { ...this.content.props, ...props }); 117 | } 118 | 119 | listen(eventName: ToppyEventName) { 120 | return Bus.listen(this.tid, eventName); 121 | } 122 | 123 | private isNotHostElement(el): boolean { 124 | const wrapperEl = this.viewEl.querySelector('.t-wrapper'); 125 | return el !== wrapperEl && !wrapperEl.contains(el); 126 | } 127 | 128 | private attach(): void { 129 | /* create component */ 130 | this.compFac = this.compResolver.resolveComponentFactory(ToppyComponent); 131 | this.compRef = this.compFac.create(this.injector); 132 | this.comp = this.compRef.instance; 133 | 134 | /* assign props */ 135 | const { position, content, config, tid } = this; 136 | content.props.close = this.close.bind(this); 137 | Object.assign(this.comp, { position, content, config, tid }); 138 | 139 | /* attach view */ 140 | this.hostView = this.compRef.hostView; 141 | this.appRef.attachView(this.hostView); 142 | this.viewEl = (this.hostView as any).rootNodes[0]; 143 | BodyEl.appendChild(this.viewEl); 144 | } 145 | 146 | private dettach(): void { 147 | if (!this.hostView) return; 148 | 149 | this.appRef.detachView(this.hostView); 150 | this.compRef.destroy(); 151 | this.hostView = this.viewEl = this.comp = null; 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /projects/toppy/src/lib/toppy.component.ts: -------------------------------------------------------------------------------- 1 | import { 2 | AfterViewInit, 3 | ChangeDetectionStrategy, 4 | ChangeDetectorRef, 5 | Component, 6 | ComponentFactoryResolver, 7 | ElementRef, 8 | Injector, 9 | OnDestroy, 10 | OnInit, 11 | ViewChild, 12 | ViewContainerRef 13 | } from '@angular/core'; 14 | import { Observable, Subject } from 'rxjs'; 15 | import { startWith, takeUntil, tap } from 'rxjs/operators'; 16 | import { Content, ContentType, TID, ToppyConfig } from './models'; 17 | import { ToppyPosition } from './position/position'; 18 | import { Bus, cssClass, toCss } from './utils'; 19 | 20 | @Component({ 21 | // tslint:disable-next-line:component-selector 22 | selector: 'toppy', 23 | templateUrl: './template.html', 24 | styleUrls: ['./styles.scss'], 25 | changeDetection: ChangeDetectionStrategy.OnPush 26 | }) 27 | export class ToppyComponent implements OnInit, AfterViewInit, OnDestroy { 28 | @ViewChild('compOutlet', { read: ViewContainerRef }) compOutlet: ViewContainerRef; 29 | content: Content = { 30 | type: ContentType.STRING, 31 | data: '', 32 | props: {} 33 | }; 34 | config: ToppyConfig; 35 | position: ToppyPosition; 36 | tid: TID; 37 | el: HTMLElement | any; 38 | wrapperEl: HTMLElement | any; 39 | extra: string; 40 | pinj: any; 41 | compInstance; 42 | private die: Subject<1> = new Subject(); 43 | 44 | constructor( 45 | public inj: Injector, 46 | private cd: ChangeDetectorRef, 47 | private compResolver: ComponentFactoryResolver, 48 | private elRef: ElementRef 49 | ) { 50 | this.pinj = Injector; 51 | } 52 | 53 | ngOnInit() { 54 | this.el = this.elRef.nativeElement; 55 | this.wrapperEl = this.el.querySelector('.t-wrapper'); 56 | let cls = ['t-container', this.config.containerClass, this.position.getClassName()]; 57 | if (this.config.closeOnDocClick) { 58 | cls = cls.concat(['no-pointers']); 59 | } 60 | this.el.setAttribute('data-tid', this.tid); 61 | cssClass('add', cls, `[data-tid='${[this.tid]}']`); 62 | cssClass('add', [this.config.bodyClass]); 63 | } 64 | 65 | ngAfterViewInit() { 66 | this.listenPos().subscribe(); 67 | if (this.content.type === ContentType.COMPONENT) { 68 | this.compInstance = this.setComponent(this.content.props); 69 | Bus.send(this.tid, 't_compins', this.compInstance); 70 | } 71 | } 72 | 73 | setComponent(props) { 74 | const compRef = this.compOutlet.createComponent( 75 | this.compResolver.resolveComponentFactory(this.content.data as any) 76 | ); 77 | Object.assign(compRef.instance, props); 78 | compRef.changeDetectorRef.detectChanges(); 79 | return compRef.instance; 80 | } 81 | 82 | updateTextContent(data: string): void { 83 | if (this.content.type === ContentType.STRING) { 84 | this.content.data = data; 85 | this.cd.detectChanges(); 86 | } 87 | } 88 | 89 | ngOnDestroy(): void { 90 | cssClass('remove', [this.config.bodyClass]); 91 | this.die.next(1); 92 | Bus.send(this.tid, 't_detach'); 93 | } 94 | 95 | private listenPos(): Observable { 96 | return Bus.listen(this.tid, 't_dynpos').pipe( 97 | startWith(1), 98 | takeUntil(this.die), 99 | tap(e => { 100 | if (!e || !e.x) return this.setPos(); 101 | const coords = { left: e.x, top: e.y }; 102 | this.wrapperEl.style = toCss(coords); 103 | }) 104 | ); 105 | } 106 | 107 | private setPos(): void { 108 | const { extra, ...coords } = this.position.getPositions(this.wrapperEl); 109 | if (this.extra !== extra) { 110 | this.extra = extra; 111 | this.cd.detectChanges(); 112 | } 113 | Object.assign(coords, { visibility: 'visible', opacity: '1' }); 114 | this.wrapperEl.style = toCss(coords); 115 | Bus.send(this.tid, 't_posupdate'); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /projects/toppy/src/lib/toppy.module.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common'; 2 | import { NgModule } from '@angular/core'; 3 | import { ToppyComponent } from './toppy.component'; 4 | 5 | @NgModule({ 6 | imports: [CommonModule], 7 | declarations: [ToppyComponent], 8 | entryComponents: [ToppyComponent] 9 | }) 10 | export class ToppyModule {} 11 | -------------------------------------------------------------------------------- /projects/toppy/src/lib/toppy.ts: -------------------------------------------------------------------------------- 1 | import { ApplicationRef, ComponentFactoryResolver, Injectable, Injector } from '@angular/core'; 2 | import { DefaultConfig } from './config'; 3 | import { ContentData, ContentProps, ContentType, Inputs, InsidePlacement, TID, ToppyConfig } from './models'; 4 | import { GlobalPosition } from './position'; 5 | import { ToppyPosition } from './position/position'; 6 | import { ToppyControl } from './toppy-control'; 7 | import { Bus, createId, getContent } from './utils'; 8 | 9 | @Injectable({ 10 | providedIn: 'root' 11 | }) 12 | export class Toppy { 13 | static controls: { [key: string]: ToppyControl } = {}; 14 | private tid: TID; 15 | private inputs: Inputs = { 16 | position: null, 17 | config: DefaultConfig, 18 | content: { type: ContentType.STRING, data: 'hello', props: {} }, 19 | tid: null 20 | }; 21 | 22 | constructor(private injector: Injector) { 23 | this.inputs.position = new GlobalPosition({ placement: InsidePlacement.TOP }); 24 | } 25 | 26 | position(position: ToppyPosition): Toppy { 27 | this.inputs.position = position; 28 | return this; 29 | } 30 | 31 | config(config: Partial): Toppy { 32 | this.inputs.config = { ...DefaultConfig, ...config }; 33 | return this; 34 | } 35 | 36 | content(data: ContentData, props: ContentProps = {}): Toppy { 37 | this.inputs.content = getContent(data, props); 38 | return this; 39 | } 40 | 41 | create(key: string = null): ToppyControl { 42 | this.tid = this.inputs.tid = key || createId(); 43 | 44 | const injector = Injector.create( 45 | [ 46 | { 47 | provide: ToppyControl, 48 | deps: [ApplicationRef, ComponentFactoryResolver, Injector] 49 | } 50 | ], 51 | this.injector 52 | ); 53 | 54 | const tc = injector.get(ToppyControl); 55 | if (Toppy.controls[this.tid]) { 56 | this.tid = createId(); 57 | } 58 | this.inputs.position.init(this.tid); 59 | Toppy.controls[this.tid] = Object.assign(tc, this.inputs); 60 | return tc; 61 | } 62 | 63 | getCtrl(tid: TID): ToppyControl { 64 | return Toppy.controls[tid]; 65 | } 66 | 67 | destroy() { 68 | // tslint:disable-next-line:forin 69 | for (const key in Toppy.controls) { 70 | Toppy.controls[key].close(); 71 | } 72 | Toppy.controls = {}; 73 | Bus.stop(); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /projects/toppy/src/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { TemplateRef } from '@angular/core'; 2 | import { Observable, Subject } from 'rxjs'; 3 | import { filter, map } from 'rxjs/operators'; 4 | import { Content, ContentData, ContentProps, ContentType, ToppyEvent, ToppyEventName } from './models'; 5 | 6 | export function getContent(data: ContentData, props: ContentProps = {}): Content { 7 | let type: ContentType = ContentType.COMPONENT; 8 | 9 | if (typeof data === 'string' && props['hasHTML']) type = ContentType.HTML; 10 | else if (typeof data === 'string') type = ContentType.STRING; 11 | else if (data instanceof TemplateRef) type = ContentType.TEMPLATE; 12 | 13 | return { data, type, props }; 14 | } 15 | 16 | export function createId() { 17 | return Math.random() 18 | .toString(36) 19 | .substr(2, 5); 20 | } 21 | 22 | /* html dom utils */ 23 | 24 | export function cssClass(method: 'add' | 'remove', cls: string[], target: string = 'body') { 25 | document.querySelector(target).classList[method](...cls); 26 | } 27 | 28 | export function toCss(styleObj) { 29 | return Object.keys(styleObj) 30 | .map(x => `${x}:${styleObj[x]}${typeof styleObj[x] === 'number' ? 'px' : ''}`) 31 | .join(';'); 32 | } 33 | 34 | export function percentToCss(max, percentage: string): string { 35 | let number = Number(percentage.slice(0, -1)); 36 | if (number > 100) { 37 | number = 100; 38 | } 39 | return `calc(${max}px - ${100 - number}%)`; 40 | } 41 | 42 | export function setWH(src, host, key, value) { 43 | if (typeof value === 'number') { 44 | host[key] = value = Math.abs(value); 45 | } 46 | 47 | if (typeof value === 'string' && value.endsWith('%')) { 48 | value = percentToCss(src[key], value); 49 | } 50 | 51 | return value; 52 | } 53 | 54 | export const BodyEl = document.querySelector('body'); 55 | 56 | /* events */ 57 | 58 | class BusClass { 59 | private _e: Subject = new Subject(); 60 | send(from: string, name: ToppyEventName, data: any = null): void { 61 | this._e.next({ from, name, data }); 62 | } 63 | listen(from: string, name: ToppyEventName): Observable { 64 | return this._e.asObservable().pipe( 65 | filter(e => e.from === from && e.name === name), 66 | map(e => e.data) 67 | ); 68 | } 69 | 70 | stop(): void { 71 | this._e.complete(); 72 | } 73 | } 74 | export const Bus = new BusClass(); 75 | -------------------------------------------------------------------------------- /projects/toppy/src/public_api.ts: -------------------------------------------------------------------------------- 1 | export { InsidePlacement, OutsidePlacement, SlidePlacement } from './lib/models'; 2 | export { FullscreenPosition, GlobalPosition, RelativePosition, SlidePosition } from './lib/position'; 3 | export { Toppy } from './lib/toppy'; 4 | export { ToppyControl } from './lib/toppy-control'; 5 | export { ToppyModule } from './lib/toppy.module'; 6 | -------------------------------------------------------------------------------- /projects/toppy/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'core-js/es7/reflect'; 4 | import 'zone.js/dist/zone'; 5 | import 'zone.js/dist/zone-testing'; 6 | import { getTestBed } from '@angular/core/testing'; 7 | import { 8 | BrowserDynamicTestingModule, 9 | platformBrowserDynamicTesting 10 | } from '@angular/platform-browser-dynamic/testing'; 11 | 12 | declare const require: any; 13 | 14 | // First, initialize the Angular testing environment. 15 | getTestBed().initTestEnvironment( 16 | BrowserDynamicTestingModule, 17 | platformBrowserDynamicTesting() 18 | ); 19 | // Then we find all the tests. 20 | const context = require.context('./', true, /\.spec\.ts$/); 21 | // And load the modules. 22 | context.keys().map(context); 23 | -------------------------------------------------------------------------------- /projects/toppy/src/tests/positions/fullscreen-position.spec.ts: -------------------------------------------------------------------------------- 1 | import { FullscreenPosition } from '../../lib/position'; 2 | 3 | describe('@ FullscreenPosition', () => { 4 | describe('#getPositions', () => { 5 | it('should return proper position', () => { 6 | const slidePos = new FullscreenPosition(); 7 | expect(slidePos.getPositions()).toEqual({ 8 | top: 0, 9 | left: 0, 10 | width: '100%', 11 | height: '100%', 12 | position: 'fixed' 13 | }); 14 | }); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /projects/toppy/src/tests/positions/global-position.spec.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import { InsidePlacement } from '../../lib/models'; 4 | import { GlobalPosition } from '../../lib/position'; 5 | 6 | describe('@ GlobalPosition', () => { 7 | let targetElement: HTMLElement; 8 | let hostElement: HTMLElement; 9 | let ww; 10 | let wh; 11 | beforeEach(() => { 12 | targetElement = document.createElement('div'); 13 | targetElement.setAttribute('class', 'foobar'); 14 | const textnode = document.createTextNode('Hello'); 15 | targetElement.appendChild(textnode); 16 | document.getElementsByTagName('body')[0].appendChild(targetElement); 17 | 18 | hostElement = document.createElement('div'); 19 | hostElement.setAttribute('class', 'hostelement'); 20 | const textnode2 = document.createTextNode('Im host'); 21 | hostElement.appendChild(textnode2); 22 | document.getElementsByTagName('body')[0].appendChild(hostElement); 23 | viewport.set(1000, 480); 24 | 25 | ww = window.innerWidth; 26 | wh = window.innerHeight; 27 | }); 28 | afterEach(() => { 29 | document.getElementsByTagName('body')[0].removeChild(targetElement); 30 | document.getElementsByTagName('body')[0].removeChild(hostElement); 31 | viewport.set(1000, 480); 32 | }); 33 | 34 | it('should have target element in document', () => { 35 | expect(document.querySelector('.foobar').textContent).toBe('Hello'); 36 | }); 37 | it('should get updated config', () => { 38 | const gloPos = new GlobalPosition({}); 39 | gloPos.updateConfig({ offset: 2 }); 40 | expect(gloPos['config']).toEqual({ 41 | placement: InsidePlacement.CENTER, 42 | width: 100, 43 | height: 100, 44 | offset: 2 45 | }); 46 | }); 47 | it('should return correct class name', () => { 48 | const gloPos = new GlobalPosition({}); 49 | expect(gloPos.getClassName()).toBe('global-position'); 50 | }); 51 | 52 | describe('#getPositions', () => { 53 | let srcCoords; 54 | beforeEach(() => { 55 | srcCoords = targetElement.getBoundingClientRect(); 56 | }); 57 | it('when exact width and height is provided in px', () => { 58 | const gloPos = new GlobalPosition({ 59 | width: 4, 60 | height: 10, 61 | placement: InsidePlacement.TOP 62 | }); 63 | expect(gloPos.getPositions(hostElement)).toEqual({ 64 | left: (ww - 4) / 2, 65 | top: 0, 66 | width: 4, 67 | height: 10, 68 | position: 'fixed', 69 | extra: InsidePlacement.TOP 70 | }); 71 | }); 72 | it('when exact width and height is provided in negative px', () => { 73 | const gloPos = new GlobalPosition({ 74 | width: -4, 75 | height: -10, 76 | placement: InsidePlacement.TOP 77 | }); 78 | expect(gloPos.getPositions(hostElement)).toEqual({ 79 | left: (ww - 4) / 2, 80 | top: 0, 81 | width: 4, 82 | height: 10, 83 | position: 'fixed', 84 | extra: InsidePlacement.TOP 85 | }); 86 | }); 87 | it('when exact width and height is provided in percentage', () => { 88 | const gloPos = new GlobalPosition({ 89 | width: '50%', 90 | height: '50%', 91 | placement: InsidePlacement.TOP 92 | }); 93 | expect(gloPos.getPositions(hostElement)).toEqual({ 94 | left: (ww - hostElement.offsetWidth) / 2, 95 | top: 0, 96 | width: `calc(${ww}px - 50%)`, 97 | height: `calc(${wh}px - 50%)`, 98 | position: 'fixed', 99 | extra: InsidePlacement.TOP 100 | }); 101 | }); 102 | it('when exact width and height is provided in higher percentage', () => { 103 | const gloPos = new GlobalPosition({ 104 | width: '150%', 105 | height: '150%', 106 | placement: InsidePlacement.TOP 107 | }); 108 | expect(gloPos.getPositions(hostElement)).toEqual({ 109 | left: (ww - hostElement.offsetWidth) / 2, 110 | top: 0, 111 | width: `calc(${ww}px - 0%)`, 112 | height: `calc(${wh}px - 0%)`, 113 | position: 'fixed', 114 | extra: InsidePlacement.TOP 115 | }); 116 | }); 117 | it('when no width and height is provided', () => { 118 | const gloPos = new GlobalPosition({ placement: InsidePlacement.TOP_RIGHT }); 119 | expect(gloPos.getPositions(hostElement)).toEqual({ 120 | right: 0, 121 | top: 0, 122 | width: 100, 123 | height: 100, 124 | position: 'fixed', 125 | extra: InsidePlacement.TOP_RIGHT 126 | }); 127 | }); 128 | }); 129 | describe('#calc', () => { 130 | const targetElCoords = { 131 | width: (window as any).innerWidth, 132 | height: (window as any).innerHeight 133 | }; 134 | 135 | const hostElCoords = { 136 | width: 4, // actual 967 137 | height: 10 // actual 18 138 | }; 139 | getData().forEach(data => { 140 | it(data.name, () => { 141 | const gloPos = new GlobalPosition({ 142 | width: hostElCoords.width, 143 | height: hostElCoords.height, 144 | placement: data.placement, 145 | offset: 2 146 | }); 147 | const pos = (gloPos as any).calc(data.placement, targetElCoords, hostElCoords); 148 | expect(pos).toEqual(data.expected); 149 | }); 150 | }); 151 | }); 152 | function getData() { 153 | // offset is 2 154 | ww = window.innerWidth; 155 | wh = window.innerHeight; 156 | const tests = [ 157 | { 158 | name: 'bottom', 159 | placement: InsidePlacement.BOTTOM, 160 | method: `calculate_${InsidePlacement.BOTTOM}`, 161 | expected: { left: (ww - 4) / 2, bottom: 2 } 162 | }, 163 | { 164 | name: 'top', 165 | placement: InsidePlacement.TOP, 166 | method: `calculate_${InsidePlacement.TOP}`, 167 | expected: { left: (ww - 4) / 2, top: 2 } 168 | }, 169 | { 170 | name: 'left', 171 | placement: InsidePlacement.LEFT, 172 | method: `calculate_${InsidePlacement.LEFT}`, 173 | expected: { left: 2, top: (wh - 10) / 2 } 174 | }, 175 | { 176 | name: 'right', 177 | placement: InsidePlacement.RIGHT, 178 | method: `calculate_${InsidePlacement.RIGHT}`, 179 | expected: { right: 2, top: (wh - 10) / 2 } 180 | }, 181 | { 182 | name: 'center', 183 | placement: InsidePlacement.CENTER, 184 | method: `calculate_${InsidePlacement.CENTER}`, 185 | expected: { left: (ww - 4) / 2, top: (wh - 10) / 2 } 186 | }, 187 | { 188 | name: 'top left', 189 | placement: InsidePlacement.TOP_LEFT, 190 | method: `calculate_${InsidePlacement.TOP_LEFT}`, 191 | expected: { left: 2, top: 2 } 192 | }, 193 | { 194 | name: 'top right', 195 | placement: InsidePlacement.TOP_RIGHT, 196 | method: `calculate_${InsidePlacement.TOP_RIGHT}`, 197 | expected: { right: 2, top: 2 } 198 | }, 199 | { 200 | name: 'bottom left', 201 | placement: InsidePlacement.BOTTOM_LEFT, 202 | method: `calculate_${InsidePlacement.BOTTOM_LEFT}`, 203 | expected: { left: 2, bottom: 2 } 204 | }, 205 | { 206 | name: 'bottom right', 207 | placement: InsidePlacement.BOTTOM_RIGHT, 208 | method: `calculate_${InsidePlacement.BOTTOM_RIGHT}`, 209 | expected: { right: 2, bottom: 2 } 210 | } 211 | ]; 212 | 213 | return tests; 214 | } 215 | }); 216 | -------------------------------------------------------------------------------- /projects/toppy/src/tests/positions/relative-position.spec.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import { Subject } from 'rxjs'; 4 | import { take } from 'rxjs/operators'; 5 | import { Bus } from 'toppy/lib/utils'; 6 | import { OutsidePlacement } from '../../lib/models'; 7 | import { RelativePosition } from '../../lib/position'; 8 | 9 | describe('@ RelativePosition', () => { 10 | let targetElement: HTMLElement; 11 | let hostElement: HTMLElement; 12 | let die: Subject; 13 | beforeEach(() => { 14 | targetElement = document.createElement('div'); 15 | targetElement.setAttribute('class', 'foobar'); 16 | const textnode = document.createTextNode('Hello'); 17 | targetElement.appendChild(textnode); 18 | document.getElementsByTagName('body')[0].appendChild(targetElement); 19 | 20 | hostElement = document.createElement('div'); 21 | hostElement.setAttribute('class', 'hostelement'); 22 | const textnode2 = document.createTextNode('Im host'); 23 | hostElement.appendChild(textnode2); 24 | document.getElementsByTagName('body')[0].appendChild(hostElement); 25 | viewport.set(1000, 480); 26 | }); 27 | afterEach(() => { 28 | document.getElementsByTagName('body')[0].removeChild(targetElement); 29 | document.getElementsByTagName('body')[0].removeChild(hostElement); 30 | viewport.set(1000, 480); 31 | }); 32 | 33 | beforeEach(() => { 34 | die = new Subject(); 35 | Bus['_e'] = new Subject(); 36 | }); 37 | 38 | afterEach(function() { 39 | die.next(true); 40 | die.complete(); 41 | Bus.stop(); 42 | }); 43 | 44 | it('should have target element in document', () => { 45 | expect(document.querySelector('.foobar').textContent).toBe('Hello'); 46 | }); 47 | it('should get updated config', () => { 48 | const relPos = new RelativePosition({ src: null }); 49 | relPos.updateConfig({ autoUpdate: true }); 50 | expect(relPos['config']).toEqual({ 51 | src: null, 52 | placement: OutsidePlacement.TOP, 53 | autoUpdate: true, 54 | width: 'auto', 55 | height: 'auto' 56 | }); 57 | }); 58 | it('should return correct class name', () => { 59 | const relPos = new RelativePosition({ src: null }); 60 | expect(relPos.getClassName()).toBe('relative-position'); 61 | }); 62 | 63 | describe('#autoUpdate', () => { 64 | it('should switch if it is true - case 1', () => { 65 | const relPos = new RelativePosition({ 66 | src: targetElement, 67 | placement: OutsidePlacement.TOP, 68 | height: 500, 69 | autoUpdate: true 70 | }); 71 | const srcCoords = targetElement.getBoundingClientRect(); 72 | const hostElCoords = { 73 | width: 4, // actual 967 74 | height: 450 75 | }; 76 | expect((relPos as any).calculatePos(OutsidePlacement.TOP, srcCoords, hostElCoords, true)).toEqual({ 77 | props: { 78 | left: 8 + (srcCoords.width - 4) / 2, 79 | top: srcCoords.top + srcCoords.height 80 | }, 81 | pos: OutsidePlacement.BOTTOM 82 | }); 83 | }); 84 | it('should switch if it is true - case 2', () => { 85 | const relPos = new RelativePosition({ 86 | src: targetElement, 87 | placement: OutsidePlacement.TOP_LEFT, 88 | height: 500, 89 | autoUpdate: true 90 | }); 91 | const srcCoords = targetElement.getBoundingClientRect(); 92 | const hostElCoords = { 93 | width: 4, // actual 967 94 | height: 450 95 | }; 96 | expect((relPos as any).calculatePos(OutsidePlacement.TOP_LEFT, srcCoords, hostElCoords, true)).toEqual({ 97 | props: { 98 | left: 8, 99 | top: srcCoords.top + srcCoords.height 100 | }, 101 | pos: OutsidePlacement.BOTTOM_LEFT 102 | }); 103 | }); 104 | it('should not switch if it is false', () => { 105 | const relPos = new RelativePosition({ 106 | src: targetElement, 107 | placement: OutsidePlacement.TOP, 108 | height: 500, 109 | autoUpdate: false 110 | }); 111 | const srcCoords = targetElement.getBoundingClientRect(); 112 | const hostElCoords = { 113 | width: 4, // actual 967 114 | height: 150 115 | }; 116 | expect((relPos as any).calculatePos(OutsidePlacement.TOP, srcCoords, hostElCoords, true)).toEqual({ 117 | props: { 118 | left: 8 + (srcCoords.width - 4) / 2, 119 | top: srcCoords.top - 150 120 | }, 121 | pos: OutsidePlacement.TOP 122 | }); 123 | }); 124 | }); 125 | describe('#getPositions', () => { 126 | let srcCoords; 127 | beforeEach(() => { 128 | srcCoords = targetElement.getBoundingClientRect(); 129 | }); 130 | it('when exact width and height is provided', () => { 131 | const relPos = new RelativePosition({ 132 | width: 4, 133 | height: 10, 134 | src: targetElement, 135 | placement: OutsidePlacement.TOP 136 | }); 137 | expect(relPos.getPositions(hostElement)).toEqual({ 138 | left: Math.round(8 + (targetElement.offsetWidth - 4) / 2), 139 | top: Math.round(srcCoords.top - 10), 140 | width: 4, 141 | height: 10, 142 | extra: OutsidePlacement.TOP 143 | }); 144 | }); 145 | it('when no width and height is provided', () => { 146 | const relPos = new RelativePosition({ src: targetElement, placement: OutsidePlacement.TOP }); 147 | expect(relPos.getPositions(hostElement)).toEqual({ 148 | left: Math.round(8 + (967 - 967) / 2), 149 | top: Math.round(srcCoords.top - 18), 150 | width: 'auto', 151 | height: 'auto', 152 | extra: OutsidePlacement.TOP 153 | }); 154 | }); 155 | }); 156 | describe('#listenDrag', () => { 157 | let relPos; 158 | beforeEach(() => { 159 | relPos = new RelativePosition({ src: targetElement, autoUpdate: true }); 160 | relPos.init('abc'); 161 | }); 162 | 163 | it('should emit proper event when drag', done => { 164 | Bus.listen('abc', 't_dynpos') 165 | .pipe(take(1)) 166 | .subscribe(res => { 167 | expect(res).toEqual(null); 168 | done(); 169 | }); 170 | targetElement.style.left = '0px'; 171 | }); 172 | }); 173 | describe('#calc', () => { 174 | const targetElCoords = { 175 | bottom: 76, 176 | height: 18, 177 | left: 8, 178 | right: 975, 179 | top: 58, 180 | width: 967 181 | }; 182 | 183 | const hostElCoords = { 184 | width: 4, // actual 967 185 | height: 10 // actual 18 186 | }; 187 | getData().forEach(data => { 188 | it(data.name, () => { 189 | const relPos = new RelativePosition({ 190 | src: targetElement, 191 | width: hostElCoords.width, 192 | height: hostElCoords.height, 193 | placement: data.placement 194 | }); 195 | const pos = (relPos as any).calc(data.placement, targetElCoords, hostElCoords); 196 | expect(pos).toEqual(data.expected); 197 | }); 198 | }); 199 | }); 200 | }); 201 | 202 | function getData() { 203 | const tests = [ 204 | { 205 | name: 'bottom', 206 | placement: OutsidePlacement.BOTTOM, 207 | method: `calculate_${OutsidePlacement.BOTTOM}`, 208 | expected: { left: 8 + (967 - 4) / 2, top: 76 } 209 | }, 210 | { 211 | name: 'top', 212 | placement: OutsidePlacement.TOP, 213 | method: `calculate_${OutsidePlacement.TOP}`, 214 | expected: { left: 8 + (967 - 4) / 2, top: 48 } 215 | }, 216 | { 217 | name: 'left', 218 | placement: OutsidePlacement.LEFT, 219 | method: `calculate_${OutsidePlacement.LEFT}`, 220 | expected: { left: 8 - 4, top: 58 + (18 - 10) / 2 } 221 | }, 222 | { 223 | name: 'right', 224 | placement: OutsidePlacement.RIGHT, 225 | method: `calculate_${OutsidePlacement.RIGHT}`, 226 | expected: { left: 975, top: 58 + (18 - 10) / 2 } 227 | }, 228 | { 229 | name: 'top left', 230 | placement: OutsidePlacement.TOP_LEFT, 231 | method: `calculate_${OutsidePlacement.TOP_LEFT}`, 232 | expected: { left: 8, top: 58 - 10 } 233 | }, 234 | { 235 | name: 'top right', 236 | placement: OutsidePlacement.TOP_RIGHT, 237 | method: `calculate_${OutsidePlacement.TOP_RIGHT}`, 238 | expected: { left: 8 + (967 - 4), top: 58 - 10 } 239 | }, 240 | { 241 | name: 'bottom left', 242 | placement: OutsidePlacement.BOTTOM_LEFT, 243 | method: `calculate_${OutsidePlacement.BOTTOM_LEFT}`, 244 | expected: { left: 8, top: 76 } 245 | }, 246 | { 247 | name: 'bottom right', 248 | placement: OutsidePlacement.BOTTOM_RIGHT, 249 | method: `calculate_${OutsidePlacement.BOTTOM_RIGHT}`, 250 | expected: { left: 8 + (967 - 4), top: 76 } 251 | }, 252 | { 253 | name: 'right top', 254 | placement: OutsidePlacement.RIGHT_TOP, 255 | method: `calculate_${OutsidePlacement.RIGHT_TOP}`, 256 | expected: { left: 975, top: 58 } 257 | }, 258 | { 259 | name: 'right bottom', 260 | placement: OutsidePlacement.RIGHT_BOTTOM, 261 | method: `calculate_${OutsidePlacement.RIGHT_BOTTOM}`, 262 | expected: { left: 975, top: 76 - 10 } 263 | }, 264 | { 265 | name: 'left top', 266 | placement: OutsidePlacement.LEFT_TOP, 267 | method: `calculate_${OutsidePlacement.LEFT_TOP}`, 268 | expected: { left: 8 - 4, top: 58 } 269 | }, 270 | { 271 | name: 'left bottom', 272 | placement: OutsidePlacement.LEFT_BOTTOM, 273 | method: `calculate_${OutsidePlacement.LEFT_BOTTOM}`, 274 | expected: { left: 8 - 4, top: 76 - 10 } 275 | } 276 | ]; 277 | 278 | return tests; 279 | } 280 | -------------------------------------------------------------------------------- /projects/toppy/src/tests/positions/slide-position.spec.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import { SlidePlacement } from '../../lib/models'; 4 | import { SlidePosition } from '../../lib/position'; 5 | 6 | describe('@ SlidePosition', () => { 7 | describe('#getPositions', () => { 8 | it('should return proper position when placement is left', () => { 9 | const slidePos = new SlidePosition({ 10 | width: '200px', 11 | placement: SlidePlacement.LEFT 12 | }); 13 | expect(slidePos.getPositions()).toEqual({ 14 | left: 0, 15 | top: 0, 16 | width: '200px', 17 | height: '100%', 18 | position: 'fixed', 19 | extra: SlidePlacement.LEFT 20 | }); 21 | }); 22 | it('should return proper position when placement is right', () => { 23 | const slidePos = new SlidePosition({ 24 | width: '500', 25 | placement: SlidePlacement.RIGHT 26 | }); 27 | expect(slidePos.getPositions()).toEqual({ 28 | right: 0, 29 | top: 0, 30 | width: '500', 31 | height: '100%', 32 | position: 'fixed', 33 | extra: SlidePlacement.RIGHT 34 | }); 35 | }); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /projects/toppy/src/tests/toppy.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { Component, DebugElement, EventEmitter, Input, NgModule, Output } from '@angular/core'; 2 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 3 | import { By } from '@angular/platform-browser'; 4 | import { Subject } from 'rxjs'; 5 | import { skip, switchMap, take } from 'rxjs/operators'; 6 | import { DefaultConfig } from '../lib/config'; 7 | import { ContentType } from '../lib/models'; 8 | import { ToppyComponent } from '../lib/toppy.component'; 9 | import { Bus } from '../lib/utils'; 10 | 11 | @Component({ 12 | selector: 'test-comp', 13 | template: 'Hello {{name||"John"}}' 14 | }) 15 | export class TestComponent { 16 | @Input() data = null; 17 | @Output() fire: EventEmitter = new EventEmitter(); 18 | name; 19 | } 20 | 21 | @NgModule({ 22 | declarations: [TestComponent], 23 | entryComponents: [TestComponent], 24 | exports: [TestComponent] 25 | }) 26 | export class TestModule {} 27 | 28 | describe('@ ToppyComponent', () => { 29 | let fixture: ComponentFixture; 30 | let debugEl: DebugElement; 31 | let toppyComp: ToppyComponent; 32 | let el: HTMLElement; 33 | let die: Subject; 34 | beforeEach(async(() => { 35 | TestBed.configureTestingModule({ 36 | imports: [TestModule], 37 | declarations: [ToppyComponent] 38 | }).compileComponents(); 39 | fixture = TestBed.createComponent(ToppyComponent); 40 | debugEl = fixture.debugElement; 41 | el = debugEl.nativeElement; 42 | toppyComp = fixture.componentInstance; 43 | })); 44 | 45 | beforeEach(() => { 46 | toppyComp.tid = 'abc'; 47 | toppyComp.config = { ...DefaultConfig, bodyClass: 'zzz' }; 48 | toppyComp.position = { 49 | getClassName: () => 'relative', 50 | getPositions: c => ({ left: 45, top: 79, extra: 't' }) 51 | } as any; 52 | die = new Subject(); 53 | Bus['_e'] = new Subject(); 54 | }); 55 | 56 | afterEach(() => { 57 | fixture.destroy(); 58 | die.next(true); 59 | die.complete(); 60 | Bus.stop(); 61 | }); 62 | 63 | it('should be initialized', () => { 64 | expect(toppyComp).toBeTruthy(); 65 | }); 66 | describe('#ngOnInit', () => { 67 | it('should add data-tid attribute', () => { 68 | fixture.detectChanges(); 69 | expect(el.getAttribute('data-tid')).toEqual('abc'); 70 | }); 71 | it('should add default classes', () => { 72 | fixture.detectChanges(); 73 | expect(el.classList.value).toBe('t-container t-overlay relative'); 74 | }); 75 | it('should add class for docClick', () => { 76 | toppyComp.config.closeOnDocClick = true; 77 | fixture.detectChanges(); 78 | expect(el.classList.value).toBe('t-container t-overlay relative no-pointers'); 79 | }); 80 | it('should add class for bodyClass', () => { 81 | fixture.detectChanges(); 82 | expect(document.querySelector('body').classList.value).toEqual('zzz'); 83 | }); 84 | }); 85 | 86 | describe('#ngAfterViewInit', () => { 87 | it('should call setPos', () => { 88 | fixture.detectChanges(); 89 | spyOn(toppyComp as any, 'setPos'); 90 | toppyComp.ngAfterViewInit(); 91 | expect(toppyComp['setPos']).toHaveBeenCalled(); 92 | }); 93 | it('should subscribe to triggerPosChange', () => { 94 | spyOn(toppyComp as any, 'setPos'); 95 | fixture.detectChanges(); 96 | toppyComp.ngAfterViewInit(); 97 | expect(toppyComp['setPos']).toHaveBeenCalled(); 98 | }); 99 | it('should subscribe to listenPos', () => { 100 | fixture.detectChanges(); 101 | spyOn(toppyComp as any, 'setPos'); 102 | Bus.send('abc', 't_dynpos', null); 103 | toppyComp.ngAfterViewInit(); 104 | expect(toppyComp['setPos']).toHaveBeenCalled(); 105 | }); 106 | it('should subscribe to listenPos when custom data is arraived', () => { 107 | fixture.detectChanges(); 108 | toppyComp.ngAfterViewInit(); 109 | Bus.send('abc', 't_dynpos', { x: 10, y: 12 }); 110 | expect(el.querySelector('.t-wrapper').getAttribute('style')).toEqual('left: 10px; top: 12px;'); 111 | }); 112 | it('should render custom props in the template', () => { 113 | toppyComp.content.data = TestComponent; 114 | toppyComp.content.type = ContentType.COMPONENT; 115 | toppyComp.content.props = { 116 | name: 'Peter', 117 | id: 22 118 | }; 119 | fixture.detectChanges(); 120 | expect(fixture.debugElement.query(By.css('test-comp')).nativeElement.textContent).toBe('Hello Peter'); 121 | }); 122 | it('should emit host component instance', done => { 123 | toppyComp.content.data = TestComponent; 124 | toppyComp.content.type = ContentType.COMPONENT; 125 | toppyComp.content.props = { 126 | name: 'Loky' 127 | }; 128 | fixture.detectChanges(); 129 | Bus.listen('abc', 't_compins').subscribe(data => { 130 | expect(data.name).toEqual('Loky'); 131 | done(); 132 | }); 133 | toppyComp.ngAfterViewInit(); 134 | }); 135 | it('should able to access "@Output()"', done => { 136 | toppyComp.content.data = TestComponent; 137 | toppyComp.content.type = ContentType.COMPONENT; 138 | toppyComp.content.props = { name: 'SSSS' }; 139 | fixture.detectChanges(); 140 | Bus.listen('abc', 't_compins') 141 | .pipe(switchMap(a => a['fire'])) 142 | .subscribe(data => { 143 | expect(data).toEqual('ABCXYZ'); 144 | done(); 145 | }); 146 | toppyComp.ngAfterViewInit(); 147 | toppyComp.compInstance.fire.emit('ABCXYZ'); 148 | }); 149 | }); 150 | 151 | describe('#updateTextContent', () => { 152 | it('should not change the text if the content is not string', () => { 153 | toppyComp.content = { 154 | data: 'DUMMY', 155 | props: {}, 156 | type: ContentType.HTML 157 | }; 158 | const text = 'Little cute Dog'; 159 | toppyComp.updateTextContent(text); 160 | fixture.detectChanges(); 161 | expect(debugEl.query(By.css('.t-wrapper div')).nativeElement.textContent).toEqual('DUMMY'); 162 | }); 163 | it('should change the text content in template', () => { 164 | const text = 'Little cute Dog'; 165 | toppyComp.updateTextContent(text); 166 | fixture.detectChanges(); 167 | expect(debugEl.query(By.css('.t-wrapper div')).nativeElement.textContent).toEqual(text); 168 | }); 169 | }); 170 | 171 | describe('#ngOnDestroy', () => { 172 | it('should remove class name from body', () => { 173 | toppyComp.config.bodyClass = 'Bunny'; 174 | fixture.detectChanges(); 175 | expect(document.querySelector('body').classList.value).toEqual('Bunny'); 176 | fixture.destroy(); 177 | expect(document.querySelector('body').classList.value).toEqual(''); 178 | }); 179 | it('should unsubscribe all events', () => { 180 | spyOn(toppyComp as any, 'setPos'); 181 | toppyComp.ngAfterViewInit(); 182 | Bus.send('abc', 't_dynpos'); 183 | expect(toppyComp['setPos']).toHaveBeenCalledTimes(2); 184 | fixture.destroy(); 185 | Bus.send('abc', 't_dynpos'); 186 | expect(toppyComp['setPos']).toHaveBeenCalledTimes(2); 187 | }); 188 | it('should fire t_detach event', () => { 189 | const spy = jasmine.createSpy().and.callThrough(); 190 | Bus.listen('abc', 't_detach') 191 | .pipe(take(1)) 192 | .subscribe(() => { 193 | spy(); 194 | spy(); 195 | }); 196 | fixture.destroy(); 197 | expect(spy.calls.count()).toEqual(2); 198 | }); 199 | }); 200 | 201 | describe('#listenPos', () => { 202 | it('should return new position', done => { 203 | fixture.detectChanges(); 204 | toppyComp['listenPos']().subscribe(data => { 205 | expect(data).toEqual(1); 206 | done(); 207 | }); 208 | }); 209 | it('should add styles', done => { 210 | fixture.detectChanges(); 211 | toppyComp['listenPos']() 212 | .pipe(take(1)) 213 | .subscribe(() => { 214 | expect(el.querySelector('.t-wrapper').getAttribute('style')).toEqual( 215 | 'left: 45px; top: 79px; visibility: visible; opacity: 1;' 216 | ); 217 | done(); 218 | }); 219 | }); 220 | it('should add styles', done => { 221 | fixture.detectChanges(); 222 | toppyComp['listenPos']() 223 | .pipe(skip(1)) 224 | .subscribe(() => { 225 | expect(el.querySelector('.t-wrapper').getAttribute('style')).toEqual('left: 99px; top: 22px;'); 226 | done(); 227 | }); 228 | Bus.send('abc', 't_dynpos', { x: 99, y: 22 }); 229 | }); 230 | }); 231 | 232 | describe('#setPos', () => { 233 | it('should set positions to wrapper element', () => { 234 | fixture.detectChanges(); 235 | toppyComp['setPos'](); 236 | expect(el.querySelector('.t-wrapper').getAttribute('style')).toEqual( 237 | 'left: 45px; top: 79px; visibility: visible; opacity: 1;' 238 | ); 239 | }); 240 | it('should emit position change event', () => { 241 | const spy = jasmine.createSpy().and.callThrough(); 242 | fixture.detectChanges(); 243 | Bus.listen('abc', 't_posupdate') 244 | .pipe(take(1)) 245 | .subscribe(() => { 246 | spy(); 247 | spy(); 248 | spy(); 249 | }); 250 | toppyComp['setPos'](); 251 | expect(spy.calls.count()).toEqual(3); 252 | }); 253 | it('should set extra class to wrapper element', () => { 254 | fixture.detectChanges(); 255 | toppyComp['setPos'](); 256 | expect(el.querySelector('.t-wrapper').classList.value).toEqual('t-wrapper t'); 257 | }); 258 | }); 259 | 260 | describe('#config', () => { 261 | it('should set custom class names', () => { 262 | toppyComp.config.backdrop = true; 263 | toppyComp.config.wrapperClass = 'custom-wrapper-class'; 264 | toppyComp.config.backdropClass = 'custom-backdrop-class'; 265 | fixture.detectChanges(); 266 | expect(el.querySelector('.t-wrapper').classList.value).toEqual('t-wrapper custom-wrapper-class t'); 267 | expect(el.querySelector('.t-backdrop').classList.value).toEqual('t-backdrop custom-backdrop-class'); 268 | }); 269 | }); 270 | }); 271 | -------------------------------------------------------------------------------- /projects/toppy/src/tests/toppy.spec.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ApplicationRef, 3 | Component, 4 | ComponentFactoryResolver, 5 | ElementRef, 6 | Injector, 7 | NgModule, 8 | TemplateRef, 9 | ViewChild 10 | } from '@angular/core'; 11 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 12 | import { Subject } from 'rxjs'; 13 | import { DefaultConfig } from '../lib/config'; 14 | import { ContentType } from '../lib/models'; 15 | import { GlobalPosition, RelativePosition } from '../lib/position'; 16 | import { Toppy } from '../lib/toppy'; 17 | import { ToppyControl } from '../lib/toppy-control'; 18 | import { Bus } from '../lib/utils'; 19 | 20 | @Component({ 21 | selector: 'lib-template-ref-test-comp', 22 | template: ` 23 | some content 24 | I am template 25 | ` 26 | }) 27 | export class TemplateRefTestComponent { 28 | @ViewChild('el', { read: ElementRef }) el: ElementRef; 29 | @ViewChild('tpl', { read: TemplateRef }) tpl; 30 | constructor(private toppy: Toppy) {} 31 | } 32 | 33 | @Component({ 34 | template: 'Hi' 35 | }) 36 | export class TestComponent {} 37 | 38 | @NgModule({ 39 | declarations: [TestComponent, TemplateRefTestComponent], 40 | entryComponents: [TestComponent] 41 | }) 42 | export class TemplateRefTestModule {} 43 | 44 | describe('@ Toppy', () => { 45 | let toppy: Toppy = null; 46 | let templateRefCompFixture: ComponentFixture; 47 | let templateRefComp: TemplateRefTestComponent; 48 | let appRef, compFact, inj; 49 | const config = DefaultConfig; 50 | 51 | beforeEach(async(() => { 52 | TestBed.configureTestingModule({ 53 | imports: [TemplateRefTestModule], 54 | declarations: [], 55 | providers: [ApplicationRef, ComponentFactoryResolver, Injector] 56 | }).compileComponents(); 57 | 58 | templateRefCompFixture = TestBed.createComponent(TemplateRefTestComponent); 59 | templateRefComp = templateRefCompFixture.componentInstance; 60 | toppy = TestBed.get(Toppy); 61 | appRef = TestBed.get(ApplicationRef); 62 | compFact = TestBed.get(ComponentFactoryResolver); 63 | inj = TestBed.get(Injector); 64 | spyOn(toppy, 'destroy').and.callThrough(); 65 | })); 66 | 67 | afterEach(function() { 68 | templateRefCompFixture.destroy(); 69 | document.querySelector('body').removeChild(templateRefCompFixture.debugElement.nativeElement); 70 | }); 71 | afterAll(() => { 72 | Bus['_e'] = new Subject(); 73 | }); 74 | 75 | it('should be initialized', () => { 76 | expect(toppy).toBeTruthy(); 77 | }); 78 | 79 | describe('#basic', () => { 80 | let ctrl: ToppyControl; 81 | beforeEach(() => { 82 | ctrl = toppy.create(); 83 | }); 84 | afterEach(() => { 85 | toppy.destroy(); 86 | }); 87 | it('should return "ToppyControl"', () => { 88 | expect(ctrl instanceof ToppyControl).toBeTruthy(); 89 | }); 90 | it('should have default "GlobalPosition"', () => { 91 | expect(ctrl.position instanceof GlobalPosition).toBeTruthy(); 92 | }); 93 | it('should have default config', () => { 94 | expect(ctrl.config).toEqual(DefaultConfig); 95 | }); 96 | it('should have default text content', () => { 97 | expect(ctrl.content).toEqual({ data: 'hello', type: ContentType.STRING, props: {} }); 98 | }); 99 | it('should add control to toppy', () => { 100 | expect(Object.keys(Toppy.controls).length).toEqual(1); 101 | }); 102 | }); 103 | describe('#config|#position|#content', () => { 104 | let ctrl: ToppyControl; 105 | let tid: string; 106 | beforeEach(() => { 107 | ctrl = toppy 108 | .position(new RelativePosition({ src: templateRefComp.el.nativeElement })) 109 | .config({ backdropClass: 't-custom-backdrop' }) 110 | .content('random text') 111 | .create(); 112 | tid = toppy['tid']; 113 | }); 114 | afterEach(() => { 115 | toppy.destroy(); 116 | }); 117 | it('should set custom config in "Toppy"', () => { 118 | expect((toppy as any).inputs.config).toEqual({ ...DefaultConfig, backdropClass: 't-custom-backdrop' }); 119 | }); 120 | it('should set custom config in "ToppyControl"', () => { 121 | expect(toppy.getCtrl(tid).config).toEqual({ ...DefaultConfig, backdropClass: 't-custom-backdrop' }); 122 | }); 123 | it('should set custom position in "Toppy"', () => { 124 | expect((toppy as any).inputs.position instanceof RelativePosition).toBeTruthy(); 125 | }); 126 | it('should set custom position in "ToppyControl"', () => { 127 | expect(toppy.getCtrl(tid).position instanceof RelativePosition).toBeTruthy(); 128 | }); 129 | it('should set custom content in "Toppy"', () => { 130 | expect((toppy as any).inputs.content).toEqual({ 131 | type: ContentType.STRING, 132 | data: 'random text', 133 | props: {} 134 | }); 135 | }); 136 | it('should set custom content in "ToppyControl"', () => { 137 | expect(toppy.getCtrl(tid).content).toEqual({ type: ContentType.STRING, data: 'random text', props: {} }); 138 | }); 139 | }); 140 | describe('#content', () => { 141 | let t: Toppy; 142 | let tid: string; 143 | beforeEach(() => { 144 | t = toppy 145 | .position(new RelativePosition({ src: templateRefComp.el.nativeElement })) 146 | .config({ backdropClass: 't-custom-backdrop' }); 147 | }); 148 | afterEach(() => { 149 | toppy.destroy(); 150 | }); 151 | describe('should return content type as STRING', () => { 152 | it('when without props', () => { 153 | t.content('hello').create(); 154 | tid = toppy['tid']; 155 | expect(toppy.getCtrl(tid).content).toEqual({ type: ContentType.STRING, data: 'hello', props: {} }); 156 | }); 157 | it('when with props', () => { 158 | t.content('hello', { class: 'abc' }).create(); 159 | tid = toppy['tid']; 160 | expect(toppy.getCtrl(tid).content).toEqual({ 161 | type: ContentType.STRING, 162 | data: 'hello', 163 | props: { class: 'abc' } 164 | }); 165 | }); 166 | }); 167 | describe('should return content type as HTML', () => { 168 | it('when without props', () => { 169 | t.content('hello').create(); 170 | tid = toppy['tid']; 171 | expect(toppy.getCtrl(tid).content).toEqual({ 172 | type: ContentType.STRING, 173 | data: 'hello', 174 | props: {} 175 | }); 176 | }); 177 | it('when with props', () => { 178 | t.content('hello', { hasHTML: true }).create(); 179 | tid = toppy['tid']; 180 | expect(toppy.getCtrl(tid).content).toEqual({ 181 | type: ContentType.HTML, 182 | data: 'hello', 183 | props: { hasHTML: true } 184 | }); 185 | }); 186 | }); 187 | describe('should return content type as TEMPLATE', () => { 188 | it('when without props', () => { 189 | t.content(templateRefComp.tpl).create(); 190 | tid = toppy['tid']; 191 | expect(toppy.getCtrl(tid).content).toEqual({ 192 | type: ContentType.TEMPLATE, 193 | data: templateRefComp.tpl, 194 | props: {} 195 | }); 196 | }); 197 | it('when with props', () => { 198 | t.content(templateRefComp.tpl, { name: 'Johny' }).create(); 199 | tid = toppy['tid']; 200 | expect(toppy.getCtrl(tid).content).toEqual({ 201 | type: ContentType.TEMPLATE, 202 | data: templateRefComp.tpl, 203 | props: { name: 'Johny' } 204 | }); 205 | }); 206 | }); 207 | describe('should return content type as COMPONENT', () => { 208 | it('when without props', () => { 209 | t.content(TestComponent).create(); 210 | tid = toppy['tid']; 211 | expect(toppy.getCtrl(tid).content).toEqual({ 212 | type: ContentType.COMPONENT, 213 | data: TestComponent, 214 | props: {} 215 | }); 216 | }); 217 | it('when with props', () => { 218 | t.content(TestComponent, { name: 'Johny' }).create(); 219 | tid = toppy['tid']; 220 | expect(toppy.getCtrl(tid).content).toEqual({ 221 | type: ContentType.COMPONENT, 222 | data: TestComponent, 223 | props: { name: 'Johny' } 224 | }); 225 | }); 226 | }); 227 | }); 228 | describe('#create', () => { 229 | let ctrl1: ToppyControl; 230 | let t: Toppy; 231 | let firstTid, secondTid; 232 | beforeEach(() => { 233 | ctrl1 = toppy.create(); 234 | firstTid = toppy['tid']; 235 | 236 | t = toppy.content('abc'); 237 | (t as any).tid = firstTid; 238 | t.create(); 239 | secondTid = toppy['tid']; 240 | }); 241 | afterEach(() => { 242 | toppy.destroy(); 243 | }); 244 | it('should create new instance if the tid already exists', () => { 245 | expect(Object.keys(Toppy.controls)).toEqual([firstTid, secondTid]); 246 | }); 247 | it('should add multiple new instances', () => { 248 | toppy.create(); 249 | toppy.create(); 250 | toppy.create(); 251 | expect(Object.keys(Toppy.controls).length).toEqual(5); 252 | }); 253 | it('should add new instance with custom key', () => { 254 | toppy.create('JKL'); 255 | expect(Object.keys(Toppy.controls)).toContain('JKL'); 256 | }); 257 | it('should create new key if same key already exists', () => { 258 | toppy.create('ABCD'); 259 | toppy.create('ABCD'); 260 | expect(Object.keys(Toppy.controls).length).toEqual(4); 261 | expect(Object.keys(Toppy.controls).filter(x => x === 'ABCD').length).toEqual(1); 262 | }); 263 | }); 264 | describe('#destroy', () => { 265 | it('should remove all controls', () => { 266 | toppy.create(); 267 | toppy.create(); 268 | toppy.create(); 269 | toppy.create(); 270 | 271 | toppy.destroy(); 272 | expect(Object.keys(Toppy.controls).length).toEqual(0); 273 | }); 274 | }); 275 | }); 276 | -------------------------------------------------------------------------------- /projects/toppy/src/tests/utils.spec.ts: -------------------------------------------------------------------------------- 1 | import { Component, TemplateRef, ViewChild } from '@angular/core'; 2 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 3 | import { Subject } from 'rxjs'; 4 | import { takeUntil } from 'rxjs/operators'; 5 | import { ContentType } from '../lib/models'; 6 | import { Bus, getContent } from '../lib/utils'; 7 | 8 | @Component({ 9 | selector: 'lib-test-component', 10 | template: ` 11 |

Hello

12 | I am a template! 13 | ` 14 | }) 15 | export class TestComponent { 16 | @ViewChild('tpl', { read: TemplateRef }) tpl: TemplateRef; 17 | } 18 | 19 | describe('@ Utils', () => { 20 | let component: TestComponent = null; 21 | let fixture: ComponentFixture = null; 22 | beforeEach(async(() => { 23 | TestBed.configureTestingModule({ 24 | declarations: [TestComponent], 25 | providers: [] 26 | }).compileComponents(); 27 | fixture = TestBed.createComponent(TestComponent); 28 | component = fixture.componentInstance; 29 | })); 30 | afterEach(function() { 31 | fixture.destroy(); 32 | document.body.removeChild(fixture.debugElement.nativeElement); 33 | }); 34 | 35 | describe('#getContent', () => { 36 | it('should return as string type', () => { 37 | const result = getContent('hello'); 38 | expect(result).toEqual({ data: 'hello', props: {}, type: ContentType.STRING }); 39 | }); 40 | it('should return html type', () => { 41 | const result = getContent('
Hello
', { hasHTML: true }); 42 | expect(result).toEqual({ 43 | data: '
Hello
', 44 | props: { hasHTML: true }, 45 | type: ContentType.HTML 46 | }); 47 | }); 48 | it('should return component type', () => { 49 | const result = getContent(fixture as any); 50 | expect(result as any).toEqual({ data: fixture, props: {}, type: ContentType.COMPONENT }); 51 | }); 52 | it('should return component type with props', () => { 53 | const result: any = getContent(fixture as any, { name: 'john' }); 54 | expect(result).toEqual({ 55 | data: fixture, 56 | props: { name: 'john' }, 57 | type: ContentType.COMPONENT 58 | } as any); 59 | }); 60 | it('should return component type with overlay id', () => { 61 | const result = getContent(fixture as any, { id: 'XYZ' }); 62 | expect(result as any).toEqual({ data: fixture, props: { id: 'XYZ' }, type: ContentType.COMPONENT }); 63 | }); 64 | it('should return template type', () => { 65 | const result = getContent(component.tpl, { id: 'ABC' }); 66 | expect(result as any).toEqual({ data: component.tpl, type: ContentType.TEMPLATE, props: { id: 'ABC' } }); 67 | }); 68 | }); 69 | describe('#BusClass', () => { 70 | let die: Subject; 71 | // spyOn(Bus,'stop').and.callFake(); 72 | beforeEach(() => { 73 | die = new Subject(); 74 | Bus['_e'] = new Subject(); 75 | }); 76 | afterEach(() => { 77 | die.next(true); 78 | die.complete(); 79 | Bus.stop(); 80 | }); 81 | afterAll(() => { 82 | Bus['_e'] = new Subject(); 83 | }); 84 | it('should send event on calling `sent` method', done => { 85 | Bus.listen('abc', 't_open') 86 | .pipe(takeUntil(die)) 87 | .subscribe(data => { 88 | expect(data).toEqual({ test: true }); 89 | done(); 90 | }); 91 | Bus.send('abc', 't_open', { test: true }); 92 | }); 93 | it('should send multiple event on calling many `sent` method', done => { 94 | const spy = jasmine.createSpy('spy').and.callThrough(); 95 | Bus.listen('xyz', 't_detach') 96 | .pipe(takeUntil(die)) 97 | .subscribe(() => { 98 | spy(); 99 | done(); 100 | }); 101 | Bus.send('xyz', 't_detach', `qwerty`); 102 | Bus.send('xyz', 't_detach', `home`); 103 | Bus.send('xyz', 't_detach', `Bakery`); 104 | expect(spy.calls.count()).toEqual(3); 105 | }); 106 | it('should complete the emission on calling `stop` method', done => { 107 | const spy = jasmine.createSpy('spy').and.callThrough(); 108 | Bus.listen('xyz', 't_dynpos') 109 | .pipe(takeUntil(die)) 110 | .subscribe( 111 | data => { 112 | spy(); 113 | }, 114 | null, 115 | () => { 116 | done(); 117 | } 118 | ); 119 | Bus.send('xyz', 't_dynpos', `qwerty`); 120 | Bus.send('xyz', 't_dynpos', `home`); 121 | Bus.stop(); 122 | Bus.send('xyz', 't_dynpos', `Bakery`); 123 | expect(spy.calls.count()).toEqual(2); 124 | }); 125 | }); 126 | }); 127 | -------------------------------------------------------------------------------- /projects/toppy/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../out-tsc/lib", 5 | "target": "es2015", 6 | "module": "es2015", 7 | "moduleResolution": "node", 8 | "declaration": true, 9 | "sourceMap": true, 10 | "inlineSources": true, 11 | "emitDecoratorMetadata": true, 12 | "experimentalDecorators": true, 13 | "importHelpers": true, 14 | "types": [], 15 | "lib": [ 16 | "dom", 17 | "es2018" 18 | ] 19 | }, 20 | "angularCompilerOptions": { 21 | "annotateForClosureCompiler": true, 22 | "skipTemplateCodegen": true, 23 | "strictMetadataEmit": true, 24 | "fullTemplateTypeCheck": true, 25 | "strictInjectionParameters": true, 26 | "enableResourceInlining": true 27 | }, 28 | "exclude": [ 29 | "src/test.ts", 30 | "**/*.spec.ts" 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /projects/toppy/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts" 12 | ], 13 | "include": [ 14 | "**/*.spec.ts", 15 | "**/*.d.ts" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /projects/toppy/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tslint.json", 3 | "rules": { 4 | "directive-selector": [true, "attribute", "lib", "camelCase"], 5 | "component-selector": [true, "element", "lib", "kebab-case"], 6 | "curly": [true, "ignore-same-line"] 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /scripts/archive.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs-extra'); 2 | const version = process.argv[2]; 3 | const archiveMetaFile = './docs/assets/archived-versions.json'; 4 | 5 | async function archiveFiles() { 6 | try { 7 | await fs.copy('./dist/toppy-app', `./dist/${version}`); 8 | await fs.copy(`./dist/${version}`, `./dist/toppy-app/${version}`); 9 | let archivedData = await fs.readJson(archiveMetaFile); 10 | archivedData = archivedData || {}; 11 | archivedData[version] = Date.now(); 12 | await fs.writeJson(archiveMetaFile, archivedData); 13 | console.log(`successfully archived version ${version}!`); 14 | } catch (err) { 15 | console.error(err); 16 | } 17 | } 18 | 19 | archiveFiles(); 20 | -------------------------------------------------------------------------------- /scripts/build-md.js: -------------------------------------------------------------------------------- 1 | const execa = require('execa'); 2 | const fs = require('fs-extra'); 3 | const Listr = require('listr'); 4 | const sane = require('sane'); 5 | var unified = require('unified'); 6 | var markdown = require('remark-parse'); 7 | var html = require('remark-html'); 8 | var bracketedSpans = require('remark-bracketed-spans'); 9 | const replace = require('replace-in-file'); 10 | const stringify = require('rehype-stringify'); 11 | var highlight = require('rehype-highlight'); 12 | const remarkAttr = require('remark-attr'); 13 | const remark2rehype = require('remark-rehype'); 14 | const slug = require('remark-slug'); 15 | const headings = require('remark-autolink-headings'); 16 | var raw = require('rehype-raw'); 17 | var format = require('rehype-format'); 18 | var watcher = sane('./docs/markdown', { glob: ['**/*.md'] }); 19 | 20 | const tasks = new Listr([ 21 | { 22 | title: 'fetch contents', 23 | task: ctx => { 24 | return fs.readFile('./docs/markdown/main.md', 'utf8').then(c => (ctx.contents = c)); 25 | } 26 | }, 27 | { 28 | title: 'converting markdown to html', 29 | task: ctx => { 30 | return unified() 31 | .use(markdown) 32 | .use(remarkAttr) 33 | .use(bracketedSpans) 34 | .use(slug) 35 | .use(headings, { behaviour: 'wrap' }) 36 | .use(remark2rehype, { allowDangerousHTML: true }) 37 | .use(raw) 38 | .use(format) 39 | .use(highlight) 40 | .use(stringify) 41 | .process(ctx.contents) 42 | .then(c => String(c)) 43 | .then(c => (ctx.contents = c)); 44 | } 45 | }, 46 | { 47 | title: 'file contents changed', 48 | task: ctx => { 49 | return fs.outputFile('./docs/app/utils/content/content.component.html', ctx.contents); 50 | } 51 | }, 52 | { 53 | title: 'replace braces', 54 | task: ctx => { 55 | return replace({ 56 | files: './docs/app/utils/content/content.component.html', 57 | from: [/\{/g, /\}/g], 58 | to: ['{', '}'] 59 | }).then(c => (ctx.contents = c)); 60 | } 61 | }, 62 | { 63 | title: 'replace links', 64 | task: ctx => { 65 | return replace({ 66 | files: './docs/app/utils/content/content.component.html', 67 | from: [/(span-classtoppy-icon-icon-)(.+?)--span-/g], 68 | to: [''] 69 | }).then(c => (ctx.contents = c)); 70 | } 71 | } 72 | ]); 73 | 74 | watcher.on('change', () => { 75 | tasks.run().catch(err => { 76 | console.error(err); 77 | }); 78 | }); 79 | -------------------------------------------------------------------------------- /scripts/gh-pages.js: -------------------------------------------------------------------------------- 1 | const ghpages = require('gh-pages'); 2 | ghpages.publish( 3 | './dist/toppy-app', 4 | { 5 | repo: 'https://' + process.env.GH_TOKEN + '@github.com/lokesh-coder/toppy.git', 6 | add: true 7 | }, 8 | function(err) { 9 | if (err) { 10 | console.log('Error occured during gh pages push', err); 11 | } else { 12 | console.log('Pushed to ghpages!'); 13 | } 14 | } 15 | ); 16 | -------------------------------------------------------------------------------- /scripts/version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | echo "The version would be: $1" 3 | echo "export const TOPPY_VERSION='$1'" > ./docs/environments/version.ts 4 | echo "Version file updated!" 5 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "module": "es2015", 9 | "moduleResolution": "node", 10 | "emitDecoratorMetadata": true, 11 | "experimentalDecorators": true, 12 | "target": "es5", 13 | "typeRoots": ["node_modules/@types"], 14 | "lib": ["es2018", "dom"], 15 | "paths": { 16 | "toppy": ["projects/toppy/src/public_api.ts"], 17 | "toppy/*": ["projects/toppy/src/*"] 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": [ 3 | "node_modules/codelyzer" 4 | ], 5 | "rules": { 6 | "arrow-return-shorthand": true, 7 | "callable-types": true, 8 | "class-name": true, 9 | "comment-format": [ 10 | true, 11 | "check-space" 12 | ], 13 | "curly": true, 14 | "deprecation": { 15 | "severity": "warn" 16 | }, 17 | "eofline": true, 18 | "forin": true, 19 | "import-blacklist": [ 20 | true, 21 | "rxjs/Rx" 22 | ], 23 | "import-spacing": true, 24 | "indent": [ 25 | true, 26 | "spaces" 27 | ], 28 | "interface-over-type-literal": true, 29 | "label-position": true, 30 | "max-line-length": [ 31 | true, 32 | 140 33 | ], 34 | "member-access": false, 35 | "member-ordering": [ 36 | true, 37 | { 38 | "order": [ 39 | "static-field", 40 | "instance-field", 41 | "static-method", 42 | "instance-method" 43 | ] 44 | } 45 | ], 46 | "no-arg": true, 47 | "no-bitwise": true, 48 | "no-console": [ 49 | true, 50 | "debug", 51 | "info", 52 | "time", 53 | "timeEnd", 54 | "trace" 55 | ], 56 | "no-construct": true, 57 | "no-debugger": true, 58 | "no-duplicate-super": true, 59 | "no-empty": false, 60 | "no-empty-interface": true, 61 | "no-eval": true, 62 | "no-inferrable-types": [ 63 | true, 64 | "ignore-params" 65 | ], 66 | "no-misused-new": true, 67 | "no-non-null-assertion": true, 68 | "no-redundant-jsdoc": true, 69 | "no-shadowed-variable": true, 70 | "no-string-literal": false, 71 | "no-string-throw": true, 72 | "no-switch-case-fall-through": true, 73 | "no-trailing-whitespace": true, 74 | "no-unnecessary-initializer": true, 75 | "no-unused-expression": true, 76 | "no-use-before-declare": true, 77 | "no-var-keyword": true, 78 | "object-literal-sort-keys": false, 79 | "one-line": [ 80 | true, 81 | "check-open-brace", 82 | "check-catch", 83 | "check-else", 84 | "check-whitespace" 85 | ], 86 | "prefer-const": true, 87 | "quotemark": [ 88 | true, 89 | "single" 90 | ], 91 | "radix": true, 92 | "semicolon": [ 93 | true, 94 | "always" 95 | ], 96 | "triple-equals": [ 97 | true, 98 | "allow-null-check" 99 | ], 100 | "typedef-whitespace": [ 101 | true, 102 | { 103 | "call-signature": "nospace", 104 | "index-signature": "nospace", 105 | "parameter": "nospace", 106 | "property-declaration": "nospace", 107 | "variable-declaration": "nospace" 108 | } 109 | ], 110 | "unified-signatures": true, 111 | "variable-name": false, 112 | "whitespace": [ 113 | true, 114 | "check-branch", 115 | "check-decl", 116 | "check-operator", 117 | "check-separator", 118 | "check-type" 119 | ], 120 | "no-output-on-prefix": true, 121 | "use-input-property-decorator": true, 122 | "use-output-property-decorator": true, 123 | "use-host-property-decorator": true, 124 | "no-input-rename": true, 125 | "no-output-rename": true, 126 | "use-life-cycle-interface": true, 127 | "use-pipe-transform-interface": true, 128 | "component-class-suffix": true, 129 | "directive-class-suffix": true 130 | } 131 | } 132 | --------------------------------------------------------------------------------