├── .github ├── dependabot.yml └── workflows │ ├── lint-pr.yml │ ├── npm-publish.yml │ └── wc.yml ├── .gitignore ├── .prettierignore ├── .vscode └── extensions.json ├── LICENSE ├── README.md ├── demo.gif ├── favicon.ico ├── index.html ├── infinite-carousel-wc.js ├── package-lock.json ├── package.json └── tsconfig.json /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "npm" 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | commit-message: 13 | prefix: "fix" 14 | prefix-development: "build" 15 | -------------------------------------------------------------------------------- /.github/workflows/lint-pr.yml: -------------------------------------------------------------------------------- 1 | name: "Lint PR" 2 | on: 3 | pull_request: 4 | types: 5 | - opened 6 | - edited 7 | - synchronize 8 | 9 | jobs: 10 | conventional-commit-pr-title: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: amannn/action-semantic-pull-request@v1.2.0 14 | env: 15 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 16 | -------------------------------------------------------------------------------- /.github/workflows/npm-publish.yml: -------------------------------------------------------------------------------- 1 | # This workflow will run tests using node and then publish a package to GitHub Packages when a release is created 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/publishing-nodejs-packages 3 | 4 | name: NPM Publish 5 | 6 | on: 7 | release: 8 | types: [created] 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | - uses: actions/setup-node@v1 16 | with: 17 | node-version: 12 18 | - run: npm ci 19 | 20 | publish-npm: 21 | needs: build 22 | runs-on: ubuntu-latest 23 | steps: 24 | - uses: actions/checkout@v2 25 | - uses: actions/setup-node@v1 26 | with: 27 | node-version: 12 28 | registry-url: https://registry.npmjs.org/ 29 | - run: npm ci 30 | - run: npm publish 31 | env: 32 | NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} 33 | -------------------------------------------------------------------------------- /.github/workflows/wc.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: Build 5 | 6 | on: 7 | push: 8 | branches: [main] 9 | pull_request: 10 | branches: [main] 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v2 18 | - uses: actions/setup-node@v1 19 | with: 20 | node-version: 12 21 | - run: npm ci 22 | - run: npm run lint 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.min.js 2 | *.d.ts 3 | 4 | # Created by https://www.gitignore.io/api/node,macos,windows,visualstudiocode 5 | # Edit at https://www.gitignore.io/?templates=node,macos,windows,visualstudiocode 6 | 7 | ### macOS ### 8 | # General 9 | .DS_Store 10 | .AppleDouble 11 | .LSOverride 12 | 13 | # Icon must end with two \r 14 | Icon 15 | 16 | # Thumbnails 17 | ._* 18 | 19 | # Files that might appear in the root of a volume 20 | .DocumentRevisions-V100 21 | .fseventsd 22 | .Spotlight-V100 23 | .TemporaryItems 24 | .Trashes 25 | .VolumeIcon.icns 26 | .com.apple.timemachine.donotpresent 27 | 28 | # Directories potentially created on remote AFP share 29 | .AppleDB 30 | .AppleDesktop 31 | Network Trash Folder 32 | Temporary Items 33 | .apdisk 34 | 35 | ### Node ### 36 | # Logs 37 | logs 38 | *.log 39 | npm-debug.log* 40 | yarn-debug.log* 41 | yarn-error.log* 42 | 43 | # Runtime data 44 | pids 45 | *.pid 46 | *.seed 47 | *.pid.lock 48 | 49 | # Directory for instrumented libs generated by jscoverage/JSCover 50 | lib-cov 51 | 52 | # Coverage directory used by tools like istanbul 53 | coverage 54 | 55 | # nyc test coverage 56 | .nyc_output 57 | 58 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 59 | .grunt 60 | 61 | # Bower dependency directory (https://bower.io/) 62 | bower_components 63 | 64 | # node-waf configuration 65 | .lock-wscript 66 | 67 | # Compiled binary addons (https://nodejs.org/api/addons.html) 68 | build/Release 69 | 70 | # Dependency directories 71 | node_modules/ 72 | jspm_packages/ 73 | 74 | # TypeScript v1 declaration files 75 | typings/ 76 | 77 | # Optional npm cache directory 78 | .npm 79 | 80 | # Optional eslint cache 81 | .eslintcache 82 | 83 | # Optional REPL history 84 | .node_repl_history 85 | 86 | # Output of 'npm pack' 87 | *.tgz 88 | 89 | # Yarn Integrity file 90 | .yarn-integrity 91 | 92 | # dotenv environment variables file 93 | .env 94 | 95 | # parcel-bundler cache (https://parceljs.org/) 96 | .cache 97 | 98 | # next.js build output 99 | .next 100 | 101 | # nuxt.js build output 102 | .nuxt 103 | 104 | # vuepress build output 105 | .vuepress/dist 106 | 107 | # Serverless directories 108 | .serverless 109 | 110 | # FuseBox cache 111 | .fusebox/ 112 | 113 | ### VisualStudioCode ### 114 | .vscode/* 115 | !.vscode/settings.json 116 | !.vscode/tasks.json 117 | !.vscode/launch.json 118 | !.vscode/extensions.json 119 | 120 | ### VisualStudioCode Patch ### 121 | # Ignore all local history of files 122 | .history 123 | 124 | ### Windows ### 125 | # Windows thumbnail cache files 126 | Thumbs.db 127 | ehthumbs.db 128 | ehthumbs_vista.db 129 | 130 | # Dump file 131 | *.stackdump 132 | 133 | # Folder config file 134 | [Dd]esktop.ini 135 | 136 | # Recycle Bin used on file shares 137 | $RECYCLE.BIN/ 138 | 139 | # Windows Installer files 140 | *.cab 141 | *.msi 142 | *.msix 143 | *.msm 144 | *.msp 145 | 146 | # Windows shortcuts 147 | *.lnk 148 | 149 | # End of https://www.gitignore.io/api/node,macos,windows,visualstudiocode -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.min.js 3 | *.d.ts 4 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. 3 | // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp 4 | 5 | // List of extensions which should be recommended for users of this workspace. 6 | "recommendations": [ 7 | "esbenp.prettier-vscode", 8 | "ritwickdey.liveserver", 9 | "plievone.vscode-template-literal-editor" 10 | ], 11 | // List of extensions recommended by VS Code that should not be recommended for users of this workspace. 12 | "unwantedRecommendations": [] 13 | } 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 wes@goulet.dev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Build](https://github.com/wes566/infinite-carousel-wc/workflows/Build/badge.svg) [![Published on webcomponents.org](https://img.shields.io/badge/webcomponents.org-published-blue.svg?style=flat-square)](https://www.webcomponents.org/element/infinite-carousel-wc) [![npm](https://img.shields.io/npm/v/infinite-carousel-wc.svg)](https://npmjs.org/package/infinite-carousel-wc) 2 | 3 | # infinite-carousel-wc 4 | 5 | An infinite carousel Web Component built with modern CSS and just a little Javascript. Supports both horizontal and vertical scrolling. 6 | 7 | ![infinite-carousel-wc demo](demo.gif) 8 | 9 | ## [Demo](https://infinite-carousel-wc.netlify.com/) 10 | 11 | ## Installation 12 | 13 | You can integrate infinite-carousel-wc via ` 24 | 25 | 26 | 30 | ``` 31 | 32 | Now you can use the `infinite-carousel-wc` element anywhere in your html, JSX, template, etc. 33 | 34 | ### Via NPM 35 | 36 | ```bash 37 | npm install infinite-carousel-wc --save 38 | ``` 39 | 40 | And then you need to import the module before you can use it in your html/jsx/template: 41 | 42 | ```js 43 | import "infinite-carousel-wc"; 44 | ``` 45 | 46 | ## Web Component Browser Support 47 | 48 | This web component uses [HTML templates](https://caniuse.com/#feat=template), the [shadow DOM](https://caniuse.com/#feat=shadowdomv1), and [custom elements](https://caniuse.com/#feat=custom-elementsv1). If you need to polyfill for any of these standards then [take a look at the web components polyfill](https://github.com/webcomponents/webcomponentsjs). 49 | 50 | ## Polyfills 51 | 52 | This custom element uses [CSS Scroll Snap](https://caniuse.com/#feat=css-snappoints), [IntersectionObserver](https://caniuse.com/#feat=intersectionobserver) and [Smooth Scrolling](https://caniuse.com/#feat=css-scroll-behavior). Browser support for Scroll Snap is pretty good (this custom element supports both v0 and v1 of the spec). There is a polyfill for [IntersectionObserver](https://github.com/w3c/IntersectionObserver/tree/master/polyfill) and [Smooth Scrolling](https://github.com/iamdustan/smoothscroll). 53 | 54 | A note about IntersectionObserver polyfill on iOS 12.1 and below: you might need to [configure the polyfill to use polling](https://github.com/w3c/IntersectionObserver/tree/master/polyfill#configuring-the-polyfill) for the carousel to work properly. 55 | 56 | ## API and Customization 57 | 58 | ### Slots 59 | 60 | The infinite carousel works by laying out 3 slots, with slot names of `1`, `2`, and `3`. The slots will be re-ordered in a circular manner as the user swipes/scrolls. 61 | 62 | When inifinite-scroller-wc first renders it will show slot 1 as visible (called the "current" position). Slot 2 will be to the right (in the "next" position), and slot 3 will be to the left (in the "previous" position), like this: 63 | 64 | | "previous" | "current" | "next" | 65 | | :--------: | :-------: | :----: | 66 | | 3 | 1 | 2 | 67 | 68 | Remember that "current" is the only slot visible to the user at rest. When the user peaks left or right they will then see the "previous" or "next" slot contents respectively. 69 | 70 | When the user swipes/scrolls forward then some CSS will get added to the slots to re-order them (technically the CSS is added to the slot's parents which are encapsulated in the shadow DOM). After 1 swipe/scroll it will look like this: 71 | 72 | | "previous" | "current" | "next" | 73 | | :--------: | :-------: | :----: | 74 | | 1 | 2 | 3 | 75 | 76 | Another swipe forward/next would produce: 77 | 78 | | "previous" | "current" | "next" | 79 | | :--------: | :-------: | :----: | 80 | | 2 | 3 | 1 | 81 | 82 | Swiping/scrolling backward would do the reverse, as you'd expect. 83 | 84 | The circular re-ordering allows the user to swipe/scroll "infinitely" in either direction. It is up to the consuming code to listen for the [`next` or `previous` events](#events). For an example of listening to the event and updating the slot contents [take a look at index.html](./index.html#L387). 85 | 86 | ### Methods 87 | 88 | - `goNext()` 89 | - Scrolls to the next slot. 90 | - Example: `document.getElementById("carousel").goNext()` 91 | - `goPrevious()` 92 | - Scrolls to the previous slot. 93 | - Example: `document.getElementById("carousel").goPrevious()` 94 | - `reset()` 95 | - Resets the slot order to the initial order. Slot 1 will be in the "current" position, slot 2 will be in the "next" position, and slot 3 will be in the "previous" position. 96 | - Example: `document.getElementById("carousel").reset()` 97 | 98 | ### Attributes/Properties 99 | 100 | - `vertical` 101 | - Add this attribute to make your carousel scroll vertically instead of horizontally. 102 | - Example: `` 103 | - Set the property in Javascript to imperatively set vertical scrolling 104 | - Example: `carousel.vertical = true` 105 | - NOTE: Dynamically changing this attribute/property will cause a reset of the slot order (it calls the `reset()` method). 106 | - `lock` 107 | - Add this attribute to prevent scrolling. 108 | - Example: `` 109 | - Set the property in Javascript to imperatively disable scrolling 110 | - Example: `carousel.lock = true` 111 | - `currentSlot` 112 | - This property will return the current slot being shown. 113 | - You cannot set this property programmatically nor can you set it as an attribute. 114 | 115 | ### Events 116 | 117 | - `next` 118 | - Raised after the user has scrolled to the next slot 119 | - Raised about 200ms before the user is allowed to scroll again 120 | - `event.detail` contains an `ChangeEventDetail` object of the following shape: 121 | ```ts 122 | export interface ChangeEventDetail { 123 | newCurrent: 1 | 2 | 3; 124 | } 125 | ``` 126 | - `ChangeEventDetail` is an exported type that you can consume if you are writing your code in Typescript. 127 | - Example: `carousel.addEventListener("next", handleCarouselNext())` 128 | - `previous` 129 | - Raised after the user has scrolled to the previous slot 130 | - Raised about 200ms before the user is allowed to scroll again 131 | - `event.detail` contains an `ChangeEventDetail` object of the following shape: 132 | ```ts 133 | export interface ChangeEventDetail { 134 | newCurrent: 1 | 2 | 3; 135 | } 136 | ``` 137 | - `ChangeEventDetail` is an exported type that you can consume if you are writing your code in Typescript. 138 | - Example: `carousel.addEventListener("previous", handleCarouselPrevious())` 139 | 140 | ### Styling 141 | 142 | You can style the infinite-carousel-wc element as you would any regular element, in CSS. You can see [an example in index.html](./index.html#L59). 143 | 144 | ## Contribute 145 | 146 | This project is built with standard HTML/CSS/JS, no frameworks or special web-component compilers here (for maximum simplicity and minimum size). If you want to learn more about writing custom elements see [MDN](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements) or [this web fundamentals page](https://developers.google.com/web/fundamentals/web-components/). 147 | 148 | The source for this web component is contained in [infinite-carousel-wc.js](infinite-carousel-wc.js) and example usage is in [index.html](index.html). To debug/run the example you can just open index.html in a browser. For a hot-reload developer experience try [using live server in vscode](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer). 149 | 150 | You will need the dev dependencies of this project installed to run the post-commit hooks. 151 | 152 | ```bash 153 | npm install 154 | ``` 155 | -------------------------------------------------------------------------------- /demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wes-goulet/infinite-carousel-wc/870af36b467a81630c1c5963ff58345a2b3dbd26/demo.gif -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wes-goulet/infinite-carousel-wc/870af36b467a81630c1c5963ff58345a2b3dbd26/favicon.ico -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | infinite-carousel-wc - An infinite carousel Web Component built with 11 | modern CSS and just a little Javascript 12 | 13 | 14 | 15 | 16 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 250 | 251 | 252 | 253 |
254 |
255 |

infinite-carousel-wc

256 |

257 | An infinite carousel Web Component built with modern CSS and just a 258 | little Javascript 259 |

260 |
261 | 262 |
263 |
264 |
265 |
266 | 267 | 268 |
269 | 270 | 275 | 276 |
277 | 278 |
279 |

280 | This small, simple web component has no dependencies and can be 281 | consumed by vanilla JS or any front-end framework. It is implemented 282 | using modern CSS and Javascript standards for maximum performance. 283 |

284 | 346 |
347 | 348 |
349 | 350 | 369 | 370 |
371 |
372 | 373 | 451 | 452 | 453 | -------------------------------------------------------------------------------- /infinite-carousel-wc.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | /** 4 | * @typedef {1 | 2 | 3} SlotId 5 | * @typedef {{ newCurrent: SlotId }} ChangeEventDetail 6 | */ 7 | 8 | const style = ` 9 | #s { 10 | height: inherit; 11 | width: inherit; 12 | display: flex; 13 | -webkit-overflow-scrolling: touch; 14 | -ms-overflow-style: none; 15 | overflow: -moz-scrollbars-none; 16 | } 17 | 18 | #s::-webkit-scrollbar { 19 | display: none; 20 | } 21 | 22 | :host(:not([vertical])) #s { 23 | flex-direction: row; 24 | scroll-snap-coordinate: 0 0; 25 | scroll-snap-points-x: repeat(100%); 26 | scroll-snap-type: x mandatory; 27 | overflow-x: auto; 28 | } 29 | 30 | :host([vertical]) #s { 31 | flex-direction: column; 32 | scroll-snap-coordinate: 0 0; 33 | scroll-snap-points-y: repeat(100%); 34 | scroll-snap-type: y mandatory; 35 | overflow-y: auto; 36 | } 37 | 38 | #s > div { 39 | width: 100%; 40 | height: 100%; 41 | flex: none; 42 | scroll-snap-align: start; 43 | scroll-snap-stop: always; 44 | } 45 | 46 | :host([lock]:not([vertical])) #s { 47 | overflow-x: hidden; 48 | } 49 | 50 | :host([lock][vertical]) #s { 51 | overflow-y: hidden; 52 | } 53 | 54 | ::slotted(*) { 55 | width: 100%; 56 | height: 100%; 57 | } 58 | 59 | .previous { 60 | order: 1; 61 | } 62 | 63 | .current { 64 | order: 2; 65 | } 66 | 67 | .next { 68 | order: 3; 69 | } 70 | 71 | .no-scroll { 72 | overflow-x: hidden !important; 73 | overflow-y: hidden !important; 74 | } 75 | `; 76 | 77 | const template = ` 78 |
79 |
80 |
81 |
82 |
83 | `; 84 | 85 | const DEBOUNCE_TIMEOUT = 200; 86 | 87 | // using a template so it only needs to be parsed once, whereas setting 88 | // innerHTML directly in the custom element ctor means the HTML would get parsed 89 | // for every custom element on the page 90 | const templateElement = document.createElement("template"); 91 | templateElement.innerHTML = `${template}`; 92 | 93 | export class InfiniteCarouselWc extends HTMLElement { 94 | constructor() { 95 | super(); 96 | 97 | this.setSlotOrder.bind(this); 98 | this.upgradeProperty.bind(this); 99 | this.raiseNextEvent.bind(this); 100 | this.raisePreviousEvent.bind(this); 101 | this.goNext.bind(this); 102 | this.goPrevious.bind(this); 103 | this.reset.bind(this); 104 | 105 | const shadowRoot = this.attachShadow({ mode: "open" }); 106 | shadowRoot.appendChild(templateElement.content.cloneNode(true)); 107 | 108 | this._scrollContainer = this.shadowRoot.getElementById("s"); 109 | this._slot1 = this.shadowRoot.getElementById("1"); 110 | this._slot2 = this.shadowRoot.getElementById("2"); 111 | this._slot3 = this.shadowRoot.getElementById("3"); 112 | 113 | // slot 2 starts in the middle, although our intersection observer will 114 | // immediately set slot 1 to current... but we want to init this to 2 115 | /** @type {1 | 2 | 3 | undefined}} */ 116 | this._current = undefined; 117 | 118 | /** @type {IntersectionObserver} */ 119 | this._observer = new IntersectionObserver( 120 | (entries, _observer) => { 121 | for (let i = 0, len = entries.length; i < len; i++) { 122 | const entry = entries[i]; 123 | if (entry.intersectionRatio === 1) { 124 | const newCurrent = /** @type {1 | 2 | 3} */ (Number( 125 | entry.target.getAttribute("id") 126 | )); 127 | if (newCurrent !== this._current) { 128 | const oldCurrent = this._current; 129 | this._current = newCurrent; 130 | this.setSlotOrder(oldCurrent, this._current); 131 | break; 132 | } 133 | } 134 | } 135 | }, 136 | { root: this._scrollContainer, threshold: 1.0 } 137 | ); 138 | } 139 | 140 | connectedCallback() { 141 | this._observer.observe(this._slot1); 142 | this._observer.observe(this._slot2); 143 | this._observer.observe(this._slot3); 144 | 145 | this.upgradeProperty("lock"); 146 | this.upgradeProperty("vertical"); 147 | } 148 | 149 | disconnectedCallback() { 150 | this._observer.disconnect(); 151 | } 152 | 153 | /** 154 | * Goes to the next slot in the carousel. 155 | * 156 | * @memberof InfiniteCarouselWc 157 | */ 158 | goNext() { 159 | if (!this._lockScroll && !this.lock) { 160 | this._scrollContainer.scrollBy({ 161 | left: this.vertical ? undefined : this._scrollContainer.clientWidth, 162 | top: this.vertical ? this._scrollContainer.clientHeight : undefined, 163 | behavior: "smooth", 164 | }); 165 | } 166 | } 167 | 168 | /** 169 | * Goes to the previous slot in the carousel. 170 | * 171 | * @memberof InfiniteCarouselWc 172 | */ 173 | goPrevious() { 174 | if (!this._lockScroll && !this.lock) { 175 | this._scrollContainer.scrollBy({ 176 | left: this.vertical 177 | ? undefined 178 | : this._scrollContainer.clientWidth * -1, 179 | top: this.vertical 180 | ? this._scrollContainer.clientHeight * -1 181 | : undefined, 182 | behavior: "smooth", 183 | }); 184 | } 185 | } 186 | 187 | /** 188 | * Resets the slot order so that slot 1 is in the "current" position, slot 2 189 | * is in the "next" position, and slot 3 is in the "previous" position. 190 | * 191 | * @memberof InfiniteCarouselWc 192 | */ 193 | reset() { 194 | this._current = 1; 195 | this.setSlotOrder(2, 1); 196 | } 197 | 198 | // from https://developers.google.com/web/fundamentals/web-components/best-practices#lazy-properties 199 | /** 200 | * @param {string} prop 201 | * 202 | * @memberOf InfiniteCarouselWc 203 | */ 204 | upgradeProperty(prop) { 205 | if (this.hasOwnProperty(prop)) { 206 | let value = this[prop]; 207 | delete this[prop]; 208 | this[prop] = value; 209 | } 210 | } 211 | 212 | get currentSlot() { 213 | if (this._current === undefined) { 214 | return 1; 215 | } 216 | 217 | return this._current; 218 | } 219 | 220 | get lock() { 221 | return this.hasAttribute("lock"); 222 | } 223 | 224 | set lock(isLocked) { 225 | if (isLocked) { 226 | this.setAttribute("lock", ""); 227 | } else { 228 | this.removeAttribute("lock"); 229 | } 230 | } 231 | 232 | get vertical() { 233 | return this.hasAttribute("vertical"); 234 | } 235 | 236 | set vertical(isVertical) { 237 | if (isVertical) { 238 | this.setAttribute("vertical", ""); 239 | } else { 240 | this.removeAttribute("vertical"); 241 | } 242 | 243 | // if the vertical attribute changes then reset the slot order to start 244 | // with slot 1 245 | this.reset(); 246 | } 247 | 248 | /** 249 | * @param {ChangeEventDetail} eventDetails 250 | * 251 | * @memberOf InfiniteCarouselWc 252 | */ 253 | raiseNextEvent(eventDetails) { 254 | this.dispatchEvent( 255 | new CustomEvent("next", { 256 | bubbles: true, 257 | detail: eventDetails, 258 | }) 259 | ); 260 | } 261 | 262 | /** 263 | * @param {ChangeEventDetail} eventDetails 264 | * 265 | * @memberOf InfiniteCarouselWc 266 | */ 267 | raisePreviousEvent(eventDetails) { 268 | this.dispatchEvent( 269 | new CustomEvent("previous", { 270 | bubbles: true, 271 | detail: eventDetails, 272 | }) 273 | ); 274 | } 275 | 276 | /** 277 | * @param {SlotId} oldCurrentSlot 278 | * @param {SlotId} newCurrentSlot 279 | * @returns 280 | * 281 | * @memberOf InfiniteCarouselWc 282 | */ 283 | setSlotOrder(oldCurrentSlot, newCurrentSlot) { 284 | if (oldCurrentSlot === newCurrentSlot || this._lockScroll) { 285 | return; 286 | } 287 | 288 | this._lockScroll = true; 289 | 290 | // safari seems to have a bug(?) where it won't programmatically 291 | // scroll within 158 milliseconds after a css scroll snap, so we use 292 | // a timeout... it's not ideal but even without that bug there kind of 293 | // needs to be a debounce timeout to prevent an eager user from 294 | // over-scrolling, which helps give the next->next view time 295 | // to update the slot content. 296 | 297 | const isPrevious = 298 | (oldCurrentSlot === 2 && newCurrentSlot === 1) || 299 | (oldCurrentSlot === 3 && newCurrentSlot === 2) || 300 | (oldCurrentSlot === 1 && newCurrentSlot === 3); 301 | 302 | // disable scrolling while we re-arrange stuff 303 | this._scrollContainer.classList.add("no-scroll"); 304 | 305 | this._observer.unobserve(this._slot1); 306 | this._observer.unobserve(this._slot2); 307 | this._observer.unobserve(this._slot3); 308 | 309 | // emit event 310 | // if (isPrevious) { 311 | // this.raisePreviousEvent({ newCurrent: newCurrentSlot }); 312 | // } else { 313 | // this.raiseNextEvent({ newCurrent: newCurrentSlot }); 314 | // } 315 | 316 | switch (newCurrentSlot) { 317 | case 1: 318 | setTimeout(() => { 319 | // emit event 320 | if (isPrevious) { 321 | this.raisePreviousEvent({ newCurrent: newCurrentSlot }); 322 | } else { 323 | this.raiseNextEvent({ newCurrent: newCurrentSlot }); 324 | } 325 | 326 | this._slot1.classList.remove("previous"); 327 | this._slot1.classList.remove("next"); 328 | this._slot1.classList.add("current"); 329 | this._slot3.classList.add("previous"); 330 | this._slot3.classList.remove("next"); 331 | this._slot3.classList.remove("current"); 332 | this._slot2.classList.remove("previous"); 333 | this._slot2.classList.add("next"); 334 | this._slot2.classList.remove("current"); 335 | 336 | if (this.vertical) { 337 | this._scrollContainer.scrollTop = this._slot3.clientHeight; 338 | } else { 339 | this._scrollContainer.scrollLeft = this._slot3.clientWidth; 340 | } 341 | 342 | // this._observer.observe(this._slot1); 343 | this._observer.observe(this._slot2); 344 | this._observer.observe(this._slot3); 345 | 346 | this._lockScroll = false; 347 | this._scrollContainer.classList.remove("no-scroll"); 348 | }, DEBOUNCE_TIMEOUT); 349 | break; 350 | case 2: 351 | setTimeout(() => { 352 | // emit event 353 | if (isPrevious) { 354 | this.raisePreviousEvent({ newCurrent: newCurrentSlot }); 355 | } else { 356 | this.raiseNextEvent({ newCurrent: newCurrentSlot }); 357 | } 358 | 359 | this._slot1.classList.add("previous"); 360 | this._slot1.classList.remove("next"); 361 | this._slot1.classList.remove("current"); 362 | this._slot3.classList.remove("previous"); 363 | this._slot3.classList.add("next"); 364 | this._slot3.classList.remove("current"); 365 | this._slot2.classList.remove("previous"); 366 | this._slot2.classList.remove("next"); 367 | this._slot2.classList.add("current"); 368 | if (this.vertical) { 369 | this._scrollContainer.scrollTop = this._slot1.clientHeight; 370 | } else { 371 | this._scrollContainer.scrollLeft = this._slot1.clientWidth; 372 | } 373 | 374 | this._observer.observe(this._slot1); 375 | // this._observer.observe(this._slot2); 376 | this._observer.observe(this._slot3); 377 | 378 | this._lockScroll = false; 379 | this._scrollContainer.classList.remove("no-scroll"); 380 | }, DEBOUNCE_TIMEOUT); 381 | break; 382 | case 3: 383 | setTimeout(() => { 384 | // emit event 385 | if (isPrevious) { 386 | this.raisePreviousEvent({ newCurrent: newCurrentSlot }); 387 | } else { 388 | this.raiseNextEvent({ newCurrent: newCurrentSlot }); 389 | } 390 | 391 | this._slot1.classList.remove("previous"); 392 | this._slot1.classList.add("next"); 393 | this._slot1.classList.remove("current"); 394 | this._slot3.classList.remove("previous"); 395 | this._slot3.classList.remove("next"); 396 | this._slot3.classList.add("current"); 397 | this._slot2.classList.add("previous"); 398 | this._slot2.classList.remove("next"); 399 | this._slot2.classList.remove("current"); 400 | if (this.vertical) { 401 | this._scrollContainer.scrollTop = this._slot2.clientHeight; 402 | } else { 403 | this._scrollContainer.scrollLeft = this._slot2.clientWidth; 404 | } 405 | 406 | this._observer.observe(this._slot1); 407 | this._observer.observe(this._slot2); 408 | // this._observer.observe(this._slot3); 409 | 410 | this._lockScroll = false; 411 | this._scrollContainer.classList.remove("no-scroll"); 412 | }, DEBOUNCE_TIMEOUT); 413 | break; 414 | default: 415 | throw `newCurrentSlot has bad value: ${newCurrentSlot}`; 416 | } 417 | } 418 | } 419 | 420 | customElements.define("infinite-carousel-wc", InfiniteCarouselWc); 421 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "infinite-carousel-wc", 3 | "version": "0.5.4", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "acorn": { 8 | "version": "8.7.0", 9 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", 10 | "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", 11 | "dev": true 12 | }, 13 | "ansi-regex": { 14 | "version": "2.1.1", 15 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", 16 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", 17 | "dev": true 18 | }, 19 | "ansi-styles": { 20 | "version": "3.2.1", 21 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 22 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 23 | "dev": true, 24 | "requires": { 25 | "color-convert": "^1.9.0" 26 | } 27 | }, 28 | "aproba": { 29 | "version": "1.2.0", 30 | "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", 31 | "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", 32 | "dev": true 33 | }, 34 | "are-we-there-yet": { 35 | "version": "1.1.7", 36 | "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", 37 | "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", 38 | "dev": true, 39 | "requires": { 40 | "delegates": "^1.0.0", 41 | "readable-stream": "^2.0.6" 42 | } 43 | }, 44 | "argparse": { 45 | "version": "1.0.10", 46 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 47 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 48 | "dev": true, 49 | "requires": { 50 | "sprintf-js": "~1.0.2" 51 | } 52 | }, 53 | "axios": { 54 | "version": "0.21.4", 55 | "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", 56 | "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", 57 | "dev": true, 58 | "requires": { 59 | "follow-redirects": "^1.14.0" 60 | } 61 | }, 62 | "balanced-match": { 63 | "version": "1.0.2", 64 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 65 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 66 | "dev": true 67 | }, 68 | "base64-js": { 69 | "version": "1.5.1", 70 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", 71 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", 72 | "dev": true 73 | }, 74 | "bl": { 75 | "version": "4.1.0", 76 | "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", 77 | "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", 78 | "dev": true, 79 | "requires": { 80 | "buffer": "^5.5.0", 81 | "inherits": "^2.0.4", 82 | "readable-stream": "^3.4.0" 83 | }, 84 | "dependencies": { 85 | "readable-stream": { 86 | "version": "3.6.0", 87 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", 88 | "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", 89 | "dev": true, 90 | "requires": { 91 | "inherits": "^2.0.3", 92 | "string_decoder": "^1.1.1", 93 | "util-deprecate": "^1.0.1" 94 | } 95 | } 96 | } 97 | }, 98 | "brace-expansion": { 99 | "version": "1.1.11", 100 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 101 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 102 | "dev": true, 103 | "requires": { 104 | "balanced-match": "^1.0.0", 105 | "concat-map": "0.0.1" 106 | } 107 | }, 108 | "brotli-size": { 109 | "version": "0.1.0", 110 | "resolved": "https://registry.npmjs.org/brotli-size/-/brotli-size-0.1.0.tgz", 111 | "integrity": "sha512-5ny7BNvpe2TSmdafF1T9dnFYp3AIrJ8qJt29K0DQJzORlK38LBim/CmlY26JtreV6SWmXza7Oa+9m61SzvxR0Q==", 112 | "dev": true, 113 | "requires": { 114 | "duplexer": "^0.1.1", 115 | "iltorb": "^2.4.3" 116 | } 117 | }, 118 | "buffer": { 119 | "version": "5.7.1", 120 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", 121 | "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", 122 | "dev": true, 123 | "requires": { 124 | "base64-js": "^1.3.1", 125 | "ieee754": "^1.1.13" 126 | } 127 | }, 128 | "buffer-from": { 129 | "version": "1.1.2", 130 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", 131 | "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", 132 | "dev": true 133 | }, 134 | "bundlesize": { 135 | "version": "0.18.1", 136 | "resolved": "https://registry.npmjs.org/bundlesize/-/bundlesize-0.18.1.tgz", 137 | "integrity": "sha512-NAsKBH6BeVmDopoa4tod0m5/koM7iLY3saKyGn7wyAravBYmKNUpDJba4zyVhwRm5Dw9WXv8FIO0N//tCkx68Q==", 138 | "dev": true, 139 | "requires": { 140 | "axios": "^0.21.1", 141 | "brotli-size": "0.1.0", 142 | "bytes": "^3.1.0", 143 | "ci-env": "^1.4.0", 144 | "commander": "^2.20.0", 145 | "cosmiconfig": "^5.2.1", 146 | "github-build": "^1.2.2", 147 | "glob": "^7.1.4", 148 | "gzip-size": "^4.0.0", 149 | "prettycli": "^1.4.3" 150 | } 151 | }, 152 | "bytes": { 153 | "version": "3.1.2", 154 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", 155 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", 156 | "dev": true 157 | }, 158 | "caller-callsite": { 159 | "version": "2.0.0", 160 | "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", 161 | "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", 162 | "dev": true, 163 | "requires": { 164 | "callsites": "^2.0.0" 165 | } 166 | }, 167 | "caller-path": { 168 | "version": "2.0.0", 169 | "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", 170 | "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", 171 | "dev": true, 172 | "requires": { 173 | "caller-callsite": "^2.0.0" 174 | } 175 | }, 176 | "callsites": { 177 | "version": "2.0.0", 178 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", 179 | "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", 180 | "dev": true 181 | }, 182 | "chalk": { 183 | "version": "2.1.0", 184 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", 185 | "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", 186 | "dev": true, 187 | "requires": { 188 | "ansi-styles": "^3.1.0", 189 | "escape-string-regexp": "^1.0.5", 190 | "supports-color": "^4.0.0" 191 | } 192 | }, 193 | "chownr": { 194 | "version": "1.1.4", 195 | "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", 196 | "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", 197 | "dev": true 198 | }, 199 | "ci-env": { 200 | "version": "1.17.0", 201 | "resolved": "https://registry.npmjs.org/ci-env/-/ci-env-1.17.0.tgz", 202 | "integrity": "sha512-NtTjhgSEqv4Aj90TUYHQLxHdnCPXnjdtuGG1X8lTfp/JqeXTdw0FTWl/vUAPuvbWZTF8QVpv6ASe/XacE+7R2A==", 203 | "dev": true 204 | }, 205 | "code-point-at": { 206 | "version": "1.1.0", 207 | "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", 208 | "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", 209 | "dev": true 210 | }, 211 | "color-convert": { 212 | "version": "1.9.3", 213 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 214 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 215 | "dev": true, 216 | "requires": { 217 | "color-name": "1.1.3" 218 | } 219 | }, 220 | "color-name": { 221 | "version": "1.1.3", 222 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 223 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", 224 | "dev": true 225 | }, 226 | "commander": { 227 | "version": "2.20.3", 228 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", 229 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", 230 | "dev": true 231 | }, 232 | "concat-map": { 233 | "version": "0.0.1", 234 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 235 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 236 | "dev": true 237 | }, 238 | "console-control-strings": { 239 | "version": "1.1.0", 240 | "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", 241 | "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", 242 | "dev": true 243 | }, 244 | "core-util-is": { 245 | "version": "1.0.3", 246 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", 247 | "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", 248 | "dev": true 249 | }, 250 | "cosmiconfig": { 251 | "version": "5.2.1", 252 | "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", 253 | "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", 254 | "dev": true, 255 | "requires": { 256 | "import-fresh": "^2.0.0", 257 | "is-directory": "^0.3.1", 258 | "js-yaml": "^3.13.1", 259 | "parse-json": "^4.0.0" 260 | } 261 | }, 262 | "decompress-response": { 263 | "version": "4.2.1", 264 | "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", 265 | "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", 266 | "dev": true, 267 | "requires": { 268 | "mimic-response": "^2.0.0" 269 | } 270 | }, 271 | "deep-extend": { 272 | "version": "0.6.0", 273 | "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", 274 | "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", 275 | "dev": true 276 | }, 277 | "delegates": { 278 | "version": "1.0.0", 279 | "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", 280 | "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", 281 | "dev": true 282 | }, 283 | "detect-libc": { 284 | "version": "1.0.3", 285 | "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", 286 | "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", 287 | "dev": true 288 | }, 289 | "duplexer": { 290 | "version": "0.1.2", 291 | "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", 292 | "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", 293 | "dev": true 294 | }, 295 | "end-of-stream": { 296 | "version": "1.4.4", 297 | "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", 298 | "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", 299 | "dev": true, 300 | "requires": { 301 | "once": "^1.4.0" 302 | } 303 | }, 304 | "error-ex": { 305 | "version": "1.3.2", 306 | "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", 307 | "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", 308 | "dev": true, 309 | "requires": { 310 | "is-arrayish": "^0.2.1" 311 | } 312 | }, 313 | "escape-string-regexp": { 314 | "version": "1.0.5", 315 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 316 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 317 | "dev": true 318 | }, 319 | "esprima": { 320 | "version": "4.0.1", 321 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 322 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", 323 | "dev": true 324 | }, 325 | "expand-template": { 326 | "version": "2.0.3", 327 | "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", 328 | "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", 329 | "dev": true 330 | }, 331 | "follow-redirects": { 332 | "version": "1.14.9", 333 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", 334 | "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==", 335 | "dev": true 336 | }, 337 | "fs-constants": { 338 | "version": "1.0.0", 339 | "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", 340 | "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", 341 | "dev": true 342 | }, 343 | "fs.realpath": { 344 | "version": "1.0.0", 345 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 346 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 347 | "dev": true 348 | }, 349 | "gauge": { 350 | "version": "2.7.4", 351 | "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", 352 | "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", 353 | "dev": true, 354 | "requires": { 355 | "aproba": "^1.0.3", 356 | "console-control-strings": "^1.0.0", 357 | "has-unicode": "^2.0.0", 358 | "object-assign": "^4.1.0", 359 | "signal-exit": "^3.0.0", 360 | "string-width": "^1.0.1", 361 | "strip-ansi": "^3.0.1", 362 | "wide-align": "^1.1.0" 363 | } 364 | }, 365 | "github-build": { 366 | "version": "1.2.3", 367 | "resolved": "https://registry.npmjs.org/github-build/-/github-build-1.2.3.tgz", 368 | "integrity": "sha512-57zUA9ZbaKQHxoUATq3dkr+gUeaOWGGC/3Vw/AJNIUkiUmd7DnYM9TMTmUknbkuvx6+SeSqWpLBunZZzCPLUMg==", 369 | "dev": true, 370 | "requires": { 371 | "axios": "0.21.3" 372 | }, 373 | "dependencies": { 374 | "axios": { 375 | "version": "0.21.3", 376 | "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.3.tgz", 377 | "integrity": "sha512-JtoZ3Ndke/+Iwt5n+BgSli/3idTvpt5OjKyoCmz4LX5+lPiY5l7C1colYezhlxThjNa/NhngCUWZSZFypIFuaA==", 378 | "dev": true, 379 | "requires": { 380 | "follow-redirects": "^1.14.0" 381 | } 382 | } 383 | } 384 | }, 385 | "github-from-package": { 386 | "version": "0.0.0", 387 | "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", 388 | "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=", 389 | "dev": true 390 | }, 391 | "glob": { 392 | "version": "7.2.0", 393 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", 394 | "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", 395 | "dev": true, 396 | "requires": { 397 | "fs.realpath": "^1.0.0", 398 | "inflight": "^1.0.4", 399 | "inherits": "2", 400 | "minimatch": "^3.0.4", 401 | "once": "^1.3.0", 402 | "path-is-absolute": "^1.0.0" 403 | } 404 | }, 405 | "gzip-size": { 406 | "version": "4.1.0", 407 | "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-4.1.0.tgz", 408 | "integrity": "sha1-iuCWJX6r59acRb4rZ8RIEk/7UXw=", 409 | "dev": true, 410 | "requires": { 411 | "duplexer": "^0.1.1", 412 | "pify": "^3.0.0" 413 | } 414 | }, 415 | "has-flag": { 416 | "version": "2.0.0", 417 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", 418 | "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", 419 | "dev": true 420 | }, 421 | "has-unicode": { 422 | "version": "2.0.1", 423 | "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", 424 | "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", 425 | "dev": true 426 | }, 427 | "ieee754": { 428 | "version": "1.2.1", 429 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", 430 | "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", 431 | "dev": true 432 | }, 433 | "iltorb": { 434 | "version": "2.4.5", 435 | "resolved": "https://registry.npmjs.org/iltorb/-/iltorb-2.4.5.tgz", 436 | "integrity": "sha512-EMCMl3LnnNSZJS5QrxyZmMTaAC4+TJkM5woD+xbpm9RB+mFYCr7C05GFE3TEGCsVQSVHmjX+3sf5AiwsylNInQ==", 437 | "dev": true, 438 | "requires": { 439 | "detect-libc": "^1.0.3", 440 | "nan": "^2.14.0", 441 | "npmlog": "^4.1.2", 442 | "prebuild-install": "^5.3.3", 443 | "which-pm-runs": "^1.0.0" 444 | } 445 | }, 446 | "import-fresh": { 447 | "version": "2.0.0", 448 | "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", 449 | "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", 450 | "dev": true, 451 | "requires": { 452 | "caller-path": "^2.0.0", 453 | "resolve-from": "^3.0.0" 454 | } 455 | }, 456 | "inflight": { 457 | "version": "1.0.6", 458 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 459 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 460 | "dev": true, 461 | "requires": { 462 | "once": "^1.3.0", 463 | "wrappy": "1" 464 | } 465 | }, 466 | "inherits": { 467 | "version": "2.0.4", 468 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 469 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 470 | "dev": true 471 | }, 472 | "ini": { 473 | "version": "1.3.8", 474 | "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", 475 | "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", 476 | "dev": true 477 | }, 478 | "is-arrayish": { 479 | "version": "0.2.1", 480 | "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", 481 | "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", 482 | "dev": true 483 | }, 484 | "is-directory": { 485 | "version": "0.3.1", 486 | "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", 487 | "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", 488 | "dev": true 489 | }, 490 | "is-fullwidth-code-point": { 491 | "version": "1.0.0", 492 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", 493 | "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", 494 | "dev": true, 495 | "requires": { 496 | "number-is-nan": "^1.0.0" 497 | } 498 | }, 499 | "isarray": { 500 | "version": "1.0.0", 501 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 502 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", 503 | "dev": true 504 | }, 505 | "js-yaml": { 506 | "version": "3.14.1", 507 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", 508 | "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", 509 | "dev": true, 510 | "requires": { 511 | "argparse": "^1.0.7", 512 | "esprima": "^4.0.0" 513 | } 514 | }, 515 | "json-parse-better-errors": { 516 | "version": "1.0.2", 517 | "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", 518 | "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", 519 | "dev": true 520 | }, 521 | "mimic-response": { 522 | "version": "2.1.0", 523 | "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", 524 | "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", 525 | "dev": true 526 | }, 527 | "minimatch": { 528 | "version": "3.1.2", 529 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 530 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 531 | "dev": true, 532 | "requires": { 533 | "brace-expansion": "^1.1.7" 534 | } 535 | }, 536 | "minimist": { 537 | "version": "1.2.6", 538 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", 539 | "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", 540 | "dev": true 541 | }, 542 | "mkdirp-classic": { 543 | "version": "0.5.3", 544 | "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", 545 | "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", 546 | "dev": true 547 | }, 548 | "nan": { 549 | "version": "2.15.0", 550 | "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", 551 | "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==", 552 | "dev": true 553 | }, 554 | "napi-build-utils": { 555 | "version": "1.0.2", 556 | "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", 557 | "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", 558 | "dev": true 559 | }, 560 | "node-abi": { 561 | "version": "2.30.1", 562 | "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.30.1.tgz", 563 | "integrity": "sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w==", 564 | "dev": true, 565 | "requires": { 566 | "semver": "^5.4.1" 567 | } 568 | }, 569 | "noop-logger": { 570 | "version": "0.1.1", 571 | "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz", 572 | "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=", 573 | "dev": true 574 | }, 575 | "npmlog": { 576 | "version": "4.1.2", 577 | "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", 578 | "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", 579 | "dev": true, 580 | "requires": { 581 | "are-we-there-yet": "~1.1.2", 582 | "console-control-strings": "~1.1.0", 583 | "gauge": "~2.7.3", 584 | "set-blocking": "~2.0.0" 585 | } 586 | }, 587 | "number-is-nan": { 588 | "version": "1.0.1", 589 | "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", 590 | "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", 591 | "dev": true 592 | }, 593 | "object-assign": { 594 | "version": "4.1.1", 595 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 596 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", 597 | "dev": true 598 | }, 599 | "once": { 600 | "version": "1.4.0", 601 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 602 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 603 | "dev": true, 604 | "requires": { 605 | "wrappy": "1" 606 | } 607 | }, 608 | "parse-json": { 609 | "version": "4.0.0", 610 | "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", 611 | "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", 612 | "dev": true, 613 | "requires": { 614 | "error-ex": "^1.3.1", 615 | "json-parse-better-errors": "^1.0.1" 616 | } 617 | }, 618 | "path-is-absolute": { 619 | "version": "1.0.1", 620 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 621 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 622 | "dev": true 623 | }, 624 | "pify": { 625 | "version": "3.0.0", 626 | "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", 627 | "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", 628 | "dev": true 629 | }, 630 | "prebuild-install": { 631 | "version": "5.3.6", 632 | "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.6.tgz", 633 | "integrity": "sha512-s8Aai8++QQGi4sSbs/M1Qku62PFK49Jm1CbgXklGz4nmHveDq0wzJkg7Na5QbnO1uNH8K7iqx2EQ/mV0MZEmOg==", 634 | "dev": true, 635 | "requires": { 636 | "detect-libc": "^1.0.3", 637 | "expand-template": "^2.0.3", 638 | "github-from-package": "0.0.0", 639 | "minimist": "^1.2.3", 640 | "mkdirp-classic": "^0.5.3", 641 | "napi-build-utils": "^1.0.1", 642 | "node-abi": "^2.7.0", 643 | "noop-logger": "^0.1.1", 644 | "npmlog": "^4.0.1", 645 | "pump": "^3.0.0", 646 | "rc": "^1.2.7", 647 | "simple-get": "^3.0.3", 648 | "tar-fs": "^2.0.0", 649 | "tunnel-agent": "^0.6.0", 650 | "which-pm-runs": "^1.0.0" 651 | } 652 | }, 653 | "prettier": { 654 | "version": "2.1.2", 655 | "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.1.2.tgz", 656 | "integrity": "sha512-16c7K+x4qVlJg9rEbXl7HEGmQyZlG4R9AgP+oHKRMsMsuk8s+ATStlf1NpDqyBI1HpVyfjLOeMhH2LvuNvV5Vg==", 657 | "dev": true 658 | }, 659 | "prettycli": { 660 | "version": "1.4.3", 661 | "resolved": "https://registry.npmjs.org/prettycli/-/prettycli-1.4.3.tgz", 662 | "integrity": "sha512-KLiwAXXfSWXZqGmZlnKPuGMTFp+0QbcySplL1ft9gfteT/BNsG64Xo8u2Qr9r+qnsIZWBQ66Zs8tg+8s2fmzvw==", 663 | "dev": true, 664 | "requires": { 665 | "chalk": "2.1.0" 666 | } 667 | }, 668 | "process-nextick-args": { 669 | "version": "2.0.1", 670 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", 671 | "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", 672 | "dev": true 673 | }, 674 | "pump": { 675 | "version": "3.0.0", 676 | "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", 677 | "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", 678 | "dev": true, 679 | "requires": { 680 | "end-of-stream": "^1.1.0", 681 | "once": "^1.3.1" 682 | } 683 | }, 684 | "rc": { 685 | "version": "1.2.8", 686 | "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", 687 | "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", 688 | "dev": true, 689 | "requires": { 690 | "deep-extend": "^0.6.0", 691 | "ini": "~1.3.0", 692 | "minimist": "^1.2.0", 693 | "strip-json-comments": "~2.0.1" 694 | } 695 | }, 696 | "readable-stream": { 697 | "version": "2.3.7", 698 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", 699 | "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", 700 | "dev": true, 701 | "requires": { 702 | "core-util-is": "~1.0.0", 703 | "inherits": "~2.0.3", 704 | "isarray": "~1.0.0", 705 | "process-nextick-args": "~2.0.0", 706 | "safe-buffer": "~5.1.1", 707 | "string_decoder": "~1.1.1", 708 | "util-deprecate": "~1.0.1" 709 | } 710 | }, 711 | "resolve-from": { 712 | "version": "3.0.0", 713 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", 714 | "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", 715 | "dev": true 716 | }, 717 | "safe-buffer": { 718 | "version": "5.1.2", 719 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 720 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", 721 | "dev": true 722 | }, 723 | "semver": { 724 | "version": "5.7.1", 725 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", 726 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", 727 | "dev": true 728 | }, 729 | "set-blocking": { 730 | "version": "2.0.0", 731 | "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", 732 | "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", 733 | "dev": true 734 | }, 735 | "signal-exit": { 736 | "version": "3.0.7", 737 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", 738 | "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", 739 | "dev": true 740 | }, 741 | "simple-concat": { 742 | "version": "1.0.1", 743 | "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", 744 | "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", 745 | "dev": true 746 | }, 747 | "simple-get": { 748 | "version": "3.1.1", 749 | "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", 750 | "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", 751 | "dev": true, 752 | "requires": { 753 | "decompress-response": "^4.2.0", 754 | "once": "^1.3.1", 755 | "simple-concat": "^1.0.0" 756 | } 757 | }, 758 | "source-map": { 759 | "version": "0.7.3", 760 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", 761 | "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", 762 | "dev": true 763 | }, 764 | "source-map-support": { 765 | "version": "0.5.21", 766 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", 767 | "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", 768 | "dev": true, 769 | "requires": { 770 | "buffer-from": "^1.0.0", 771 | "source-map": "^0.6.0" 772 | }, 773 | "dependencies": { 774 | "source-map": { 775 | "version": "0.6.1", 776 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 777 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 778 | "dev": true 779 | } 780 | } 781 | }, 782 | "sprintf-js": { 783 | "version": "1.0.3", 784 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 785 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 786 | "dev": true 787 | }, 788 | "string-width": { 789 | "version": "1.0.2", 790 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", 791 | "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", 792 | "dev": true, 793 | "requires": { 794 | "code-point-at": "^1.0.0", 795 | "is-fullwidth-code-point": "^1.0.0", 796 | "strip-ansi": "^3.0.0" 797 | } 798 | }, 799 | "string_decoder": { 800 | "version": "1.1.1", 801 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 802 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 803 | "dev": true, 804 | "requires": { 805 | "safe-buffer": "~5.1.0" 806 | } 807 | }, 808 | "strip-ansi": { 809 | "version": "3.0.1", 810 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", 811 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", 812 | "dev": true, 813 | "requires": { 814 | "ansi-regex": "^2.0.0" 815 | } 816 | }, 817 | "strip-json-comments": { 818 | "version": "2.0.1", 819 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 820 | "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", 821 | "dev": true 822 | }, 823 | "supports-color": { 824 | "version": "4.5.0", 825 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", 826 | "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", 827 | "dev": true, 828 | "requires": { 829 | "has-flag": "^2.0.0" 830 | } 831 | }, 832 | "tar-fs": { 833 | "version": "2.1.1", 834 | "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", 835 | "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", 836 | "dev": true, 837 | "requires": { 838 | "chownr": "^1.1.1", 839 | "mkdirp-classic": "^0.5.2", 840 | "pump": "^3.0.0", 841 | "tar-stream": "^2.1.4" 842 | } 843 | }, 844 | "tar-stream": { 845 | "version": "2.2.0", 846 | "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", 847 | "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", 848 | "dev": true, 849 | "requires": { 850 | "bl": "^4.0.3", 851 | "end-of-stream": "^1.4.1", 852 | "fs-constants": "^1.0.0", 853 | "inherits": "^2.0.3", 854 | "readable-stream": "^3.1.1" 855 | }, 856 | "dependencies": { 857 | "readable-stream": { 858 | "version": "3.6.0", 859 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", 860 | "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", 861 | "dev": true, 862 | "requires": { 863 | "inherits": "^2.0.3", 864 | "string_decoder": "^1.1.1", 865 | "util-deprecate": "^1.0.1" 866 | } 867 | } 868 | } 869 | }, 870 | "terser": { 871 | "version": "5.12.1", 872 | "resolved": "https://registry.npmjs.org/terser/-/terser-5.12.1.tgz", 873 | "integrity": "sha512-NXbs+7nisos5E+yXwAD+y7zrcTkMqb0dEJxIGtSKPdCBzopf7ni4odPul2aechpV7EXNvOudYOX2bb5tln1jbQ==", 874 | "dev": true, 875 | "requires": { 876 | "acorn": "^8.5.0", 877 | "commander": "^2.20.0", 878 | "source-map": "~0.7.2", 879 | "source-map-support": "~0.5.20" 880 | } 881 | }, 882 | "tunnel-agent": { 883 | "version": "0.6.0", 884 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", 885 | "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", 886 | "dev": true, 887 | "requires": { 888 | "safe-buffer": "^5.0.1" 889 | } 890 | }, 891 | "typescript": { 892 | "version": "4.6.3", 893 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.3.tgz", 894 | "integrity": "sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==", 895 | "dev": true 896 | }, 897 | "util-deprecate": { 898 | "version": "1.0.2", 899 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 900 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", 901 | "dev": true 902 | }, 903 | "which-pm-runs": { 904 | "version": "1.1.0", 905 | "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz", 906 | "integrity": "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==", 907 | "dev": true 908 | }, 909 | "wide-align": { 910 | "version": "1.1.5", 911 | "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", 912 | "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", 913 | "dev": true, 914 | "requires": { 915 | "string-width": "^1.0.2 || 2 || 3 || 4" 916 | } 917 | }, 918 | "wrappy": { 919 | "version": "1.0.2", 920 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 921 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 922 | "dev": true 923 | } 924 | } 925 | } 926 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "infinite-carousel-wc", 3 | "version": "0.5.4", 4 | "description": "A small, infinite carousel Web Component built with modern CSS and just a little Javascript", 5 | "keywords": [ 6 | "web component", 7 | "carousel", 8 | "slider", 9 | "infinite", 10 | "infinite-carousel", 11 | "slideshow", 12 | "web-component", 13 | "custom-element" 14 | ], 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/wes566/infinite-carousel-wc" 18 | }, 19 | "author": "wes@goulet.dev", 20 | "license": "MIT", 21 | "bugs": { 22 | "url": "https://github.com/wes566/infinite-carousel-wc" 23 | }, 24 | "homepage": "https://github.com/wes566/infinite-carousel-wc", 25 | "module": "infinite-carousel-wc.js", 26 | "main": "infinite-carousel-wc.js", 27 | "source": "infinite-carousel-wc.js", 28 | "types": "infinite-carousel-wc.d.ts", 29 | "scripts": { 30 | "prepare": "npm run build", 31 | "build": "tsc && npm run minify", 32 | "minify": "terser infinite-carousel-wc.js -o infinite-carousel-wc.min.js -c -m", 33 | "lint": "npm run lint:formatting && npm run lint:size", 34 | "lint:formatting": "prettier --check .", 35 | "lint:size": "bundlesize", 36 | "fix:formatting": "prettier --write ." 37 | }, 38 | "devDependencies": { 39 | "bundlesize": "^0.18.0", 40 | "prettier": "^2.1.2", 41 | "terser": "^5.3.5", 42 | "typescript": "^4.0.3" 43 | }, 44 | "files": [ 45 | "infinite-carousel-wc.js", 46 | "infinite-carousel-wc.min.js", 47 | "infinite-carousel-wc.d.ts" 48 | ], 49 | "exports": { 50 | ".": { 51 | "import": "./infinite-carousel-wc.js", 52 | "default": "./infinite-carousel-wc.js" 53 | } 54 | }, 55 | "bundlesize": [ 56 | { 57 | "path": "./infinite-carousel-wc.min.js", 58 | "maxSize": "2 KB" 59 | } 60 | ] 61 | } 62 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "es6", 4 | "target": "es2015", 5 | "allowJs": true, 6 | "checkJs": true, 7 | "emitDeclarationOnly": true, 8 | "declaration": true 9 | }, 10 | "files": ["infinite-carousel-wc.js"] 11 | } 12 | --------------------------------------------------------------------------------