From 427726bd4b27c53a229ef63f1a0c08bf9610236d Mon Sep 17 00:00:00 2001 From: sairaj mote Date: Fri, 16 Jul 2021 18:50:54 +0530 Subject: [PATCH] Added theme-toggle component --- Layouts/tabs layout/index.html | 1 + components/css/main.css | 26 +-- components/css/main.min.css | 2 +- components/css/main.scss | 25 +-- components/dist/select.js | 245 ++++++++++++++++------------ components/dist/select.min.js | 2 +- components/dist/theme-toggle.js | 178 ++++++++++++++++++++ components/dist/theme-toggle.min.js | 1 + components/index.html | 70 ++------ 9 files changed, 336 insertions(+), 214 deletions(-) create mode 100644 components/dist/theme-toggle.js create mode 100644 components/dist/theme-toggle.min.js diff --git a/Layouts/tabs layout/index.html b/Layouts/tabs layout/index.html index 9e937fb..5df1fea 100644 --- a/Layouts/tabs layout/index.html +++ b/Layouts/tabs layout/index.html @@ -54,6 +54,7 @@

Lorem ipsum dolor sit amet consectetur adipisicing elit.

+ This is a button

Card

diff --git a/components/css/main.css b/components/css/main.css index 99946c8..5f5ae53 100644 --- a/components/css/main.css +++ b/components/css/main.css @@ -96,7 +96,8 @@ ul { display: grid; gap: 1rem; padding: 1rem; - grid-template-columns: 12rem minmax(0, 1fr); + grid-template-columns: 12rem 1fr; + width: 100%; } .tr:nth-of-type(odd) { background-color: rgba(var(--text-color), 0.04); @@ -320,29 +321,6 @@ ul { margin-left: 0.5rem; } -.theme-switcher { - position: relative; - justify-self: flex-end; - width: 1.5rem; - height: 1.5rem; - cursor: pointer; - -webkit-tap-highlight-color: transparent; -} -.theme-switcher .icon { - position: absolute; - transition: transform 0.6s; -} - -.theme-switcher__checkbox { - display: none; -} -.theme-switcher__checkbox:checked ~ .moon-icon { - transform: scale(0) rotate(90deg); -} -.theme-switcher__checkbox:not(:checked) ~ .sun-icon { - transform: scale(0) rotate(-90deg); -} - .token.comment, .token.block-comment, .token.prolog, diff --git a/components/css/main.min.css b/components/css/main.min.css index c521c12..98df5aa 100644 --- a/components/css/main.min.css +++ b/components/css/main.min.css @@ -1 +1 @@ -p,pre{line-height:1.7}.list,ul{list-style:none}p,strong{max-width:65ch}*{padding:0;margin:0;box-sizing:border-box;font-family:Roboto,sans-serif}:root{font-size:clamp(1rem,1.2vmax,3rem)}body,html{height:100%;scroll-behavior:smooth}body{background:rgba(var(--background-color),1)}body,body *{--accent-color:#0D7377;--text-color:17,17,17;--background-color:255,255,255;--danger-color:red;color:rgba(var(--text-color),1)}body[data-theme=dark],body[data-theme=dark] *{--accent-color:#32E0C4;--text-color:240,240,240;--text-color-light:170,170,170;--background-color:10,10,10;--danger-color:rgb(255, 106, 106)}p{font-size:.8;margin-bottom:1.5rem;color:rgba(var(--text-color),.8)}p:not(:last-of-type){margin-bottom:1rem}img{object-fit:cover}a{color:inherit;text-decoration:none}a:focus-visible{box-shadow:0 0 0 .1rem rgba(var(--text-color),1) inset}button{display:inline-flex;border:none;background-color:inherit}.table,.tr{display:grid}a:any-link:focus-visible{outline:solid rgba(var(--text-color),1)}sm-button{--border-radius:0.3rem}.table{gap:.5rem;margin:1rem 0;position:relative;text-align:left;overflow-x:auto;border-radius:.3rem;border-collapse:separate;border-spacing:1rem 1.5rem;background-color:rgba(var(--text-color),.04)}.table p:only-of-type{margin-bottom:0}.tr{gap:1rem;padding:1rem;grid-template-columns:12rem minmax(0,1fr)}.tr:nth-of-type(odd){background-color:rgba(var(--text-color),.04)}.tr p{min-width:30ch}.hide{opacity:0;pointer-events:none}.hide-completely{display:none!important}.no-transformations{transform:none!important}.overflow-ellipsis{width:100%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.breakable{overflow-wrap:break-word;word-wrap:break-word;-ms-word-break:break-all;word-break:break-word;-ms-hyphens:auto;-moz-hyphens:auto;-webkit-hyphens:auto;hyphens:auto}.full-bleed{grid-column:1/4}.h1{font-size:2.5rem}.h2{font-size:2rem}.h3{font-size:1.4rem}.h4{font-size:1rem}.h5{font-size:.8rem}.uppercase{text-transform:uppercase}.capitalize,.list__item,h2,ol li::first-letter{text-transform:capitalize}.flex{display:flex}.grid{display:grid}.grid-3{grid-template-columns:1fr auto auto}.flow-column{grid-auto-flow:column}.gap-0-5{gap:.5rem}.gap-1{gap:1rem}.gap-1-5{gap:1.5rem}.gap-2{gap:2rem}.gap-3{gap:3rem}.text-align-right{text-align:right}.align-start{align-items:flex-start}.align-center{align-items:center}.text-center{text-align:center}.justify-start{justify-content:start}.justify-center{justify-content:center}.justify-right{margin-left:auto}.button__icon--right,.comp-checkbox__title{margin-left:.5rem}.align-self-center{align-self:center}.justify-self-center{justify-self:center}.justify-self-start{justify-self:start}.justify-self-end{justify-self:end}.card,.direction-column,.list{flex-direction:column}.space-between{justify-content:space-between}.w-100{width:100%}.color-0-8{color:rgba(var(--text-color),.8)}.weight-400{font-weight:400}.weight-500{font-weight:500}.ripple{position:absolute;border-radius:50%;transform:scale(0);background:rgba(var(--text-color),.16);pointer-events:none}.interact,.theme-switcher{position:relative;cursor:pointer;-webkit-tap-highlight-color:transparent}.interact{overflow:hidden}.observe-empty-state:empty{display:none}.observe-empty-state:not(:empty)~.empty-state{display:none}.icon{width:1.5rem;height:1.5rem;fill:rgba(var(--text-color),.9)}.button__icon{height:1.2rem;width:1.2rem}.button__icon--left{margin-right:.5rem}.theme-switcher{justify-self:flex-end;width:1.5rem;height:1.5rem}.theme-switcher .icon{position:absolute;transition:transform .6s}.theme-switcher__checkbox{display:none}.theme-switcher__checkbox:checked~.moon-icon{transform:scale(0) rotate(90deg)}.theme-switcher__checkbox:not(:checked)~.sun-icon{transform:scale(0) rotate(-90deg)}.token.block-comment,.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#AEAEAE}.token.punctuation{color:#9789ee}.token.tag{color:#29B6F6}.token.attr-name,.token.deleted,.token.namespace{color:#1DE9B6}.token.function-name{color:#6196cc}.token.boolean,.token.function,.token.number{color:#f08d49}.token.class-name,.token.constant,.token.property,.token.symbol{color:#f8c555}.token.atrule,.token.builtin,.token.important,.token.keyword,.token.selector{color:#cc99cd}.token.attr-value,.token.char,.token.regex,.token.string,.token.variable{color:#84FFFF}.token.entity,.token.operator,.token.url{color:#67cdcc}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.token.inserted{color:green}pre{max-width:100%;margin:1rem 0;padding:0 1.5rem;overflow-x:auto;font-size:.9rem;font-weight:500;white-space:pre-line;border-radius:.5rem;background:rgba(0,0,0,.9)}code{border-radius:.3rem;font-weight:400;padding:.2rem .4rem;color:rgba(255,255,255,.9);background:rgba(var(--text-color),.1)}code *{font-family:"Roboto Mono",monospace}pre code{line-height:1.4;border-radius:none;background:0 0;width:100%}h1,h2,h3,h4.h5{font-family:Poppins,sans-serif}h2{margin:3rem 0 1rem}h2:first-of-type{margin-top:1rem}main{display:grid;height:100%}.card,.list,.list__item,.page,strong.important{display:flex}#main_header{padding:.5rem 1.5rem;border-bottom:1px solid rgba(var(--text-color),.1)}#side_nav_button{padding:.5rem;margin-left:-.5rem}#side_nav>:last-child{padding-bottom:3rem}#side_nav h4{font-size:.9rem;letter-spacing:.08em;text-transform:uppercase;padding:1.5rem}.right{max-height:100%;overflow-y:auto;padding:1.5rem}.right h1{margin-bottom:1.5rem}.list{margin-bottom:.8rem}ol li,sm-carousel{margin-bottom:1rem}.list__item{padding:.8rem 1.5rem}.list__item--active{color:var(--accent-color);background:rgba(var(--text-color),.06)}.card{margin-right:1rem;border-radius:.4rem;padding:1.5rem;min-width:min(24rem,80%);background-color:rgba(var(--text-color),.06)}sm-tab-header{margin-bottom:1.5rem}.page{flex-direction:column;padding-bottom:3rem}ol{padding:.6rem 1rem;max-width:75ch;margin-bottom:3rem}ol li:last-of-type{margin-bottom:0}strong.important{padding:.5rem;margin:.5rem 0;border-radius:.3rem;color:rgba(0,0,0,.8);background-color:khaki}.highlight{display:inline-flex;font-family:"Roboto Mono",monospace;background-color:rgba(var(--text-color),.1);border-radius:.2rem;padding:.1rem .5rem;font-size:.9rem;line-height:1.6}#total_components_count{font-size:4rem}#components_selection_list{display:grid;gap:1.5rem;grid-template-columns:repeat(auto-fill,minmax(10rem,1fr));padding:1.5rem 0 3rem}@media screen and (max-width:640px){main{grid-template-rows:auto 1fr;grid-template-columns:1fr}}@media screen and (min-width:640px){#main_header{padding:1rem 1.5rem;grid-area:main-header}#side_nav_button{display:none}main{grid-template-columns:14rem minmax(0,1fr);grid-template-areas:"main-header main-header" ". ."}.right{display:grid;grid-template-columns:1fr 90% 1fr}.right>*{grid-column:2/3}.page__title{font-size:2.5rem}#overview_page{display:grid;gap:1.5rem;grid-template-columns:1fr auto}#overview_page>div:first-of-type{grid-column:2/3;text-align:right}#overview_page>div:nth-of-type(2){grid-row:1/2}}@media (any-hover:hover){::-webkit-scrollbar{width:.5rem;height:.5rem}::-webkit-scrollbar-thumb{background:rgba(var(--text-color),.3);border-radius:1rem}::-webkit-scrollbar-thumb:hover{background:rgba(var(--text-color),.5)}.list__item:hover{background:rgba(var(--text-color),.1);cursor:pointer}} \ No newline at end of file +p,pre{line-height:1.7}.list,ul{list-style:none}p,strong{max-width:65ch}*{padding:0;margin:0;box-sizing:border-box;font-family:Roboto,sans-serif}:root{font-size:clamp(1rem,1.2vmax,3rem)}body,html{height:100%;scroll-behavior:smooth}body{background:rgba(var(--background-color),1)}body,body *{--accent-color:#0D7377;--text-color:17,17,17;--background-color:255,255,255;--danger-color:red;color:rgba(var(--text-color),1)}body[data-theme=dark],body[data-theme=dark] *{--accent-color:#32E0C4;--text-color:240,240,240;--text-color-light:170,170,170;--background-color:10,10,10;--danger-color:rgb(255, 106, 106)}p{font-size:.8;margin-bottom:1.5rem;color:rgba(var(--text-color),.8)}p:not(:last-of-type){margin-bottom:1rem}img{object-fit:cover}a{color:inherit;text-decoration:none}a:focus-visible{box-shadow:0 0 0 .1rem rgba(var(--text-color),1) inset}button{display:inline-flex;border:none;background-color:inherit}a:any-link:focus-visible{outline:solid rgba(var(--text-color),1)}sm-button{--border-radius:0.3rem}.table{display:grid;gap:.5rem;margin:1rem 0;position:relative;text-align:left;overflow-x:auto;border-radius:.3rem;border-collapse:separate;border-spacing:1rem 1.5rem;background-color:rgba(var(--text-color),.04)}.table p:only-of-type{margin-bottom:0}.tr{display:grid;gap:1rem;padding:1rem;grid-template-columns:12rem 1fr;width:100%}.tr:nth-of-type(odd){background-color:rgba(var(--text-color),.04)}.tr p{min-width:30ch}.hide{opacity:0;pointer-events:none}.hide-completely{display:none!important}.no-transformations{transform:none!important}.overflow-ellipsis{width:100%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.breakable{overflow-wrap:break-word;word-wrap:break-word;-ms-word-break:break-all;word-break:break-word;-ms-hyphens:auto;-moz-hyphens:auto;-webkit-hyphens:auto;hyphens:auto}.full-bleed{grid-column:1/4}.h1{font-size:2.5rem}.h2{font-size:2rem}.h3{font-size:1.4rem}.h4{font-size:1rem}.h5{font-size:.8rem}#side_nav h4,.highlight,pre{font-size:.9rem}.uppercase{text-transform:uppercase}.capitalize,.list__item,h2,ol li::first-letter{text-transform:capitalize}.flex{display:flex}.grid{display:grid}.grid-3{grid-template-columns:1fr auto auto}.flow-column{grid-auto-flow:column}.gap-0-5{gap:.5rem}.gap-1{gap:1rem}.gap-1-5{gap:1.5rem}.gap-2{gap:2rem}.gap-3{gap:3rem}.text-align-right{text-align:right}.align-start{align-items:flex-start}.align-center{align-items:center}.text-center{text-align:center}.justify-start{justify-content:start}.justify-center{justify-content:center}.justify-right{margin-left:auto}.button__icon--right,.comp-checkbox__title{margin-left:.5rem}.align-self-center{align-self:center}.justify-self-center{justify-self:center}.justify-self-start{justify-self:start}.justify-self-end{justify-self:end}.card,.direction-column,.list{flex-direction:column}.space-between{justify-content:space-between}.w-100{width:100%}.color-0-8{color:rgba(var(--text-color),.8)}.weight-400{font-weight:400}.weight-500{font-weight:500}.ripple{position:absolute;border-radius:50%;transform:scale(0);background:rgba(var(--text-color),.16);pointer-events:none}.interact{position:relative;overflow:hidden;cursor:pointer;-webkit-tap-highlight-color:transparent}.observe-empty-state:empty{display:none}.observe-empty-state:not(:empty)~.empty-state{display:none}.icon{width:1.5rem;height:1.5rem;fill:rgba(var(--text-color),.9)}.button__icon{height:1.2rem;width:1.2rem}.button__icon--left{margin-right:.5rem}.token.block-comment,.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#AEAEAE}.token.punctuation{color:#9789ee}.token.tag{color:#29B6F6}.token.attr-name,.token.deleted,.token.namespace{color:#1DE9B6}.token.function-name{color:#6196cc}.token.boolean,.token.function,.token.number{color:#f08d49}.token.class-name,.token.constant,.token.property,.token.symbol{color:#f8c555}.token.atrule,.token.builtin,.token.important,.token.keyword,.token.selector{color:#cc99cd}.token.attr-value,.token.char,.token.regex,.token.string,.token.variable{color:#84FFFF}.token.entity,.token.operator,.token.url{color:#67cdcc}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.token.inserted{color:green}pre{max-width:100%;margin:1rem 0;padding:0 1.5rem;overflow-x:auto;font-weight:500;white-space:pre-line;border-radius:.5rem;background:rgba(0,0,0,.9)}code{border-radius:.3rem;font-weight:400;padding:.2rem .4rem;color:rgba(255,255,255,.9);background:rgba(var(--text-color),.1)}code *{font-family:"Roboto Mono",monospace}pre code{line-height:1.4;border-radius:none;background:0 0;width:100%}h1,h2,h3,h4.h5{font-family:Poppins,sans-serif}h2{margin:3rem 0 1rem}h2:first-of-type{margin-top:1rem}main{display:grid;height:100%}.card,.list,.list__item,.page,strong.important{display:flex}#main_header{padding:.5rem 1.5rem;border-bottom:1px solid rgba(var(--text-color),.1)}#side_nav_button{padding:.5rem;margin-left:-.5rem}#side_nav>:last-child{padding-bottom:3rem}#side_nav h4{letter-spacing:.08em;text-transform:uppercase;padding:1.5rem}.right{max-height:100%;overflow-y:auto;padding:1.5rem}.right h1{margin-bottom:1.5rem}.list{margin-bottom:.8rem}ol li,sm-carousel{margin-bottom:1rem}.list__item{padding:.8rem 1.5rem}.list__item--active{color:var(--accent-color);background:rgba(var(--text-color),.06)}.card{margin-right:1rem;border-radius:.4rem;padding:1.5rem;min-width:min(24rem,80%);background-color:rgba(var(--text-color),.06)}sm-tab-header{margin-bottom:1.5rem}.page{flex-direction:column;padding-bottom:3rem}ol{padding:.6rem 1rem;max-width:75ch;margin-bottom:3rem}ol li:last-of-type{margin-bottom:0}strong.important{padding:.5rem;margin:.5rem 0;border-radius:.3rem;color:rgba(0,0,0,.8);background-color:khaki}.highlight{display:inline-flex;font-family:"Roboto Mono",monospace;background-color:rgba(var(--text-color),.1);border-radius:.2rem;padding:.1rem .5rem;line-height:1.6}#total_components_count{font-size:4rem}#components_selection_list{display:grid;gap:1.5rem;grid-template-columns:repeat(auto-fill,minmax(10rem,1fr));padding:1.5rem 0 3rem}@media screen and (max-width:640px){main{grid-template-rows:auto 1fr;grid-template-columns:1fr}}@media screen and (min-width:640px){#main_header{padding:1rem 1.5rem;grid-area:main-header}#side_nav_button{display:none}main{grid-template-columns:14rem minmax(0,1fr);grid-template-areas:"main-header main-header" ". ."}.right{display:grid;grid-template-columns:1fr 90% 1fr}.right>*{grid-column:2/3}.page__title{font-size:2.5rem}#overview_page{display:grid;gap:1.5rem;grid-template-columns:1fr auto}#overview_page>div:first-of-type{grid-column:2/3;text-align:right}#overview_page>div:nth-of-type(2){grid-row:1/2}}@media (any-hover:hover){::-webkit-scrollbar{width:.5rem;height:.5rem}::-webkit-scrollbar-thumb{background:rgba(var(--text-color),.3);border-radius:1rem}::-webkit-scrollbar-thumb:hover{background:rgba(var(--text-color),.5)}.list__item:hover{background:rgba(var(--text-color),.1);cursor:pointer}} \ No newline at end of file diff --git a/components/css/main.scss b/components/css/main.scss index a60c8e2..0970ca5 100644 --- a/components/css/main.scss +++ b/components/css/main.scss @@ -89,7 +89,8 @@ ul{ display: grid; gap: 1rem; padding: 1rem; - grid-template-columns: 12rem minmax(0, 1fr); + grid-template-columns: 12rem 1fr; + width: 100%; &:nth-of-type(odd){ background-color: rgba(var(--text-color), .04); } @@ -268,28 +269,6 @@ ul{ margin-left: 0.5rem; } } -.theme-switcher{ - position: relative; - justify-self: flex-end; - width: 1.5rem; - height: 1.5rem; - cursor: pointer; - -webkit-tap-highlight-color: transparent; - .icon{ - position: absolute; - transition: transform 0.6s; - } -} -.theme-switcher__checkbox{ - display: none; - &:checked ~ .moon-icon{ - transform: scale(0) rotate(90deg); - } - &:not(:checked) ~ .sun-icon{ - transform: scale(0) rotate(-90deg); - } -} - //Syntax highlighting .token.comment, diff --git a/components/dist/select.js b/components/dist/select.js index 073b142..b4b4e63 100644 --- a/components/dist/select.js +++ b/components/dist/select.js @@ -7,16 +7,6 @@ smSelect.innerHTML = ` -webkit-box-sizing: border-box; box-sizing: border-box; } -.icon { - fill: none; - height: 0.8rem; - width: 0.8rem; - stroke: rgba(var(--text-color), 0.7); - stroke-width: 6; - overflow: visible; - stroke-linecap: round; - stroke-linejoin: round; -} :host{ display: -webkit-inline-box; display: -ms-inline-flexbox; @@ -27,6 +17,10 @@ smSelect.innerHTML = ` --max-height: auto; --min-width: 100%; } +:host([disabled]) .select{ + opacity: 0.6; + cursor: not-allowed; +} .hide{ display: none !important; } @@ -37,12 +31,17 @@ smSelect.innerHTML = ` display: flex; -webkit-box-orient: vertical; -webkit-box-direction: normal; - -ms-flex-direction: column; - flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; cursor: pointer; width: 100%; -webkit-tap-highlight-color: transparent; } +.icon { + height: 1.5rem; + width: 1.5rem; + fill: rgba(var(--text-color), 0.7); +} .option-text{ font-size: 0.9rem; overflow: hidden; @@ -80,7 +79,7 @@ smSelect.innerHTML = ` } .options{ top: 100%; - margin-top: 0.5rem; + margin-top: 0.2rem; overflow: hidden auto; position: absolute; grid-area: options; @@ -121,11 +120,9 @@ smSelect.innerHTML = ` }
-
+
- - - +
@@ -139,9 +136,45 @@ customElements.define('sm-select', class extends HTMLElement { }).append(smSelect.content.cloneNode(true)) this.reset = this.reset.bind(this) + this.open = this.open.bind(this) + this.collapse = this.collapse.bind(this) + this.toggle = this.toggle.bind(this) + this.handleSelectKeyDown = this.handleSelectKeyDown.bind(this) + this.handleOptionsKeyDown = this.handleOptionsKeyDown.bind(this) + this.handleOptionsKeyDown = this.handleOptionsKeyDown.bind(this) + + this.availableOptions + this.optionList = this.shadowRoot.querySelector('.options') + this.chevron = this.shadowRoot.querySelector('.toggle') + this.selection = this.shadowRoot.querySelector('.selection'), + this.previousOption + this.isOpen = false; + this.slideDown = [{ + transform: `translateY(-0.5rem)`, + opacity: 0 + }, + { + transform: `translateY(0)`, + opacity: 1 + } + ] + this.slideUp = [{ + transform: `translateY(0)`, + opacity: 1 + }, + { + transform: `translateY(-0.5rem)`, + opacity: 0 + } + ] + this.animationOptions = { + duration: 300, + fill: "forwards", + easing: 'ease' + } } static get observedAttributes() { - return ['value'] + return ['value', 'disabled'] } get value() { return this.getAttribute('value') @@ -150,94 +183,89 @@ customElements.define('sm-select', class extends HTMLElement { this.setAttribute('value', val) } - reset(){ + reset() { } + open() { + this.optionList.classList.remove('hide') + this.optionList.animate(this.slideDown, this.animationOptions) + this.chevron.classList.add('rotate') + this.isOpen = true + } collapse() { this.chevron.classList.remove('rotate') this.optionList.animate(this.slideUp, this.animationOptions) - .onfinish = () => { - this.optionList.classList.add('hide') - this.open = false + .onfinish = () => { + this.optionList.classList.add('hide') + this.isOpen = false + } + } + toggle() { + if (!this.isOpen && !this.hasAttribute('disabled')) { + this.open() + } else { + this.collapse() } } - connectedCallback() { - this.availableOptions - this.optionList = this.shadowRoot.querySelector('.options') - this.chevron = this.shadowRoot.querySelector('.toggle') - let slot = this.shadowRoot.querySelector('.options slot'), - selection = this.shadowRoot.querySelector('.selection'), - previousOption - this.open = false; - this.slideDown = [{ - transform: `translateY(-0.5rem)`, - opacity: 0 - }, - { - transform: `translateY(0)`, - opacity: 1 - } - ] - this.slideUp = [{ - transform: `translateY(0)`, - opacity: 1 - }, - { - transform: `translateY(-0.5rem)`, - opacity: 0 - } - ] - this.animationOptions = { - duration: 300, - fill: "forwards", - easing: 'ease' + handleSelectKeyDown(e) { + if (e.code === 'ArrowDown' || e.code === 'ArrowRight') { + e.preventDefault() + this.availableOptions[0].focus() } - selection.addEventListener('click', e => { - if (!this.open) { + else if (e.code === 'Enter' || e.code === 'Space') { + if (!this.isOpen) { this.optionList.classList.remove('hide') this.optionList.animate(this.slideDown, this.animationOptions) this.chevron.classList.add('rotate') - this.open = true + this.isOpen = true } else { this.collapse() } - }) - selection.addEventListener('keydown', e => { - if (e.code === 'ArrowDown' || e.code === 'ArrowRight') { - e.preventDefault() + } + } + handleOptionsKeyDown(e) { + if (e.code === 'ArrowUp' || e.code === 'ArrowRight') { + e.preventDefault() + if (document.activeElement.previousElementSibling) { + document.activeElement.previousElementSibling.focus() + } else { + this.availableOptions[this.availableOptions.length - 1].focus() + } + } + else if (e.code === 'ArrowDown' || e.code === 'ArrowLeft') { + e.preventDefault() + if (document.activeElement.nextElementSibling) { + document.activeElement.nextElementSibling.focus() + } else { this.availableOptions[0].focus() } - if (e.code === 'Enter' || e.code === 'Space') - if (!this.open) { - this.optionList.classList.remove('hide') - this.optionList.animate(this.slideDown, this.animationOptions) - this.chevron.classList.add('rotate') - this.open = true - } else { - this.collapse() - } - }) - this.optionList.addEventListener('keydown', e => { - if (e.code === 'ArrowUp' || e.code === 'ArrowRight') { - e.preventDefault() - if (document.activeElement.previousElementSibling) { - document.activeElement.previousElementSibling.focus() - } else { - this.availableOptions[this.availableOptions.length - 1].focus() - } + } + } + connectedCallback() { + this.setAttribute('role', 'listbox') + if (!this.hasAttribute('disabled')) { + this.selection.setAttribute('tabindex', '0') + } + let slot = this.shadowRoot.querySelector('slot') + slot.addEventListener('slotchange', e => { + this.availableOptions = slot.assignedElements() + if (this.availableOptions[0]) { + let firstElement = this.availableOptions[0]; + this.previousOption = firstElement; + firstElement.classList.add('check-selected') + this.setAttribute('value', firstElement.getAttribute('value')) + this.shadowRoot.querySelector('.option-text').textContent = firstElement.textContent + this.availableOptions.forEach((element, index) => { + element.setAttribute('tabindex', "0"); + }) } - if (e.code === 'ArrowDown' || e.code === 'ArrowLeft') { - e.preventDefault() - if (document.activeElement.nextElementSibling) { - document.activeElement.nextElementSibling.focus() - } else{ - this.availableOptions[0].focus() - } - } - }) + }); + this.selection.addEventListener('click', this.toggle) + this.selection.addEventListener('keydown', this.handleSelectKeyDown) + this.optionList.addEventListener('keydown', this.handleOptionsKeyDown) this.addEventListener('optionSelected', e => { - if (previousOption !== e.target) { + if (this.previousOption !== e.target) { this.setAttribute('value', e.detail.value) this.shadowRoot.querySelector('.option-text').textContent = e.detail.text; this.dispatchEvent(new CustomEvent('change', { @@ -247,36 +275,36 @@ customElements.define('sm-select', class extends HTMLElement { value: e.detail.value } })) - if (previousOption) { - previousOption.classList.remove('check-selected') + if (this.previousOption) { + this.previousOption.classList.remove('check-selected') } - previousOption = e.target; + this.previousOption = e.target; } if (!e.detail.switching) this.collapse() e.target.classList.add('check-selected') }) - slot.addEventListener('slotchange', e => { - this.availableOptions = slot.assignedElements() - if (this.availableOptions[0]) { - let firstElement = this.availableOptions[0]; - previousOption = firstElement; - firstElement.classList.add('check-selected') - this.setAttribute('value', firstElement.getAttribute('value')) - this.shadowRoot.querySelector('.option-text').textContent = firstElement.textContent - this.availableOptions.forEach((element, index) => { - element.setAttribute('data-rank', index + 1); - element.setAttribute('tabindex', "0"); - }) - } - }); document.addEventListener('mousedown', e => { - if (!this.contains(e.target) && this.open) { + if (this.isOpen && !this.contains(e.target)) { this.collapse() } }) } + attributeChangedCallback(name, oldVal, newVal) { + if (name === "disabled") { + if (this.hasAttribute('disabled')) { + this.selection.removeAttribute('tabindex') + }else { + this.selection.setAttribute('tabindex', '0') + } + } + } + disconnectedCallback() { + this.selection.removeEventListener('click', this.toggle) + this.selection.removeEventListener('keydown', this.handleSelectKeyDown) + this.optionList.removeEventListener('keydown', this.handleOptionsKeyDown) + } }) // option @@ -351,6 +379,8 @@ customElements.define('sm-option', class extends HTMLElement { this.attachShadow({ mode: 'open' }).append(smOption.content.cloneNode(true)) + + this.sendDetails = this.sendDetails.bind(this) } sendDetails(switching) { @@ -367,15 +397,14 @@ customElements.define('sm-option', class extends HTMLElement { } connectedCallback() { + this.setAttribute('role', 'option') let validKey = [ 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight' ] - this.addEventListener('click', e => { - this.sendDetails() - }) + this.addEventListener('click', this.sendDetails) this.addEventListener('keyup', e => { if (e.code === 'Enter' || e.code === 'Space') { e.preventDefault() diff --git a/components/dist/select.min.js b/components/dist/select.min.js index 714a626..49995b6 100644 --- a/components/dist/select.min.js +++ b/components/dist/select.min.js @@ -1 +1 @@ -const smSelect=document.createElement("template");smSelect.innerHTML='\n\n
\n
\n
\n \n \n \n
\n
\n \n
\n
',customElements.define("sm-select",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smSelect.content.cloneNode(!0)),this.reset=this.reset.bind(this)}static get observedAttributes(){return["value"]}get value(){return this.getAttribute("value")}set value(e){this.setAttribute("value",e)}reset(){}collapse(){this.chevron.classList.remove("rotate"),this.optionList.animate(this.slideUp,this.animationOptions).onfinish=(()=>{this.optionList.classList.add("hide"),this.open=!1})}connectedCallback(){this.availableOptions,this.optionList=this.shadowRoot.querySelector(".options"),this.chevron=this.shadowRoot.querySelector(".toggle");let e,t=this.shadowRoot.querySelector(".options slot"),n=this.shadowRoot.querySelector(".selection");this.open=!1,this.slideDown=[{transform:"translateY(-0.5rem)",opacity:0},{transform:"translateY(0)",opacity:1}],this.slideUp=[{transform:"translateY(0)",opacity:1},{transform:"translateY(-0.5rem)",opacity:0}],this.animationOptions={duration:300,fill:"forwards",easing:"ease"},n.addEventListener("click",e=>{this.open?this.collapse():(this.optionList.classList.remove("hide"),this.optionList.animate(this.slideDown,this.animationOptions),this.chevron.classList.add("rotate"),this.open=!0)}),n.addEventListener("keydown",e=>{"ArrowDown"!==e.code&&"ArrowRight"!==e.code||(e.preventDefault(),this.availableOptions[0].focus()),"Enter"!==e.code&&"Space"!==e.code||(this.open?this.collapse():(this.optionList.classList.remove("hide"),this.optionList.animate(this.slideDown,this.animationOptions),this.chevron.classList.add("rotate"),this.open=!0))}),this.optionList.addEventListener("keydown",e=>{"ArrowUp"!==e.code&&"ArrowRight"!==e.code||(e.preventDefault(),document.activeElement.previousElementSibling?document.activeElement.previousElementSibling.focus():this.availableOptions[this.availableOptions.length-1].focus()),"ArrowDown"!==e.code&&"ArrowLeft"!==e.code||(e.preventDefault(),document.activeElement.nextElementSibling?document.activeElement.nextElementSibling.focus():this.availableOptions[0].focus())}),this.addEventListener("optionSelected",t=>{e!==t.target&&(this.setAttribute("value",t.detail.value),this.shadowRoot.querySelector(".option-text").textContent=t.detail.text,this.dispatchEvent(new CustomEvent("change",{bubbles:!0,composed:!0,detail:{value:t.detail.value}})),e&&e.classList.remove("check-selected"),e=t.target),t.detail.switching||this.collapse(),t.target.classList.add("check-selected")}),t.addEventListener("slotchange",n=>{if(this.availableOptions=t.assignedElements(),this.availableOptions[0]){let t=this.availableOptions[0];e=t,t.classList.add("check-selected"),this.setAttribute("value",t.getAttribute("value")),this.shadowRoot.querySelector(".option-text").textContent=t.textContent,this.availableOptions.forEach((e,t)=>{e.setAttribute("data-rank",t+1),e.setAttribute("tabindex","0")})}}),document.addEventListener("mousedown",e=>{!this.contains(e.target)&&this.open&&this.collapse()})}});const smOption=document.createElement("template");smOption.innerHTML='\n\n
\n \n \n \n \n
',customElements.define("sm-option",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smOption.content.cloneNode(!0))}sendDetails(e){let t=new CustomEvent("optionSelected",{bubbles:!0,composed:!0,detail:{text:this.textContent,value:this.getAttribute("value"),switching:e}});this.dispatchEvent(t)}connectedCallback(){let e=["ArrowUp","ArrowDown","ArrowLeft","ArrowRight"];this.addEventListener("click",e=>{this.sendDetails()}),this.addEventListener("keyup",t=>{"Enter"!==t.code&&"Space"!==t.code||(t.preventDefault(),this.sendDetails(!1)),e.includes(t.code)&&(t.preventDefault(),this.sendDetails(!0))}),this.hasAttribute("default")&&setTimeout(()=>{this.sendDetails()},0)}}); \ No newline at end of file +const smSelect=document.createElement("template");smSelect.innerHTML='\n\n
\n
\n
\n \n
\n
\n \n
\n
',customElements.define("sm-select",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smSelect.content.cloneNode(!0)),this.reset=this.reset.bind(this),this.open=this.open.bind(this),this.collapse=this.collapse.bind(this),this.toggle=this.toggle.bind(this),this.handleSelectKeyDown=this.handleSelectKeyDown.bind(this),this.handleOptionsKeyDown=this.handleOptionsKeyDown.bind(this),this.handleOptionsKeyDown=this.handleOptionsKeyDown.bind(this),this.availableOptions,this.optionList=this.shadowRoot.querySelector(".options"),this.chevron=this.shadowRoot.querySelector(".toggle"),this.selection=this.shadowRoot.querySelector(".selection"),this.previousOption,this.isOpen=!1,this.slideDown=[{transform:"translateY(-0.5rem)",opacity:0},{transform:"translateY(0)",opacity:1}],this.slideUp=[{transform:"translateY(0)",opacity:1},{transform:"translateY(-0.5rem)",opacity:0}],this.animationOptions={duration:300,fill:"forwards",easing:"ease"}}static get observedAttributes(){return["value","disabled"]}get value(){return this.getAttribute("value")}set value(t){this.setAttribute("value",t)}reset(){}open(){this.optionList.classList.remove("hide"),this.optionList.animate(this.slideDown,this.animationOptions),this.chevron.classList.add("rotate"),this.isOpen=!0}collapse(){this.chevron.classList.remove("rotate"),this.optionList.animate(this.slideUp,this.animationOptions).onfinish=(()=>{this.optionList.classList.add("hide"),this.isOpen=!1})}toggle(){this.isOpen||this.hasAttribute("disabled")?this.collapse():this.open()}handleSelectKeyDown(t){"ArrowDown"===t.code||"ArrowRight"===t.code?(t.preventDefault(),this.availableOptions[0].focus()):"Enter"!==t.code&&"Space"!==t.code||(this.isOpen?this.collapse():(this.optionList.classList.remove("hide"),this.optionList.animate(this.slideDown,this.animationOptions),this.chevron.classList.add("rotate"),this.isOpen=!0))}handleOptionsKeyDown(t){"ArrowUp"===t.code||"ArrowRight"===t.code?(t.preventDefault(),document.activeElement.previousElementSibling?document.activeElement.previousElementSibling.focus():this.availableOptions[this.availableOptions.length-1].focus()):"ArrowDown"!==t.code&&"ArrowLeft"!==t.code||(t.preventDefault(),document.activeElement.nextElementSibling?document.activeElement.nextElementSibling.focus():this.availableOptions[0].focus())}connectedCallback(){this.setAttribute("role","listbox"),this.hasAttribute("disabled")||this.selection.setAttribute("tabindex","0");let t=this.shadowRoot.querySelector("slot");t.addEventListener("slotchange",e=>{if(this.availableOptions=t.assignedElements(),this.availableOptions[0]){let t=this.availableOptions[0];this.previousOption=t,t.classList.add("check-selected"),this.setAttribute("value",t.getAttribute("value")),this.shadowRoot.querySelector(".option-text").textContent=t.textContent,this.availableOptions.forEach((t,e)=>{t.setAttribute("tabindex","0")})}}),this.selection.addEventListener("click",this.toggle),this.selection.addEventListener("keydown",this.handleSelectKeyDown),this.optionList.addEventListener("keydown",this.handleOptionsKeyDown),this.addEventListener("optionSelected",t=>{this.previousOption!==t.target&&(this.setAttribute("value",t.detail.value),this.shadowRoot.querySelector(".option-text").textContent=t.detail.text,this.dispatchEvent(new CustomEvent("change",{bubbles:!0,composed:!0,detail:{value:t.detail.value}})),this.previousOption&&this.previousOption.classList.remove("check-selected"),this.previousOption=t.target),t.detail.switching||this.collapse(),t.target.classList.add("check-selected")}),document.addEventListener("mousedown",t=>{this.isOpen&&!this.contains(t.target)&&this.collapse()})}attributeChangedCallback(t,e,n){"disabled"===t&&(this.hasAttribute("disabled")?this.selection.removeAttribute("tabindex"):this.selection.setAttribute("tabindex","0"))}disconnectedCallback(){this.selection.removeEventListener("click",this.toggle),this.selection.removeEventListener("keydown",this.handleSelectKeyDown),this.optionList.removeEventListener("keydown",this.handleOptionsKeyDown)}});const smOption=document.createElement("template");smOption.innerHTML='\n\n
\n \n \n \n \n
',customElements.define("sm-option",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smOption.content.cloneNode(!0)),this.sendDetails=this.sendDetails.bind(this)}sendDetails(t){let e=new CustomEvent("optionSelected",{bubbles:!0,composed:!0,detail:{text:this.textContent,value:this.getAttribute("value"),switching:t}});this.dispatchEvent(e)}connectedCallback(){this.setAttribute("role","option");let t=["ArrowUp","ArrowDown","ArrowLeft","ArrowRight"];this.addEventListener("click",this.sendDetails),this.addEventListener("keyup",e=>{"Enter"!==e.code&&"Space"!==e.code||(e.preventDefault(),this.sendDetails(!1)),t.includes(e.code)&&(e.preventDefault(),this.sendDetails(!0))}),this.hasAttribute("default")&&setTimeout(()=>{this.sendDetails()},0)}}); \ No newline at end of file diff --git a/components/dist/theme-toggle.js b/components/dist/theme-toggle.js new file mode 100644 index 0000000..c0fe31c --- /dev/null +++ b/components/dist/theme-toggle.js @@ -0,0 +1,178 @@ +const themeToggle = document.createElement('template') +themeToggle.innerHTML = ` + + +` + +class ThemeToggle extends HTMLElement { + constructor() { + super(); + + this.attachShadow({ + mode: 'open' + }).append(themeToggle.content.cloneNode(true)) + + this.isChecked = false + this.hasTheme = 'light' + + this.toggleState = this.toggleState.bind(this) + this.fireEvent = this.fireEvent.bind(this) + this.handleThemeChange = this.handleThemeChange.bind(this) + } + static get observedAttributes() { + return ['checked']; + } + + daylight() { + this.hasTheme = 'light' + document.body.dataset.theme = 'light' + } + + nightlight() { + this.hasTheme = 'dark' + document.body.dataset.theme = 'dark' + } + + toggleState() { + this.toggleAttribute('checked') + this.fireEvent() + } + handleKeyDown(e) { + if (e.code === 'Space') { + this.toggleState() + } + } + handleThemeChange(e) { + if (e.detail.theme !== this.hasTheme) { + if (e.detail.theme === 'dark') { + this.setAttribute('checked', '') + } + else { + this.removeAttribute('checked') + } + } + } + + fireEvent() { + this.dispatchEvent( + new CustomEvent('themechange', { + bubbles: true, + composed: true, + detail: { + theme: this.hasTheme + } + }) + ) + } + + connectedCallback() { + this.setAttribute('role', 'switch') + this.setAttribute('aria-label', 'theme toggle') + if (localStorage.theme === "dark") { + this.nightlight(); + this.setAttribute('checked', '') + } else if (localStorage.theme === "light") { + this.daylight(); + this.removeAttribute('checked') + } + else { + if (window.matchMedia(`(prefers-color-scheme: dark)`).matches) { + this.nightlight(); + this.setAttribute('checked', '') + } else { + this.daylight(); + this.removeAttribute('checked') + } + } + this.addEventListener("click", this.toggleState); + this.addEventListener("keydown", this.handleKeyDown); + document.addEventListener('themechange', this.handleThemeChange) + } + + disconnectedCallback() { + this.removeEventListener("click", this.toggleState); + this.removeEventListener("keydown", this.handleKeyDown); + document.removeEventListener('themechange', this.handleThemeChange) + } + + attributeChangedCallback(name, oldVal, newVal) { + if (name === 'checked') { + if (this.hasAttribute('checked')) { + this.nightlight(); + localStorage.setItem("theme", "dark"); + } else { + this.daylight(); + localStorage.setItem("theme", "light"); + } + } + } +} + +window.customElements.define('theme-toggle', ThemeToggle); \ No newline at end of file diff --git a/components/dist/theme-toggle.min.js b/components/dist/theme-toggle.min.js new file mode 100644 index 0000000..792a7ce --- /dev/null +++ b/components/dist/theme-toggle.min.js @@ -0,0 +1 @@ +const themeToggle=document.createElement("template");themeToggle.innerHTML='\n \n \n';class ThemeToggle extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(themeToggle.content.cloneNode(!0)),this.isChecked=!1,this.hasTheme="light",this.toggleState=this.toggleState.bind(this),this.fireEvent=this.fireEvent.bind(this),this.handleThemeChange=this.handleThemeChange.bind(this)}static get observedAttributes(){return["checked"]}daylight(){this.hasTheme="light",document.body.dataset.theme="light"}nightlight(){this.hasTheme="dark",document.body.dataset.theme="dark"}toggleState(){this.toggleAttribute("checked"),this.fireEvent()}handleKeyDown(e){"Space"===e.code&&this.toggleState()}handleThemeChange(e){e.detail.theme!==this.hasTheme&&("dark"===e.detail.theme?this.setAttribute("checked",""):this.removeAttribute("checked"))}fireEvent(){this.dispatchEvent(new CustomEvent("themechange",{bubbles:!0,composed:!0,detail:{theme:this.hasTheme}}))}connectedCallback(){this.setAttribute("role","switch"),this.setAttribute("aria-label","theme toggle"),"dark"===localStorage.theme?(this.nightlight(),this.setAttribute("checked","")):"light"===localStorage.theme?(this.daylight(),this.removeAttribute("checked")):window.matchMedia("(prefers-color-scheme: dark)").matches?(this.nightlight(),this.setAttribute("checked","")):(this.daylight(),this.removeAttribute("checked")),this.addEventListener("click",this.toggleState),this.addEventListener("keydown",this.handleKeyDown),document.addEventListener("themechange",this.handleThemeChange)}disconnectedCallback(){this.removeEventListener("click",this.toggleState),this.removeEventListener("keydown",this.handleKeyDown),document.removeEventListener("themechange",this.handleThemeChange)}attributeChangedCallback(e,t,n){"checked"===e&&(this.hasAttribute("checked")?(this.nightlight(),localStorage.setItem("theme","dark")):(this.daylight(),localStorage.setItem("theme","light")))}}window.customElements.define("theme-toggle",ThemeToggle); \ No newline at end of file diff --git a/components/index.html b/components/index.html index 5a2e378..0bffbf4 100644 --- a/components/index.html +++ b/components/index.html @@ -28,22 +28,7 @@

SM Components

- +

Getting Started

@@ -282,7 +267,7 @@ touch enabled devices swipe can be used.

Interactive demo

- +

Title

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Provident, optio.

@@ -525,10 +510,9 @@

Interactive demo

- - + - Submit + Login

Supported functions

@@ -806,6 +790,10 @@

+
+

Theme toggle

+ +