diff --git a/components/assets/ham-menu-closed.png b/components/assets/ham-menu-closed.png
new file mode 100644
index 0000000..cbe542a
Binary files /dev/null and b/components/assets/ham-menu-closed.png differ
diff --git a/components/assets/ham-menu-open.png b/components/assets/ham-menu-open.png
new file mode 100644
index 0000000..1016ca8
Binary files /dev/null and b/components/assets/ham-menu-open.png differ
diff --git a/components/css/main.css b/components/css/main.css
index fe54639..2f23c56 100644
--- a/components/css/main.css
+++ b/components/css/main.css
@@ -96,7 +96,7 @@ ul {
display: grid;
gap: 1rem;
padding: 1rem;
- grid-template-columns: 12rem 1fr;
+ grid-template-columns: 11rem 1fr;
width: 100%;
}
.tr:nth-of-type(odd) {
@@ -414,6 +414,7 @@ code {
font-weight: 400;
padding: 0.2rem 0.4rem;
background: rgba(var(--text-color), 0.1);
+ color: rgba(255, 255, 255, 0.9);
}
code * {
@@ -565,6 +566,23 @@ strong.important {
margin-left: 0.5rem;
}
+.auto-grid-2 {
+ justify-content: center;
+ justify-items: center;
+ text-align: center;
+ grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
+}
+
+.screenshot {
+ object-fit: cover;
+ object-position: top;
+ height: 30rem;
+ width: min(16rem, 100%);
+ border-radius: 1rem;
+ justify-self: center;
+ box-shadow: 0 0.5rem 1.5rem -0.5rem rgba(0, 0, 0, 0.3), 0 0 0 0.3rem black;
+}
+
@media screen and (max-width: 640px) {
main {
grid-template-rows: auto 1fr;
diff --git a/components/css/main.min.css b/components/css/main.min.css
index 2b22b44..9dcfbbb 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{color:rgba(var(--text-color),1);background:rgba(var(--background-color),1)}body,body *{--accent-color:#0D7377;--text-color:17,17,17;--background-color:255,255,255;--danger-color:red}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 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,h2{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:#50CB93}.token.punctuation,.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:#FF6767}.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;border-radius:.5rem;background:rgba(0,0,0,.9)}code{border-radius:.3rem;font-weight:400;padding:.2rem .4rem;background:rgba(var(--text-color),.1)}code *{color:rgba(255,255,255,.9);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}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,sm-tab-header{margin-bottom:1.5rem}ol li,sm-carousel{margin-bottom:1rem}.list__item{padding:.8rem 1.5rem;text-transform:capitalize}.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)}.page{flex-direction:column;padding-bottom:3rem}ol{padding:.6rem 1rem;max-width:75ch}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){sm-popup{--width:32rem}#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,strong{max-width:65ch}p,pre{line-height:1.7}.screenshot,img{object-fit:cover}.highlight,button{display:inline-flex}.list,ul{list-style:none}.hide,.ripple{pointer-events:none}*{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{color:rgba(var(--text-color),1);background:rgba(var(--background-color),1)}body,body *{--accent-color:#0D7377;--text-color:17,17,17;--background-color:255,255,255;--danger-color:red}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}a{color:inherit;text-decoration:none}a:focus-visible{box-shadow:0 0 0 .1rem rgba(var(--text-color),1) inset}button{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:11rem 1fr;width:100%}.tr:nth-of-type(odd){background-color:rgba(var(--text-color),.04)}.tr p{min-width:30ch}.hide{opacity:0}.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,h2{text-transform:capitalize}.flex{display:flex}.grid,main{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}.auto-grid-2,.text-center{text-align:center}.align-start{align-items:flex-start}.align-center{align-items:center}.justify-start{justify-content:start}.auto-grid-2,.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}.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)}.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:#50CB93}.token.punctuation,.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:#FF6767}.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}code,code *{color:rgba(255,255,255,.9)}pre{max-width:100%;margin:1rem 0;padding:0 1.5rem;overflow-x:auto;font-size:.9rem;font-weight:500;white-space:pre;border-radius:.5rem;background:rgba(0,0,0,.9)}code{border-radius:.3rem;font-weight:400;padding:.2rem .4rem;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}main{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,sm-tab-header{margin-bottom:1.5rem}ol li,sm-carousel{margin-bottom:1rem}.list__item{padding:.8rem 1.5rem;text-transform:capitalize}.list__item--active{color:var(--accent-color);background:rgba(var(--text-color),.06)}.card{flex-direction:column;margin-right:1rem;border-radius:.4rem;padding:1.5rem;min-width:min(24rem,80%);background-color:rgba(var(--text-color),.06)}.page{flex-direction:column;padding-bottom:3rem}ol{padding:.6rem 1rem;max-width:75ch}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{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}.auto-grid-2{justify-items:center;grid-template-columns:repeat(auto-fill,minmax(18rem,1fr))}.screenshot{object-position:top;height:30rem;width:min(16rem,100%);border-radius:1rem;justify-self:center;box-shadow:0 .5rem 1.5rem -.5rem rgba(0,0,0,.3),0 0 0 .3rem #000}@media screen and (max-width:640px){main{grid-template-rows:auto 1fr;grid-template-columns:1fr}}@media screen and (min-width:640px){sm-popup{--width:32rem}#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 99af1b3..a538a5f 100644
--- a/components/css/main.scss
+++ b/components/css/main.scss
@@ -89,7 +89,7 @@ ul{
display: grid;
gap: 1rem;
padding: 1rem;
- grid-template-columns: 12rem 1fr;
+ grid-template-columns: 11rem 1fr;
width: 100%;
&:nth-of-type(odd){
background-color: rgba(var(--text-color), .04);
@@ -252,8 +252,6 @@ ul{
.observe-empty-state:not(:empty) ~ .empty-state{
display: none;
}
-
-
.icon{
width: 1.5rem;
height: 1.5rem;
@@ -360,6 +358,7 @@ code{
font-weight: 400;
padding: 0.2rem 0.4rem;
background: rgba(var(--text-color), .1);
+ color: rgba(255, 255, 255, 0.9);
}
code *{
color: rgba(255, 255, 255, 0.9);
@@ -491,6 +490,22 @@ strong.important{
.comp-checkbox__title{
margin-left: 0.5rem;
}
+.auto-grid-2{
+ justify-content: center;
+ justify-items: center;
+ text-align: center;
+ grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
+}
+.screenshot{
+ object-fit: cover;
+ object-position: top;
+ height: 30rem;
+ width: min(16rem, 100%);
+ border-radius: 1rem;
+ justify-self: center;
+ box-shadow: 0 0.5rem 1.5rem -0.5rem rgba(0,0,0, 0.3),
+ 0 0 0 0.3rem black;
+}
@media screen and (max-width: 640px){
main{
grid-template-rows: auto 1fr;
diff --git a/components/dist/carousel.js b/components/dist/carousel.js
index 86c1dd1..a2f6196 100644
--- a/components/dist/carousel.js
+++ b/components/dist/carousel.js
@@ -23,6 +23,10 @@ smCarousel.innerHTML = `
--nav-box-shadow: 0 0.2rem 0.2rem #00000020, 0 0.5rem 1rem #00000040;
--indicator-top: auto;
--indicator-bottom: -1.5rem;
+ --indicator-height: 0.2rem;
+ --indicator-width: 0.4rem;
+ --indicator-border-radius: 0.4rem;
+ --indicators-gap: 0.5rem;
--active-indicator-color: var(--accent-color);
}
.carousel__button{
@@ -39,7 +43,7 @@ smCarousel.innerHTML = `
-webkit-box-shadow: var(--nav-box-shadow);
box-shadow: var(--nav-box-shadow);
-webkit-tap-highlight-color: transparent;
- transition: transform 0.3s;
+ transition: transform 0.3s, opacity 0.3s;
z-index: 1;
border-radius: 3rem;
padding: 0.5rem;
@@ -96,22 +100,24 @@ button:focus-visible{
-ms-flex-pack: center;
justify-content: center;
position: absolute;
+ padding: 0.5rem 0;
top: var(--indicator-top);
bottom: var(--indicator-bottom);
- gap: 0.5rem;
+ gap: var(--indicators-gap);
width: 100%;
}
-.dot{
+.indicator{
position: relative;
- padding: 0.2rem;
+ height: var(--indicator-height);
+ width: var(--indicator-width);
background: rgba(var(--text-color), 0.3);
- border-radius: 1rem;
+ border-radius: var(--indicator-border-radius);
-webkit-transition: 0.2s;
-o-transition: 0.2s;
transition: 0.2s;
cursor: pointer;
}
-.dot.active{
+.indicator.active{
-webkit-transform: scale(1.5);
-ms-transform: scale(1.5);
transform: scale(1.5);
@@ -133,9 +139,24 @@ slot::slotted(*){
.carousel{
overflow: hidden;
}
+ .carousel__button{
+ opacity: 0.8;
+ }
+ :host(:hover) .carousel__button{
+ opacity: 1;
+ }
.left,.right{
display: none;
}
+ .indicators{
+ transition: gap 0.3s;
+ }
+ .indicators:hover{
+ gap: calc(var(--indicators-gap) * 2);
+ }
+ .indicators:hover .indicator{
+ transform: scale(2);
+ }
}
@media (hover: none){
::-webkit-scrollbar-track {
@@ -252,15 +273,15 @@ customElements.define('sm-carousel', class extends HTMLElement {
}
createIndicator(index) {
- let dot = document.createElement('div')
- dot.classList.add('dot')
- dot.dataset.rank = index
- return dot
+ let indicator = document.createElement('div')
+ indicator.classList.add('indicator')
+ indicator.dataset.rank = index
+ return indicator
}
handleIndicatorClick(e) {
- if (e.target.closest('.dot')) {
- const slideNum = parseInt(e.target.closest('.dot').dataset.rank)
+ if (e.target.closest('.indicator')) {
+ const slideNum = parseInt(e.target.closest('.indicator').dataset.rank)
if (this.activeSlideNum !== slideNum) {
this.showSlide(slideNum)
}
diff --git a/components/dist/carousel.min.js b/components/dist/carousel.min.js
index 99d3c9c..fff5728 100644
--- a/components/dist/carousel.min.js
+++ b/components/dist/carousel.min.js
@@ -1 +1 @@
-const smCarousel=document.createElement("template");smCarousel.innerHTML='\n\n
\n
\n \n \n
\n \n
\n
\n \n \n
\n
\n',customElements.define("sm-carousel",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smCarousel.content.cloneNode(!0)),this.isAutoPlaying=!1,this.autoPlayInterval=5e3,this.autoPlayTimeout,this.initialTimeout,this.activeSlideNum=0,this.carouselItems,this.indicators,this.showIndicator=!1,this.carousel=this.shadowRoot.querySelector(".carousel"),this.carouselContainer=this.shadowRoot.querySelector(".carousel-container"),this.carouselSlot=this.shadowRoot.querySelector("slot"),this.navButtonRight=this.shadowRoot.querySelector(".carousel__button--right"),this.navButtonLeft=this.shadowRoot.querySelector(".carousel__button--left"),this.indicatorsContainer=this.shadowRoot.querySelector(".indicators"),this.scrollLeft=this.scrollLeft.bind(this),this.scrollRight=this.scrollRight.bind(this),this.handleIndicatorClick=this.handleIndicatorClick.bind(this),this.showSlide=this.showSlide.bind(this),this.nextSlide=this.nextSlide.bind(this),this.autoPlay=this.autoPlay.bind(this),this.startAutoPlay=this.startAutoPlay.bind(this),this.stopAutoPlay=this.stopAutoPlay.bind(this)}static get observedAttributes(){return["indicator","autoplay","interval"]}scrollLeft(){this.carousel.scrollBy({left:-this.scrollDistance,behavior:"smooth"})}scrollRight(){this.carousel.scrollBy({left:this.scrollDistance,behavior:"smooth"})}showSlide(t){this.carousel.scrollTo({left:this.carouselItems[t].getBoundingClientRect().left-this.carousel.getBoundingClientRect().left+this.carousel.scrollLeft,behavior:"smooth"})}nextSlide(){if(!this.carouselItems)return;let t=this.activeSlideNum+1{this.autoPlay()},this.autoPlayInterval))}startAutoPlay(){this.setAttribute("autoplay","")}stopAutoPlay(){this.removeAttribute("autoplay")}createIndicator(t){let n=document.createElement("div");return n.classList.add("dot"),n.dataset.rank=t,n}handleIndicatorClick(t){if(t.target.closest(".dot")){const n=parseInt(t.target.closest(".dot").dataset.rank);this.activeSlideNum!==n&&this.showSlide(n)}}handleKeyDown(t){"ArrowLeft"===t.code?this.scrollRight():"ArrowRight"===t.code&&this.scrollRight()}connectedCallback(){let t=document.createDocumentFragment();this.carouselSlot.addEventListener("slotchange",n=>{this.carouselItems=this.carouselSlot.assignedElements(),this.carouselItems.forEach(t=>e.observe(t)),this.carouselItems.length>0?(i.observe(this.carouselItems[0]),o.observe(this.carouselItems[this.carouselItems.length-1])):(navButtonLeft.classList.add("hide"),navButtonRight.classList.add("hide"),i.disconnect(),o.disconnect()),this.showIndicator&&(this.indicatorsContainer.innerHTML="",this.carouselItems.forEach((n,e)=>{t.append(this.createIndicator(e)),n.dataset.rank=e}),this.indicatorsContainer.append(t),this.indicators=this.indicatorsContainer.children)});const n={threshold:.9,root:this},e=new IntersectionObserver(t=>{t.forEach(t=>{if(this.showIndicator){const n=parseInt(t.target.dataset.rank);t.isIntersecting?(this.indicators[n].classList.add("active"),this.activeSlideNum=n):this.indicators[n].classList.remove("active")}})},n),i=new IntersectionObserver(t=>{t.forEach(t=>{t.isIntersecting?this.navButtonLeft.classList.add("hide"):this.navButtonLeft.classList.remove("hide")})},n),o=new IntersectionObserver(t=>{t.forEach(t=>{t.isIntersecting?this.navButtonRight.classList.add("hide"):this.navButtonRight.classList.remove("hide")})},n),s=new ResizeObserver(t=>{t.forEach(t=>{if(t.contentBoxSize){const n=Array.isArray(t.contentBoxSize)?t.contentBoxSize[0]:t.contentBoxSize;this.scrollDistance=.6*n.inlineSize}else this.scrollDistance=.6*t.contentRect.width})});s.observe(this),this.addEventListener("keydown",this.handleKeyDown),this.navButtonRight.addEventListener("click",this.scrollRight),this.navButtonLeft.addEventListener("click",this.scrollLeft),this.indicatorsContainer.addEventListener("click",this.handleIndicatorClick)}attributeChangedCallback(t,n,e){n!==e&&("indicator"===t&&(this.showIndicator=this.hasAttribute("indicator")),"autoplay"===t&&(this.hasAttribute("autoplay")?this.initialTimeout=setTimeout(()=>{this.isAutoPlaying=!0,this.autoPlay()},this.autoPlayInterval):(this.isAutoPlaying=!1,clearTimeout(this.autoPlayTimeout),clearTimeout(this.initialTimeout))),"interval"===t&&(this.hasAttribute("interval")&&""!==this.getAttribute("interval").trim()?this.autoPlayInterval=Math.abs(parseInt(this.getAttribute("interval").trim())):this.autoPlayInterval=5e3))}disconnectedCallback(){this.navButtonRight.removeEventListener("click",this.scrollRight),this.navButtonLeft.removeEventListener("click",this.scrollLeft),this.indicatorsContainer.removeEventListener("click",this.handleIndicatorClick)}});
\ No newline at end of file
+const smCarousel=document.createElement("template");smCarousel.innerHTML='\n\n\n
\n \n \n
\n \n
\n
\n \n \n
\n
\n',customElements.define("sm-carousel",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smCarousel.content.cloneNode(!0)),this.isAutoPlaying=!1,this.autoPlayInterval=5e3,this.autoPlayTimeout,this.initialTimeout,this.activeSlideNum=0,this.carouselItems,this.indicators,this.showIndicator=!1,this.carousel=this.shadowRoot.querySelector(".carousel"),this.carouselContainer=this.shadowRoot.querySelector(".carousel-container"),this.carouselSlot=this.shadowRoot.querySelector("slot"),this.navButtonRight=this.shadowRoot.querySelector(".carousel__button--right"),this.navButtonLeft=this.shadowRoot.querySelector(".carousel__button--left"),this.indicatorsContainer=this.shadowRoot.querySelector(".indicators"),this.scrollLeft=this.scrollLeft.bind(this),this.scrollRight=this.scrollRight.bind(this),this.handleIndicatorClick=this.handleIndicatorClick.bind(this),this.showSlide=this.showSlide.bind(this),this.nextSlide=this.nextSlide.bind(this),this.autoPlay=this.autoPlay.bind(this),this.startAutoPlay=this.startAutoPlay.bind(this),this.stopAutoPlay=this.stopAutoPlay.bind(this)}static get observedAttributes(){return["indicator","autoplay","interval"]}scrollLeft(){this.carousel.scrollBy({left:-this.scrollDistance,behavior:"smooth"})}scrollRight(){this.carousel.scrollBy({left:this.scrollDistance,behavior:"smooth"})}showSlide(t){this.carousel.scrollTo({left:this.carouselItems[t].getBoundingClientRect().left-this.carousel.getBoundingClientRect().left+this.carousel.scrollLeft,behavior:"smooth"})}nextSlide(){if(!this.carouselItems)return;let t=this.activeSlideNum+1{this.autoPlay()},this.autoPlayInterval))}startAutoPlay(){this.setAttribute("autoplay","")}stopAutoPlay(){this.removeAttribute("autoplay")}createIndicator(t){let n=document.createElement("div");return n.classList.add("indicator"),n.dataset.rank=t,n}handleIndicatorClick(t){if(t.target.closest(".indicator")){const n=parseInt(t.target.closest(".indicator").dataset.rank);this.activeSlideNum!==n&&this.showSlide(n)}}handleKeyDown(t){"ArrowLeft"===t.code?this.scrollRight():"ArrowRight"===t.code&&this.scrollRight()}connectedCallback(){let t=document.createDocumentFragment();this.carouselSlot.addEventListener("slotchange",n=>{this.carouselItems=this.carouselSlot.assignedElements(),this.carouselItems.forEach(t=>i.observe(t)),this.carouselItems.length>0?(o.observe(this.carouselItems[0]),e.observe(this.carouselItems[this.carouselItems.length-1])):(navButtonLeft.classList.add("hide"),navButtonRight.classList.add("hide"),o.disconnect(),e.disconnect()),this.showIndicator&&(this.indicatorsContainer.innerHTML="",this.carouselItems.forEach((n,i)=>{t.append(this.createIndicator(i)),n.dataset.rank=i}),this.indicatorsContainer.append(t),this.indicators=this.indicatorsContainer.children)});const n={threshold:.9,root:this},i=new IntersectionObserver(t=>{t.forEach(t=>{if(this.showIndicator){const n=parseInt(t.target.dataset.rank);t.isIntersecting?(this.indicators[n].classList.add("active"),this.activeSlideNum=n):this.indicators[n].classList.remove("active")}})},n),o=new IntersectionObserver(t=>{t.forEach(t=>{t.isIntersecting?this.navButtonLeft.classList.add("hide"):this.navButtonLeft.classList.remove("hide")})},n),e=new IntersectionObserver(t=>{t.forEach(t=>{t.isIntersecting?this.navButtonRight.classList.add("hide"):this.navButtonRight.classList.remove("hide")})},n),s=new ResizeObserver(t=>{t.forEach(t=>{if(t.contentBoxSize){const n=Array.isArray(t.contentBoxSize)?t.contentBoxSize[0]:t.contentBoxSize;this.scrollDistance=.6*n.inlineSize}else this.scrollDistance=.6*t.contentRect.width})});s.observe(this),this.addEventListener("keydown",this.handleKeyDown),this.navButtonRight.addEventListener("click",this.scrollRight),this.navButtonLeft.addEventListener("click",this.scrollLeft),this.indicatorsContainer.addEventListener("click",this.handleIndicatorClick)}attributeChangedCallback(t,n,i){n!==i&&("indicator"===t&&(this.showIndicator=this.hasAttribute("indicator")),"autoplay"===t&&(this.hasAttribute("autoplay")?this.initialTimeout=setTimeout(()=>{this.isAutoPlaying=!0,this.autoPlay()},this.autoPlayInterval):(this.isAutoPlaying=!1,clearTimeout(this.autoPlayTimeout),clearTimeout(this.initialTimeout))),"interval"===t&&(this.hasAttribute("interval")&&""!==this.getAttribute("interval").trim()?this.autoPlayInterval=Math.abs(parseInt(this.getAttribute("interval").trim())):this.autoPlayInterval=5e3))}disconnectedCallback(){this.navButtonRight.removeEventListener("click",this.scrollRight),this.navButtonLeft.removeEventListener("click",this.scrollLeft),this.indicatorsContainer.removeEventListener("click",this.handleIndicatorClick)}});
\ No newline at end of file
diff --git a/components/dist/menu.js b/components/dist/menu.js
index e9b8ee1..fdbdfc8 100644
--- a/components/dist/menu.js
+++ b/components/dist/menu.js
@@ -6,12 +6,16 @@ smMenu.innerHTML = `
margin: 0;
-webkit-box-sizing: border-box;
box-sizing: border-box;
-}
+}
+:host{
+ display: -webkit-inline-box;
+ display: -ms-inline-flexbox;
+ display: inline-flex;
+}
.menu{
display: -ms-grid;
display: grid;
place-items: center;
- position: relative;
height: 2rem;
width: 2rem;
outline: none;
@@ -27,16 +31,6 @@ smMenu.innerHTML = `
-o-transition: background 0.3s;
transition: background 0.3s;
}
-:host{
- display: -webkit-inline-box;
- display: -ms-inline-flexbox;
- display: inline-flex;
-}
-.hide{
- opacity: 0;
- pointer-events: none;
- user-select: none;
-}
.select{
position: relative;
display: -webkit-box;
@@ -70,42 +64,29 @@ smMenu.innerHTML = `
min-width: -webkit-max-content;
min-width: -moz-max-content;
min-width: max-content;
- -webkit-transform: translateY(-1rem);
- -ms-transform: translateY(-1rem);
- transform: translateY(-1rem);
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
background: rgba(var(--background-color), 1);
- -webkit-transition: opacity 0.3s, -webkit-transform 0.3s;
- transition: opacity 0.3s, -webkit-transform 0.3s;
- -o-transition: opacity 0.3s, transform 0.3s;
- transition: opacity 0.3s, transform 0.3s;
- transition: opacity 0.3s, transform 0.3s, -webkit-transform 0.3s;
- border: solid 1px rgba(var(--text-color), 0.2);
border-radius: 0.3rem;
z-index: 1;
- -webkit-box-shadow: 0.4rem 0.8rem 1.2rem #00000030;
- box-shadow: 0.4rem 0.8rem 1.2rem #00000030;
- top: 100%;
+ -webkit-box-shadow: 0 0.5rem 1.5rem -0.5rem rgba(0,0,0,0.3);
+ box-shadow: 0 0.5rem 1.5rem -0.5rem rgba(0,0,0,0.3);
bottom: auto;
}
-.moveUp{
- top: auto;
- bottom: 100%;
- -webkit-transform: translateY(3rem);
- -ms-transform: translateY(3rem);
- transform: translateY(3rem);
+.hide{
+ display: none;
}
-.moveLeft{
- left: auto;
- right: 0;
-}
-.no-transformations{
- -webkit-transform: none !important;
- -ms-transform: none !important;
- transform: none !important;
+@media screen and (max-width: 640px){
+ .options{
+ position: fixed;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ top: auto;
+ border-radius: 0.5rem 0.5rem 0 0;
+ }
}
@media (hover: hover){
.menu:hover .icon{
@@ -128,15 +109,24 @@ customElements.define('sm-menu', class extends HTMLElement {
mode: 'open'
}).append(smMenu.content.cloneNode(true))
- this.open = false;
+ this.isOpen = false;
this.availableOptions
this.containerDimensions
+ this.animOptions = {
+ duration: 200,
+ easing: 'ease'
+ }
+
this.optionList = this.shadowRoot.querySelector('.options')
this.menu = this.shadowRoot.querySelector('.menu')
this.icon = this.shadowRoot.querySelector('.icon')
this.expand = this.expand.bind(this)
-
+ this.collapse = this.collapse.bind(this)
+ this.toggle = this.toggle.bind(this)
+ this.handleKeyDown = this.handleKeyDown.bind(this)
+ this.handleClickoutSide = this.handleClickoutSide.bind(this)
+
}
static get observedAttributes() {
return ['value']
@@ -147,58 +137,64 @@ customElements.define('sm-menu', class extends HTMLElement {
set value(val) {
this.setAttribute('value', val)
}
- expand(){
- if (!this.open) {
+ expand() {
+ if (!this.isOpen) {
this.optionList.classList.remove('hide')
- this.optionList.classList.add('no-transformations')
- this.open = true
- this.icon.classList.add('focused')
- this.availableOptions.forEach(option => {
- option.setAttribute('tabindex', '0')
- })
+ this.optionList.animate([
+ {
+ transform: window.innerWidth < 640 ? 'translateY(1.5rem)' : 'translateY(-1rem)',
+ opacity: '0'
+ },
+ {
+ transform: 'none',
+ opacity: '1'
+ },
+ ], this.animOptions)
+ .onfinish = () => {
+ this.isOpen = true
+ this.icon.classList.add('focused')
+ }
}
}
collapse() {
- if (this.open) {
- this.open = false
- this.icon.classList.remove('focused')
- this.optionList.classList.add('hide')
- this.optionList.classList.remove('no-transformations')
- this.availableOptions.forEach(option => {
- option.removeAttribute('tabindex')
- })
+ if (this.isOpen) {
+ this.optionList.animate([
+ {
+ transform: 'none',
+ opacity: '1'
+ },
+ {
+ transform: window.innerWidth < 640 ? 'translateY(1.5rem)' : 'translateY(-1rem)',
+ opacity: '0'
+ },
+ ], this.animOptions)
+ .onfinish = () => {
+ this.isOpen = false
+ this.icon.classList.remove('focused')
+ this.optionList.classList.add('hide')
+ }
}
}
- connectedCallback() {
- this.setAttribute('role', 'listbox')
- const slot = this.shadowRoot.querySelector('.options slot')
- slot.addEventListener('slotchange', e => {
- this.availableOptions = slot.assignedElements()
- this.containerDimensions = this.optionList.getBoundingClientRect()
- });
- this.menu.addEventListener('click', e => {
- if (!this.open) {
- this.expand()
- } else {
- this.collapse()
- }
- })
- this.menu.addEventListener('keydown', e => {
- if (e.code === 'ArrowDown' || e.code === 'ArrowRight') {
+ toggle() {
+ if (!this.isOpen) {
+ this.expand()
+ } else {
+ this.collapse()
+ }
+ }
+ handleKeyDown(e) {
+ // If key is pressed on menu button
+ if (e.target === this) {
+ if (e.code === 'ArrowDown') {
e.preventDefault()
this.availableOptions[0].focus()
}
- if (e.code === 'Enter' || e.code === 'Space') {
+ else if (e.code === 'Enter' || e.code === 'Space') {
e.preventDefault()
- if (!this.open) {
- this.expand()
- } else {
- this.collapse()
- }
+ this.toggle()
}
- })
- this.optionList.addEventListener('keydown', e => {
- if (e.code === 'ArrowUp' || e.code === 'ArrowRight') {
+ } else { // If mey is pressed over menu options
+ if (e.code === 'ArrowUp') {
e.preventDefault()
if (document.activeElement.previousElementSibling) {
document.activeElement.previousElementSibling.focus()
@@ -206,23 +202,41 @@ customElements.define('sm-menu', class extends HTMLElement {
this.availableOptions[this.availableOptions.length - 1].focus()
}
}
- if (e.code === 'ArrowDown' || e.code === 'ArrowLeft') {
+ else if (e.code === 'ArrowDown') {
e.preventDefault()
if (document.activeElement.nextElementSibling) {
document.activeElement.nextElementSibling.focus()
- } else{
+ } else {
this.availableOptions[0].focus()
}
}
- })
- this.optionList.addEventListener('click', e => {
- this.collapse()
- })
- window.addEventListener('mousedown', e => {
- if (!this.contains(e.target) && e.button !== 2) {
- this.collapse()
+ else if (e.code === 'Enter' || e.code === 'Space') {
+ e.preventDefault()
+ e.target.click()
}
- })
+ }
+ }
+ handleClickoutSide(e) {
+ if (!this.contains(e.target) && e.button !== 2) {
+ this.collapse()
+ }
+ }
+ connectedCallback() {
+ this.setAttribute('role', 'listbox')
+ this.setAttribute('aria-label', 'dropdown menu')
+ const slot = this.shadowRoot.querySelector('.options slot')
+ slot.addEventListener('slotchange', e => {
+ this.availableOptions = e.target.assignedElements()
+ this.containerDimensions = this.optionList.getBoundingClientRect()
+ });
+ this.addEventListener('click', this.toggle)
+ this.addEventListener('keydown', this.handleKeyDown)
+ document.addEventListener('mousedown', this.handleClickoutSide)
+ }
+ disconnectedCallback() {
+ this.removeEventListener('click', this.toggle)
+ this.removeEventListener('keydown', this.handleKeyDown)
+ document.removeEventListener('mousedown', this.handleClickoutSide)
}
})
@@ -262,7 +276,10 @@ menuOption.innerHTML = `
outline: none;
background: rgba(var(--text-color), 0.1);
}
-@media (hover: hover){
+@media (any-hover: hover){
+ :host{
+ --padding: 0.8rem 1.6rem;
+ }
.option:hover{
background: rgba(var(--text-color), 0.1);
}
diff --git a/components/dist/menu.min.js b/components/dist/menu.min.js
index 4e7966c..606b807 100644
--- a/components/dist/menu.min.js
+++ b/components/dist/menu.min.js
@@ -1 +1 @@
-const smMenu=document.createElement("template");smMenu.innerHTML='\n\n',customElements.define("sm-menu",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smMenu.content.cloneNode(!0)),this.open=!1,this.availableOptions,this.containerDimensions,this.optionList=this.shadowRoot.querySelector(".options"),this.menu=this.shadowRoot.querySelector(".menu"),this.icon=this.shadowRoot.querySelector(".icon"),this.expand=this.expand.bind(this)}static get observedAttributes(){return["value"]}get value(){return this.getAttribute("value")}set value(n){this.setAttribute("value",n)}expand(){this.open||(this.optionList.classList.remove("hide"),this.optionList.classList.add("no-transformations"),this.open=!0,this.icon.classList.add("focused"),this.availableOptions.forEach(n=>{n.setAttribute("tabindex","0")}))}collapse(){this.open&&(this.open=!1,this.icon.classList.remove("focused"),this.optionList.classList.add("hide"),this.optionList.classList.remove("no-transformations"),this.availableOptions.forEach(n=>{n.removeAttribute("tabindex")}))}connectedCallback(){this.setAttribute("role","listbox");const n=this.shadowRoot.querySelector(".options slot");n.addEventListener("slotchange",t=>{this.availableOptions=n.assignedElements(),this.containerDimensions=this.optionList.getBoundingClientRect()}),this.menu.addEventListener("click",n=>{this.open?this.collapse():this.expand()}),this.menu.addEventListener("keydown",n=>{"ArrowDown"!==n.code&&"ArrowRight"!==n.code||(n.preventDefault(),this.availableOptions[0].focus()),"Enter"!==n.code&&"Space"!==n.code||(n.preventDefault(),this.open?this.collapse():this.expand())}),this.optionList.addEventListener("keydown",n=>{"ArrowUp"!==n.code&&"ArrowRight"!==n.code||(n.preventDefault(),document.activeElement.previousElementSibling?document.activeElement.previousElementSibling.focus():this.availableOptions[this.availableOptions.length-1].focus()),"ArrowDown"!==n.code&&"ArrowLeft"!==n.code||(n.preventDefault(),document.activeElement.nextElementSibling?document.activeElement.nextElementSibling.focus():this.availableOptions[0].focus())}),this.optionList.addEventListener("click",n=>{this.collapse()}),window.addEventListener("mousedown",n=>{this.contains(n.target)||2===n.button||this.collapse()})}});const menuOption=document.createElement("template");menuOption.innerHTML='\n\n\n \n
',customElements.define("menu-option",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(menuOption.content.cloneNode(!0))}connectedCallback(){this.setAttribute("role","option"),this.addEventListener("keyup",n=>{"Enter"!==n.code&&"Space"!==n.code||(n.preventDefault(),this.click())})}});
\ No newline at end of file
+const smMenu=document.createElement("template");smMenu.innerHTML='\n\n',customElements.define("sm-menu",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smMenu.content.cloneNode(!0)),this.isOpen=!1,this.availableOptions,this.containerDimensions,this.animOptions={duration:200,easing:"ease"},this.optionList=this.shadowRoot.querySelector(".options"),this.menu=this.shadowRoot.querySelector(".menu"),this.icon=this.shadowRoot.querySelector(".icon"),this.expand=this.expand.bind(this),this.collapse=this.collapse.bind(this),this.toggle=this.toggle.bind(this),this.handleKeyDown=this.handleKeyDown.bind(this),this.handleClickoutSide=this.handleClickoutSide.bind(this)}static get observedAttributes(){return["value"]}get value(){return this.getAttribute("value")}set value(n){this.setAttribute("value",n)}expand(){this.isOpen||(this.optionList.classList.remove("hide"),this.optionList.animate([{transform:window.innerWidth<640?"translateY(1.5rem)":"translateY(-1rem)",opacity:"0"},{transform:"none",opacity:"1"}],this.animOptions).onfinish=(()=>{this.isOpen=!0,this.icon.classList.add("focused")}))}collapse(){this.isOpen&&(this.optionList.animate([{transform:"none",opacity:"1"},{transform:window.innerWidth<640?"translateY(1.5rem)":"translateY(-1rem)",opacity:"0"}],this.animOptions).onfinish=(()=>{this.isOpen=!1,this.icon.classList.remove("focused"),this.optionList.classList.add("hide")}))}toggle(){this.isOpen?this.collapse():this.expand()}handleKeyDown(n){n.target===this?"ArrowDown"===n.code?(n.preventDefault(),this.availableOptions[0].focus()):"Enter"!==n.code&&"Space"!==n.code||(n.preventDefault(),this.toggle()):"ArrowUp"===n.code?(n.preventDefault(),document.activeElement.previousElementSibling?document.activeElement.previousElementSibling.focus():this.availableOptions[this.availableOptions.length-1].focus()):"ArrowDown"===n.code?(n.preventDefault(),document.activeElement.nextElementSibling?document.activeElement.nextElementSibling.focus():this.availableOptions[0].focus()):"Enter"!==n.code&&"Space"!==n.code||(n.preventDefault(),n.target.click())}handleClickoutSide(n){this.contains(n.target)||2===n.button||this.collapse()}connectedCallback(){this.setAttribute("role","listbox"),this.setAttribute("aria-label","dropdown menu");const n=this.shadowRoot.querySelector(".options slot");n.addEventListener("slotchange",n=>{this.availableOptions=n.target.assignedElements(),this.containerDimensions=this.optionList.getBoundingClientRect()}),this.addEventListener("click",this.toggle),this.addEventListener("keydown",this.handleKeyDown),document.addEventListener("mousedown",this.handleClickoutSide)}disconnectedCallback(){this.removeEventListener("click",this.toggle),this.removeEventListener("keydown",this.handleKeyDown),document.removeEventListener("mousedown",this.handleClickoutSide)}});const menuOption=document.createElement("template");menuOption.innerHTML='\n\n\n \n
',customElements.define("menu-option",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(menuOption.content.cloneNode(!0))}connectedCallback(){this.setAttribute("role","option"),this.addEventListener("keyup",n=>{"Enter"!==n.code&&"Space"!==n.code||(n.preventDefault(),this.click())})}});
\ No newline at end of file
diff --git a/components/dist/tabs.js b/components/dist/tabs.js
index 7472688..a712daf 100644
--- a/components/dist/tabs.js
+++ b/components/dist/tabs.js
@@ -14,6 +14,7 @@ smTabHeader.innerHTML = `
--accent-color: #4d2588;
--text-color: 17, 17, 17;
--background-color: 255, 255, 255;
+ --tab-indicator-border-radius: 0.3rem;
}
.tabs{
position: relative;
@@ -50,10 +51,7 @@ smTabHeader.innerHTML = `
}
:host([variant="tab"]) .indicator{
height: 100%;
- border-radius: 0.3rem;
- }
- :host(.round) .indicator{
- border-radius: 3rem;
+ border-radius: var(--tab-indicator-border-radius);
}
:host([variant="tab"]) .tab-header{
border-bottom: none;
diff --git a/components/dist/tabs.min.js b/components/dist/tabs.min.js
index b0e82e2..82d6ba2 100644
--- a/components/dist/tabs.min.js
+++ b/components/dist/tabs.min.js
@@ -1 +1 @@
-const smTabHeader=document.createElement("template");smTabHeader.innerHTML='\n\n\n \n
\n',customElements.define("sm-tab-header",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smTabHeader.content.cloneNode(!0)),this.prevTab,this.allTabs,this.activeTab,this.indicator=this.shadowRoot.querySelector(".indicator"),this.tabSlot=this.shadowRoot.querySelector("slot"),this.tabHeader=this.shadowRoot.querySelector(".tab-header"),this.changeTab=this.changeTab.bind(this),this.handleClick=this.handleClick.bind(this),this.handlePanelChange=this.handlePanelChange.bind(this)}fireEvent(t){this.dispatchEvent(new CustomEvent(`switchedtab${this.target}`,{bubbles:!0,detail:{index:parseInt(t)}}))}moveIndiactor(t){this.indicator.setAttribute("style",`width: ${t.width}px; transform: translateX(${t.left-this.tabHeader.getBoundingClientRect().left+this.tabHeader.scrollLeft}px)`)}changeTab(t){t!==this.prevTab&&t.closest("sm-tab")&&(this.prevTab&&this.prevTab.classList.remove("active"),t.classList.add("active"),t.scrollIntoView({behavior:"smooth",block:"nearest",inline:"center"}),this.moveIndiactor(t.getBoundingClientRect()),this.prevTab=t,this.activeTab=t)}handleClick(t){t.target.closest("sm-tab")&&(this.changeTab(t.target),this.fireEvent(t.target.dataset.index))}handlePanelChange(t){console.log(this.allTabs),this.changeTab(this.allTabs[t.detail.index])}connectedCallback(){if(!this.hasAttribute("target")||""===this.getAttribute("target").value)return;this.target=this.getAttribute("target"),this.tabSlot.addEventListener("slotchange",()=>{this.allTabs=this.tabSlot.assignedElements(),this.allTabs.forEach((t,n)=>{t.dataset.index=n})}),this.addEventListener("click",this.handleClick),document.addEventListener(`switchedpanel${this.target}`,this.handlePanelChange);let t=new ResizeObserver(t=>{t.forEach(t=>{if(this.prevTab){let t=this.activeTab.getBoundingClientRect();this.moveIndiactor(t)}})});t.observe(this);let n=new IntersectionObserver(t=>{t.forEach(t=>{if(t.isIntersecting)if(this.indicator.style.transition="none",this.activeTab){let t=this.activeTab.getBoundingClientRect();this.moveIndiactor(t)}else{this.allTabs[0].classList.add("active");let t=this.allTabs[0].getBoundingClientRect();this.moveIndiactor(t),this.fireEvent(0),this.prevTab=this.tabSlot.assignedElements()[0],this.activeTab=this.prevTab}})},{threshold:1});n.observe(this)}disconnectedCallback(){this.removeEventListener("click",this.handleClick),document.removeEventListener(`switchedpanel${this.target}`,this.handlePanelChange)}});const smTab=document.createElement("template");smTab.innerHTML='\n\n\n \n
\n',customElements.define("sm-tab",class extends HTMLElement{constructor(){super(),this.shadow=this.attachShadow({mode:"open"}).append(smTab.content.cloneNode(!0))}});const smTabPanels=document.createElement("template");smTabPanels.innerHTML='\n\n\n Nothing to see here. \n
\n',customElements.define("sm-tab-panels",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smTabPanels.content.cloneNode(!0)),this.isTransitioning=!1,this.panelContainer=this.shadowRoot.querySelector(".panel-container"),this.panelSlot=this.shadowRoot.querySelector("slot"),this.handleTabChange=this.handleTabChange.bind(this)}handleTabChange(t){this.isTransitioning=!0,this.panelContainer.scrollTo({left:this.allPanels[t.detail.index].getBoundingClientRect().left-this.panelContainer.getBoundingClientRect().left+this.panelContainer.scrollLeft,behavior:"smooth"}),setTimeout(()=>{this.isTransitioning=!1},300)}fireEvent(t){this.dispatchEvent(new CustomEvent(`switchedpanel${this.id}`,{bubbles:!0,detail:{index:parseInt(t)}}))}connectedCallback(){this.panelSlot.addEventListener("slotchange",()=>{this.allPanels=this.panelSlot.assignedElements(),this.allPanels.forEach((n,e)=>{n.dataset.index=e,t.observe(n)})}),document.addEventListener(`switchedtab${this.id}`,this.handleTabChange);const t=new IntersectionObserver(t=>{t.forEach(t=>{!this.isTransitioning&&t.isIntersecting&&this.fireEvent(t.target.dataset.index)})},{threshold:.6})}disconnectedCallback(){intersectionObserver.disconnect(),document.removeEventListener(`switchedtab${this.id}`,this.handleTabChange)}});
\ No newline at end of file
+const smTabHeader=document.createElement("template");smTabHeader.innerHTML='\n\n\n \n
\n',customElements.define("sm-tab-header",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smTabHeader.content.cloneNode(!0)),this.prevTab,this.allTabs,this.activeTab,this.indicator=this.shadowRoot.querySelector(".indicator"),this.tabSlot=this.shadowRoot.querySelector("slot"),this.tabHeader=this.shadowRoot.querySelector(".tab-header"),this.changeTab=this.changeTab.bind(this),this.handleClick=this.handleClick.bind(this),this.handlePanelChange=this.handlePanelChange.bind(this)}fireEvent(t){this.dispatchEvent(new CustomEvent(`switchedtab${this.target}`,{bubbles:!0,detail:{index:parseInt(t)}}))}moveIndiactor(t){this.indicator.setAttribute("style",`width: ${t.width}px; transform: translateX(${t.left-this.tabHeader.getBoundingClientRect().left+this.tabHeader.scrollLeft}px)`)}changeTab(t){t!==this.prevTab&&t.closest("sm-tab")&&(this.prevTab&&this.prevTab.classList.remove("active"),t.classList.add("active"),t.scrollIntoView({behavior:"smooth",block:"nearest",inline:"center"}),this.moveIndiactor(t.getBoundingClientRect()),this.prevTab=t,this.activeTab=t)}handleClick(t){t.target.closest("sm-tab")&&(this.changeTab(t.target),this.fireEvent(t.target.dataset.index))}handlePanelChange(t){console.log(this.allTabs),this.changeTab(this.allTabs[t.detail.index])}connectedCallback(){if(!this.hasAttribute("target")||""===this.getAttribute("target").value)return;this.target=this.getAttribute("target"),this.tabSlot.addEventListener("slotchange",()=>{this.allTabs=this.tabSlot.assignedElements(),this.allTabs.forEach((t,n)=>{t.dataset.index=n})}),this.addEventListener("click",this.handleClick),document.addEventListener(`switchedpanel${this.target}`,this.handlePanelChange);let t=new ResizeObserver(t=>{t.forEach(t=>{if(this.prevTab){let t=this.activeTab.getBoundingClientRect();this.moveIndiactor(t)}})});t.observe(this);let n=new IntersectionObserver(t=>{t.forEach(t=>{if(t.isIntersecting)if(this.indicator.style.transition="none",this.activeTab){let t=this.activeTab.getBoundingClientRect();this.moveIndiactor(t)}else{this.allTabs[0].classList.add("active");let t=this.allTabs[0].getBoundingClientRect();this.moveIndiactor(t),this.fireEvent(0),this.prevTab=this.tabSlot.assignedElements()[0],this.activeTab=this.prevTab}})},{threshold:1});n.observe(this)}disconnectedCallback(){this.removeEventListener("click",this.handleClick),document.removeEventListener(`switchedpanel${this.target}`,this.handlePanelChange)}});const smTab=document.createElement("template");smTab.innerHTML='\n\n\n \n
\n',customElements.define("sm-tab",class extends HTMLElement{constructor(){super(),this.shadow=this.attachShadow({mode:"open"}).append(smTab.content.cloneNode(!0))}});const smTabPanels=document.createElement("template");smTabPanels.innerHTML='\n\n\n Nothing to see here. \n
\n',customElements.define("sm-tab-panels",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smTabPanels.content.cloneNode(!0)),this.isTransitioning=!1,this.panelContainer=this.shadowRoot.querySelector(".panel-container"),this.panelSlot=this.shadowRoot.querySelector("slot"),this.handleTabChange=this.handleTabChange.bind(this)}handleTabChange(t){this.isTransitioning=!0,this.panelContainer.scrollTo({left:this.allPanels[t.detail.index].getBoundingClientRect().left-this.panelContainer.getBoundingClientRect().left+this.panelContainer.scrollLeft,behavior:"smooth"}),setTimeout(()=>{this.isTransitioning=!1},300)}fireEvent(t){this.dispatchEvent(new CustomEvent(`switchedpanel${this.id}`,{bubbles:!0,detail:{index:parseInt(t)}}))}connectedCallback(){this.panelSlot.addEventListener("slotchange",()=>{this.allPanels=this.panelSlot.assignedElements(),this.allPanels.forEach((n,e)=>{n.dataset.index=e,t.observe(n)})}),document.addEventListener(`switchedtab${this.id}`,this.handleTabChange);const t=new IntersectionObserver(t=>{t.forEach(t=>{!this.isTransitioning&&t.isIntersecting&&this.fireEvent(t.target.dataset.index)})},{threshold:.6})}disconnectedCallback(){intersectionObserver.disconnect(),document.removeEventListener(`switchedtab${this.id}`,this.handleTabChange)}});
\ No newline at end of file
diff --git a/components/dist/text-field.js b/components/dist/text-field.js
index 4c6deeb..ae9679d 100644
--- a/components/dist/text-field.js
+++ b/components/dist/text-field.js
@@ -115,7 +115,7 @@ customElements.define('text-field', class extends HTMLElement{
this.removeAttribute('disabled')
}
fireEvent(value){
- let event = new CustomEvent('contentchanged', {
+ let event = new CustomEvent('change', {
bubbles: true,
cancelable: true,
composed: true,
diff --git a/components/dist/text-field.min.js b/components/dist/text-field.min.js
index 33b9621..52845cc 100644
--- a/components/dist/text-field.min.js
+++ b/components/dist/text-field.min.js
@@ -1 +1 @@
-const textField=document.createElement("template");textField.innerHTML='\n\n\n
\n
\n
\n Edit \n \n \n
\n Save \n \n \n
\n
\n',customElements.define("text-field",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(textField.content.cloneNode(!0)),this.textField=this.shadowRoot.querySelector(".text-field"),this.textContainer=this.textField.children[0],this.iconsContainer=this.textField.children[1],this.editButton=this.textField.querySelector(".edit-button"),this.saveButton=this.textField.querySelector(".save-button"),this.isTextEditable=!1,this.isDisabled=!1,this.fireEvent=this.fireEvent.bind(this),this.setEditable=this.setEditable.bind(this),this.setNonEditable=this.setNonEditable.bind(this),this.revert=this.revert.bind(this)}static get observedAttributes(){return["disabled"]}get value(){return this.text}set value(t){this.text=t,this.textContainer.textContent=t,this.setAttribute("value",t)}set disabled(t){this.isDisabled=t,this.isDisabled?this.setAttribute("disabled",""):this.removeAttribute("disabled")}fireEvent(t){let e=new CustomEvent("contentchanged",{bubbles:!0,cancelable:!0,composed:!0,detail:{value:t}});this.dispatchEvent(e)}setEditable(){this.isTextEditable||(this.textContainer.contentEditable=!0,this.textContainer.classList.add("editable"),this.textContainer.focus(),document.execCommand("selectAll",!1,null),this.editButton.animate(this.rotateOut,this.animOptions).onfinish=(()=>{this.editButton.classList.add("hide")}),setTimeout(()=>{this.saveButton.classList.remove("hide"),this.saveButton.animate(this.rotateIn,this.animOptions)},100),this.isTextEditable=!0)}setNonEditable(){this.isTextEditable&&(this.textContainer.contentEditable=!1,this.textContainer.classList.remove("editable"),this.text!==this.textContainer.textContent.trim()&&(this.setAttribute("value",this.textContainer.textContent),this.text=this.textContainer.textContent.trim(),this.fireEvent(this.text)),this.saveButton.animate(this.rotateOut,this.animOptions).onfinish=(()=>{this.saveButton.classList.add("hide")}),setTimeout(()=>{this.editButton.classList.remove("hide"),this.editButton.animate(this.rotateIn,this.animOptions)},100),this.isTextEditable=!1)}revert(){this.textContainer.isContentEditable&&(this.value=this.text,this.setNonEditable())}connectedCallback(){this.text,this.hasAttribute("value")&&(this.text=this.getAttribute("value"),this.textContainer.textContent=this.text),this.hasAttribute("disable")?this.isDisabled=!0:this.isDisabled=!1,this.rotateOut=[{transform:"rotate(0)",opacity:1},{transform:"rotate(90deg)",opacity:0}],this.rotateIn=[{transform:"rotate(-90deg)",opacity:0},{transform:"rotate(0)",opacity:1}],this.animOptions={duration:300,easing:"cubic-bezier(0.175, 0.885, 0.32, 1.275)",fill:"forwards"},this.isDisabled||(this.iconsContainer.classList.remove("hide"),this.textContainer.addEventListener("dblclick",this.setEditable),this.editButton.addEventListener("click",this.setEditable),this.saveButton.addEventListener("click",this.setNonEditable))}attributeChangedCallback(t){"disabled"===t&&(this.hasAttribute("disabled")?(this.textContainer.removeEventListener("dblclick",this.setEditable),this.editButton.removeEventListener("click",this.setEditable),this.saveButton.removeEventListener("click",this.setNonEditable),this.revert()):(this.textContainer.addEventListener("dblclick",this.setEditable),this.editButton.addEventListener("click",this.setEditable),this.saveButton.addEventListener("click",this.setNonEditable)))}disconnectedCallback(){this.textContainer.removeEventListener("dblclick",this.setEditable),this.editButton.removeEventListener("click",this.setEditable),this.saveButton.removeEventListener("click",this.setNonEditable)}});
\ No newline at end of file
+const textField=document.createElement("template");textField.innerHTML='\n\n\n
\n
\n
\n Edit \n \n \n
\n Save \n \n \n
\n
\n',customElements.define("text-field",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(textField.content.cloneNode(!0)),this.textField=this.shadowRoot.querySelector(".text-field"),this.textContainer=this.textField.children[0],this.iconsContainer=this.textField.children[1],this.editButton=this.textField.querySelector(".edit-button"),this.saveButton=this.textField.querySelector(".save-button"),this.isTextEditable=!1,this.isDisabled=!1,this.fireEvent=this.fireEvent.bind(this),this.setEditable=this.setEditable.bind(this),this.setNonEditable=this.setNonEditable.bind(this),this.revert=this.revert.bind(this)}static get observedAttributes(){return["disabled"]}get value(){return this.text}set value(t){this.text=t,this.textContainer.textContent=t,this.setAttribute("value",t)}set disabled(t){this.isDisabled=t,this.isDisabled?this.setAttribute("disabled",""):this.removeAttribute("disabled")}fireEvent(t){let e=new CustomEvent("change",{bubbles:!0,cancelable:!0,composed:!0,detail:{value:t}});this.dispatchEvent(e)}setEditable(){this.isTextEditable||(this.textContainer.contentEditable=!0,this.textContainer.classList.add("editable"),this.textContainer.focus(),document.execCommand("selectAll",!1,null),this.editButton.animate(this.rotateOut,this.animOptions).onfinish=(()=>{this.editButton.classList.add("hide")}),setTimeout(()=>{this.saveButton.classList.remove("hide"),this.saveButton.animate(this.rotateIn,this.animOptions)},100),this.isTextEditable=!0)}setNonEditable(){this.isTextEditable&&(this.textContainer.contentEditable=!1,this.textContainer.classList.remove("editable"),this.text!==this.textContainer.textContent.trim()&&(this.setAttribute("value",this.textContainer.textContent),this.text=this.textContainer.textContent.trim(),this.fireEvent(this.text)),this.saveButton.animate(this.rotateOut,this.animOptions).onfinish=(()=>{this.saveButton.classList.add("hide")}),setTimeout(()=>{this.editButton.classList.remove("hide"),this.editButton.animate(this.rotateIn,this.animOptions)},100),this.isTextEditable=!1)}revert(){this.textContainer.isContentEditable&&(this.value=this.text,this.setNonEditable())}connectedCallback(){this.text,this.hasAttribute("value")&&(this.text=this.getAttribute("value"),this.textContainer.textContent=this.text),this.hasAttribute("disable")?this.isDisabled=!0:this.isDisabled=!1,this.rotateOut=[{transform:"rotate(0)",opacity:1},{transform:"rotate(90deg)",opacity:0}],this.rotateIn=[{transform:"rotate(-90deg)",opacity:0},{transform:"rotate(0)",opacity:1}],this.animOptions={duration:300,easing:"cubic-bezier(0.175, 0.885, 0.32, 1.275)",fill:"forwards"},this.isDisabled||(this.iconsContainer.classList.remove("hide"),this.textContainer.addEventListener("dblclick",this.setEditable),this.editButton.addEventListener("click",this.setEditable),this.saveButton.addEventListener("click",this.setNonEditable))}attributeChangedCallback(t){"disabled"===t&&(this.hasAttribute("disabled")?(this.textContainer.removeEventListener("dblclick",this.setEditable),this.editButton.removeEventListener("click",this.setEditable),this.saveButton.removeEventListener("click",this.setNonEditable),this.revert()):(this.textContainer.addEventListener("dblclick",this.setEditable),this.editButton.addEventListener("click",this.setEditable),this.saveButton.addEventListener("click",this.setNonEditable)))}disconnectedCallback(){this.textContainer.removeEventListener("dblclick",this.setEditable),this.editButton.removeEventListener("click",this.setEditable),this.saveButton.removeEventListener("click",this.setNonEditable)}});
\ No newline at end of file
diff --git a/components/dist/theme-toggle.js b/components/dist/theme-toggle.js
index 64d03f0..92b224d 100644
--- a/components/dist/theme-toggle.js
+++ b/components/dist/theme-toggle.js
@@ -99,11 +99,13 @@ class ThemeToggle extends HTMLElement {
daylight() {
this.hasTheme = 'light'
document.body.dataset.theme = 'light'
+ this.setAttribute('aria-checked', 'false')
}
-
+
nightlight() {
this.hasTheme = 'dark'
document.body.dataset.theme = 'dark'
+ this.setAttribute('aria-checked', 'true')
}
toggleState() {
diff --git a/components/dist/theme-toggle.min.js b/components/dist/theme-toggle.min.js
index b91a9af..12bffba 100644
--- a/components/dist/theme-toggle.min.js
+++ b/components/dist/theme-toggle.min.js
@@ -1 +1 @@
-const themeToggle=document.createElement("template");themeToggle.innerHTML='\n \n \n \n \n \n \n \n \n \n \n \n \n \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
+const themeToggle=document.createElement("template");themeToggle.innerHTML='\n \n \n \n \n \n \n \n \n \n \n \n \n \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",this.setAttribute("aria-checked","false")}nightlight(){this.hasTheme="dark",document.body.dataset.theme="dark",this.setAttribute("aria-checked","true")}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 3c2b3b8..8e758a3 100644
--- a/components/index.html
+++ b/components/index.html
@@ -21,7 +21,8 @@
-
+
@@ -284,7 +285,9 @@
-<sm-carousel align-items="start" indicator> ...carousel items... </sm-carousel>
+<sm-carousel align-items="start" indicator>
+ <!-- carousel items -->
+</sm-carousel>
Custom attributes
@@ -459,6 +462,16 @@
<sm-copy value="copy this message"></sm-copy>
+
+ Usage
+
+
+<sm-copy id="text_to_copy" value="sample text"></sm-copy>
+<script>
+ const textToCopy = document.getElementById('text_to_copy')
+ textToCopy.value = 'Different value'; /* Setting value to be copied */
+</script>
+
Attributes
- Usage
-
-
-<sm-copy id="text_to_copy" value="sample text"></sm-copy>
-<script>
- const textToCopy = document.getElementById('text_to_copy')
- textToCopy.value = 'Different value'; /* Setting value to be copied */
-</script>
-
-
-
+ Supported events
+
+
+
Event
+ Description
+
+
+
copy
+
+ Fired when text is copied by user.
+
+
+
Nested element behaviour
-
-
-
+
+
+
Element
+ behaviour
+
+
+
+ sm-button
+ variant="primary"
+ or
+ type="submit"
+
+
+ Whenever enter is pressed inside an active sm-input , this will fire click event.
+ This will also change state depending opon validation conditions.
+
+
+
+
+ sm-button
+ type="reset"
+
+
+ When clicked, the whole form will reset.
+
+
+
Input
@@ -631,6 +693,50 @@
+ Styling
+ CSS variables used to style this component
+
+
+
Variable
+ Description
+
+
+
--background
+
+ Defines background property of input. Any valid CSS background values are supported.
+
+
+
+
--border-radius
+
+ Sets border-radius of input.
+
+
+
+
--icon-gap
+
+ Sets space between input icon and input box. Default is "0.5rem"
+
+
+
+
--font-size
+
+ Sets font size of input text. Default is "1rem".
+
+
+
+
--padding
+
+ Sets padding around whole input box including icon.
+
+
+
+
--width
+
+ Sets width of input box.
+
+
+
Supported functions
@@ -1084,6 +1190,22 @@
<sm-option value="3">option3</sm-option>
</sm-select>
+
+
Usage
+
+
+<sm-select id="my_select">
+ <sm-option value="1">option1</sm-option>
+ <sm-option value="2">option2</sm-option>
+ <sm-option value="3">option3</sm-option>
+</sm-select>
+<script>
+ const mySelect = document.getElementById('my_select')
+ mySelect.addEventListener('change', event => {
+ console.log(event.detail.value) // logs out value of selected option
+ })
+</script>
+
States
Disabled
@@ -1096,9 +1218,7 @@
<sm-select disabled>
- <sm-option value="1">option1</sm-option>
- <sm-option value="2">option2</sm-option>
- <sm-option value="3">option3</sm-option>
+ <!-- Options -->
</sm-select>
@@ -1119,22 +1239,6 @@
- Usage
-
-
-<sm-select id="my_select">
- <sm-option value="1">option1</sm-option>
- <sm-option value="2">option2</sm-option>
- <sm-option value="3">option3</sm-option>
-</sm-select>
-<script>
- const mySelect = document.getElementById('my_select')
- mySelect.addEventListener('change', event => {
- console.log(event.detail.value) // logs out value of selected option
- })
-</script>
-
-
Spinner
@@ -1268,7 +1372,7 @@
Description
-
multiline ( Boolean )
+
multiline ( Boolean )
If present, options will wrap around instead of overflowing horizontally.
@@ -1384,7 +1488,8 @@
target ( string )
- Pass in the ID of respective sm-tab-panels to link them. This is how sm-tab-header communicates with sm-tab-panel on which tab or panel should be displayed.
+ Pass in the ID of respective sm-tab-panels to link them. This is how sm-tab-header
+ communicates with sm-tab-panel on which tab or panel should be displayed.
@@ -1651,9 +1756,57 @@
Text field
- To start using SM Components
+ This component can be used in scenarios where you need to display a name or something that user
+ should be able to edit directly
+ in-place instead of going to other UI element.
-
+ Interactive demo
+
+ Usage
+
+
+<text-field id="name_field" value="John doe"></text-field>
+<script>
+ const nameField = document.getElementById('name_field')
+ nameField.addEventListener('change', event => {
+ console.log(event.detail.value) // logs out new value set by user
+ console.log(nameField.value) // Accessing value directly with getter
+ })
+</script>
+
+
+ Custom attributes
+
+
+
Attribute
+ Description
+
+
+
disabled ( Boolean )
+
+ If present, text can't be edited.
+
+
+
+
value ( string )
+
+ Set initial text that can be edited by user.
+
+
+
+ Supported events
+
+
+
Event
+ Description
+
+
+
change
+
+ Fired when text changes are saved by user.
+
+
+
Theme toggle
@@ -1757,7 +1910,7 @@
-
+
diff --git a/components/index.min.html b/components/index.min.html
index a912de3..42ef3b4 100644
--- a/components/index.min.html
+++ b/components/index.min.html
@@ -1,4 +1,4 @@
-SM Components Getting Started Components
Total components Overview Component-based design is the cornerstone of the modern UI development process. With rise of more UI frameworks every day, the web platform has a serious issue of fragmentation and portability.
Web components to the rescue! This is the collection of web components (WC here forward) that we use at RanchiMall, especially since we are a framework-less development environment so this was a logical choice.
Features Native and Cross framework support Encapsulated style and functionality Easy styling Adaptive scaling Quick Start To start using these components, Select the ones you want to add to your project. You can un-check 'get minified' to get the readable code. Now you can download or copy the source code for selected components. You might get a warning while downloading like this file is not safe, please allow the download as this is caused when downloading files with '.js' extension. These components are 100% safe to use. Link the downloaded js before </body>
+SM Components Getting Started Components
Total components Overview Component-based design is the cornerstone of the modern UI development process. With rise of more UI frameworks every day, the web platform has a serious issue of fragmentation and portability.
Web components to the rescue! This is the collection of web components (WC here forward) that we use at RanchiMall, especially since we are a framework-less development environment so this was a logical choice.
Features Native and Cross framework support Encapsulated style and functionality Easy styling Adaptive scaling Quick Start To start using these components, Select the ones you want to add to your project. You can un-check 'get minified' to get the readable code. Now you can download or copy the source code for selected components. You might get a warning while downloading like this file is not safe, please allow the download as this is caused when downloading files with '.js' extension. These components are 100% safe to use. Link the downloaded js before </body>
<script src=".../components.js"></script>
@@ -14,7 +14,9 @@
Attributes All the native HTML checkbox attributes are valid
Attribute Description disabled (boolean)
Button is disabled by default. all the interactions are disabled
type (string)
Has values submit reset Can only used withingsm-form to submit or reset the form.
Styling CSS variables used to style this component
Variable Description --background
Define background of button. accepts all values of CSS background property
--border-radius
Set curvature at button corners
--padding
Specify padding of button
Carousel Carousel is a very common UI component primarily used to display images or slides. This carousel switches user interactions based on type of input devices present. For hover capable devices slides can be scrolled with buttons and on touch enabled devices swipe can be used.
Interactive demo Title Lorem ipsum dolor sit amet, consectetur adipisicing elit. Provident, optio.
Title Lorem ipsum dolor sit amet, consectetur adipisicing elit. Provident, optio.
Title Lorem ipsum dolor sit amet, consectetur adipisicing elit. Provident, optio.
Title Lorem ipsum dolor sit amet, consectetur adipisicing elit. Provident, optio.
-<sm-carousel align-items="start" indicator> ...carousel items... </sm-carousel>
+<sm-carousel align-items="start" indicator>
+ <!-- carousel items -->
+</sm-carousel>
Custom attributes These attributes cane used to customize carousel behaviour and features
Attribute Description align-items
Has values start center end Specifies how carousel items should align. default is center .
indicator (boolean)
if added carousel shows dot indicators of carousel items.
Styling CSS variables used to style this component
Variable Description --active-indicator-color
Defines background color of active slide indicator
--nav-background-color
Defines background color of carousel navigation buttons
--nav-box-shadow
Defines box shadow of carousel navigation buttons
--nav-icon-fill
Defines fill of arrow icon on carousel navigation buttons
Checkbox sm-checkbox supports all the attributes of native HTML5 checkbox
linking some HTML element with sm-checbox using label tag won't work. Add the element inside the opening and closing checkbox tag. Interactive demo Check this box
States Checked To make checkbox checked by default add checked attribute.
Checked checkbox
@@ -32,7 +34,7 @@
<sm-copy value="copy this message"></sm-copy>
- Attributes
Attribute Description value ( string )
Defines content that will be copied when copy button is clicked
Styling CSS variables used to style this component
Variable Description --button-background-color
Defines background color of copy button
--button-border-radius
Defines border-radius of copy button
Usage
+ Usage
<sm-copy id="text_to_copy" value="sample text"></sm-copy>
<script>
@@ -40,11 +42,24 @@
textToCopy.value = 'Different value'; /* Setting value to be copied */
</script>
- File input <file-input> is essentially native <input type="file"/> with added style. So every attribute supported by native file input is supported as can be used in exactly same way.
Interactive demo Select multiple files
+ Attributes
Attribute Description value ( string )
Defines content that will be copied when copy button is clicked
Styling CSS variables used to style this component
Variable Description --button-background-color
Defines background color of copy button
--button-border-radius
Defines border-radius of copy button
Supported events
Event Description copy
Fired when text is copied by user.
File input <file-input> is essentially native <input type="file"/> with added style. So every attribute supported by native file input is supported as can be used in exactly same way.
Interactive demo Select multiple files
<file-input multiple>Select multiple files</file-input>
- Attributes
Attribute Description accept
One or more unique file type specifiers describing file types to allow
capture
What source to use for capturing image or video data
files
A FileList listing the chosen files
multiple
A Boolean which, if present, indicates that the user may choose more than one file
Form Browser support for web components form validation or form submition is not perfect. so to circumvent this problem <sm-form> can be used.
Interactive demo Login Supported functions
Function Description reset()
When this function is called upon form element. all the form elements (sm- form components only) will be reset to default state.
Nested element behaviour
Input Interactive demo
+ Attributes
Attribute Description accept
One or more unique file type specifiers describing file types to allow
capture
What source to use for capturing image or video data
files
A FileList listing the chosen files
multiple
A Boolean which, if present, indicates that the user may choose more than one file
Form Browser support for web components form validation or form submition is not perfect. so to circumvent this problem <sm-form> can be used.
Interactive demo Login Supported functions
Function Description reset()
When this function is called upon form element. all the form elements (sm- form components only) will be reset to default state.
Nested element behaviour
Element behaviour sm-button variant="primary" or type="submit"
Whenever enter is pressed inside an active sm-input , this will fire click event. This will also change state depending opon validation conditions.
sm-button type="reset"
When clicked, the whole form will reset.
Input Interactive demo
<sm-input id="my_input" placeholder="Email" type="email" value="john@doe" animate></sm-input>
@@ -52,7 +67,7 @@
<sm-input placeholder="Name" variant="outlined" animate></sm-input>
- Custom Attributes All the native HTML input attributes are valid. These are additional attributes which can be used to add more functionality
Attribute Description animate (boolean)
If present, placeholder of input will be animated to occupy space above enterned text instead of vanishing.
error-text (string)
Message specified as value of this attribute will be shown if validation fails.
Supported functions
Function Description focusIn()
To give focus to this component use this function instead of focus()
reset()
When this function is called value will be set to empty string.
Custom Setters
Function Description customValidation
If you want to perform custom validation on input value, set the desired validation function.
disabled
Set disabled state to true or false
value
Sets the value of input with JS
+ Custom Attributes All the native HTML input attributes are valid. These are additional attributes which can be used to add more functionality
Attribute Description animate (boolean)
If present, placeholder of input will be animated to occupy space above enterned text instead of vanishing.
error-text (string)
Message specified as value of this attribute will be shown if validation fails.
Styling CSS variables used to style this component
Variable Description --background
Defines background property of input. Any valid CSS background values are supported.
--border-radius
Sets border-radius of input.
--icon-gap
Sets space between input icon and input box. Default is "0.5rem"
--font-size
Sets font size of input text. Default is "1rem".
--padding
Sets padding around whole input box including icon.
--width
Sets width of input box.
Supported functions
Function Description focusIn()
To give focus to this component use this function instead of focus()
reset()
When this function is called value will be set to empty string.
Custom Setters
Function Description customValidation
If you want to perform custom validation on input value, set the desired validation function.
disabled
Set disabled state to true or false
value
Sets the value of input with JS
<script>
/* Setting custom validation function */
@@ -131,15 +146,7 @@
<sm-option value="3">option3</sm-option>
</sm-select>
- States Disabled To disable the select add disabled attribute.
option1 option2 option3
-
-<sm-select disabled>
- <sm-option value="1">option1</sm-option>
- <sm-option value="2">option2</sm-option>
- <sm-option value="3">option3</sm-option>
-</sm-select>
-
- Supported events These are the events that will be fired when component state changes
Event Description change
Whenever a different options is selected by user the this event is fired. You can listen to this event and access the current value with event object event.detail.value
Usage
+ Usage
<sm-select id="my_select">
<sm-option value="1">option1</sm-option>
@@ -153,7 +160,13 @@
})
</script>
- Spinner Just drop the sm-spinner in markup where you want to show the spinner
+ States Disabled To disable the select add disabled attribute.
option1 option2 option3
+
+<sm-select disabled>
+ <!-- Options -->
+</sm-select>
+
+ Supported events These are the events that will be fired when component state changes
Event Description change
Whenever a different options is selected by user the this event is fired. You can listen to this event and access the current value with event object event.detail.value
Spinner Just drop the sm-spinner in markup where you want to show the spinner
<sm-spinner></sm-spinner>
@@ -186,7 +199,7 @@
<strip-option value="rating">Rating</strip-option>
</strip-select>
- Custom attributes
Attribute Description multiline ( Boolean )
If present, options will wrap around instead of overflowing horizontally.
Styling CSS variables used to style this component
Variable Description --gap
Defines space between options. Default is "0.5rem".
Supported events These are the events that will be fired when component state changes
Event Description change
Whenever a different options is selected by user the this event is fired. You can listen to this event and access the current value with event object event.detail.value
Usage
+ Custom attributes
Attribute Description multiline ( Boolean )
If present, options will wrap around instead of overflowing horizontally.
Styling CSS variables used to style this component
Variable Description --gap
Defines space between options. Default is "0.5rem".
Supported events These are the events that will be fired when component state changes
Event Description change
Whenever a different options is selected by user the this event is fired. You can listen to this event and access the current value with event object event.detail.value
Usage
<strip-select id="sort_by">
<strip-option value="relevance" selected>Relevance</strip-option>
@@ -266,7 +279,18 @@
})
</script>
- Text field To start using SM Components
Theme toggle Use theme-toggle to create light/dark theme easily with CSS variables.
When this is toggled by user the component changes the custom data attribute data-theme="" on HTML body tag to either light or dark
By default theme is set to OS level preferred-color-scheme ( supported by Android, iOS, Windows and MacOS ).
Interactive demo HTML
+ Text field This component can be used in scenarios where you need to display a name or something that user should be able to edit directly in-place instead of going to other UI element.
Interactive demo Usage
+
+<text-field id="name_field" value="John doe"></text-field>
+<script>
+ const nameField = document.getElementById('name_field')
+ nameField.addEventListener('change', event => {
+ console.log(event.detail.value) // logs out new value set by user
+ console.log(nameField.value) // Accessing value directly with getter
+ })
+</script>
+
+ Custom attributes
Attribute Description disabled ( Boolean )
If present, text can't be edited.
value ( string )
Set initial text that can be edited by user.
Supported events
Event Description change
Fired when text changes are saved by user.
Theme toggle Use theme-toggle to create light/dark theme easily with CSS variables.
When this is toggled by user the component changes the custom data attribute data-theme="" on HTML body tag to either light or dark
By default theme is set to OS level preferred-color-scheme ( supported by Android, iOS, Windows and MacOS ).
Interactive demo HTML
<theme-toggle></theme-toggle>