[
  {
    "path": ".babelrc",
    "content": "{\n  \"presets\": [\n    [\n      \"@babel/preset-env\",\n      {\n        \"useBuiltIns\": \"entry\",\n        \"corejs\": \"3\"\n      }\n    ]\n  ]\n}\n"
  },
  {
    "path": ".eslintrc.json",
    "content": "{\n    \"env\": {\n        \"browser\": true,\n        \"commonjs\": true,\n        \"es2021\": true\n    },\n    \"extends\": \"eslint:recommended\",\n    \"parserOptions\": {\n        \"ecmaVersion\": 12\n    },\n    \"rules\": {\n        \"accessor-pairs\": \"error\",\n        \"array-bracket-newline\": \"error\",\n        \"array-bracket-spacing\": [\n            \"error\",\n            \"never\"\n        ],\n        \"array-callback-return\": \"error\",\n        \"array-element-newline\": \"off\",\n        \"arrow-body-style\": \"error\",\n        \"arrow-parens\": \"error\",\n        \"arrow-spacing\": [\n            \"error\",\n            {\n                \"after\": true,\n                \"before\": true\n            }\n        ],\n        \"block-scoped-var\": \"error\",\n        \"block-spacing\": \"error\",\n        \"brace-style\": [\n            \"error\",\n            \"1tbs\"\n        ],\n        \"callback-return\": \"error\",\n        \"camelcase\": \"off\",\n        \"capitalized-comments\": \"off\",\n        \"class-methods-use-this\": \"error\",\n        \"comma-dangle\": \"error\",\n        \"comma-spacing\": [\n            \"error\",\n            {\n                \"after\": true,\n                \"before\": false\n            }\n        ],\n        \"comma-style\": [\n            \"error\",\n            \"last\"\n        ],\n        \"complexity\": \"error\",\n        \"computed-property-spacing\": [\n            \"error\",\n            \"never\"\n        ],\n        \"consistent-return\": \"off\",\n        \"consistent-this\": \"error\",\n        \"curly\": \"error\",\n        \"default-case\": \"off\",\n        \"dot-location\": \"error\",\n        \"dot-notation\": \"error\",\n        \"eol-last\": \"error\",\n        \"eqeqeq\": \"error\",\n        \"func-call-spacing\": \"error\",\n        \"func-name-matching\": \"error\",\n        \"func-names\": \"off\",\n        \"func-style\": [\n            \"error\",\n            \"declaration\",\n            {\n                \"allowArrowFunctions\": true\n            }\n        ],\n        \"function-paren-newline\": \"error\",\n        \"generator-star-spacing\": \"error\",\n        \"global-require\": \"error\",\n        \"guard-for-in\": \"error\",\n        \"handle-callback-err\": \"error\",\n        \"id-blacklist\": \"error\",\n        \"id-length\": \"off\",\n        \"id-match\": \"error\",\n        \"implicit-arrow-linebreak\": [\n            \"error\",\n            \"beside\"\n        ],\n        \"indent\": \"off\",\n        \"indent-legacy\": \"off\",\n        \"init-declarations\": \"off\",\n        \"jsx-quotes\": \"error\",\n        \"key-spacing\": \"error\",\n        \"keyword-spacing\": \"off\",\n        \"line-comment-position\": \"error\",\n        \"linebreak-style\": [\n            \"error\",\n            \"unix\"\n        ],\n        \"lines-around-comment\": \"error\",\n        \"lines-around-directive\": \"error\",\n        \"lines-between-class-members\": \"error\",\n        \"max-classes-per-file\": \"error\",\n        \"max-depth\": \"error\",\n        \"max-len\": \"off\",\n        \"max-lines\": \"off\",\n        \"max-lines-per-function\": \"off\",\n        \"max-nested-callbacks\": \"error\",\n        \"max-params\": \"error\",\n        \"max-statements\": \"off\",\n        \"max-statements-per-line\": \"error\",\n        \"multiline-comment-style\": [\n            \"error\",\n            \"separate-lines\"\n        ],\n        \"new-parens\": \"error\",\n        \"newline-after-var\": \"off\",\n        \"newline-before-return\": \"off\",\n        \"newline-per-chained-call\": \"error\",\n        \"no-alert\": \"error\",\n        \"no-array-constructor\": \"error\",\n        \"no-async-promise-executor\": \"error\",\n        \"no-await-in-loop\": \"error\",\n        \"no-bitwise\": \"off\",\n        \"no-buffer-constructor\": \"error\",\n        \"no-caller\": \"error\",\n        \"no-catch-shadow\": \"error\",\n        \"no-confusing-arrow\": \"error\",\n        \"no-continue\": \"error\",\n        \"no-div-regex\": \"error\",\n        \"no-duplicate-imports\": \"error\",\n        \"no-else-return\": \"error\",\n        \"no-empty-function\": \"error\",\n        \"no-eq-null\": \"error\",\n        \"no-eval\": \"error\",\n        \"no-extend-native\": \"error\",\n        \"no-extra-bind\": \"error\",\n        \"no-extra-label\": \"error\",\n        \"no-extra-parens\": \"off\",\n        \"no-floating-decimal\": \"error\",\n        \"no-implicit-coercion\": \"error\",\n        \"no-implicit-globals\": \"error\",\n        \"no-implied-eval\": \"error\",\n        \"no-inline-comments\": \"error\",\n        \"no-inner-declarations\": [\n            \"error\",\n            \"functions\"\n        ],\n        \"no-invalid-this\": \"off\",\n        \"no-iterator\": \"error\",\n        \"no-label-var\": \"error\",\n        \"no-labels\": \"error\",\n        \"no-lone-blocks\": \"error\",\n        \"no-lonely-if\": \"error\",\n        \"no-loop-func\": \"error\",\n        \"no-magic-numbers\": \"off\",\n        \"no-misleading-character-class\": \"error\",\n        \"no-mixed-operators\": \"off\",\n        \"no-mixed-requires\": \"error\",\n        \"no-multi-assign\": \"error\",\n        \"no-multi-spaces\": \"off\",\n        \"no-multi-str\": \"error\",\n        \"no-multiple-empty-lines\": \"error\",\n        \"no-native-reassign\": \"error\",\n        \"no-negated-condition\": \"error\",\n        \"no-negated-in-lhs\": \"error\",\n        \"no-nested-ternary\": \"error\",\n        \"no-new\": \"error\",\n        \"no-new-func\": \"error\",\n        \"no-new-object\": \"error\",\n        \"no-new-require\": \"error\",\n        \"no-new-wrappers\": \"error\",\n        \"no-octal-escape\": \"error\",\n        \"no-param-reassign\": \"error\",\n        \"no-path-concat\": \"error\",\n        \"no-plusplus\": [\n            \"error\",\n            {\n                \"allowForLoopAfterthoughts\": true\n            }\n        ],\n        \"no-process-env\": \"error\",\n        \"no-process-exit\": \"error\",\n        \"no-proto\": \"error\",\n        \"no-prototype-builtins\": \"error\",\n        \"no-restricted-globals\": \"error\",\n        \"no-restricted-imports\": \"error\",\n        \"no-restricted-modules\": \"error\",\n        \"no-restricted-properties\": \"error\",\n        \"no-restricted-syntax\": \"error\",\n        \"no-return-assign\": \"error\",\n        \"no-return-await\": \"error\",\n        \"no-script-url\": \"error\",\n        \"no-self-compare\": \"error\",\n        \"no-sequences\": \"error\",\n        \"no-shadow\": \"off\",\n        \"no-shadow-restricted-names\": \"error\",\n        \"no-spaced-func\": \"error\",\n        \"no-sync\": \"error\",\n        \"no-tabs\": \"error\",\n        \"no-template-curly-in-string\": \"error\",\n        \"no-ternary\": \"off\",\n        \"no-throw-literal\": \"off\",\n        \"no-trailing-spaces\": \"error\",\n        \"no-undef-init\": \"error\",\n        \"no-undefined\": \"error\",\n        \"no-underscore-dangle\": \"error\",\n        \"no-unmodified-loop-condition\": \"error\",\n        \"no-unneeded-ternary\": \"error\",\n        \"no-unused-expressions\": \"error\",\n        \"no-use-before-define\": \"off\",\n        \"no-useless-call\": \"error\",\n        \"no-useless-computed-key\": \"error\",\n        \"no-useless-concat\": \"error\",\n        \"no-useless-constructor\": \"error\",\n        \"no-useless-rename\": \"error\",\n        \"no-useless-return\": \"error\",\n        \"no-var\": \"off\",\n        \"no-void\": \"error\",\n        \"no-warning-comments\": \"off\",\n        \"no-whitespace-before-property\": \"error\",\n        \"no-with\": \"error\",\n        \"nonblock-statement-body-position\": \"error\",\n        \"object-curly-newline\": \"error\",\n        \"object-curly-spacing\": [\n            \"error\",\n            \"never\"\n        ],\n        \"object-shorthand\": \"error\",\n        \"one-var\": \"off\",\n        \"one-var-declaration-per-line\": \"error\",\n        \"operator-assignment\": \"error\",\n        \"operator-linebreak\": \"error\",\n        \"padded-blocks\": \"off\",\n        \"padding-line-between-statements\": \"error\",\n        \"prefer-arrow-callback\": \"off\",\n        \"prefer-const\": \"error\",\n        \"prefer-destructuring\": \"off\",\n        \"prefer-numeric-literals\": \"error\",\n        \"prefer-object-spread\": \"error\",\n        \"prefer-promise-reject-errors\": \"error\",\n        \"prefer-reflect\": \"error\",\n        \"prefer-rest-params\": \"error\",\n        \"prefer-spread\": \"error\",\n        \"prefer-template\": \"off\",\n        \"quote-props\": \"off\",\n        \"quotes\": [\n            \"error\",\n            \"single\"\n        ],\n        \"radix\": \"error\",\n        \"require-atomic-updates\": \"error\",\n        \"require-await\": \"error\",\n        \"require-jsdoc\": \"off\",\n        \"require-unicode-regexp\": \"off\",\n        \"rest-spread-spacing\": [\n            \"error\",\n            \"never\"\n        ],\n        \"semi\": \"error\",\n        \"semi-spacing\": [\n            \"error\",\n            {\n                \"after\": true,\n                \"before\": false\n            }\n        ],\n        \"semi-style\": [\n            \"error\",\n            \"last\"\n        ],\n        \"sort-imports\": \"error\",\n        \"sort-keys\": \"off\",\n        \"sort-vars\": \"error\",\n        \"space-before-blocks\": \"off\",\n        \"space-before-function-paren\": \"off\",\n        \"space-in-parens\": [\n            \"error\",\n            \"never\"\n        ],\n        \"space-infix-ops\": \"error\",\n        \"space-unary-ops\": \"error\",\n        \"spaced-comment\": [\n            \"error\",\n            \"always\"\n        ],\n        \"strict\": [\n            \"error\",\n            \"function\"\n        ],\n        \"switch-colon-spacing\": \"error\",\n        \"symbol-description\": \"error\",\n        \"template-curly-spacing\": [\n            \"error\",\n            \"never\"\n        ],\n        \"template-tag-spacing\": \"error\",\n        \"unicode-bom\": [\n            \"error\",\n            \"never\"\n        ],\n        \"valid-jsdoc\": \"error\",\n        \"vars-on-top\": \"off\",\n        \"wrap-iife\": \"error\",\n        \"wrap-regex\": \"off\",\n        \"yield-star-spacing\": \"error\",\n        \"yoda\": [\n            \"error\",\n            \"never\"\n        ]\n    }\n}\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: [sparanoid]\npatreon: # Replace with a single Patreon username\nopen_collective: # Replace with a single Open Collective username\nko_fi: # Replace with a single Ko-fi username\ntidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel\ncustom: https://sparanoid.com/donate/\n"
  },
  {
    "path": ".github/workflows/test.yml",
    "content": "# This workflow will run tests using node and then publish a package to GitHub Packages when a release is created\n# For more information see: https://help.github.com/actions/language-and-framework-guides/publishing-nodejs-packages\n\nname: Test\n\non:\n  push:\n    branches:\n      - '**'\n    tags:\n      - '**'\n  pull_request:\n    branches:\n      - '**'\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n      - uses: actions/setup-node@v3\n        with:\n          node-version: 16\n      - run: yarn --frozen-lockfile\n      - run: yarn test\n"
  },
  {
    "path": ".gitignore",
    "content": "# Numerous always-ignore extensions\n*.diff\n*.err\n*.orig\n*.log\n*.rej\n*.swo\n*.swp\n*.zip\n*.vi\n*~\n\n# OS or Editor folders\n.DS_Store\n._*\nThumbs.db\n.cache\n.project\n.settings\n.tmproj\n*.esproj\nnbproject\n*.sublime-project\n*.sublime-workspace\n.idea\n\n# Folders to ignore\nnode_modules\n"
  },
  {
    "path": ".huskyrc",
    "content": "{\n  \"hooks\": {\n    \"pre-commit\": \"yarn test && git add .\",\n    \"pre-push\": \"yarn build\"\n  }\n}\n"
  },
  {
    "path": ".jshintrc",
    "content": "{\n  \"esnext\": true\n}\n"
  },
  {
    "path": ".npmrc",
    "content": "message=\"chore(release): %s :tada:\"\n"
  },
  {
    "path": ".travis.yml",
    "content": "sudo: false\nlanguage: node_js\nnode_js:\n  - \"10\"\nnotifications:\n  email: false\n  slack:\n    secure: P/ngpvqinM/t9tdXZO2qHQvq2XCkcerKM+KwNJlQoVHnkl/Z/EtzB1yxiZZ6LGdHp+r3nShBhfW+gJVojU80EObt0iWHbFTkUUMFf6WI6c056937CksQI4atmDBiCJxMAnkd6DCLWfBexVtKDhkc5vX0bYhgoiXEzCYUhFd8pZ4=\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "Deprecated. See GitHub releases for latest updates.\n\n## [1.0.10](https://github.com/sparanoid/lightense-images/compare/v1.0.9...v1.0.10) (2020-07-16)\n\n\n### Features\n\n* **js:** native dark theme support via root-variables ([bfdd5c6](https://github.com/sparanoid/lightense-images/commit/bfdd5c605a8468e71cfc94818041e6938cdafdbd))\n\n\n\n## [1.0.9](https://github.com/sparanoid/lightense-images/compare/v1.0.8...v1.0.9) (2019-09-01)\n\n\n### Bug Fixes\n\n* **css:** blur effect not supported corrently for chrome ([640acc9](https://github.com/sparanoid/lightense-images/commit/640acc968371092e990cae2662f7533df1615156))\n* **js:** z-index too high, ref https://github.com/sparanoid/lightense-images/issues/41 ([a60342a](https://github.com/sparanoid/lightense-images/commit/a60342a4ea49b9c20fc0375ca939f9450630d617))\n\n\n### Features\n\n* update demo page ([5af3700](https://github.com/sparanoid/lightense-images/commit/5af3700caa047974a478d0eacae8563604ea7e88))\n\n\n\n## [1.0.8](https://github.com/sparanoid/lightense-images/compare/v1.0.7...v1.0.8) (2019-02-20)\n\n\n### Features\n\n* **js:** use native css variables ([ea3fcc5](https://github.com/sparanoid/lightense-images/commit/ea3fcc51a1d2516c9910cc5be37dbdfb467927b8))\n\n\n\n## [1.0.7](https://github.com/sparanoid/lightense-images/compare/v1.0.6...v1.0.7) (2019-02-19)\n\n\n\n## [1.0.6](https://github.com/sparanoid/lightense-images/compare/v1.0.5...v1.0.6) (2018-12-09)\n\n\n### Bug Fixes\n\n* **js:** blurry images with transform, should fixes https://github.com/sparanoid/lightense-images/issues/31 ([1e318d9](https://github.com/sparanoid/lightense-images/commit/1e318d93f42270f89fcd429720292366f774a7a4))\n\n\n### Features\n\n* basic linting ([d7e0595](https://github.com/sparanoid/lightense-images/commit/d7e05954cfe17ca85834b52748e71c2b28bdce09))\n* **js:** check if elements already inited, fixes https://github.com/sparanoid/lightense-images/issues/34 ([f2f0d84](https://github.com/sparanoid/lightense-images/commit/f2f0d841ccf59d4d47777e36d74099af17f30a2b))\n\n\n\n## [1.0.5](https://github.com/sparanoid/lightense-images/compare/v1.0.4...v1.0.5) (2018-03-28)\n\n\n### Bug Fixes\n\n* missing fallback for deprecated  attribute ([0285b80](https://github.com/sparanoid/lightense-images/commit/0285b80c00174ae7dc751df7b918e8f72da870c7))\n\n\n### Features\n\n* better config inheritance, should fix https://github.com/sparanoid/lightense-images/issues/32 ([0d57306](https://github.com/sparanoid/lightense-images/commit/0d57306e0cc62a79a54147039a0301791f3c973a))\n* generate Safari specific background color, automatically ([ae48d3b](https://github.com/sparanoid/lightense-images/commit/ae48d3bb888e7ff3227f3aad302e8f6d9c3ae610))\n\n\n\n## [1.0.4](https://github.com/sparanoid/lightense-images/compare/v1.0.3...v1.0.4) (2017-03-13)\n\n\n### Features\n\n* smaller output ([143773d](https://github.com/sparanoid/lightense-images/commit/143773d69a377669530bd2d3e0e2ffa26c269ff0))\n\n\n\n## [1.0.3](https://github.com/sparanoid/lightense-images/compare/v1.0.2...v1.0.3) (2017-01-17)\n\n\n### Features\n\n* allow passing string as target ([6608acc](https://github.com/sparanoid/lightense-images/commit/6608acc82397ff19201ed1763ec24ab90b9847dd))\n* **demo:** add lazy load example ([1a16d81](https://github.com/sparanoid/lightense-images/commit/1a16d81b2da0bf0f653810ccd6a43fc0f7b891fc))\n* **js:** allow select images, user should have the rights to select them ([7d24343](https://github.com/sparanoid/lightense-images/commit/7d243436fce23171a1393875b473dad322e4294a))\n\n\n\n## [1.0.2](https://github.com/sparanoid/lightense-images/compare/v1.0.1...v1.0.2) (2016-12-21)\n\n\n### Bug Fixes\n\n* **js:** selectable `.lightense-wrap` causes zoom out not working in some area ([860d632](https://github.com/sparanoid/lightense-images/commit/860d632b73497ed37d33adf7894dea600557d17f))\n\n\n### Features\n\n* **js:** ability to override image padding ([bac3c4f](https://github.com/sparanoid/lightense-images/commit/bac3c4f664fb3daad30d3671e8f4e7c765a79654))\n* **js:** avoid select images ([adf3a7e](https://github.com/sparanoid/lightense-images/commit/adf3a7ecdb8c572eed1a8f39b6e185653e4c152d))\n\n\n\n## [1.0.1](https://github.com/sparanoid/lightense-images/compare/v1.0.0...v1.0.1) (2016-10-28)\n\n\n### Bug Fixes\n\n* missing timeout for Firefox to work ([b7ffebc](https://github.com/sparanoid/lightense-images/commit/b7ffebca240b2bc52291a5098357d3e3cef69ead))\n* **docs:** wrong demo link ([91d663b](https://github.com/sparanoid/lightense-images/commit/91d663bacd0d6a28e21342d11d436c3a5823b148))\n* **docs:** wrong dep check link [ci skip] ([c256f30](https://github.com/sparanoid/lightense-images/commit/c256f30c02c17ee6dda37fa8588d0f2c2587411c))\n* **travis:** remove `0.12` support ([dcd3124](https://github.com/sparanoid/lightense-images/commit/dcd3124124ea2235c936213e5dff5da1ce859922))\n\n\n### Features\n\n* ability to toggle keyboard feature ([c1b9800](https://github.com/sparanoid/lightense-images/commit/c1b98002d5c0f401a67cba58f680e4909c9d1082))\n* add `config.offset` support ([515fba7](https://github.com/sparanoid/lightense-images/commit/515fba73fdd0eb4d7b6682705bf0d99d075e412d))\n* add demo page ([3924ac5](https://github.com/sparanoid/lightense-images/commit/3924ac51cb2d07a104d93a937b28bf8a70a0f1e9))\n* add modifier keys support ([8a82ade](https://github.com/sparanoid/lightense-images/commit/8a82ade305f6af7e1daddbd8573b3f7cd418066a))\n* add more options ([e0f994e](https://github.com/sparanoid/lightense-images/commit/e0f994e15c02b48171b643661efe3e1a1d70eb69))\n* brand new effect as seen on Medium.com ([2323092](https://github.com/sparanoid/lightense-images/commit/23230929e50cba666c2e034064448890677a76e4))\n* enable Travis CI ([644495f](https://github.com/sparanoid/lightense-images/commit/644495fe6f1413cff597f1b5480b647b4c113de3))\n* handle user options ([9f5956d](https://github.com/sparanoid/lightense-images/commit/9f5956d88f0798b83e50465e402fabc41b5fe3c9))\n* **docs:** add badges ([3e41f1b](https://github.com/sparanoid/lightense-images/commit/3e41f1b31059b891ffc8cdcb5e8b3dfc6c314d08))\n* **docs:** add license ([6e960f6](https://github.com/sparanoid/lightense-images/commit/6e960f63b67f439d8d86c201f89158715cf6f379))\n\n\n\n# [1.0.0](https://github.com/sparanoid/lightense-images/compare/1ade8c2f4c0afc745d37ec388234fab6397223b0...v1.0.0) (2016-03-11)\n\n\n### Features\n\n* init release ([1ade8c2](https://github.com/sparanoid/lightense-images/commit/1ade8c2f4c0afc745d37ec388234fab6397223b0))\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2021 Tunghsiao Liu\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Lightense Images\n\n[![Build Status](https://travis-ci.org/sparanoid/lightense-images.svg?branch=master)](https://travis-ci.org/sparanoid/lightense-images)\n[![devDependency Status](https://david-dm.org/sparanoid/lightense-images/dev-status.svg?theme=shields.io)](https://david-dm.org/sparanoid/lightense-images?type=dev)\n\nA dependency-free pure JavaScript image zooming library less than 2 KB (gzipped). Inspired by [tholman/intense-images](https://github.com/tholman/intense-images). You can play with the code [live on CodePen](http://codepen.io/sparanoid/pen/yOJyjV).\n\nThis library is mainly used by [Almace Scaffolding](https://github.com/sparanoid/almace-scaffolding).\n\n-----\n\n## [Getting Started](http://sparanoid.com/work/lightense-images/)\n\n## Donate\n\nWanna buy me a cup of coffee? [Great](http://sparanoid.com/donate/).\n\n## Author\n\n**Tunghsiao Liu**\n\n- Twitter: @[tunghsiao](http://twitter.com/tunghsiao)\n- GitHub: @[sparanoid](http://github.com/sparanoid)\n\n## License\n\nMIT\n"
  },
  {
    "path": "demo.html",
    "content": "<!DOCTYPE html>\n\n<link rel=\"stylesheet\" href=\"https://unpkg.com/root-variables\">\n\n<style>\n  @media (prefers-color-scheme: dark) {\n    :root {\n      --text-color-h: 213;\n      --text-color-s: 32%;\n      --text-color-l: 70%;\n\n      --link-color-h: 202;\n      --link-color-s: 100%;\n      --link-color-l: 60%;\n\n      --bg-color-h: 220;\n      --bg-color-s: 10%;\n      --bg-color-l: 12%;\n    }\n  }\n\n  /* Basic styles */\n  body {\n    color: var(--text-color);\n    background: var(--bg-color);\n    padding: 1vw 2vw;\n    font-family: \"Helvetica Neue\", Arial, sans-serif;\n    text-align: center;\n  }\n\n  img {\n    width: 300px;\n  }\n\n  a {\n    color: var(--link-color);\n    font-weight: 600;\n  }\n\n  h2 {\n    margin-top: 2em;\n  }\n\n  .gallery {\n    display: flex;\n    flex-wrap: wrap;\n  }\n\n  .gallery > div {\n    flex-grow: 1;\n    margin: 0 .25rem .5rem;\n    width: 30%;\n  }\n\n  /* Example: Lazy Lightense */\n  .lightense-lazy {\n    filter: blur(16px);\n    transform: scale(1.2);\n  }\n\n  .lightense-lazy-wrap {\n    position: relative;\n    width: 300px;\n    height: 115px;\n    margin: 0 auto;\n  }\n\n  .lightense-lazy-thumb {\n    position: relative;\n    width: 100%;\n    height: 100%;\n    overflow: hidden;\n    opacity: 1;\n    transition: opacity 1s ease;\n  }\n\n  .lightense-lazy-large {\n    position: absolute;\n    top: 0;\n    left: 0;\n    opacity: 0;\n    transition: opacity 1s ease;\n  }\n\n  .lightense-lazy-wrap.on .lightense-lazy-thumb {\n    opacity: 0;\n  }\n\n  .lightense-lazy-wrap.on .lightense-lazy-large {\n    opacity: 1;\n  }\n</style>\n\n<h1>\n  <a href=\"https://sparanoid.com/work/lightense-images/\" target=\"_blank\"\n    >Lightense Images</a\n  >\n  by <a href=\"https://sparanoid.com/\" target=\"_blank\">Tunghsiao Liu</a>\n</h1>\n\n<h2>General Usage</h2>\n\n<p>\n  <img\n    src=\"https://d349cztnlupsuf.cloudfront.net/girls_dead_monster_logo.png\"\n  />\n</p>\n\n<h2>Custom Background</h2>\n\n<p>\n  <img\n    src=\"https://d349cztnlupsuf.cloudfront.net/railgun-logo.png\"\n    data-lightense-background=\"rgba(23, 29, 54, .8)\"\n  />\n</p>\n\n<h2>Disable Lightense Images with Specific Class</h2>\n\n<p>\n  <img\n    src=\"https://d349cztnlupsuf.cloudfront.net/imouto-logo-large.png\"\n    class=\"no-lightense\"\n  />\n</p>\n\n<h2>Custom Padding</h2>\n\n<p>\n  <img\n    src=\"https://d349cztnlupsuf.cloudfront.net/delicious.com-logo.png\"\n    data-lightense-padding=\"0\"\n  />\n</p>\n\n<h2>Custom Background</h2>\n\n<p>\n  <img\n    src=\"https://d349cztnlupsuf.cloudfront.net/almace-scaffolding-text-vertical.svg\"\n    data-lightense-background=\"rgba(255, 1, 180, .2)\"\n  />\n</p>\n\n<h2>Custom Thumbnail Preview</h2>\n\n<p>\n  <img\n    src=\"https://d349cztnlupsuf.cloudfront.net/tianjin-impression-brochure-03-thumb.jpg?test\"\n    data-original=\"https://d349cztnlupsuf.cloudfront.net/tianjin-impression-brochure-03.jpg\"\n    class=\"lightense-lazy\"\n  />\n</p>\n\n<h2>Flexbox Gallery</h2>\n\n<div class=\"gallery\">\n  <div><img src=\"https://d349cztnlupsuf.cloudfront.net/girls_dead_monster_logo.png\" /></div>\n  <div><img src=\"https://d349cztnlupsuf.cloudfront.net/girls_dead_monster_logo.png\" /></div>\n  <div><img src=\"https://d349cztnlupsuf.cloudfront.net/girls_dead_monster_logo.png\" /></div>\n</div>\n\n<h2>Event Hooks</h2>\n\n<p>\n  <img\n    src=\"https://d349cztnlupsuf.cloudfront.net/girls_dead_monster_logo.png\"\n    before-show-alert=\"Showing!\"\n    after-show-alert=\"Showed!\"\n    before-hide-alert=\"Hiding!\"\n    after-hide-alert=\"Hidden!\"\n  />\n</p>\n\n<script src=\"dist/lightense.js\"></script>\n\n<script>\n  // Init Lightense\n  window.addEventListener(\"load\", function() {\n    Lightense(\"img:not(.no-lightense),.lightense\", {\n\n      // Example: Event Hooks\n      beforeShow(config) {\n        var beforeShowAttr = config.target.getAttribute(\"before-show-alert\");\n        beforeShowAttr && alert(beforeShowAttr);\n      },\n      afterShow(config) {\n        var afterShowAttr = config.target.getAttribute(\"after-show-alert\");\n        afterShowAttr && alert(afterShowAttr);\n      },\n      beforeHide(config) {\n        var beforeHideMessage = config.target.getAttribute(\"before-hide-alert\");\n        beforeHideMessage && alert(beforeHideMessage);\n      },\n      afterHide(config) {\n        var afterHideMessage = config.target.getAttribute(\"after-hide-alert\");\n        afterHideMessage && alert(afterHideMessage);\n      }\n    });\n  }, false);\n\n  // Example: Lazy Lightense\n  document.addEventListener(\"DOMContentLoaded\", function(e) {\n    function createDom(type, cssClass) {\n      var div = document.createElement(type);\n      div.className = cssClass;\n      return div;\n    }\n\n    var thumb = document.querySelector(\".lightense-lazy\");\n    var original = new Image();\n\n    // Init wrapper\n    var wrap = createDom(\"div\", \"lightense-lazy-wrap\");\n    thumb.parentNode.insertBefore(wrap, thumb);\n    wrap.appendChild(thumb);\n\n    // Wrap thumbnail\n    var thumbWrap = createDom(\"div\", \"lightense-lazy-thumb\");\n    thumbWrap.appendChild(thumb);\n    wrap.appendChild(thumbWrap);\n\n    // Wrap original\n    var originalWrap = createDom(\"div\", \"lightense-lazy-large\");\n    original.src = thumb.dataset.original;\n    originalWrap.appendChild(original);\n    wrap.appendChild(originalWrap);\n\n    // Load original image\n    original.addEventListener(\n      \"load\",\n      function() {\n        wrap.classList.add(\"on\");\n      },\n      false\n    );\n  });\n</script>\n"
  },
  {
    "path": "dist/lightense.js",
    "content": "/*! lightense-images v1.0.17 | © Tunghsiao Liu | MIT */\n(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"Lightense\"] = factory();\n\telse\n\t\troot[\"Lightense\"] = factory();\n})(this, function() {\nreturn /******/ (() => { // webpackBootstrap\n/******/ \tvar __webpack_modules__ = ({\n\n/***/ 352:\n/***/ ((module) => {\n\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nvar Lightense = function Lightense() {\n  'use strict'; // default options\n\n  var defaults = {\n    time: 300,\n    padding: 40,\n    offset: 40,\n    keyboard: true,\n    cubicBezier: 'cubic-bezier(.2, 0, .1, 1)',\n    background: 'var(--bg-color-80, rgba(255, 255, 255, .98))',\n    backgroundFilter: 'blur(30px)',\n    zIndex: 1000000,\n\n    /* eslint-disable no-undefined */\n    beforeShow: undefined,\n    afterShow: undefined,\n    beforeHide: undefined,\n    afterHide: undefined\n    /* eslint-enable no-undefined  */\n\n  }; // Init user options\n\n  var config = {};\n\n  function invokeCustomHook(methodName) {\n    var method = config[methodName];\n\n    if (!method) {\n      return;\n    }\n\n    if (typeof method !== 'function') {\n      throw \"config.\".concat(methodName, \" must be a function!\");\n    }\n\n    Reflect.apply(method, config, [config]);\n  } // Init target elements\n\n\n  var elements;\n\n  function getElements(elements) {\n    switch (_typeof(elements)) {\n      case 'undefined':\n        throw 'You need to pass an element!';\n\n      case 'string':\n        return document.querySelectorAll(elements);\n\n      case 'object':\n        return elements;\n    }\n  }\n\n  function startTracking(passedElements) {\n    // If passed an array of elements, assign tracking to all\n    var len = passedElements.length;\n\n    if (len) {\n      // Loop and assign\n      for (var i = 0; i < len; i++) {\n        track(passedElements[i]);\n      }\n    } else {\n      track(passedElements);\n    }\n  }\n\n  function track(element) {\n    if (element.src && !element.classList.contains('lightense-target')) {\n      element.classList.add('lightense-target');\n      element.addEventListener('click', function (event) {\n        if (config.keyboard) {\n          // If Command (macOS) or Ctrl (Windows) key pressed, stop processing\n          // and open the image in a new tab\n          if (event.metaKey || event.ctrlKey) {\n            return window.open(element.src, '_blank');\n          }\n        } // Init instance\n\n\n        init(this);\n      }, false);\n    }\n  }\n\n  function insertCss(styleId, styleContent) {\n    var head = document.head || document.getElementsByTagName('head')[0]; // Remove existing instance\n\n    if (document.getElementById(styleId)) {\n      document.getElementById(styleId).remove();\n    } // Create new instance\n\n\n    var styleEl = document.createElement('style');\n    styleEl.id = styleId; // Check if content exists\n\n    if (styleEl.styleSheet) {\n      styleEl.styleSheet.cssText = styleContent;\n    } else {\n      styleEl.appendChild(document.createTextNode(styleContent));\n    }\n\n    head.appendChild(styleEl);\n  }\n\n  function createDefaultCss() {\n    var css = \"\\n:root {\\n  --lightense-z-index: \".concat(config.zIndex - 1, \";\\n  --lightense-backdrop: \").concat(config.background, \";\\n  --lightense-backdrop-filter: \").concat(config.backgroundFilter, \";\\n  --lightense-duration: \").concat(config.time, \"ms;\\n  --lightense-timing-func: \").concat(config.cubicBezier, \";\\n}\\n\\n.lightense-backdrop {\\n  box-sizing: border-box;\\n  width: 100%;\\n  height: 100%;\\n  position: fixed;\\n  top: 0;\\n  left: 0;\\n  overflow: hidden;\\n  z-index: calc(var(--lightense-z-index) - 1);\\n  padding: 0;\\n  margin: 0;\\n  transition: opacity var(--lightense-duration) ease;\\n  cursor: zoom-out;\\n  opacity: 0;\\n  background-color: var(--lightense-backdrop);\\n  visibility: hidden;\\n}\\n\\n@supports (-webkit-backdrop-filter: blur(30px)) {\\n  .lightense-backdrop {\\n    background-color: var(--lightense-backdrop);\\n    -webkit-backdrop-filter: var(--lightense-backdrop-filter);\\n  }\\n}\\n\\n@supports (backdrop-filter: blur(30px)) {\\n  .lightense-backdrop {\\n    background-color: var(--lightense-backdrop);\\n    backdrop-filter: var(--lightense-backdrop-filter);\\n  }\\n}\\n\\n.lightense-wrap {\\n  position: relative;\\n  transition: transform var(--lightense-duration) var(--lightense-timing-func);\\n  z-index: var(--lightense-z-index);\\n  pointer-events: none;\\n}\\n\\n.lightense-target {\\n  cursor: zoom-in;\\n  transition: transform var(--lightense-duration) var(--lightense-timing-func);\\n  pointer-events: auto;\\n}\\n\\n.lightense-open {\\n  cursor: zoom-out;\\n}\\n\\n.lightense-transitioning {\\n  pointer-events: none;\\n}\");\n    insertCss('lightense-images-css', css);\n  }\n\n  function createBackdrop() {\n    if (document.querySelector('.lightense-backdrop') === null) {\n      config.container = document.createElement('div');\n      config.container.className = 'lightense-backdrop';\n      document.body.appendChild(config.container);\n    } else {\n      config.container = document.querySelector('.lightense-backdrop');\n    }\n  }\n\n  function createTransform(img) {\n    // Get original image size\n    var naturalWidth = img.width;\n    var naturalHeight = img.height; // Calc zoom ratio\n\n    var scrollTop = window.pageYOffset || document.documentElement.scrollTop || 0;\n    var scrollLeft = window.pageXOffset || document.documentElement.scrollLeft || 0;\n    var targetImage = config.target.getBoundingClientRect();\n    var maxScaleFactor = naturalWidth / targetImage.width;\n    var viewportWidth = window.innerWidth || document.documentElement.clientWidth || 0;\n    var viewportHeight = window.innerHeight || document.documentElement.clientHeight || 0;\n    var viewportPadding = config.target.getAttribute('data-lightense-padding') || config.target.getAttribute('data-padding') || config.padding;\n    var viewportWidthOffset = viewportWidth > viewportPadding ? viewportWidth - viewportPadding : viewportWidth - defaults.padding;\n    var viewportHeightOffset = viewportHeight > viewportPadding ? viewportHeight - viewportPadding : viewportHeight - defaults.padding;\n    var imageRatio = naturalWidth / naturalHeight;\n    var viewportRatio = viewportWidthOffset / viewportHeightOffset;\n\n    if (naturalWidth < viewportWidthOffset && naturalHeight < viewportHeightOffset) {\n      config.scaleFactor = maxScaleFactor;\n    } else if (imageRatio < viewportRatio) {\n      config.scaleFactor = viewportHeightOffset / naturalHeight * maxScaleFactor;\n    } else {\n      config.scaleFactor = viewportWidthOffset / naturalWidth * maxScaleFactor;\n    } // Calc animation\n\n\n    var viewportX = viewportWidth / 2;\n    var viewportY = scrollTop + viewportHeight / 2;\n    var imageCenterX = targetImage.left + scrollLeft + targetImage.width / 2;\n    var imageCenterY = targetImage.top + scrollTop + targetImage.height / 2;\n    config.translateX = Math.round(viewportX - imageCenterX);\n    config.translateY = Math.round(viewportY - imageCenterY);\n  }\n\n  function createViewer() {\n    config.target.classList.add('lightense-open'); // Create wrapper element\n\n    config.wrap = document.createElement('div');\n    config.wrap.className = 'lightense-wrap'; // Apply zoom ratio to target image\n\n    setTimeout(function () {\n      config.target.style.transform = 'scale(' + config.scaleFactor + ')';\n    }, 20); // Apply animation to outer wrapper\n\n    config.target.parentNode.insertBefore(config.wrap, config.target);\n    config.wrap.appendChild(config.target);\n    setTimeout(function () {\n      config.wrap.style.transform = 'translate3d(' + config.translateX + 'px, ' + config.translateY + 'px, 0)';\n    }, 20); // Show backdrop\n\n    var item_options = {\n      cubicBezier: config.target.getAttribute('data-lightense-cubic-bezier') || config.cubicBezier,\n      background: config.target.getAttribute('data-lightense-background') || config.target.getAttribute('data-background') || config.background,\n      zIndex: config.target.getAttribute('data-lightense-z-index') || config.zIndex\n    }; // Create new config for item-specified styles\n\n    var config_computed = _objectSpread(_objectSpread({}, config), item_options);\n\n    var css = \"\\n    :root {\\n      --lightense-z-index: \".concat(config_computed.zIndex - 1, \";\\n      --lightense-backdrop: \").concat(config_computed.background, \";\\n      --lightense-duration: \").concat(config_computed.time, \"ms;\\n      --lightense-timing-func: \").concat(config_computed.cubicBezier, \";\\n    }\");\n    insertCss('lightense-images-css-computed', css);\n    config.container.style.visibility = 'visible';\n    setTimeout(function () {\n      config.container.style.opacity = '1';\n    }, 20);\n  }\n\n  function removeViewer() {\n    invokeCustomHook('beforeHide');\n    unbindEvents();\n    config.target.classList.remove('lightense-open'); // Remove transform styles\n\n    config.wrap.style.transform = '';\n    config.target.style.transform = '';\n    config.target.classList.add('lightense-transitioning'); // Fadeout backdrop\n\n    config.container.style.opacity = ''; // Hide backdrop and remove target element wrapper\n\n    setTimeout(function () {\n      invokeCustomHook('afterHide');\n      config.container.style.visibility = '';\n      config.container.style.backgroundColor = '';\n      config.wrap.parentNode.replaceChild(config.target, config.wrap);\n      config.target.classList.remove('lightense-transitioning');\n    }, config.time);\n  }\n\n  function checkViewer() {\n    var scrollOffset = Math.abs(config.scrollY - window.scrollY);\n\n    if (scrollOffset >= config.offset) {\n      removeViewer();\n    }\n  }\n\n  function once(target, event, handler) {\n    target.addEventListener(event, function fn(args) {\n      Reflect.apply(handler, this, args);\n      target.removeEventListener(event, fn);\n    });\n  }\n\n  function init(element) {\n    config.target = element; // TODO: need refine\n    // If element already openned, close it\n\n    if (config.target.classList.contains('lightense-open')) {\n      return removeViewer();\n    }\n\n    invokeCustomHook('beforeShow'); // Save current window scroll position for later use\n\n    config.scrollY = window.scrollY;\n    once(config.target, 'transitionend', function () {\n      invokeCustomHook('afterShow');\n    });\n    var img = new Image();\n\n    img.onload = function () {\n      createTransform(this);\n      createViewer();\n      bindEvents();\n    };\n\n    img.src = config.target.src;\n  }\n\n  function bindEvents() {\n    window.addEventListener('keyup', onKeyUp, false);\n    window.addEventListener('scroll', checkViewer, false);\n    config.container.addEventListener('click', removeViewer, false);\n  }\n\n  function unbindEvents() {\n    window.removeEventListener('keyup', onKeyUp, false);\n    window.removeEventListener('scroll', checkViewer, false);\n    config.container.removeEventListener('click', removeViewer, false);\n  } // Exit on excape (esc) key pressed\n\n\n  function onKeyUp(event) {\n    event.preventDefault();\n\n    if (event.keyCode === 27) {\n      removeViewer();\n    }\n  }\n\n  function main(target) {\n    var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n    // Parse elements\n    elements = getElements(target); // Parse user options\n\n    config = _objectSpread(_objectSpread({}, defaults), options); // Prepare stylesheets\n\n    createDefaultCss(); // Prepare backdrop element\n\n    createBackdrop(); // Pass and prepare elements\n\n    startTracking(elements);\n  }\n\n  return main;\n};\n\nvar singleton = Lightense();\nmodule.exports = singleton;\n\n/***/ })\n\n/******/ \t});\n/************************************************************************/\n/******/ \t// The module cache\n/******/ \tvar __webpack_module_cache__ = {};\n/******/ \t\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/ \t\t// Check if module is in cache\n/******/ \t\tvar cachedModule = __webpack_module_cache__[moduleId];\n/******/ \t\tif (cachedModule !== undefined) {\n/******/ \t\t\treturn cachedModule.exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = __webpack_module_cache__[moduleId] = {\n/******/ \t\t\t// no module.id needed\n/******/ \t\t\t// no module.loaded needed\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/ \t\n/******/ \t\t// Execute the module function\n/******/ \t\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n/******/ \t\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/ \t\n/************************************************************************/\n/******/ \t\n/******/ \t// startup\n/******/ \t// Load entry module and return exports\n/******/ \t// This entry module is referenced by other modules so it can't be inlined\n/******/ \tvar __webpack_exports__ = __webpack_require__(352);\n/******/ \t\n/******/ \treturn __webpack_exports__;\n/******/ })()\n;\n});"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"lightense-images\",\n  \"version\": \"1.0.17\",\n  \"description\": \"A dependency-free pure JavaScript image zooming library less than 2 KB (gzipped)\",\n  \"main\": \"dist/lightense.js\",\n  \"scripts\": {\n    \"build\": \"webpack --progress --mode=production\",\n    \"test\": \"yarn eslint src/index.js\",\n    \"watch\": \"webpack --progress --watch --mode=development\",\n    \"release\": \"release-it\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/sparanoid/lightense-images.git\"\n  },\n  \"publishConfig\": {\n    \"registry\": \"https://registry.npmjs.org/\"\n  },\n  \"keywords\": [\n    \"css\",\n    \"image\",\n    \"javascript\",\n    \"webpack\"\n  ],\n  \"author\": \"Tunghsiao Liu\",\n  \"license\": \"MIT\",\n  \"bugs\": {\n    \"url\": \"https://github.com/sparanoid/lightense-images/issues\"\n  },\n  \"homepage\": \"http://sparanoid.com/work/lightense-images/\",\n  \"devDependencies\": {\n    \"@babel/core\": \"^7.10.5\",\n    \"@babel/preset-env\": \"^7.10.4\",\n    \"babel-loader\": \"^8.1.0\",\n    \"core-js\": \"^3.15.2\",\n    \"eslint\": \"^8.0.0\",\n    \"eslint-webpack-plugin\": \"^3.0.0\",\n    \"husky\": \"^8.0.0\",\n    \"release-it\": \"^15.0.0\",\n    \"terser-webpack-plugin\": \"^5.1.4\",\n    \"webpack\": \"^5.41.1\",\n    \"webpack-cli\": \"^4.7.2\"\n  },\n  \"release-it\": {\n    \"hooks\": {\n      \"before:bump\": [\n        \"yarn test\"\n      ],\n      \"after:bump\": [\n        \"yarn build\"\n      ]\n    },\n    \"github\": {\n      \"release\": true\n    }\n  }\n}\n"
  },
  {
    "path": "renovate.json",
    "content": "{\n  \"extends\": [\n    \"config:base\",\n    \":preserveSemverRanges\"\n  ]\n}\n"
  },
  {
    "path": "src/index.js",
    "content": "const Lightense = () => {\n  'use strict';\n\n  // default options\n  const defaults = {\n    time: 300,\n    padding: 40,\n    offset: 40,\n    keyboard: true,\n    cubicBezier: 'cubic-bezier(.2, 0, .1, 1)',\n    background: 'var(--bg-color-80, rgba(255, 255, 255, .98))',\n    backgroundFilter: 'blur(30px)',\n    zIndex: 1000000,\n    /* eslint-disable no-undefined */\n    beforeShow: undefined,\n    afterShow: undefined,\n    beforeHide: undefined,\n    afterHide: undefined\n    /* eslint-enable no-undefined  */\n  };\n  // Init user options\n  var config = {};\n\n  function invokeCustomHook(methodName) {\n    const method = config[methodName];\n\n    if (!method) {\n      return;\n    }\n\n    if (typeof method !== 'function') {\n      throw `config.${methodName} must be a function!`;\n    }\n\n    Reflect.apply(method, config, [config]);\n  }\n\n  // Init target elements\n  var elements;\n\n  function getElements(elements) {\n    switch (typeof elements) {\n      case 'undefined':\n        throw 'You need to pass an element!';\n\n      case 'string':\n        return document.querySelectorAll(elements);\n\n      case 'object':\n        return elements;\n    }\n  }\n\n  function startTracking(passedElements) {\n    // If passed an array of elements, assign tracking to all\n    var len = passedElements.length;\n    if (len) {\n      // Loop and assign\n      for (var i = 0; i < len; i++) {\n        track(passedElements[i]);\n      }\n    } else {\n      track(passedElements);\n    }\n  }\n\n  function track(element) {\n    if (element.src && !element.classList.contains('lightense-target')) {\n      element.classList.add('lightense-target');\n      element.addEventListener(\n        'click',\n        function(event) {\n          if (config.keyboard) {\n            // If Command (macOS) or Ctrl (Windows) key pressed, stop processing\n            // and open the image in a new tab\n            if (event.metaKey || event.ctrlKey) {\n              return window.open(element.src, '_blank');\n            }\n          }\n\n          // Init instance\n          init(this);\n        },\n        false\n      );\n    }\n  }\n\n  function insertCss(styleId, styleContent) {\n    var head = document.head || document.getElementsByTagName('head')[0];\n\n    // Remove existing instance\n    if (document.getElementById(styleId)) {\n      document.getElementById(styleId).remove();\n    }\n\n    // Create new instance\n    var styleEl = document.createElement('style');\n    styleEl.id = styleId;\n\n    // Check if content exists\n    if (styleEl.styleSheet) {\n      styleEl.styleSheet.cssText = styleContent;\n    } else {\n      styleEl.appendChild(document.createTextNode(styleContent));\n    }\n    head.appendChild(styleEl);\n  }\n\n  function createDefaultCss() {\n    var css = `\n:root {\n  --lightense-z-index: ${config.zIndex - 1};\n  --lightense-backdrop: ${config.background};\n  --lightense-backdrop-filter: ${config.backgroundFilter};\n  --lightense-duration: ${config.time}ms;\n  --lightense-timing-func: ${config.cubicBezier};\n}\n\n.lightense-backdrop {\n  box-sizing: border-box;\n  width: 100%;\n  height: 100%;\n  position: fixed;\n  top: 0;\n  left: 0;\n  overflow: hidden;\n  z-index: calc(var(--lightense-z-index) - 1);\n  padding: 0;\n  margin: 0;\n  transition: opacity var(--lightense-duration) ease;\n  cursor: zoom-out;\n  opacity: 0;\n  background-color: var(--lightense-backdrop);\n  visibility: hidden;\n}\n\n@supports (-webkit-backdrop-filter: blur(30px)) {\n  .lightense-backdrop {\n    background-color: var(--lightense-backdrop);\n    -webkit-backdrop-filter: var(--lightense-backdrop-filter);\n  }\n}\n\n@supports (backdrop-filter: blur(30px)) {\n  .lightense-backdrop {\n    background-color: var(--lightense-backdrop);\n    backdrop-filter: var(--lightense-backdrop-filter);\n  }\n}\n\n.lightense-wrap {\n  position: relative;\n  transition: transform var(--lightense-duration) var(--lightense-timing-func);\n  z-index: var(--lightense-z-index);\n  pointer-events: none;\n}\n\n.lightense-target {\n  cursor: zoom-in;\n  transition: transform var(--lightense-duration) var(--lightense-timing-func);\n  pointer-events: auto;\n}\n\n.lightense-open {\n  cursor: zoom-out;\n}\n\n.lightense-transitioning {\n  pointer-events: none;\n}`;\n    insertCss('lightense-images-css', css);\n  }\n\n  function createBackdrop() {\n    if (document.querySelector('.lightense-backdrop') === null) {\n      config.container = document.createElement('div');\n      config.container.className = 'lightense-backdrop';\n      document.body.appendChild(config.container);\n    } else {\n      config.container = document.querySelector('.lightense-backdrop');\n    }\n  }\n\n  function createTransform(img) {\n    // Get original image size\n    var naturalWidth = img.width;\n    var naturalHeight = img.height;\n\n    // Calc zoom ratio\n    var scrollTop = window.pageYOffset || document.documentElement.scrollTop || 0;\n    var scrollLeft = window.pageXOffset || document.documentElement.scrollLeft || 0;\n    var targetImage = config.target.getBoundingClientRect();\n    var maxScaleFactor = naturalWidth / targetImage.width;\n    var viewportWidth = window.innerWidth || document.documentElement.clientWidth || 0;\n    var viewportHeight = window.innerHeight || document.documentElement.clientHeight || 0;\n    var viewportPadding =\n      config.target.getAttribute('data-lightense-padding') ||\n      config.target.getAttribute('data-padding') ||\n      config.padding;\n    var viewportWidthOffset =\n      viewportWidth > viewportPadding\n        ? viewportWidth - viewportPadding\n        : viewportWidth - defaults.padding;\n    var viewportHeightOffset =\n      viewportHeight > viewportPadding\n        ? viewportHeight - viewportPadding\n        : viewportHeight - defaults.padding;\n    var imageRatio = naturalWidth / naturalHeight;\n    var viewportRatio = viewportWidthOffset / viewportHeightOffset;\n\n    if (\n      naturalWidth < viewportWidthOffset &&\n      naturalHeight < viewportHeightOffset\n    ) {\n      config.scaleFactor = maxScaleFactor;\n    } else if (imageRatio < viewportRatio) {\n      config.scaleFactor =\n        (viewportHeightOffset / naturalHeight) * maxScaleFactor;\n    } else {\n      config.scaleFactor =\n        (viewportWidthOffset / naturalWidth) * maxScaleFactor;\n    }\n\n    // Calc animation\n    var viewportX = viewportWidth / 2;\n    var viewportY = scrollTop + viewportHeight / 2;\n    var imageCenterX = targetImage.left + scrollLeft + targetImage.width / 2;\n    var imageCenterY = targetImage.top + scrollTop + targetImage.height / 2;\n\n    config.translateX = Math.round(viewportX - imageCenterX);\n    config.translateY = Math.round(viewportY - imageCenterY);\n  }\n\n  function createViewer() {\n    config.target.classList.add('lightense-open');\n\n    // Create wrapper element\n    config.wrap = document.createElement('div');\n    config.wrap.className = 'lightense-wrap';\n\n    // Apply zoom ratio to target image\n    setTimeout(function() {\n      config.target.style.transform = 'scale(' + config.scaleFactor + ')';\n    }, 20);\n\n    // Apply animation to outer wrapper\n    config.target.parentNode.insertBefore(config.wrap, config.target);\n    config.wrap.appendChild(config.target);\n    setTimeout(function() {\n      config.wrap.style.transform =\n        'translate3d(' +\n        config.translateX +\n        'px, ' +\n        config.translateY +\n        'px, 0)';\n    }, 20);\n\n    // Show backdrop\n    var item_options = {\n      cubicBezier:\n        config.target.getAttribute('data-lightense-cubic-bezier') ||\n        config.cubicBezier,\n      background:\n        config.target.getAttribute('data-lightense-background') ||\n        config.target.getAttribute('data-background') ||\n        config.background,\n      zIndex:\n        config.target.getAttribute('data-lightense-z-index') || config.zIndex\n    };\n\n    // Create new config for item-specified styles\n    var config_computed = {...config, ...item_options};\n\n    var css = `\n    :root {\n      --lightense-z-index: ${config_computed.zIndex - 1};\n      --lightense-backdrop: ${config_computed.background};\n      --lightense-duration: ${config_computed.time}ms;\n      --lightense-timing-func: ${config_computed.cubicBezier};\n    }`;\n    insertCss('lightense-images-css-computed', css);\n\n    config.container.style.visibility = 'visible';\n    setTimeout(function() {\n      config.container.style.opacity = '1';\n    }, 20);\n  }\n\n  function removeViewer() {\n    invokeCustomHook('beforeHide');\n    unbindEvents();\n\n    config.target.classList.remove('lightense-open');\n\n    // Remove transform styles\n    config.wrap.style.transform = '';\n    config.target.style.transform = '';\n    config.target.classList.add('lightense-transitioning');\n\n    // Fadeout backdrop\n    config.container.style.opacity = '';\n\n    // Hide backdrop and remove target element wrapper\n    setTimeout(function() {\n      invokeCustomHook('afterHide');\n      config.container.style.visibility = '';\n      config.container.style.backgroundColor = '';\n      config.wrap.parentNode.replaceChild(config.target, config.wrap);\n      config.target.classList.remove('lightense-transitioning');\n    }, config.time);\n  }\n\n  function checkViewer() {\n    var scrollOffset = Math.abs(config.scrollY - window.scrollY);\n    if (scrollOffset >= config.offset) {\n      removeViewer();\n    }\n  }\n\n  function once(target, event, handler) {\n    target.addEventListener(event, function fn(args) {\n      Reflect.apply(handler, this, args);\n\n      target.removeEventListener(event, fn);\n    });\n  }\n\n  function init(element) {\n    config.target = element;\n\n    // TODO: need refine\n    // If element already openned, close it\n    if (config.target.classList.contains('lightense-open')) {\n      return removeViewer();\n    }\n\n    invokeCustomHook('beforeShow');\n\n    // Save current window scroll position for later use\n    config.scrollY = window.scrollY;\n\n    once(config.target, 'transitionend', function() {\n      invokeCustomHook('afterShow');\n    });\n\n    var img = new Image();\n    img.onload = function() {\n      createTransform(this);\n      createViewer();\n      bindEvents();\n    };\n\n    img.src = config.target.src;\n  }\n\n  function bindEvents() {\n    window.addEventListener('keyup', onKeyUp, false);\n    window.addEventListener('scroll', checkViewer, false);\n    config.container.addEventListener('click', removeViewer, false);\n  }\n\n  function unbindEvents() {\n    window.removeEventListener('keyup', onKeyUp, false);\n    window.removeEventListener('scroll', checkViewer, false);\n    config.container.removeEventListener('click', removeViewer, false);\n  }\n\n  // Exit on excape (esc) key pressed\n  function onKeyUp(event) {\n    event.preventDefault();\n    if (event.keyCode === 27) {\n      removeViewer();\n    }\n  }\n\n  function main(target, options = {}) {\n    // Parse elements\n    elements = getElements(target);\n\n    // Parse user options\n    config = {...defaults, ...options};\n\n    // Prepare stylesheets\n    createDefaultCss();\n\n    // Prepare backdrop element\n    createBackdrop();\n\n    // Pass and prepare elements\n    startTracking(elements);\n  }\n\n  return main;\n};\n\nconst singleton = Lightense();\n\nmodule.exports = singleton;\n"
  },
  {
    "path": "webpack.config.js",
    "content": "const webpack = require('webpack');\nconst path = require('path');\nconst pkg = require('./package.json');\nconst banner = `/*! ${ pkg.name } v${ pkg.version } | © ${ pkg.author } | ${ pkg.license } */`;\nconst ESLintPlugin = require('eslint-webpack-plugin');\nconst TerserPlugin = require(\"terser-webpack-plugin\");\n\nmodule.exports = {\n  entry: {\n    './dist/lightense': './src/index.js',\n    './dist/lightense.min': './src/index.js',\n  },\n  output: {\n    path: path.resolve(__dirname, './'),\n    filename: '[name].js',\n    libraryTarget: 'umd',\n    library: 'Lightense',\n    globalObject: 'this',\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.js$/,\n        exclude: /node_modules/,\n        enforce: 'pre',\n        use: {\n          loader: 'babel-loader',\n          options: {\n            presets: ['@babel/preset-env']\n          },\n        },\n      }\n    ]\n  },\n  optimization: {\n    minimize: true,\n    minimizer: [\n      new TerserPlugin({\n        include: /\\.min\\.js$/,\n        parallel: true,\n        extractComments: false,\n      })\n    ]\n  },\n  plugins: [\n    new webpack.BannerPlugin({\n      banner: banner,\n      raw: true,\n      entryOnly: true\n    }),\n    new ESLintPlugin({\n      extensions: 'js'\n    })\n  ]\n};\n"
  }
]