@localnerve/jump-scroll 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,14 +1,18 @@
1
1
  # jump-scroll
2
2
  [![npm version](https://badge.fury.io/js/%40localnerve%2Fjump-scroll.svg)](http://badge.fury.io/js/%40localnerve%2Fjump-scroll)
3
3
 
4
- > A small, fast, no-dependency, jump scroll component.
4
+ > A small, fast, no-dependency, jump scroll webcomponent.
5
5
 
6
6
  ## Live example
7
7
  https://localnerve.github.io/ui-elements/dist/jump-scroll/
8
8
 
9
+ ## Summary
10
+
11
+ Provides a small scrolling control that allows the user to go to the top or bottom, or jump to the next (or previous) section of a page.
12
+
9
13
  ## Attributes
10
14
 
11
- * target - A selector that selects all the elements to vertically jump scroll to in the page. Defaults to 'section'.
15
+ * target - A selector to select all the elements to vertically "jump scroll" to in the page. Defaults to 'section'.
12
16
  * display - "both" | "best"
13
17
  * `both` - Default. The control displays both [top, previous] AND [bottom, next] jump scrolling options simulataneously.
14
18
  * `best` - The control displays either [top, previous] OR [bottom, next] jump scrolling options. Which one is displayed depends on the position on the page and the direction of scrolling. If the user is in the middle of the page and scrolls, the control only displays the jump scroll options in the direction of the scroll. Less vertical space required.
package/dist/index.js CHANGED
@@ -1 +1,23 @@
1
- /*! jump-scroll, Copyright (c) 2023 Alex Grant (@localnerve), LocalNerve LLC, BSD-3-Clause */(()=>{"use strict";var t={d:(e,n)=>{for(var s in n)t.o(n,s)&&!t.o(e,s)&&Object.defineProperty(e,s,{enumerable:!0,get:n[s]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}},e={};t.r(e),t.d(e,{JumpScroll:()=>s,JumpScrollCss:()=>n});const n="\n :host {\n --js-width: 2em;\n --js-height: 8em;\n --js-bg-color: black;\n --js-color: white;\n --js-opacity-full: 0.7;\n --js-opacity-rest: 0.3;\n\n position: fixed;\n bottom: 1rem;\n right: 0.8rem;\n width: var(--js-width);\n height: var(--js-height);\n color: var(--js-color);\n }\n\n .container {\n display: block;\n transition: opacity 1s;\n opacity: var(--js-opacity-full);\n }\n .container.none {\n display: none;\n }\n .container.rest {\n opacity: var(--js-opacity-rest);\n }\n .container.mid {\n transform: none;\n }\n .container.best.mid.down .top,\n .container.start .top {\n pointer-events: none;\n opacity: 0;\n }\n .container.best.mid.up .bot,\n .container.end .bot {\n pointer-events: none;\n opacity: 0;\n transform: translateY(102%);\n }\n .container.best.mid.down .top,\n .container.best.mid.up .top,\n .container.end .top {\n transform: translateY(102%);\n }\n\n .top,\n .bot {\n position: absolute;\n width: 100%;\n height: calc(var(--js-height) / 2);\n transition: opacity 1s, transform 1s;\n pointer-events: auto;\n }\n .top {\n top: 0;\n }\n .bot {\n bottom: 0;\n }\n\n .top .start,\n .top .prev,\n .bot .next,\n .bot .end {\n content: '';\n position: absolute;\n left: 50%;\n width: 100%;\n background: var(--js-bg-color);\n }\n .top .start,\n .bot .end {\n height: calc(var(--js-height) / 6);\n clip-path: polygon(15% 5%, 85% 5%, 85% 30%, 60% 30%, 85% 95%, 15% 95%, 40% 30%, 15% 30%);\n }\n .top .prev,\n .bot .next {\n height: calc(var(--js-height) / 4);\n clip-path: polygon(50% 5%, 85% 60%, 60% 60%, 85% 95%, 15% 95%, 40% 60%, 15% 60%);\n }\n .top .start,\n .top .prev {\n transform: translateX(-50%);\n }\n .bot .next,\n .bot .end {\n transform: translateX(-50%) rotateX(180deg);\n }\n .top .start {\n top: 0;\n }\n .top .prev {\n top: calc((var(--js-height) / 6) + 10%);\n }\n .bot .next {\n bottom: calc((var(--js-height) / 6) + 10%);\n }\n .bot .end {\n bottom: 0;\n }\n";class s extends HTMLElement{#t=null;#e=null;#n=null;#s=null;#i=null;#r=null;#o=!0;#a=!1;static#c=["target"];static#l={target:"section",display:"both"};static get observedAttributes(){return[...s.#c,"display"]}constructor(){super(),this.attachShadow({mode:"open"}),this.intersectionCallback=this.intersectionCallback.bind(this),this.setup=this.setup.bind(this),this.clickTop=this.clickTop.bind(this),this.clickBottom=this.clickBottom.bind(this),this.clickNext=this.clickNext.bind(this),this.clickPrev=this.clickPrev.bind(this),this.createTargetProperties()}createTargetProperties(){s.#c.forEach((t=>{Object.defineProperty(this,t,{get(){return this.hasAttribute(t)?this.getAttribute(t):s.#l[t]},set(e){e?this.setAttribute(t,e):this.removeAttribute(t),this.updateTargetMap(e)}})}))}get display(){const t="display";return this.hasAttribute(t)?this.getAttribute(t):s.#l[t]}set display(t){const e="display",n=["both","best"],s=this.#r??{classList:{remove:()=>{},add:()=>{}}};s.classList.remove(...n.concat("up","down")),n.includes(t)?(this.setAttribute(e,t),s.classList.add(t)):this.removeAttribute(e)}update(t){const e=[t];"best"===this.display&&"mid"===t&&(this.#o?e.push("down"):e.push("up")),this.#r.classList.remove("mid","start","end","none","rest","up","down"),this.#r.classList.add(...e),setTimeout((()=>{this.#r.classList.add("rest")}),500)}clickTop(){this.#e.scrollIntoView(),this.#s=this.#e,this.update("start")}clickBottom(){this.#n.scrollIntoView(),this.#s=this.#n,this.update("end")}clickNext(){const t=this.#i.get(this.#s);t&&t.next&&(t.next.scrollIntoView({block:t.next===this.#n?"start":"center",behavior:"smooth"}),this.#s=t.next)}clickPrev(){const t=this.#i.get(this.#s);t&&t.prev&&(t.prev.scrollIntoView({block:t.prev===this.#e?"start":"center",behavior:"smooth"}),this.#s=t.prev)}updateTargetMap(t,e){if(!s.#c.includes(t)||!this.#a)return;let n,i;this.#e=null,this.#n=null,this.#s=null,this.#i=new WeakMap;const r=[];document.querySelectorAll(this[t]).forEach((t=>{for(n=t.getBoundingClientRect(),i=0;i<r.length&&!(n.top<r[i].top);i++);r.splice(i,0,{top:n.top,el:t}),"function"==typeof e&&e(t)})),this.#e=r[0].el,this.#n=r[r.length-1].el;let o=0;for(i=0;i<r.length;i++)0>r[i].top&&(o=i+1),this.#i.set(r[i].el,{prev:i>0?r[i-1].el:null,next:i<r.length-1?r[i+1].el:null});this.#s=r[o].el,0===o?this.update("start"):o===r.length-1?this.update("end"):this.update("mid")}intersectionCallback(t){const e=t[0];if(e.isIntersecting){this.#o=e.boundingClientRect.top>=0;const t=e.target;let n="mid";t===this.#e?n="start":t===this.#n&&(n="end"),this.#s=t,this.update(n)}}setup(){this.#a=!0,this.#t=new IntersectionObserver(this.intersectionCallback,{threshold:.5}),s.#c.forEach((t=>{this.updateTargetMap(t,(t=>{this.#t.observe(t)}))}))}teardown(){this.#t&&this.#t.disconnect(),this.#t=null,this.#e=null,this.#n=null,this.#s=null,this.#r=null,this.#i=null,this.#a=!1}connectedCallback(){"complete"!==document.readyState?window.addEventListener("load",(()=>{this.setup()}),{once:!0}):this.setup();const{shadowRoot:t}=this;t.innerHTML=`\n <style>\n ${n}\n </style>\n\n <div class="container none">\n <div class="top">\n <div class="start"></div>\n <div class="prev"></div>\n </div>\n <div class="bot">\n <div class="next"></div>\n <div class="end"></div>\n </div>\n </div>\n `,this.#r=t.querySelector(".container"),this.display=this.display,t.querySelector(".top .start").addEventListener("click",this.clickTop),t.querySelector(".bot .end").addEventListener("click",this.clickBottom),t.querySelector(".top .prev").addEventListener("click",this.clickPrev),t.querySelector(".bot .next").addEventListener("click",this.clickNext)}disconnectedCallback(){this.#r=null,this.shadowRoot.querySelector(".top .start").removeEventListener("click",this.clickTop),this.shadowRoot.querySelector(".bot .end").removeEventListener("click",this.clickBottom),this.shadowRoot.querySelector(".top. .prev").removeEventListener("click",this.clickPrev),this.shadowRoot.querySelector(".bot .next").removeEventListener("click",this.clickNext),this.teardown()}attributeChangedCallback(t,e,n){n!==e&&(this[t]=this.getAttribute(t))}}customElements.define("jump-scroll",s),exports.JumpScroll=e.JumpScroll,exports.JumpScrollCss=e.JumpScrollCss,Object.defineProperty(exports,"__esModule",{value:!0})})();
1
+ /**
2
+ * jump-scroll Node entry point
3
+ *
4
+ * Copyright (c) 2023 Alex Grant (@localnerve), LocalNerve LLC
5
+ * Copyrights licensed under the BSD License. See the accompanying LICENSE file for terms.
6
+ */
7
+ import * as path from 'node:path';
8
+ import * as fs from 'node:fs/promises';
9
+ import * as url from 'node:url';
10
+
11
+ const thisDir = url.fileURLToPath(new URL('.', import.meta.url));
12
+
13
+ /**
14
+ * Get the css file contents.
15
+ * Useful for CSP builds.
16
+ *
17
+ * @returns {String} The utf8 css file content
18
+ */
19
+ export async function JumpScrollCssText () {
20
+ return await fs.readFile(path.join(thisDir, 'jump-scroll.css'), {
21
+ encoding: 'utf8'
22
+ });
23
+ }
@@ -0,0 +1 @@
1
+ :host{--js-width:2em;--js-height:8em;--js-bg-color:black;--js-color:white;--js-opacity-full:0.7;--js-opacity-rest:0.3;position:fixed;bottom:1rem;right:.8rem;width:var(--js-width);height:var(--js-height);color:var(--js-color)}.container{display:block;transition:opacity 1s;opacity:var(--js-opacity-full)}.container.none{display:none}.container.rest{opacity:var(--js-opacity-rest)}.container.mid{transform:none}.container.best.mid.down .top,.container.start .top{pointer-events:none;opacity:0}.container.best.mid.up .bot,.container.end .bot{pointer-events:none;opacity:0;transform:translateY(102%)}.container.best.mid.down .top,.container.best.mid.up .top,.container.end .top{transform:translateY(102%)}.bot,.top{position:absolute;width:100%;height:calc(var(--js-height)/ 2);transition:opacity 1s,transform 1s;pointer-events:auto}.top{top:0}.bot{bottom:0}.bot .end,.bot .next,.top .prev,.top .start{content:'';position:absolute;left:50%;width:100%;background:var(--js-bg-color)}.bot .end,.top .start{height:calc(var(--js-height)/ 6);clip-path:polygon(15% 5%,85% 5%,85% 30%,60% 30%,85% 95%,15% 95%,40% 30%,15% 30%)}.bot .next,.top .prev{height:calc(var(--js-height)/ 4);clip-path:polygon(50% 5%,85% 60%,60% 60%,85% 95%,15% 95%,40% 60%,15% 60%)}.top .prev,.top .start{transform:translateX(-50%)}.bot .end,.bot .next{transform:translateX(-50%) rotateX(180deg)}.top .start{top:0}.top .prev{top:calc((var(--js-height)/ 6) + 10%)}.bot .next{bottom:calc((var(--js-height)/ 6) + 10%)}.bot .end{bottom:0}
@@ -0,0 +1,2 @@
1
+ /*! jump-scroll, Copyright (c) 2023 Alex Grant (@localnerve), LocalNerve LLC, BSD-3-Clause */
2
+ class t extends HTMLElement{#t=null;#e=null;#s=null;#i=null;#r=null;#o=null;#n=!0;#a=!1;static#c=["target"];static#l={target:"section",display:"both"};static get observedAttributes(){return[...t.#c,"display"]}constructor(){super(),this.attachShadow({mode:"open"}),this.intersectionCallback=this.intersectionCallback.bind(this),this.setup=this.setup.bind(this),this.clickTop=this.clickTop.bind(this),this.clickBottom=this.clickBottom.bind(this),this.clickNext=this.clickNext.bind(this),this.clickPrev=this.clickPrev.bind(this),this.createTargetProperties()}createTargetProperties(){t.#c.forEach((e=>{Object.defineProperty(this,e,{get(){return this.hasAttribute(e)?this.getAttribute(e):t.#l[e]},set(t){t?this.setAttribute(e,t):this.removeAttribute(e),this.updateTargetMap(t)}})}))}get display(){const e="display";return this.hasAttribute(e)?this.getAttribute(e):t.#l[e]}set display(t){const e="display",s=["both","best"],i=this.#o??{classList:{remove:()=>{},add:()=>{}}};i.classList.remove(...s.concat("up","down")),s.includes(t)?(this.setAttribute(e,t),i.classList.add(t)):this.removeAttribute(e)}update(t){const e=[t];"best"===this.display&&"mid"===t&&(this.#n?e.push("down"):e.push("up")),this.#o.classList.remove("mid","start","end","none","rest","up","down"),this.#o.classList.add(...e),setTimeout((()=>{this.#o.classList.add("rest")}),500)}clickTop(){this.#e.scrollIntoView(),this.#i=this.#e,this.update("start")}clickBottom(){this.#s.scrollIntoView(),this.#i=this.#s,this.update("end")}clickNext(){const t=this.#r.get(this.#i);t&&t.next&&(t.next.scrollIntoView({block:t.next===this.#s?"start":"center",behavior:"smooth"}),this.#i=t.next)}clickPrev(){const t=this.#r.get(this.#i);t&&t.prev&&(t.prev.scrollIntoView({block:t.prev===this.#e?"start":"center",behavior:"smooth"}),this.#i=t.prev)}updateTargetMap(e,s){if(!t.#c.includes(e)||!this.#a)return;let i,r;this.#e=null,this.#s=null,this.#i=null,this.#r=new WeakMap;const o=[];document.querySelectorAll(this[e]).forEach((t=>{for(i=t.getBoundingClientRect(),r=0;r<o.length&&!(i.top<o[r].top);r++);o.splice(r,0,{top:i.top,el:t}),"function"==typeof s&&s(t)})),this.#e=o[0].el,this.#s=o[o.length-1].el;let n=0;for(r=0;r<o.length;r++)0>o[r].top&&(n=r+1),this.#r.set(o[r].el,{prev:r>0?o[r-1].el:null,next:r<o.length-1?o[r+1].el:null});this.#i=o[n].el,0===n?this.update("start"):n===o.length-1?this.update("end"):this.update("mid")}intersectionCallback(t){const e=t[0];if(e.isIntersecting){this.#n=e.boundingClientRect.top>=0;const t=e.target;let s="mid";t===this.#e?s="start":t===this.#s&&(s="end"),this.#i=t,this.update(s)}}setup(){this.#a=!0,this.#t=new IntersectionObserver(this.intersectionCallback,{threshold:.5}),t.#c.forEach((t=>{this.updateTargetMap(t,(t=>{this.#t.observe(t)}))}))}teardown(){this.#t&&this.#t.disconnect(),this.#t=null,this.#e=null,this.#s=null,this.#i=null,this.#o=null,this.#r=null,this.#a=!1}connectedCallback(){"complete"!==document.readyState?window.addEventListener("load",(()=>{this.setup()}),{once:!0}):this.setup();const{shadowRoot:t}=this;t.innerHTML='<style>:host{--js-width:2em;--js-height:8em;--js-bg-color:black;--js-color:white;--js-opacity-full:0.7;--js-opacity-rest:0.3;position:fixed;bottom:1rem;right:.8rem;width:var(--js-width);height:var(--js-height);color:var(--js-color)}.container{display:block;transition:opacity 1s;opacity:var(--js-opacity-full)}.container.none{display:none}.container.rest{opacity:var(--js-opacity-rest)}.container.mid{transform:none}.container.best.mid.down .top,.container.start .top{pointer-events:none;opacity:0}.container.best.mid.up .bot,.container.end .bot{pointer-events:none;opacity:0;transform:translateY(102%)}.container.best.mid.down .top,.container.best.mid.up .top,.container.end .top{transform:translateY(102%)}.bot,.top{position:absolute;width:100%;height:calc(var(--js-height)/ 2);transition:opacity 1s,transform 1s;pointer-events:auto}.top{top:0}.bot{bottom:0}.bot .end,.bot .next,.top .prev,.top .start{content:\'\';position:absolute;left:50%;width:100%;background:var(--js-bg-color)}.bot .end,.top .start{height:calc(var(--js-height)/ 6);clip-path:polygon(15% 5%,85% 5%,85% 30%,60% 30%,85% 95%,15% 95%,40% 30%,15% 30%)}.bot .next,.top .prev{height:calc(var(--js-height)/ 4);clip-path:polygon(50% 5%,85% 60%,60% 60%,85% 95%,15% 95%,40% 60%,15% 60%)}.top .prev,.top .start{transform:translateX(-50%)}.bot .end,.bot .next{transform:translateX(-50%) rotateX(180deg)}.top .start{top:0}.top .prev{top:calc((var(--js-height)/ 6) + 10%)}.bot .next{bottom:calc((var(--js-height)/ 6) + 10%)}.bot .end{bottom:0}</style><div class="container none"><div class="top"><div class="start"></div><div class="prev"></div></div><div class="bot"><div class="next"></div><div class="end"></div></div></div>',this.#o=t.querySelector(".container"),this.display=this.display,t.querySelector(".top .start").addEventListener("click",this.clickTop),t.querySelector(".bot .end").addEventListener("click",this.clickBottom),t.querySelector(".top .prev").addEventListener("click",this.clickPrev),t.querySelector(".bot .next").addEventListener("click",this.clickNext)}disconnectedCallback(){this.#o=null,this.shadowRoot.querySelector(".top .start").removeEventListener("click",this.clickTop),this.shadowRoot.querySelector(".bot .end").removeEventListener("click",this.clickBottom),this.shadowRoot.querySelector(".top. .prev").removeEventListener("click",this.clickPrev),this.shadowRoot.querySelector(".bot .next").removeEventListener("click",this.clickNext),this.teardown()}attributeChangedCallback(t,e,s){s!==e&&(this[t]=this.getAttribute(t))}}customElements.define("jump-scroll",t);
package/package.json CHANGED
@@ -1,15 +1,18 @@
1
1
  {
2
2
  "name": "@localnerve/jump-scroll",
3
- "version": "0.2.1",
4
- "description": "A small, fast, no-dep, jump scroll control",
3
+ "version": "0.3.0",
4
+ "description": "A small, fast, no-dep, jump-scroll web component",
5
5
  "main": "dist/index.js",
6
+ "browser": "dist/jump-scroll.js",
7
+ "type": "module",
6
8
  "scripts": {
7
- "build": "webpack-cli --config webpack.prod.config.js",
9
+ "build": "node build.js && webpack-cli --config webpack.prod.config.js",
8
10
  "prepublishOnly": "npm run build"
9
11
  },
10
12
  "devDependencies": {
11
13
  "webpack": "^5.88.2",
12
- "webpack-cli": "^5.1.4"
14
+ "webpack-cli": "^5.1.4",
15
+ "clean-css": "^5.3.2"
13
16
  },
14
17
  "repository": {
15
18
  "type": "git",
@@ -19,7 +22,7 @@
19
22
  "vertical",
20
23
  "jump",
21
24
  "scroll",
22
- "web-component",
25
+ "webcomponent",
23
26
  "javascript"
24
27
  ],
25
28
  "author": "Alex Grant (@localnerve)",