Feature and bug fixing update

This commit is contained in:
sairaj mote 2022-09-04 17:37:45 +05:30
parent 5aa58c4349
commit 019addd855
48 changed files with 1774 additions and 1244 deletions

View File

@ -6,48 +6,50 @@
}
:root {
font-size: clamp(1rem, 1.2vmax, 3rem);
font-size: clamp(1rem, 1.2vmax, 1.2rem);
}
html, body {
html,
body {
height: 100%;
scroll-behavior: smooth;
}
body {
--accent-color: #0d7377;
--secondary-color: #ffac2e;
--text-color: 20, 20, 20;
--foreground-color: 252, 253, 255;
--background-color: 241, 243, 248;
--danger-color: rgb(255, 75, 75);
--green: #1cad59;
--yellow: rgb(220, 165, 0);
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;
background-color: rgba(var(--background-color), 1);
overflow-y: hidden;
}
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;
body[data-theme=dark] {
--accent-color: #32e0c4;
--secondary-color: #d60739;
--text-color: 220, 220, 220;
--foreground-color: 27, 28, 29;
--background-color: 21, 22, 22;
--danger-color: rgb(255, 106, 106);
--green: #00e676;
--yellow: rgb(255, 213, 5);
}
p {
font-size: 0.8;
p,
strong {
font-size: 0.9rem;
max-width: 65ch;
line-height: 1.7;
margin-bottom: 1.5rem;
color: rgba(var(--text-color), 0.8);
}
p:not(:last-of-type) {
margin-bottom: 1rem;
color: rgba(var(--text-color), 0.9);
}
img {
object-fit: cover;
-o-object-fit: cover;
object-fit: cover;
}
a {
@ -64,6 +66,14 @@ button {
background-color: inherit;
}
a:-webkit-any-link:focus-visible {
outline: rgba(var(--text-color), 1) 0.1rem solid;
}
a:-moz-any-link:focus-visible {
outline: rgba(var(--text-color), 1) 0.1rem solid;
}
a:any-link:focus-visible {
outline: rgba(var(--text-color), 1) 0.1rem solid;
}
@ -139,8 +149,6 @@ ul {
word-wrap: break-word;
-ms-word-break: break-all;
word-break: break-word;
-ms-hyphens: auto;
-moz-hyphens: auto;
-webkit-hyphens: auto;
hyphens: auto;
}
@ -282,10 +290,12 @@ ul {
}
.ripple {
height: 8rem;
width: 8rem;
position: absolute;
border-radius: 50%;
transform: scale(0);
background: rgba(var(--text-color), 0.16);
background: radial-gradient(circle, rgba(var(--text-color), 0.3) 0%, rgba(0, 0, 0, 0) 50%);
pointer-events: none;
}
@ -326,18 +336,18 @@ ul {
.token.prolog,
.token.doctype,
.token.cdata {
color: #50CB93;
color: #50cb93;
}
.token.punctuation,
.token.tag {
color: #29B6F6;
color: #29b6f6;
}
.token.attr-name,
.token.namespace,
.token.deleted {
color: #1DE9B6;
color: #1de9b6;
}
.token.function-name {
@ -362,7 +372,7 @@ ul {
.token.atrule,
.token.keyword,
.token.builtin {
color: #FF6767;
color: #ff6767;
}
.token.string,
@ -370,7 +380,7 @@ ul {
.token.attr-value,
.token.regex,
.token.variable {
color: #84FFFF;
color: #84ffff;
}
.token.operator,
@ -429,7 +439,10 @@ pre code {
width: 100%;
}
h1, h2, h3, h4.h5 {
h1,
h2,
h3,
h4.h5 {
font-family: "Poppins", sans-serif;
}
@ -574,8 +587,10 @@ strong.important {
}
.screenshot {
object-fit: cover;
object-position: top;
-o-object-fit: cover;
object-fit: cover;
-o-object-position: top;
object-position: top;
height: 30rem;
width: 16rem;
border-radius: 1rem;
@ -593,21 +608,17 @@ strong.important {
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;
@ -615,11 +626,9 @@ strong.important {
.right > * {
grid-column: 2/3;
}
.page__title {
font-size: 2.5rem;
}
#overview_page {
display: grid;
gap: 1.5rem;
@ -638,7 +647,6 @@ strong.important {
width: 0.5rem;
height: 0.5rem;
}
::-webkit-scrollbar-thumb {
background: rgba(var(--text-color), 0.3);
border-radius: 1rem;
@ -646,7 +654,6 @@ strong.important {
::-webkit-scrollbar-thumb:hover {
background: rgba(var(--text-color), 0.5);
}
.list__item:hover {
background: rgba(var(--text-color), 0.1);
cursor: pointer;

View File

@ -1 +0,0 @@
{"version":3,"sources":["main.scss"],"names":[],"mappings":"AAAQ,gGAAA;AACA,iGAAA;AACA,gFAAA;AACR;EACI,sBAAA;EACA,UAAA;EACA,SAAA;EACA,iCAAA;AACJ;;AACA;EACI,uBAAA;AAEJ;;AAAA;EACI,uBAAA;EACA,wCAAA;EACA,wBAAA;EACA,iCAAA;EACA,mCAAA;EACA,sBAAA;AAGJ;;AAGA;EAAsB,cAAA;AACtB;;AADwC,oBAAA;AACxC;EAAsB,cAAA;AAKtB;;AALwC,wBAAA;AACxC;EAAsB,cAAA;EAAgB,kBAAA;AAUtC;;AAV4D,mBAAA;AAC5D;EAAsB,cAAA;AActB;;AAdwC,sBAAA;AACxC;EAAsB,cAAA;AAkBtB;;AAlBwC,YAAA;AACxC;EAAsB,WAAA;AAsBtB;;AAtBqC,gBAAA;AACrC;EAAsB,WAAA;AA0BtB;;AA1BqC,cAAA;AACrC;EAAsB,cAAA;AA8BtB;;AA9BwC,iBAAA;AACxC;EAAsB,cAAA;AAkCtB;;AAlCwC,4BAAA;AACxC;EAAsB,cAAA;AAsCtB;;AAtCwC,4BAAA;AACxC;EAAsB,cAAA;AA0CtB;;AA1CwC,mBAAA;AAExC;EACC,cAAA;EACG,iBAAA;EACA,qBAAA;EACA,qBAAA;EACA,yCAAA;AA4CJ;;AA1CA;EACI,qCAAA;EACA,qBAAA;EACA,gBAAA;EACA,sBAAA;EACA,yCAAA;AA6CJ;;AA3CA;EACI,qCAAA;AA8CJ;;AA5CA;EACI,gBAAA;EACA,mBAAA;EACA,gBAAA;EACA,WAAA;AA+CJ;;AA1CA;EACI,aAAA;AA6CJ;;AA3CA;EACI,kCAAA;EACA,gBAAA;AA8CJ;;AA5CA;EACI,qBAAA;EACA,0BAAA;AA+CJ;;AAjDA;EACI,qBAAA;EACA,0BAAA;AA+CJ;;AAjDA;EACI,qBAAA;EACA,0BAAA;AA+CJ;;AA7CA;EACE,qBAAA;EACA,0BAAA;AAgDF;AA/CE;EACI,gBAAA;AAiDN;;AA9CA;EACI,iCAAA;AAiDJ;;AA/CA;EACI,aAAA;EACA,aAAA;EACA,sBAAA;EACA,uBAAA;EACA,mBAAA;EACA,sBAAA;EACA,kBAAA;EACA,iCAAA;EACA,aAAA;EACA,qDAAA;AAkDJ;AAjDI;EACI,gBAAA;EACA,iBAAA;EACA,kBAAA;EACA,UAAA;EACA,yBAAA;EACA,sBAAA;AAmDR;AAjDI;EACI,UAAA;EACA,gBAAA;EACA,kBAAA;AAmDR;AAjDI;EACI,aAAA;EACA,kBAAA;EACA,kBAAA;EACA,8CAAA;EACA,WAAA;EACA,WAAA;EACA,wBAAA;EACA,sCAAA;EACA,WAAA;AAmDR;AAjDI;EACI,gBAAA;EACA,gBAAA;AAmDR;AAjDI;EACI,gBAAA;AAmDR;AAjDI;EACI,kBAAA;AAmDR;;AAhDA;EACI,aAAA;AAmDJ;;AAjDA;EACI,uBAAA;EACA,kBAAA;EACA,mCAAA;EACA,eAAA;AAoDJ;AAnDI;EACI,0BAAA;AAqDR;;AAlDA;EACI,oBAAA;AAqDJ;AApDI;EACI,mBAAA;AAsDR;AArDQ;EACI,gBAAA;AAuDZ;AArDQ;EACI,0BAAA;AAuDZ;;AAnDA;EACI,gBAAA;EACA,gBAAA;AAsDJ;AArDI;EACI,eAAA;AAuDR;;AApDA;EACI,eAAA;AAuDJ;AAtDI;EACI,qBAAA;AAwDR;;AArDA;EACI,gBAAA;EACA,aAAA;EACA,sBAAA;EACA,qBAAA;AAwDJ;AAvDI;EACI,sBAAA;EACA,0BAAA;AAyDR;AAvDI;EACI,0BAAA;EACA,yCAAA;AAyDR;;AAtDA;EACI,aAAA;EACA,aAAA;EACA,kBAAA;EACA,qBAAA;EACA,WAAA;EACA,oBAAA;KAAA,iBAAA;AAyDJ;;AAvDA;EACI,mBAAA;AA0DJ;;AAxDA;EACI,qBAAA;AA2DJ;;AAzDA;EACI;IACI,aAAA;IACA,2CAAA;IACA,WAAA;EA4DN;;EA1DE;IACI,eAAA;EA6DN;;EA3DE;IACI,uBAAA;IACA,sBAAA;EA8DN;AACF;AA5DA;EACI;IACI,eAAA;IACA,UAAA;IACA,sCAAA;IACA,4CAAA;IACA,aAAA;IACA,4BAAA;EA8DN;AACF;AA5DA;EACI;IACI,wCAAA;IACA,eAAA;EA8DN;AACF","file":"main.css"}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,4 @@
//Button
const smButton = document.createElement('template')
smButton.innerHTML = `
<style>
@ -10,7 +11,6 @@ smButton.innerHTML = `
:host{
display: inline-flex;
width: auto;
--background-color: 255, 255, 255;
--padding: 0.6rem 1.2rem;
--border-radius: 0.3rem;
--background: rgba(var(--text-color, (17,17,17)), 0.1);

View File

@ -1 +1 @@
const smButton=document.createElement("template");smButton.innerHTML="\n<style> \n*{\n padding: 0;\n margin: 0;\n -webkit-box-sizing: border-box;\n box-sizing: border-box;\n} \n:host{\n display: inline-flex;\n width: auto;\n --background-color: 255, 255, 255;\n --padding: 0.6rem 1.2rem;\n --border-radius: 0.3rem;\n --background: rgba(var(--text-color, (17,17,17)), 0.1);\n}\n:host([variant='primary']) .button{\n background: var(--accent-color,teal);\n color: rgba(var(--background-color, (255,255,255)), 1);\n}\n:host([variant='outlined']) .button{\n box-shadow: 0 0 0 1px rgba(var(--text-color, (17,17,17)), 0.2) inset;\n background: transparent; \n color: var(--accent-color,teal);\n}\n:host([variant='no-outline']) .button{\n background: inherit; \n color: var(--accent-color,teal);\n}\n:host([disabled]){\n pointer-events: none;\n cursor: not-allowed;\n}\n.button {\n position: relative;\n display: flex;\n width: 100%;\n padding: var(--padding);\n cursor: pointer;\n user-select: none;\n border-radius: var(--border-radius); \n justify-content: center;\n transition: box-shadow 0.3s, background-color 0.3s;\n font-family: inherit;\n font-size: 0.9rem;\n font-weight: 500;\n background-color: var(--background); \n -webkit-tap-highlight-color: transparent;\n outline: none;\n overflow: hidden;\n border: none;\n color: inherit;\n align-items: center;\n}\n:host([disabled]) .button{\n pointer-events: none;\n cursor: not-allowed;\n opacity: 0.6;\n color: rgba(var(--text-color, (17,17,17)), 1);\n background-color: rgba(var(--text-color, (17,17,17)), 0.3);\n}\n@media (hover: hover){\n :host(:not([disabled])) .button:hover,\n :host(:focus-within:not([disabled])) .button{\n -webkit-box-shadow: 0 0.1rem 0.1rem rgba(0, 0, 0, 0.1), 0 0.2rem 0.8rem rgba(0, 0, 0, 0.12);\n box-shadow: 0 0.1rem 0.1rem rgba(0, 0, 0, 0.1), 0 0.2rem 0.8rem rgba(0, 0, 0, 0.12);\n }\n :host([variant='outlined']:not([disabled])) .button:hover,\n :host(:focus-within[variant='outlined']:not([disabled])) .button:hover{\n -webkit-box-shadow: 0 0 0 1px rgba(var(--text-color, (17,17,17)), 0.2) inset, 0 0.1rem 0.1rem rgba(0, 0, 0, 0.1), 0 0.4rem 0.8rem rgba(0, 0, 0, 0.12);\n box-shadow: 0 0 0 1px rgba(var(--text-color, (17,17,17)), 0.2) inset, 0 0.1rem 0.1rem rgba(0, 0, 0, 0.1), 0 0.4rem 0.8rem rgba(0, 0, 0, 0.12);\n }\n}\n@media (hover: none){\n :host(:not([disabled])) .button:active{\n -webkit-box-shadow: 0 0.1rem 0.1rem rgba(0, 0, 0, 0.1), 0 0.2rem 0.8rem rgba(0, 0, 0, 0.2);\n box-shadow: 0 0.1rem 0.1rem rgba(0, 0, 0, 0.1), 0 0.2rem 0.8rem rgba(0, 0, 0, 0.2);\n }\n :host([variant='outlined']) .button:active{\n -webkit-box-shadow: 0 0 0 1px rgba(var(--text-color, (17,17,17)), 0.2) inset, 0 0.1rem 0.1rem rgba(0, 0, 0, 0.1), 0 0.4rem 0.8rem rgba(0, 0, 0, 0.2);\n box-shadow: 0 0 0 1px rgba(var(--text-color, (17,17,17)), 0.2) inset, 0 0.1rem 0.1rem rgba(0, 0, 0, 0.1), 0 0.4rem 0.8rem rgba(0, 0, 0, 0.2);\n }\n}\n</style>\n<div part=\"button\" class=\"button\">\n <slot></slot> \n</div>",customElements.define("sm-button",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smButton.content.cloneNode(!0))}static get observedAttributes(){return["disabled"]}get disabled(){return this.hasAttribute("disabled")}set disabled(t){t?this.setAttribute("disabled",""):this.removeAttribute("disabled")}focusIn(){this.focus()}handleKeyDown(t){this.hasAttribute("disabled")||"Enter"!==t.key&&" "!==t.key||(t.preventDefault(),this.click())}connectedCallback(){this.hasAttribute("disabled")||this.setAttribute("tabindex","0"),this.setAttribute("role","button"),this.addEventListener("keydown",this.handleKeyDown)}attributeChangedCallback(t){"disabled"===t&&(this.hasAttribute("disabled")?this.removeAttribute("tabindex"):this.setAttribute("tabindex","0"),this.setAttribute("aria-disabled",this.hasAttribute("disabled")))}});
const smButton=document.createElement("template");smButton.innerHTML="\n<style> \n*{\n padding: 0;\n margin: 0;\n -webkit-box-sizing: border-box;\n box-sizing: border-box;\n} \n:host{\n display: inline-flex;\n width: auto;\n --padding: 0.6rem 1.2rem;\n --border-radius: 0.3rem;\n --background: rgba(var(--text-color, (17,17,17)), 0.1);\n}\n:host([variant='primary']) .button{\n background: var(--accent-color,teal);\n color: rgba(var(--background-color, (255,255,255)), 1);\n}\n:host([variant='outlined']) .button{\n box-shadow: 0 0 0 1px rgba(var(--text-color, (17,17,17)), 0.2) inset;\n background: transparent; \n color: var(--accent-color,teal);\n}\n:host([variant='no-outline']) .button{\n background: inherit; \n color: var(--accent-color,teal);\n}\n:host([disabled]){\n pointer-events: none;\n cursor: not-allowed;\n}\n.button {\n position: relative;\n display: flex;\n width: 100%;\n padding: var(--padding);\n cursor: pointer;\n user-select: none;\n border-radius: var(--border-radius); \n justify-content: center;\n transition: box-shadow 0.3s, background-color 0.3s;\n font-family: inherit;\n font-size: 0.9rem;\n font-weight: 500;\n background-color: var(--background); \n -webkit-tap-highlight-color: transparent;\n outline: none;\n overflow: hidden;\n border: none;\n color: inherit;\n align-items: center;\n}\n:host([disabled]) .button{\n pointer-events: none;\n cursor: not-allowed;\n opacity: 0.6;\n color: rgba(var(--text-color, (17,17,17)), 1);\n background-color: rgba(var(--text-color, (17,17,17)), 0.3);\n}\n@media (hover: hover){\n :host(:not([disabled])) .button:hover,\n :host(:focus-within:not([disabled])) .button{\n -webkit-box-shadow: 0 0.1rem 0.1rem rgba(0, 0, 0, 0.1), 0 0.2rem 0.8rem rgba(0, 0, 0, 0.12);\n box-shadow: 0 0.1rem 0.1rem rgba(0, 0, 0, 0.1), 0 0.2rem 0.8rem rgba(0, 0, 0, 0.12);\n }\n :host([variant='outlined']:not([disabled])) .button:hover,\n :host(:focus-within[variant='outlined']:not([disabled])) .button:hover{\n -webkit-box-shadow: 0 0 0 1px rgba(var(--text-color, (17,17,17)), 0.2) inset, 0 0.1rem 0.1rem rgba(0, 0, 0, 0.1), 0 0.4rem 0.8rem rgba(0, 0, 0, 0.12);\n box-shadow: 0 0 0 1px rgba(var(--text-color, (17,17,17)), 0.2) inset, 0 0.1rem 0.1rem rgba(0, 0, 0, 0.1), 0 0.4rem 0.8rem rgba(0, 0, 0, 0.12);\n }\n}\n@media (hover: none){\n :host(:not([disabled])) .button:active{\n -webkit-box-shadow: 0 0.1rem 0.1rem rgba(0, 0, 0, 0.1), 0 0.2rem 0.8rem rgba(0, 0, 0, 0.2);\n box-shadow: 0 0.1rem 0.1rem rgba(0, 0, 0, 0.1), 0 0.2rem 0.8rem rgba(0, 0, 0, 0.2);\n }\n :host([variant='outlined']) .button:active{\n -webkit-box-shadow: 0 0 0 1px rgba(var(--text-color, (17,17,17)), 0.2) inset, 0 0.1rem 0.1rem rgba(0, 0, 0, 0.1), 0 0.4rem 0.8rem rgba(0, 0, 0, 0.2);\n box-shadow: 0 0 0 1px rgba(var(--text-color, (17,17,17)), 0.2) inset, 0 0.1rem 0.1rem rgba(0, 0, 0, 0.1), 0 0.4rem 0.8rem rgba(0, 0, 0, 0.2);\n }\n}\n</style>\n<div part=\"button\" class=\"button\">\n <slot></slot> \n</div>",customElements.define("sm-button",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smButton.content.cloneNode(!0))}static get observedAttributes(){return["disabled"]}get disabled(){return this.hasAttribute("disabled")}set disabled(t){t?this.setAttribute("disabled",""):this.removeAttribute("disabled")}focusIn(){this.focus()}handleKeyDown(t){this.hasAttribute("disabled")||"Enter"!==t.key&&" "!==t.key||(t.preventDefault(),this.click())}connectedCallback(){this.hasAttribute("disabled")||this.setAttribute("tabindex","0"),this.setAttribute("role","button"),this.addEventListener("keydown",this.handleKeyDown)}attributeChangedCallback(t){"disabled"===t&&(this.hasAttribute("disabled")?this.removeAttribute("tabindex"):this.setAttribute("tabindex","0"),this.setAttribute("aria-disabled",this.hasAttribute("disabled")))}});

View File

@ -11,15 +11,12 @@ smCarousel.innerHTML = `
display: -webkit-box;
display: -ms-flexbox;
display: flex;
--accent-color: #4d2588;
--text-color: 17, 17, 17;
--background-color: 255, 255, 255;
--arrow-left: 1rem;
--arrow-right: 1rem;
--arrow-top: auto;
--arrow-bottom: auto;
--nav-icon-fill: rgba(var(--background-color), 1);
--nav-background-color: rgba(var(--text-color), 1);
--nav-icon-fill: rgba(var(--background-color, (255, 255, 255)), 1);
--nav-background-color: rgba(var(--text-color, (17,17,17)), 1);
--nav-box-shadow: 0 0.2rem 0.2rem #00000020, 0 0.5rem 1rem #00000040;
--indicator-top: auto;
--indicator-bottom: -1.5rem;
@ -27,7 +24,7 @@ smCarousel.innerHTML = `
--indicator-width: 0.4rem;
--indicator-border-radius: 0.4rem;
--indicators-gap: 0.5rem;
--active-indicator-color: var(--accent-color);
--active-indicator-color: var(--accent-color, teal);
}
.carousel__button{
position: absolute;
@ -52,7 +49,7 @@ button:focus{
outline: none;
}
button:focus-visible{
outline: rgba(var(--text-color), 1) 0.1rem solid;
outline: rgba(var(--text-color, (17,17,17)), 1) 0.1rem solid;
}
.carousel__button:active{
transform: scale(0.9);
@ -110,7 +107,7 @@ button:focus-visible{
position: relative;
height: var(--indicator-height);
width: var(--indicator-width);
background: rgba(var(--text-color), 0.3);
background: rgba(var(--text-color, (17,17,17)), 0.3);
border-radius: var(--indicator-border-radius);
-webkit-transition: 0.2s;
-o-transition: 0.2s;
@ -370,14 +367,14 @@ customElements.define('sm-carousel', class extends HTMLElement {
const resObs = new ResizeObserver(entries => {
entries.forEach(entry => {
if(entry.contentBoxSize) {
if (entry.contentBoxSize) {
// Firefox implements `contentBoxSize` as a single content rect, rather than an array
const contentBoxSize = Array.isArray(entry.contentBoxSize) ? entry.contentBoxSize[0] : entry.contentBoxSize;
this.scrollDistance = contentBoxSize.inlineSize * 0.6
} else {
this.scrollDistance = entry.contentRect.width * 0.6
}
}
})
})
resObs.observe(this)

File diff suppressed because one or more lines are too long

View File

@ -11,13 +11,10 @@ smCheckbox.innerHTML = `
display: -webkit-inline-box;
display: -ms-inline-flexbox;
display: inline-flex;
--accent-color: #4d2588;
--text-color: 17, 17, 17;
--background-color: 255, 255, 255;
--height: 1.2rem;
--width: 1.2rem;
--border-radius: 0.2rem;
--border-color: rgba(var(--text-color), 0.7);
--border-color: rgba(var(--text-color, (17,17,17)), 0.7);
}
:host([disabled]) {
opacity: 0.6;
@ -42,7 +39,7 @@ smCheckbox.innerHTML = `
}
.checkbox:active .icon,
.checkbox:focus-within .icon{
box-shadow: 0 0 0 0.1rem var(--accent-color) inset;
box-shadow: 0 0 0 0.1rem var(--accent-color, teal) inset;
}
input {
@ -59,11 +56,11 @@ smCheckbox.innerHTML = `
:host([checked]) .checkmark {
stroke-dashoffset: 0;
stroke: rgba(var(--background-color), 1);
stroke: rgba(var(--background-color, (255,255,255)), 1);
}
:host([checked]) .icon {
background: var(--accent-color);
box-shadow: 0 0 0 0.1rem var(--accent-color) inset;
background: var(--accent-color, teal);
box-shadow: 0 0 0 0.1rem var(--accent-color, teal) inset;
}
.icon {
fill: none;

View File

@ -1 +1 @@
const smCheckbox=document.createElement("template");smCheckbox.innerHTML='\n<style>\n *{\n padding: 0;\n margin: 0;\n -webkit-box-sizing: border-box;\n box-sizing: border-box;\n } \n :host{\n display: -webkit-inline-box;\n display: -ms-inline-flexbox;\n display: inline-flex;\n --accent-color: #4d2588;\n --text-color: 17, 17, 17;\n --background-color: 255, 255, 255;\n --height: 1.2rem;\n --width: 1.2rem;\n --border-radius: 0.2rem;\n --border-color: rgba(var(--text-color), 0.7);\n }\n :host([disabled]) {\n opacity: 0.6;\n user-select: none;\n pointer-events: none;\n }\n .checkbox {\n position: relative;\n display:-webkit-box;\n display:-ms-flexbox;\n display:flex;\n -webkit-box-align: center;\n -ms-flex-align: center;\n align-items: center;\n cursor: pointer;\n outline: none;\n -webkit-tap-highlight-color: transparent;\n }\n \n .checkbox:focus-visible{\n outline: auto;\n }\n .checkbox:active .icon,\n .checkbox:focus-within .icon{\n box-shadow: 0 0 0 0.1rem var(--accent-color) inset;\n }\n \n input {\n display: none;\n }\n \n .checkmark {\n stroke-dashoffset: -65;\n stroke-dasharray: 65;\n -webkit-transition: stroke-dashoffset 0.3s; \n -o-transition: stroke-dashoffset 0.3s; \n transition: stroke-dashoffset 0.3s;\n }\n \n :host([checked]) .checkmark {\n stroke-dashoffset: 0;\n stroke: rgba(var(--background-color), 1);\n }\n :host([checked]) .icon {\n background: var(--accent-color);\n box-shadow: 0 0 0 0.1rem var(--accent-color) inset;\n } \n .icon {\n fill: none;\n height: var(--height);\n width: var(--width);\n padding: 0.1rem;\n stroke-width: 8; \n stroke: var(--border-color);\n overflow: visible;\n stroke-linecap: round;\n stroke-linejoin: round;\n -webkit-transition: background 0.3s;\n -o-transition: background 0.3s;\n transition: background 0.3s;\n border-radius: var(--border-radius);\n box-shadow: 0 0 0 0.1rem var(--border-color) inset;\n }\n</style>\n<label class="checkbox">\n <svg class="icon" viewBox="0 0 64 64">\n <path class="checkmark" d="M50.52,19.56,26,44.08,13.48,31.56" />\n </svg>\n <slot></slot>\n</label>',customElements.define("sm-checkbox",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smCheckbox.content.cloneNode(!0)),this.defaultState,this.checkbox=this.shadowRoot.querySelector(".checkbox"),this.reset=this.reset.bind(this),this.dispatch=this.dispatch.bind(this),this.handleKeyDown=this.handleKeyDown.bind(this),this.handleClick=this.handleClick.bind(this)}static get observedAttributes(){return["value","disabled","checked"]}get disabled(){return this.hasAttribute("disabled")}set disabled(e){e?this.setAttribute("disabled",""):this.removeAttribute("disabled")}get checked(){return this.hasAttribute("checked")}set checked(e){e?this.setAttribute("checked",""):this.removeAttribute("checked")}set value(e){this.setAttribute("value",e)}get value(){return this.getAttribute("value")}focusIn(){this.focus()}reset(){this.value=this.defaultState}dispatch(){this.dispatchEvent(new CustomEvent("change",{bubbles:!0,composed:!0}))}handleKeyDown(e){" "===e.key&&(e.preventDefault(),this.click())}handleClick(e){this.toggleAttribute("checked")}connectedCallback(){this.hasAttribute("disabled")||this.setAttribute("tabindex","0"),this.setAttribute("role","checkbox"),this.defaultState=this.hasAttribute("checked"),this.hasAttribute("checked")||this.setAttribute("aria-checked","false"),this.addEventListener("keydown",this.handleKeyDown),this.addEventListener("click",this.handleClick)}attributeChangedCallback(e,t,n){t!==n&&("checked"===e?(this.setAttribute("aria-checked",this.hasAttribute("checked")),this.dispatch()):"disabled"===e&&(this.hasAttribute("disabled")?this.removeAttribute("tabindex"):this.setAttribute("tabindex","0")))}disconnectedCallback(){this.removeEventListener("keydown",this.handleKeyDown),this.removeEventListener("change",this.handleClick)}});
const smCheckbox=document.createElement("template");smCheckbox.innerHTML='\n<style>\n *{\n padding: 0;\n margin: 0;\n -webkit-box-sizing: border-box;\n box-sizing: border-box;\n } \n :host{\n display: -webkit-inline-box;\n display: -ms-inline-flexbox;\n display: inline-flex;\n --height: 1.2rem;\n --width: 1.2rem;\n --border-radius: 0.2rem;\n --border-color: rgba(var(--text-color, (17,17,17)), 0.7);\n }\n :host([disabled]) {\n opacity: 0.6;\n user-select: none;\n pointer-events: none;\n }\n .checkbox {\n position: relative;\n display:-webkit-box;\n display:-ms-flexbox;\n display:flex;\n -webkit-box-align: center;\n -ms-flex-align: center;\n align-items: center;\n cursor: pointer;\n outline: none;\n -webkit-tap-highlight-color: transparent;\n }\n \n .checkbox:focus-visible{\n outline: auto;\n }\n .checkbox:active .icon,\n .checkbox:focus-within .icon{\n box-shadow: 0 0 0 0.1rem var(--accent-color, teal) inset;\n }\n \n input {\n display: none;\n }\n \n .checkmark {\n stroke-dashoffset: -65;\n stroke-dasharray: 65;\n -webkit-transition: stroke-dashoffset 0.3s; \n -o-transition: stroke-dashoffset 0.3s; \n transition: stroke-dashoffset 0.3s;\n }\n \n :host([checked]) .checkmark {\n stroke-dashoffset: 0;\n stroke: rgba(var(--background-color, (255,255,255)), 1);\n }\n :host([checked]) .icon {\n background: var(--accent-color, teal);\n box-shadow: 0 0 0 0.1rem var(--accent-color, teal) inset;\n } \n .icon {\n fill: none;\n height: var(--height);\n width: var(--width);\n padding: 0.1rem;\n stroke-width: 8; \n stroke: var(--border-color);\n overflow: visible;\n stroke-linecap: round;\n stroke-linejoin: round;\n -webkit-transition: background 0.3s;\n -o-transition: background 0.3s;\n transition: background 0.3s;\n border-radius: var(--border-radius);\n box-shadow: 0 0 0 0.1rem var(--border-color) inset;\n }\n</style>\n<label class="checkbox">\n <svg class="icon" viewBox="0 0 64 64">\n <path class="checkmark" d="M50.52,19.56,26,44.08,13.48,31.56" />\n </svg>\n <slot></slot>\n</label>',customElements.define("sm-checkbox",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smCheckbox.content.cloneNode(!0)),this.defaultState,this.checkbox=this.shadowRoot.querySelector(".checkbox"),this.reset=this.reset.bind(this),this.dispatch=this.dispatch.bind(this),this.handleKeyDown=this.handleKeyDown.bind(this),this.handleClick=this.handleClick.bind(this)}static get observedAttributes(){return["value","disabled","checked"]}get disabled(){return this.hasAttribute("disabled")}set disabled(e){e?this.setAttribute("disabled",""):this.removeAttribute("disabled")}get checked(){return this.hasAttribute("checked")}set checked(e){e?this.setAttribute("checked",""):this.removeAttribute("checked")}set value(e){this.setAttribute("value",e)}get value(){return this.getAttribute("value")}focusIn(){this.focus()}reset(){this.value=this.defaultState}dispatch(){this.dispatchEvent(new CustomEvent("change",{bubbles:!0,composed:!0}))}handleKeyDown(e){" "===e.key&&(e.preventDefault(),this.click())}handleClick(e){this.toggleAttribute("checked")}connectedCallback(){this.hasAttribute("disabled")||this.setAttribute("tabindex","0"),this.setAttribute("role","checkbox"),this.defaultState=this.hasAttribute("checked"),this.hasAttribute("checked")||this.setAttribute("aria-checked","false"),this.addEventListener("keydown",this.handleKeyDown),this.addEventListener("click",this.handleClick)}attributeChangedCallback(e,t,n){t!==n&&("checked"===e?(this.setAttribute("aria-checked",this.hasAttribute("checked")),this.dispatch()):"disabled"===e&&(this.hasAttribute("disabled")?this.removeAttribute("tabindex"):this.setAttribute("tabindex","0")))}disconnectedCallback(){this.removeEventListener("keydown",this.handleKeyDown),this.removeEventListener("change",this.handleClick)}});

150
components/dist/color-grid.js vendored Normal file
View File

@ -0,0 +1,150 @@
//Color Grid
const colorGrid = document.createElement('template');
colorGrid.innerHTML = `
<style>
*{
padding:0;
margin:0;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
:host{
display: flex;
}
.color-tile-container{
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.color-tile{
position: relative;
cursor: pointer;
display: flex;
height: 2.5rem;
width: 2.5rem;
border-radius: 0.3rem;
align-items: center;
justify-content: center;
}
.color-tile input[type="radio"]{
display: none;
}
.checkmark{
display: flex;
position: absolute;
top: 0;
right: 0;
align-items: center;
justify-content: center;
padding: 0.3rem;
border-radius: 0.3rem;
background-color: rgba(var(--background-color, (255,255,255)), 0.8);
animation: checkmark 0.1s ease;
}
.icon{
height: 1rem;
width: 1rem;
fill: rgba(var(--text-color, (17,17,17)), 1);
}
@keyframes checkmark{
from{
transform: scale(0);
}
to{
transform: scale(1);
}
}
</style>
<div class="color-tile-container">
</div>`;
customElements.define('color-grid',
class extends HTMLElement {
constructor() {
super()
this.attachShadow({
mode: 'open'
}).append(colorGrid.content.cloneNode(true))
this.colorArray = []
this.container = this.shadowRoot.querySelector('.color-tile-container')
this.handleChange = this.handleChange.bind(this)
this.setCheckMark = this.setCheckMark.bind(this)
}
set colors(arr) {
this.colorArray = arr
this.renderTiles()
}
set selectedColor(color) {
if (this.colorArray.includes(color) && this.container.querySelector(`[data-color="${color}"]`)) {
const selectedTile = this.container.querySelector(`[data-color="${color}"]`)
if (selectedTile) {
selectedTile.querySelector('input').checked = true
this.setCheckMark(selectedTile)
}
}
}
randString(length) {
let result = '';
let characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (let i = 0; i < length; i++)
result += characters.charAt(Math.floor(Math.random() * characters.length));
return result;
}
renderTiles() {
this.container.innerHTML = ''
const frag = document.createDocumentFragment()
const groupName = this.randString(6)
this.colorArray.forEach(color => {
const label = document.createElement('label')
label.classList.add('color-tile')
label.setAttribute('data-color', color)
if (color.includes('--'))
label.setAttribute('style', `background-color: var(${color})`)
else
label.setAttribute('style', `background-color: ${color}`)
label.innerHTML = `
<input type="radio" name="${groupName}">
`
frag.append(label)
})
this.container.append(frag)
}
setCheckMark(target) {
target.parentNode.querySelectorAll('.checkmark').forEach(checkmark => checkmark.remove())
const checkMark = document.createElement('div')
checkMark.classList.add('checkmark')
checkMark.innerHTML = `
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0z" fill="none"/><path d="M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z"/></svg>
`
target.append(checkMark)
}
handleChange(e) {
const clickedTile = e.target.closest('.color-tile')
this.setCheckMark(clickedTile)
const clickedTileColor = clickedTile.dataset.color
const tileSelected = new CustomEvent('colorselected', {
bubbles: true,
composed: true,
detail: {
value: clickedTileColor,
}
})
this.dispatchEvent(tileSelected)
}
connectedCallback() {
this.container.addEventListener('change', this.handleChange)
}
disconnectedCallback() {
this.container.removeEventListener('change', this.handleChange)
}
})

1
components/dist/color-grid.min.js vendored Normal file
View File

@ -0,0 +1 @@
const colorGrid=document.createElement("template");colorGrid.innerHTML='\n<style>\n *{\n padding:0;\n margin:0;\n -webkit-box-sizing: border-box;\n box-sizing: border-box;\n }\n :host{\n display: flex;\n }\n .color-tile-container{\n display: flex;\n flex-wrap: wrap;\n gap: 0.5rem;\n }\n .color-tile{\n position: relative;\n cursor: pointer;\n display: flex;\n height: 2.5rem;\n width: 2.5rem;\n border-radius: 0.3rem;\n align-items: center;\n justify-content: center;\n }\n .color-tile input[type="radio"]{\n display: none;\n }\n .checkmark{\n display: flex;\n position: absolute;\n top: 0;\n right: 0;\n align-items: center;\n justify-content: center;\n padding: 0.3rem;\n border-radius: 0.3rem;\n background-color: rgba(var(--background-color, (255,255,255)), 0.8);\n animation: checkmark 0.1s ease;\n }\n .icon{\n height: 1rem;\n width: 1rem;\n fill: rgba(var(--text-color, (17,17,17)), 1);\n }\n @keyframes checkmark{\n from{\n transform: scale(0);\n }\n to{\n transform: scale(1);\n }\n }\n\n</style>\n<div class="color-tile-container">\n</div>',customElements.define("color-grid",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(colorGrid.content.cloneNode(!0)),this.colorArray=[],this.container=this.shadowRoot.querySelector(".color-tile-container"),this.handleChange=this.handleChange.bind(this),this.setCheckMark=this.setCheckMark.bind(this)}set colors(e){this.colorArray=e,this.renderTiles()}set selectedColor(e){if(this.colorArray.includes(e)&&this.container.querySelector(`[data-color="${e}"]`)){const n=this.container.querySelector(`[data-color="${e}"]`);n&&(n.querySelector("input").checked=!0,this.setCheckMark(n))}}randString(e){let n="",t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";for(let r=0;r<e;r++)n+=t.charAt(Math.floor(Math.random()*t.length));return n}renderTiles(){this.container.innerHTML="";const e=document.createDocumentFragment(),n=this.randString(6);this.colorArray.forEach(t=>{const r=document.createElement("label");r.classList.add("color-tile"),r.setAttribute("data-color",t),t.includes("--")?r.setAttribute("style",`background-color: var(${t})`):r.setAttribute("style",`background-color: ${t}`),r.innerHTML=`\n <input type="radio" name="${n}">\n `,e.append(r)}),this.container.append(e)}setCheckMark(e){e.parentNode.querySelectorAll(".checkmark").forEach(e=>e.remove());const n=document.createElement("div");n.classList.add("checkmark"),n.innerHTML='\n <svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0z" fill="none"/><path d="M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z"/></svg>\n ',e.append(n)}handleChange(e){const n=e.target.closest(".color-tile");this.setCheckMark(n);const t=n.dataset.color,r=new CustomEvent("colorselected",{bubbles:!0,composed:!0,detail:{value:t}});this.dispatchEvent(r)}connectedCallback(){this.container.addEventListener("change",this.handleChange)}disconnectedCallback(){this.container.removeEventListener("change",this.handleChange)}});

View File

@ -10,16 +10,11 @@ smCopy.innerHTML = `
:host{
display: -webkit-box;
display: flex;
--accent-color: #4d2588;
--text-color: 17, 17, 17;
--background-color: 255, 255, 255;
--padding: 0;
--background-color: inherit;
--button-background-color: rgba(var(--text-color), 0.2);
--button-background-color: rgba(var(--text-color, (17,17,17)), 0.2);
}
.copy{
display: grid;
width: 100%;
gap: 0.5rem;
padding: var(--padding);
align-items: center;
@ -40,8 +35,15 @@ smCopy.innerHTML = `
cursor: pointer;
border: none;
padding: 0.4rem;
background-color: inherit;
background-color: rgba(var(--text-color, (17,17,17)), 0.06);
border-radius: var(--button-border-radius, 0.3rem);
transition: background-color 0.2s;
font-family: inherit;
color: inherit;
font-size: 0.7rem;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.05rem;
}
.copy-button:active{
background-color: var(--button-background-color);
@ -49,15 +51,12 @@ smCopy.innerHTML = `
.icon{
height: 1.2rem;
width: 1.2rem;
fill: rgba(var(--text-color), 0.8);
fill: rgba(var(--text-color, (17,17,17)), 0.8);
}
@media (any-hover: hover){
.copy:hover .copy-button{
opacity: 1;
}
.copy-button{
opacity: 0.6;
}
.copy-button:hover{
background-color: var(--button-background-color);
}
@ -67,7 +66,7 @@ smCopy.innerHTML = `
<p class="copy-content"></p>
<button part="button" class="copy-button" title="copy">
<slot name="copy-icon">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M7 6V3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1h-3v3c0 .552-.45 1-1.007 1H4.007A1.001 1.001 0 0 1 3 21l.003-14c0-.552.45-1 1.007-1H7zM5.003 8L5 20h10V8H5.003zM9 6h8v10h2V4H9v2z"/></svg>
COPY
</slot>
</button>
</section>

View File

@ -1 +1 @@
const smCopy=document.createElement("template");smCopy.innerHTML='\n<style> \n*{\n padding: 0;\n margin: 0;\n -webkit-box-sizing: border-box;\n box-sizing: border-box;\n} \n:host{\n display: -webkit-box;\n display: flex;\n --accent-color: #4d2588;\n --text-color: 17, 17, 17;\n --background-color: 255, 255, 255;\n --padding: 0;\n --background-color: inherit;\n --button-background-color: rgba(var(--text-color), 0.2);\n}\n.copy{\n display: grid;\n width: 100%;\n gap: 0.5rem;\n padding: var(--padding);\n align-items: center;\n grid-template-columns: minmax(0, 1fr) auto;\n}\n:host(:not([clip-text])) .copy-content{\n overflow-wrap: break-word;\n word-wrap: break-word;\n}\n:host([clip-text]) .copy-content{\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.copy-button{\n display: inline-flex;\n justify-content: center;\n cursor: pointer;\n border: none;\n padding: 0.4rem;\n background-color: inherit;\n border-radius: var(--button-border-radius, 0.3rem);\n}\n.copy-button:active{\n background-color: var(--button-background-color);\n}\n.icon{\n height: 1.2rem;\n width: 1.2rem;\n fill: rgba(var(--text-color), 0.8);\n}\n@media (any-hover: hover){\n .copy:hover .copy-button{\n opacity: 1;\n }\n .copy-button{\n opacity: 0.6;\n }\n .copy-button:hover{\n background-color: var(--button-background-color);\n }\n}\n</style>\n<section class="copy">\n <p class="copy-content"></p>\n <button part="button" class="copy-button" title="copy">\n <slot name="copy-icon">\n <svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M7 6V3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1h-3v3c0 .552-.45 1-1.007 1H4.007A1.001 1.001 0 0 1 3 21l.003-14c0-.552.45-1 1.007-1H7zM5.003 8L5 20h10V8H5.003zM9 6h8v10h2V4H9v2z"/></svg>\n </slot>\n </button>\n</section>\n',customElements.define("sm-copy",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smCopy.content.cloneNode(!0)),this.copyContent=this.shadowRoot.querySelector(".copy-content"),this.copyButton=this.shadowRoot.querySelector(".copy-button"),this.copy=this.copy.bind(this)}static get observedAttributes(){return["value"]}set value(n){this.setAttribute("value",n)}get value(){return this.getAttribute("value")}fireEvent(){this.dispatchEvent(new CustomEvent("copy",{composed:!0,bubbles:!0,cancelable:!0}))}copy(){navigator.clipboard.writeText(this.copyContent.textContent).then(n=>this.fireEvent()).catch(n=>console.error(n))}connectedCallback(){this.copyButton.addEventListener("click",this.copy)}attributeChangedCallback(n,t,o){"value"===n&&(this.copyContent.textContent=o)}disconnectedCallback(){this.copyButton.removeEventListener("click",this.copy)}});
const smCopy=document.createElement("template");smCopy.innerHTML='\n<style> \n*{\n padding: 0;\n margin: 0;\n -webkit-box-sizing: border-box;\n box-sizing: border-box;\n} \n:host{\n display: -webkit-box;\n display: flex;\n --padding: 0;\n --button-background-color: rgba(var(--text-color, (17,17,17)), 0.2);\n}\n.copy{\n display: grid;\n gap: 0.5rem;\n padding: var(--padding);\n align-items: center;\n grid-template-columns: minmax(0, 1fr) auto;\n}\n:host(:not([clip-text])) .copy-content{\n overflow-wrap: break-word;\n word-wrap: break-word;\n}\n:host([clip-text]) .copy-content{\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.copy-button{\n display: inline-flex;\n justify-content: center;\n cursor: pointer;\n border: none;\n padding: 0.4rem;\n background-color: rgba(var(--text-color, (17,17,17)), 0.06);\n border-radius: var(--button-border-radius, 0.3rem);\n transition: background-color 0.2s;\n font-family: inherit;\n color: inherit;\n font-size: 0.7rem;\n font-weight: 500;\n text-transform: uppercase;\n letter-spacing: 0.05rem;\n}\n.copy-button:active{\n background-color: var(--button-background-color);\n}\n.icon{\n height: 1.2rem;\n width: 1.2rem;\n fill: rgba(var(--text-color, (17,17,17)), 0.8);\n}\n@media (any-hover: hover){\n .copy:hover .copy-button{\n opacity: 1;\n }\n .copy-button:hover{\n background-color: var(--button-background-color);\n }\n}\n</style>\n<section class="copy">\n <p class="copy-content"></p>\n <button part="button" class="copy-button" title="copy">\n <slot name="copy-icon">\n COPY\n </slot>\n </button>\n</section>\n',customElements.define("sm-copy",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smCopy.content.cloneNode(!0)),this.copyContent=this.shadowRoot.querySelector(".copy-content"),this.copyButton=this.shadowRoot.querySelector(".copy-button"),this.copy=this.copy.bind(this)}static get observedAttributes(){return["value"]}set value(n){this.setAttribute("value",n)}get value(){return this.getAttribute("value")}fireEvent(){this.dispatchEvent(new CustomEvent("copy",{composed:!0,bubbles:!0,cancelable:!0}))}copy(){navigator.clipboard.writeText(this.copyContent.textContent).then(n=>this.fireEvent()).catch(n=>console.error(n))}connectedCallback(){this.copyButton.addEventListener("click",this.copy)}attributeChangedCallback(n,t,o){"value"===n&&(this.copyContent.textContent=o)}disconnectedCallback(){this.copyButton.removeEventListener("click",this.copy)}});

View File

@ -7,13 +7,10 @@ fileInput.innerHTML = `
box-sizing: border-box;
}
:host{
--accent-color: #4d2588;
--text-color: 17, 17, 17;
--background-color: 255, 255, 255;
--border-radius: 0.3rem;
--button-color: rgba(var(--background-color), 1);
--button-color: rgba(var(--background-color, (255, 255, 255)), 1);
--button-font-weight: 500;
--button-background-color: var(--accent-color);
--button-background-color: var(--accent-color, teal);
}
.file-input {
display: flex;
@ -44,14 +41,14 @@ fileInput.innerHTML = `
align-items: center;
padding: 0.5rem 0.8rem;
border-radius: var(--border-radius);
background-color: rgba(var(--text-color), 0.06)
background-color: rgba(var(--text-color, (17,17,17)), 0.06)
}
.file-name{
}
.file-size{
font-size: 0.8rem;
font-weight: 400;
color: rgba(var(--text-color), 0.8);
color: rgba(var(--text-color, (17,17,17)), 0.8);
}
input[type=file] {
display: none;

View File

@ -1 +1 @@
const fileInput=document.createElement("template");fileInput.innerHTML='\n \t<style>\n\t\t*{\n\t\t\tpadding: 0;\n\t\t\tmargin: 0;\n\t\t\tbox-sizing: border-box;\n\t\t}\n\t\t:host{\n\t\t\t--accent-color: #4d2588;\n\t\t\t--text-color: 17, 17, 17;\n\t\t\t--background-color: 255, 255, 255;\n\t\t\t--border-radius: 0.3rem;\n\t\t\t--button-color: rgba(var(--background-color), 1);\n\t\t\t--button-font-weight: 500;\n\t\t\t--button-background-color: var(--accent-color);\n\t\t}\n\t\t.file-input {\n\t\t\tdisplay: flex;\n\t\t}\n\t\t\n\t\t.file-picker-button {\n display: flex;\n\t\t\tcursor: pointer;\n\t\t\tuser-select: none;\n align-items: center;\n\t\t\tpadding: 0.5rem 0.8rem;\n\t\t\tcolor: var(--button-color);\n\t\t\tborder-radius: var(--border-radius);\n\t\t\tfont-weight: var(--button-font-weight);\n\t\t\tbackground-color: var(--button-background-color);\n\t\t}\n\t\t.files-preview-wrapper{\n\t\t\tdisplay: grid;\n\t\t\tgap: 0.5rem;\n\t\t\tlist-style: none;\n\t\t}\n\t\t.files-preview-wrapper:not(:empty){\n margin-bottom: 1rem;\n\t\t}\n\t\t.file-preview{\n\t\t\tdisplay: grid;\n gap: 0.5rem;\n align-items: center;\n\t\t\tpadding: 0.5rem 0.8rem;\n\t\t\tborder-radius: var(--border-radius);\n\t\t\tbackground-color: rgba(var(--text-color), 0.06)\n\t\t}\n\t\t.file-name{\n\t\t}\n .file-size{\n font-size: 0.8rem;\n font-weight: 400;\n color: rgba(var(--text-color), 0.8);\n }\n\t\tinput[type=file] {\n\t\t\tdisplay: none;\n\t\t}\n \t</style>\n\t<ul class="files-preview-wrapper"></ul>\n \t<label tabindex="0" class="file-input">\n\t\t<div class="file-picker-button"><slot>Choose file</slot></div>\n\t\t<input type="file">\n\t</label>\n',customElements.define("file-input",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(fileInput.content.cloneNode(!0)),this.input=this.shadowRoot.querySelector("input"),this.fileInput=this.shadowRoot.querySelector(".file-input"),this.filesPreviewWrapper=this.shadowRoot.querySelector(".files-preview-wrapper"),this.reflectedAttributes=["accept","multiple","capture","type"],this.reset=this.reset.bind(this),this.formatBytes=this.formatBytes.bind(this),this.createFilePreview=this.createFilePreview.bind(this),this.handleChange=this.handleChange.bind(this),this.handleKeyDown=this.handleKeyDown.bind(this)}static get observedAttributes(){return["accept","multiple","capture","type"]}get files(){return this.input.files}set accept(t){this.setAttribute("accept",t)}set multiple(t){t?this.setAttribute("multiple",""):this.removeAttribute("multiple")}set capture(t){this.setAttribute("capture",t)}set value(t){this.input.value=t}get isValid(){return""!==this.input.value}reset(){this.input.value="",this.filesPreviewWrapper.innerHTML=""}formatBytes(t,e=2){if(0===t)return"0 Bytes";const n=0>e?0:e,i=Math.floor(Math.log(t)/Math.log(1024));return parseFloat((t/Math.pow(1024,i)).toFixed(n))+" "+["Bytes","KB","MB","GB","TB","PB","EB","ZB","YB"][i]}createFilePreview(t){const e=document.createElement("li"),{name:n,size:i}=t;return e.className="file-preview",e.innerHTML=`\n\t\t\t<div class="file-name">${n}</div>\n <h5 class="file-size">${this.formatBytes(i)}</h5>\n\t\t`,e}handleChange(t){this.filesPreviewWrapper.innerHTML="";const e=document.createDocumentFragment();Array.from(t.target.files).forEach(t=>{e.append(this.createFilePreview(t))}),this.filesPreviewWrapper.append(e)}handleKeyDown(t){"Enter"!==t.key&&" "!==t.key||(t.preventDefault(),this.input.click())}connectedCallback(){this.setAttribute("role","button"),this.setAttribute("aria-label","File upload"),this.input.addEventListener("change",this.handleChange),this.fileInput.addEventListener("keydown",this.handleKeyDown)}attributeChangedCallback(t){this.reflectedAttributes.includes(t)&&(this.hasAttribute(t)?this.input.setAttribute(t,this.getAttribute(t)?this.getAttribute(t):""):this.input.removeAttribute(t))}disconnectedCallback(){this.input.removeEventListener("change",this.handleChange),this.fileInput.removeEventListener("keydown",this.handleKeyDown)}});
const fileInput=document.createElement("template");fileInput.innerHTML='\n \t<style>\n\t\t*{\n\t\t\tpadding: 0;\n\t\t\tmargin: 0;\n\t\t\tbox-sizing: border-box;\n\t\t}\n\t\t:host{\n\t\t\t--border-radius: 0.3rem;\n\t\t\t--button-color: rgba(var(--background-color, (255, 255, 255)), 1);\n\t\t\t--button-font-weight: 500;\n\t\t\t--button-background-color: var(--accent-color, teal);\n\t\t}\n\t\t.file-input {\n\t\t\tdisplay: flex;\n\t\t}\n\t\t\n\t\t.file-picker-button {\n display: flex;\n\t\t\tcursor: pointer;\n\t\t\tuser-select: none;\n align-items: center;\n\t\t\tpadding: 0.5rem 0.8rem;\n\t\t\tcolor: var(--button-color);\n\t\t\tborder-radius: var(--border-radius);\n\t\t\tfont-weight: var(--button-font-weight);\n\t\t\tbackground-color: var(--button-background-color);\n\t\t}\n\t\t.files-preview-wrapper{\n\t\t\tdisplay: grid;\n\t\t\tgap: 0.5rem;\n\t\t\tlist-style: none;\n\t\t}\n\t\t.files-preview-wrapper:not(:empty){\n margin-bottom: 1rem;\n\t\t}\n\t\t.file-preview{\n\t\t\tdisplay: grid;\n gap: 0.5rem;\n align-items: center;\n\t\t\tpadding: 0.5rem 0.8rem;\n\t\t\tborder-radius: var(--border-radius);\n\t\t\tbackground-color: rgba(var(--text-color, (17,17,17)), 0.06)\n\t\t}\n\t\t.file-name{\n\t\t}\n .file-size{\n font-size: 0.8rem;\n font-weight: 400;\n color: rgba(var(--text-color, (17,17,17)), 0.8);\n }\n\t\tinput[type=file] {\n\t\t\tdisplay: none;\n\t\t}\n \t</style>\n\t<ul class="files-preview-wrapper"></ul>\n \t<label tabindex="0" class="file-input">\n\t\t<div class="file-picker-button"><slot>Choose file</slot></div>\n\t\t<input type="file">\n\t</label>\n',customElements.define("file-input",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(fileInput.content.cloneNode(!0)),this.input=this.shadowRoot.querySelector("input"),this.fileInput=this.shadowRoot.querySelector(".file-input"),this.filesPreviewWrapper=this.shadowRoot.querySelector(".files-preview-wrapper"),this.reflectedAttributes=["accept","multiple","capture","type"],this.reset=this.reset.bind(this),this.formatBytes=this.formatBytes.bind(this),this.createFilePreview=this.createFilePreview.bind(this),this.handleChange=this.handleChange.bind(this),this.handleKeyDown=this.handleKeyDown.bind(this)}static get observedAttributes(){return["accept","multiple","capture","type"]}get files(){return this.input.files}set accept(t){this.setAttribute("accept",t)}set multiple(t){t?this.setAttribute("multiple",""):this.removeAttribute("multiple")}set capture(t){this.setAttribute("capture",t)}set value(t){this.input.value=t}get isValid(){return""!==this.input.value}reset(){this.input.value="",this.filesPreviewWrapper.innerHTML=""}formatBytes(t,e=2){if(0===t)return"0 Bytes";const n=0>e?0:e,i=Math.floor(Math.log(t)/Math.log(1024));return parseFloat((t/Math.pow(1024,i)).toFixed(n))+" "+["Bytes","KB","MB","GB","TB","PB","EB","ZB","YB"][i]}createFilePreview(t){const e=document.createElement("li"),{name:n,size:i}=t;return e.className="file-preview",e.innerHTML=`\n\t\t\t<div class="file-name">${n}</div>\n <h5 class="file-size">${this.formatBytes(i)}</h5>\n\t\t`,e}handleChange(t){this.filesPreviewWrapper.innerHTML="";const e=document.createDocumentFragment();Array.from(t.target.files).forEach(t=>{e.append(this.createFilePreview(t))}),this.filesPreviewWrapper.append(e)}handleKeyDown(t){"Enter"!==t.key&&" "!==t.key||(t.preventDefault(),this.input.click())}connectedCallback(){this.setAttribute("role","button"),this.setAttribute("aria-label","File upload"),this.input.addEventListener("change",this.handleChange),this.fileInput.addEventListener("keydown",this.handleKeyDown)}attributeChangedCallback(t){this.reflectedAttributes.includes(t)&&(this.hasAttribute(t)?this.input.setAttribute(t,this.getAttribute(t)?this.getAttribute(t):""):this.input.removeAttribute(t))}disconnectedCallback(){this.input.removeEventListener("change",this.handleChange),this.fileInput.removeEventListener("keydown",this.handleKeyDown)}});

View File

@ -1,25 +1,25 @@
const smForm = document.createElement('template');
smForm.innerHTML = `
<style>
*{
padding: 0;
margin: 0;
box-sizing: border-box;
}
:host{
display: flex;
width: 100%;
}
form{
display: grid;
gap: var(--gap, 1.5rem);
width: 100%;
}
</style>
<form part="form" onsubmit="return false">
<slot></slot>
</form>
`;
<style>
*{
padding: 0;
margin: 0;
box-sizing: border-box;
}
:host{
display: grid;
width: 100%;
}
form{
display: inherit;
gap: var(--gap, 1.5rem);
width: 100%;
}
</style>
<form part="form" onsubmit="return false">
<slot></slot>
</form>
`;
customElements.define('sm-form', class extends HTMLElement {
constructor() {
@ -33,7 +33,7 @@ customElements.define('sm-form', class extends HTMLElement {
this.requiredElements
this.submitButton
this.resetButton
this.allRequiredValid = false;
this.invalidFields = false;
this.debounce = this.debounce.bind(this)
this._checkValidity = this._checkValidity.bind(this)
@ -51,18 +51,13 @@ customElements.define('sm-form', class extends HTMLElement {
};
}
_checkValidity() {
this.allRequiredValid = this.requiredElements.every(elem => elem.isValid)
if (!this.submitButton) return;
if (this.allRequiredValid) {
this.submitButton.disabled = false;
}
else {
this.submitButton.disabled = true;
}
this.invalidFields = this.requiredElements.filter(elem => !elem.isValid)
this.submitButton.disabled = this.invalidFields.length;
}
handleKeydown(e) {
if (e.key === 'Enter' && !e.target.tagName.includes('TEXTAREA')) {
if (this.allRequiredValid) {
if (e.key === 'Enter' && e.target.tagName.includes('SM-INPUT')) {
if (!this.invalidFields.length) {
if (this.submitButton) {
this.submitButton.click()
}
@ -70,9 +65,8 @@ customElements.define('sm-form', class extends HTMLElement {
bubbles: true,
composed: true,
}))
}
else {
this.requiredElements.find(elem => !elem.isValid).vibrate()
} else {
this.requiredElements.forEach(elem => { if (!elem.isValid) elem.vibrate() })
}
}
}
@ -90,13 +84,21 @@ customElements.define('sm-form', class extends HTMLElement {
this._checkValidity()
}
connectedCallback() {
const slot = this.shadowRoot.querySelector('slot')
slot.addEventListener('slotchange', this.elementsChanged)
this.shadowRoot.querySelector('slot').addEventListener('slotchange', this.elementsChanged)
this.addEventListener('input', this.debounce(this._checkValidity, 100));
this.addEventListener('keydown', this.debounce(this.handleKeydown, 100));
const mutationObserver = new MutationObserver(mutations => {
mutations.forEach(mutation => {
if (mutation.type === 'childList') {
this.elementsChanged()
}
})
})
mutationObserver.observe(this, { childList: true, subtree: true })
}
disconnectedCallback() {
this.removeEventListener('input', this.debounce(this._checkValidity, 100));
this.removeEventListener('keydown', this.debounce(this.handleKeydown, 100));
mutationObserver.disconnect()
}
})

View File

@ -1 +1 @@
const smForm=document.createElement("template");smForm.innerHTML='\n <style>\n *{\n padding: 0;\n margin: 0;\n box-sizing: border-box;\n }\n :host{\n display: flex;\n width: 100%;\n }\n form{\n display: grid;\n gap: var(--gap, 1.5rem);\n width: 100%;\n }\n </style>\n\t<form part="form" onsubmit="return false">\n\t\t<slot></slot>\n\t</form>\n',customElements.define("sm-form",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smForm.content.cloneNode(!0)),this.form=this.shadowRoot.querySelector("form"),this.formElements,this.requiredElements,this.submitButton,this.resetButton,this.allRequiredValid=!1,this.debounce=this.debounce.bind(this),this._checkValidity=this._checkValidity.bind(this),this.handleKeydown=this.handleKeydown.bind(this),this.reset=this.reset.bind(this),this.elementsChanged=this.elementsChanged.bind(this)}debounce(t,e){let i=null;return(...s)=>{window.clearTimeout(i),i=window.setTimeout(()=>{t.apply(null,s)},e)}}_checkValidity(){this.allRequiredValid=this.requiredElements.every(t=>t.isValid),this.submitButton&&(this.allRequiredValid?this.submitButton.disabled=!1:this.submitButton.disabled=!0)}handleKeydown(t){"Enter"!==t.key||t.target.tagName.includes("TEXTAREA")||(this.allRequiredValid?(this.submitButton&&this.submitButton.click(),this.dispatchEvent(new CustomEvent("submit",{bubbles:!0,composed:!0}))):this.requiredElements.find(t=>!t.isValid).vibrate())}reset(){this.formElements.forEach(t=>t.reset())}elementsChanged(){this.formElements=[...this.querySelectorAll("sm-input, sm-textarea, sm-checkbox, tags-input, file-input, sm-switch, sm-radio")],this.requiredElements=this.formElements.filter(t=>t.hasAttribute("required")),this.submitButton=this.querySelector('[variant="primary"], [type="submit"]'),this.resetButton=this.querySelector('[type="reset"]'),this.resetButton&&this.resetButton.addEventListener("click",this.reset),this._checkValidity()}connectedCallback(){const t=this.shadowRoot.querySelector("slot");t.addEventListener("slotchange",this.elementsChanged),this.addEventListener("input",this.debounce(this._checkValidity,100)),this.addEventListener("keydown",this.debounce(this.handleKeydown,100))}disconnectedCallback(){this.removeEventListener("input",this.debounce(this._checkValidity,100)),this.removeEventListener("keydown",this.debounce(this.handleKeydown,100))}});
const smForm=document.createElement("template");smForm.innerHTML='\n <style>\n *{\n padding: 0;\n margin: 0;\n box-sizing: border-box;\n }\n :host{\n display: grid;\n width: 100%;\n }\n form{\n display: inherit;\n gap: var(--gap, 1.5rem);\n width: 100%;\n }\n </style>\n <form part="form" onsubmit="return false">\n <slot></slot>\n </form>\n ',customElements.define("sm-form",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smForm.content.cloneNode(!0)),this.form=this.shadowRoot.querySelector("form"),this.formElements,this.requiredElements,this.submitButton,this.resetButton,this.invalidFields=!1,this.debounce=this.debounce.bind(this),this._checkValidity=this._checkValidity.bind(this),this.handleKeydown=this.handleKeydown.bind(this),this.reset=this.reset.bind(this),this.elementsChanged=this.elementsChanged.bind(this)}debounce(e,t){let i=null;return(...s)=>{window.clearTimeout(i),i=window.setTimeout(()=>{e.apply(null,s)},t)}}_checkValidity(){this.submitButton&&(this.invalidFields=this.requiredElements.filter(e=>!e.isValid),this.submitButton.disabled=this.invalidFields.length)}handleKeydown(e){"Enter"===e.key&&e.target.tagName.includes("SM-INPUT")&&(this.invalidFields.length?this.requiredElements.forEach(e=>{e.isValid||e.vibrate()}):(this.submitButton&&this.submitButton.click(),this.dispatchEvent(new CustomEvent("submit",{bubbles:!0,composed:!0}))))}reset(){this.formElements.forEach(e=>e.reset())}elementsChanged(){this.formElements=[...this.querySelectorAll("sm-input, sm-textarea, sm-checkbox, tags-input, file-input, sm-switch, sm-radio")],this.requiredElements=this.formElements.filter(e=>e.hasAttribute("required")),this.submitButton=this.querySelector('[variant="primary"], [type="submit"]'),this.resetButton=this.querySelector('[type="reset"]'),this.resetButton&&this.resetButton.addEventListener("click",this.reset),this._checkValidity()}connectedCallback(){this.shadowRoot.querySelector("slot").addEventListener("slotchange",this.elementsChanged),this.addEventListener("input",this.debounce(this._checkValidity,100)),this.addEventListener("keydown",this.debounce(this.handleKeydown,100));const e=new MutationObserver(e=>{e.forEach(e=>{"childList"===e.type&&this.elementsChanged()})});e.observe(this,{childList:!0,subtree:!0})}disconnectedCallback(){this.removeEventListener("input",this.debounce(this._checkValidity,100)),this.removeEventListener("keydown",this.debounce(this.handleKeydown,100)),mutationObserver.disconnect()}});

View File

@ -14,9 +14,6 @@ hamburgerMenu.innerHTML = `
height: 100%;
overflow-y: auto;
scrollbar-width: thin;
--accent-color: #4d2588;
--text-color: 17, 17, 17;
--background-color: 255, 255, 255;
--padding: 0 0 3rem 0;
--backdrop-color: rgba(0,0,0,0.5);
}
@ -41,7 +38,7 @@ hamburgerMenu.innerHTML = `
overflow-y: auto;
width: calc(100% - 4rem);
transition: transform 0.3s;
background-color: rgba(var(--background-color), 1);
background-color: rgba(var(--background-color, (255, 255, 255)), 1);
box-shadow: 0.5rem 0 2rem rgba(0,0,0, 0.1);
z-index: 1;
}
@ -73,9 +70,9 @@ hamburgerMenu.innerHTML = `
}
::-webkit-scrollbar-thumb{
border-radius: 1rem;
background: rgba(var(--text-color), 0.3);
background: rgba(var(--text-color, (17,17,17)), 0.3);
&:hover{
background: rgba(var(--text-color), 0.5);
background: rgba(var(--text-color, (17,17,17)), 0.5);
}
}
}

View File

@ -1 +1 @@
const hamburgerMenu=document.createElement("template");hamburgerMenu.innerHTML='\n<style>\n*{\n padding: 0;\n margin: 0;\n -webkit-box-sizing: border-box;\n box-sizing: border-box;\n} \n:host{\n display: flex;\n width: 100%;\n height: 100%;\n overflow-y: auto;\n scrollbar-width: thin;\n --accent-color: #4d2588;\n --text-color: 17, 17, 17;\n --background-color: 255, 255, 255;\n --padding: 0 0 3rem 0;\n --backdrop-color: rgba(0,0,0,0.5);\n}\n.backdrop{\n position: fixed;\n}\n.side-nav{\n display: flex;\n flex-direction: column;\n width: 100%;\n}\n.hide{\n display: none !important;\n}\n@media screen and (max-width: 640px){\n :host{\n position: fixed;\n z-index: 10;\n }\n .side-nav{\n height: 100%;\n overflow-y: auto; \n width: calc(100% - 4rem);\n transition: transform 0.3s;\n background-color: rgba(var(--background-color), 1);\n box-shadow: 0.5rem 0 2rem rgba(0,0,0, 0.1);\n z-index: 1;\n }\n .side-nav:not(.reveal){\n transform: translateX(-100%);\n }\n .reveal{\n transform: none;\n }\n .backdrop{\n top: 0;\n bottom: 0;\n left: 0;\n right: 0;\n background-color: var(--backdrop-color);\n -webkit-transition: opacity 0.3s;\n -o-transition: opacity 0.3s;\n transition: opacity 0.3s;\n }\n}\n@media screen and (min-width: 640px){\n .backdrop{\n pointer-events: none;\n }\n}\n@media (any-hover: hover){\n ::-webkit-scrollbar{\n width: 0.5rem;\n }\n ::-webkit-scrollbar-thumb{\n border-radius: 1rem;\n background: rgba(var(--text-color), 0.3);\n &:hover{\n background: rgba(var(--text-color), 0.5);\n }\n }\n}\n</style>\n<section class="backdrop hide"></section>\n<nav class="side-nav">\n <slot></slot>\n</nav>\n';class HamburgerMenu extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(hamburgerMenu.content.cloneNode(!0)),this.resumeScrolling=this.resumeScrolling.bind(this),this.open=this.open.bind(this),this.close=this.close.bind(this),this.sideNav=this.shadowRoot.querySelector(".side-nav"),this.backdrop=this.shadowRoot.querySelector(".backdrop"),this.isOpen=!1,this.animeOptions={duration:300,easing:"ease"}}static get observedAttributes(){return["open"]}resumeScrolling(){const n=document.body.style.top;window.scrollTo(0,-1*parseInt(n||"0")),setTimeout(()=>{document.body.style.overflow="auto",document.body.style.top="initial"},300)}open(){this.isOpen||(document.body.style.overflow="hidden",document.body.style.top=`-${window.scrollY}px`,this.classList.remove("hide"),this.sideNav.classList.add("reveal"),this.backdrop.classList.remove("hide"),this.backdrop.animate([{opacity:0},{opacity:1}],this.animeOptions).onfinish=(()=>{this.isOpen=!0,this.setAttribute("open","")}))}close(){this.isOpen&&(this.sideNav.classList.remove("reveal"),this.backdrop.animate([{opacity:1},{opacity:0}],this.animeOptions).onfinish=(()=>{this.backdrop.classList.add("hide"),this.classList.add("hide"),this.isOpen=!1,this.removeAttribute("open")}))}connectedCallback(){this.backdrop.addEventListener("click",this.close);const n=new ResizeObserver(n=>{window.innerWidth<640&&this.isOpen?this.classList.remove("hide"):this.classList.add("hide"),window.innerWidth>640&&this.classList.remove("hide")});n.observe(this)}disconnectedCallback(){this.backdrop.removeEventListener("click",this.close)}attributeChangedCallback(n,e,t){"open"===n&&this.hasAttribute("open")&&this.open()}}window.customElements.define("hamburger-menu",HamburgerMenu);
const hamburgerMenu=document.createElement("template");hamburgerMenu.innerHTML='\n<style>\n*{\n padding: 0;\n margin: 0;\n -webkit-box-sizing: border-box;\n box-sizing: border-box;\n} \n:host{\n display: flex;\n width: 100%;\n height: 100%;\n overflow-y: auto;\n scrollbar-width: thin;\n --padding: 0 0 3rem 0;\n --backdrop-color: rgba(0,0,0,0.5);\n}\n.backdrop{\n position: fixed;\n}\n.side-nav{\n display: flex;\n flex-direction: column;\n width: 100%;\n}\n.hide{\n display: none !important;\n}\n@media screen and (max-width: 640px){\n :host{\n position: fixed;\n z-index: 10;\n }\n .side-nav{\n height: 100%;\n overflow-y: auto; \n width: calc(100% - 4rem);\n transition: transform 0.3s;\n background-color: rgba(var(--background-color, (255, 255, 255)), 1);\n box-shadow: 0.5rem 0 2rem rgba(0,0,0, 0.1);\n z-index: 1;\n }\n .side-nav:not(.reveal){\n transform: translateX(-100%);\n }\n .reveal{\n transform: none;\n }\n .backdrop{\n top: 0;\n bottom: 0;\n left: 0;\n right: 0;\n background-color: var(--backdrop-color);\n -webkit-transition: opacity 0.3s;\n -o-transition: opacity 0.3s;\n transition: opacity 0.3s;\n }\n}\n@media screen and (min-width: 640px){\n .backdrop{\n pointer-events: none;\n }\n}\n@media (any-hover: hover){\n ::-webkit-scrollbar{\n width: 0.5rem;\n }\n ::-webkit-scrollbar-thumb{\n border-radius: 1rem;\n background: rgba(var(--text-color, (17,17,17)), 0.3);\n &:hover{\n background: rgba(var(--text-color, (17,17,17)), 0.5);\n }\n }\n}\n</style>\n<section class="backdrop hide"></section>\n<nav class="side-nav">\n <slot></slot>\n</nav>\n';class HamburgerMenu extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(hamburgerMenu.content.cloneNode(!0)),this.resumeScrolling=this.resumeScrolling.bind(this),this.open=this.open.bind(this),this.close=this.close.bind(this),this.sideNav=this.shadowRoot.querySelector(".side-nav"),this.backdrop=this.shadowRoot.querySelector(".backdrop"),this.isOpen=!1,this.animeOptions={duration:300,easing:"ease"}}static get observedAttributes(){return["open"]}resumeScrolling(){const n=document.body.style.top;window.scrollTo(0,-1*parseInt(n||"0")),setTimeout(()=>{document.body.style.overflow="auto",document.body.style.top="initial"},300)}open(){this.isOpen||(document.body.style.overflow="hidden",document.body.style.top=`-${window.scrollY}px`,this.classList.remove("hide"),this.sideNav.classList.add("reveal"),this.backdrop.classList.remove("hide"),this.backdrop.animate([{opacity:0},{opacity:1}],this.animeOptions).onfinish=(()=>{this.isOpen=!0,this.setAttribute("open","")}))}close(){this.isOpen&&(this.sideNav.classList.remove("reveal"),this.backdrop.animate([{opacity:1},{opacity:0}],this.animeOptions).onfinish=(()=>{this.backdrop.classList.add("hide"),this.classList.add("hide"),this.isOpen=!1,this.removeAttribute("open")}))}connectedCallback(){this.backdrop.addEventListener("click",this.close);const n=new ResizeObserver(n=>{window.innerWidth<640&&this.isOpen?this.classList.remove("hide"):this.classList.add("hide"),window.innerWidth>640&&this.classList.remove("hide")});n.observe(this)}disconnectedCallback(){this.backdrop.removeEventListener("click",this.close)}attributeChangedCallback(n,e,t){"open"===n&&this.hasAttribute("open")&&this.open()}}window.customElements.define("hamburger-menu",HamburgerMenu);

View File

@ -1,202 +1,208 @@
//Input
const smInput = document.createElement('template')
smInput.innerHTML = `
<style>
*{
padding: 0;
margin: 0;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
input[type="search"]::-webkit-search-decoration,
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-results-button,
input[type="search"]::-webkit-search-results-decoration { display: none; }
input[type=number] {
-moz-appearance:textfield;
}
input[type=number]::-webkit-inner-spin-button,
input[type=number]::-webkit-outer-spin-button {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
margin: 0;
}
input::-ms-reveal,
input::-ms-clear {
display: none;
}
input:invalid{
outline: none;
-webkit-box-shadow: none;
box-shadow: none;
}
::-moz-focus-inner{
border: none;
}
:host{
display: flex;
--success-color: #00C853;
--danger-color: red;
--width: 100%;
--icon-gap: 0.5rem;
--border-radius: 0.3rem;
--background: rgba(var(--text-color, (17,17,17)), 0.06);
}
.hide{
opacity: 0 !important;
pointer-events: none !important;
}
.hide-completely{
display: none;
}
.icon {
fill: rgba(var(--text-color, (17,17,17)), 0.6);
height: 1.4rem;
width: 1.4rem;
border-radius: 1rem;
cursor: pointer;
min-width: 0;
}
:host(.round) .input{
border-radius: 10rem;
}
.input {
display: flex;
cursor: text;
min-width: 0;
text-align: left;
align-items: center;
position: relative;
gap: var(--icon-gap);
padding: var(--padding, 0.6rem 0.8rem);
border-radius: var(--border-radius);
transition: opacity 0.3s, box-shadow 0.2s;
background: var(--background);
width: 100%;
outline: none;
}
.input.readonly .clear{
opacity: 0 !important;
margin-right: -2rem;
pointer-events: none !important;
}
.readonly{
pointer-events: none;
}
.input:focus-within:not(.readonly){
box-shadow: 0 0 0 0.1rem var(--accent-color,teal) inset !important;
}
.disabled{
pointer-events: none;
opacity: 0.6;
}
.label {
font-size: inherit;
opacity: .7;
font-weight: 400;
position: absolute;
top: 0;
-webkit-transition: -webkit-transform 0.3s;
transition: -webkit-transform 0.3s;
-o-transition: transform 0.3s;
transition: transform 0.3s;
transition: transform 0.3s, -webkit-transform 0.3s, color .03;
-webkit-transform-origin: left;
-ms-transform-origin: left;
transform-origin: left;
pointer-events: none;
white-space: nowrap;
overflow: hidden;
-o-text-overflow: ellipsis;
text-overflow: ellipsis;
width: 100%;
user-select: none;
will-change: transform;
}
.outer-container{
position: relative;
width: var(--width);
}
.container{
width: 100%;
display: flex;
position: relative;
align-items: center;
flex: 1;
}
input{
font-size: inherit;
<style>
*{
padding: 0;
margin: 0;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
input[type="search"]::-webkit-search-decoration,
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-results-button,
input[type="search"]::-webkit-search-results-decoration { display: none; }
input[type=number] {
-moz-appearance:textfield;
}
input[type=number]::-webkit-inner-spin-button,
input[type=number]::-webkit-outer-spin-button {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
margin: 0;
}
input::-ms-reveal,
input::-ms-clear {
display: none;
}
input:invalid{
outline: none;
-webkit-box-shadow: none;
box-shadow: none;
}
::-moz-focus-inner{
border: none;
background: transparent;
outline: none;
color: rgba(var(--text-color, (17,17,17)), 1);
width: 100%;
}
:host([animate]) .input:focus-within .container input,
.animate-label .container input {
-webkit-transform: translateY(0.6rem);
-ms-transform: translateY(0.6rem);
transform: translateY(0.6rem);
}
:host([animate]) .input:focus-within .label,
.animate-label .label {
-webkit-transform: translateY(-0.7em) scale(0.8);
-ms-transform: translateY(-0.7em) scale(0.8);
transform: translateY(-0.7em) scale(0.8);
opacity: 1;
color: var(--accent-color,teal)
}
:host([variant="outlined"]) .input {
box-shadow: 0 0 0 1px var(--border-color, rgba(var(--text-color, (17,17,17)), 0.3)) inset;
background: rgba(var(--background-color, (255,255,255)), 1);
}
.animate-label:focus-within:not(.readonly) .label{
color: var(--accent-color,teal)
}
.feedback-text:not(:empty){
display: flex;
width: 100%;
text-align: left;
font-size: 0.9rem;
align-items: center;
padding: 0.8rem 0;
color: rgba(var(--text-color, (17,17,17)), 0.8);
}
.success{
color: var(--success-color);
}
.error{
color: var(--danger-color);
}
.status-icon{
margin-right: 0.2rem;
}
.status-icon--error{
fill: var(--danger-color);
}
.status-icon--success{
fill: var(--success-color);
}
@media (any-hover: hover){
.icon:hover{
background: rgba(var(--text-color, (17,17,17)), 0.1);
:host{
display: flex;
--success-color: #00C853;
--danger-color: red;
--width: 100%;
--icon-gap: 0.5rem;
--min-height: 3.2rem;
--background: rgba(var(--text-color, (17,17,17)), 0.06);
}
}
</style>
<div class="outer-container">
<label part="input" class="input">
<slot name="icon"></slot>
<div class="container">
<input type="text"/>
<div part="placeholder" class="label"></div>
</div>
<svg class="icon clear hide" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm0-11.414L9.172 7.757 7.757 9.172 10.586 12l-2.829 2.828 1.415 1.415L12 13.414l2.828 2.829 1.415-1.415L13.414 12l2.829-2.828-1.415-1.415L12 10.586z"/></svg>
</label>
<p class="feedback-text"></p>
</div>
`;
.hide{
display: none !important;
}
button{
display: flex;
border: none;
background: none;
padding: 0;
border-radius: 1rem;
min-width: 0;
cursor: pointer;
}
button:focus{
outline: var(--accent-color, teal) solid medium;
}
.icon {
height: 1.2rem;
width: 1.2rem;
fill: rgba(var(--text-color, (17,17,17)), 0.6);
}
:host(.round) .input{
border-radius: 10rem;
}
.input {
display: flex;
cursor: text;
min-width: 0;
text-align: left;
align-items: center;
position: relative;
gap: var(--icon-gap);
padding: var(--padding, 0.6rem 0.8rem);
border-radius: var(--border-radius,0.3rem);
transition: opacity 0.3s, box-shadow 0.2s;
background: var(--background);
width: 100%;
outline: none;
min-height: var(--min-height);
}
.input.readonly .clear{
opacity: 0 !important;
margin-right: -2rem;
pointer-events: none !important;
}
.readonly{
pointer-events: none;
}
.input:focus-within:not(.readonly){
box-shadow: 0 0 0 0.1rem var(--accent-color,teal) inset !important;
}
.disabled{
pointer-events: none;
opacity: 0.6;
}
.label {
grid-area: 1/1/2/2;
font-size: inherit;
opacity: .7;
font-weight: 400;
transition: -webkit-transform 0.3s;
transition: transform 0.3s;
transition: transform 0.3s, -webkit-transform 0.3s, color .03;
transform-origin: left;
pointer-events: none;
white-space: nowrap;
overflow: hidden;
width: 100%;
user-select: none;
will-change: transform;
}
.outer-container{
position: relative;
width: var(--width);
}
.container{
width: 100%;
display: grid;
grid-template-columns: 1fr auto;
position: relative;
align-items: center;
}
input{
grid-area: 1/1/2/2;
font-size: inherit;
border: none;
background: transparent;
outline: none;
color: inherit;
font-family: inherit;
width: 100%;
caret-color: var(--accent-color, teal);
}
:host([animate]) .input:focus-within .container input,
.animate-placeholder .container input {
-webkit-transform: translateY(0.6rem);
-ms-transform: translateY(0.6rem);
transform: translateY(0.6rem);
}
:host([animate]) .input:focus-within .label,
.animate-placeholder .label {
-webkit-transform: translateY(-0.7em) scale(0.8);
-ms-transform: translateY(-0.7em) scale(0.8);
transform: translateY(-0.7em) scale(0.8);
opacity: 1;
color: var(--accent-color,teal)
}
:host([variant="outlined"]) .input {
box-shadow: 0 0 0 1px var(--border-color, rgba(var(--text-color, (17,17,17)), 0.3)) inset;
background: rgba(var(--background-color, (255,255,255)), 1);
}
.animate-placeholder:focus-within:not(.readonly) .label{
color: var(--accent-color,teal)
}
.feedback-text:not(:empty){
display: flex;
width: 100%;
text-align: left;
font-size: 0.9rem;
align-items: center;
padding: 0.8rem 0;
color: rgba(var(--text-color, (17,17,17)), 0.8);
}
.success{
color: var(--success-color);
}
.error{
color: var(--danger-color);
}
.status-icon{
margin-right: 0.2rem;
}
.status-icon--error{
fill: var(--danger-color);
}
.status-icon--success{
fill: var(--success-color);
}
@media (any-hover: hover){
.icon:hover{
background: rgba(var(--text-color, (17,17,17)), 0.1);
}
}
</style>
<div class="outer-container">
<label part="input" class="input">
<slot name="icon"></slot>
<div class="container">
<input type="text"/>
<div part="placeholder" class="label"></div>
<button class="clear hide" title="Clear" tabindex="-1">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm0-11.414L9.172 7.757 7.757 9.172 10.586 12l-2.829 2.828 1.415 1.415L12 13.414l2.828 2.829 1.415-1.415L13.414 12l2.829-2.828-1.415-1.415L12 10.586z"/></svg>
</button>
</div>
<slot name="right"></slot>
</label>
<p class="feedback-text"></p>
</div>
`;
customElements.define('sm-input',
class extends HTMLElement {
@ -219,10 +225,12 @@ customElements.define('sm-input',
this.reflectedAttributes = ['value', 'required', 'disabled', 'type', 'inputmode', 'readonly', 'min', 'max', 'pattern', 'minlength', 'maxlength', 'step'];
this.reset = this.reset.bind(this);
this.clear = this.clear.bind(this);
this.focusIn = this.focusIn.bind(this);
this.focusOut = this.focusOut.bind(this);
this.fireEvent = this.fireEvent.bind(this);
this.checkInput = this.checkInput.bind(this);
this.handleKeydown = this.handleKeydown.bind(this);
this.vibrate = this.vibrate.bind(this);
}
@ -235,9 +243,9 @@ customElements.define('sm-input',
}
set value(val) {
if (val === this.input.value) return;
this.input.value = val;
this.checkInput();
this.fireEvent();
}
get placeholder() {
@ -304,9 +312,9 @@ customElements.define('sm-input',
this.feedbackText.classList.add('error');
this.feedbackText.classList.remove('success');
this.feedbackText.innerHTML = `
<svg class="status-icon status-icon--error" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm-1-7v2h2v-2h-2zm0-8v6h2V7h-2z"/></svg>
${this._errorText}
`;
<svg class="status-icon status-icon--error" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm-1-7v2h2v-2h-2zm0-8v6h2V7h-2z"/></svg>
${this._errorText}
`;
}
}
return (_isValid && _customValid);
@ -315,6 +323,10 @@ customElements.define('sm-input',
reset() {
this.value = '';
}
clear() {
this.value = '';
this.input.focus();
}
focusIn() {
this.input.focus();
@ -344,14 +356,24 @@ customElements.define('sm-input',
if (!this.hasAttribute('placeholder') || this.getAttribute('placeholder').trim() === '') return;
if (this.input.value !== '') {
if (this.animate)
this.inputParent.classList.add('animate-label');
this.inputParent.classList.add('animate-placeholder');
else
this.label.classList.add('hide');
} else {
if (this.animate)
this.inputParent.classList.remove('animate-label');
this.inputParent.classList.remove('animate-placeholder');
else
this.label.classList.remove('hide');
this.feedbackText.textContent = '';
}
}
handleKeydown(e) {
if (e.key.length === 1) {
if (!['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.'].includes(e.key)) {
e.preventDefault();
} else if (e.key === '.' && e.target.value.includes('.')) {
e.preventDefault();
}
}
}
vibrate() {
@ -372,7 +394,7 @@ customElements.define('sm-input',
this.animate = this.hasAttribute('animate');
this.setAttribute('role', 'textbox');
this.input.addEventListener('input', this.checkInput);
this.clearBtn.addEventListener('click', this.reset);
this.clearBtn.addEventListener('click', this.clear);
}
attributeChangedCallback(name, oldValue, newValue) {
@ -394,7 +416,11 @@ customElements.define('sm-input',
}
else if (name === 'type') {
if (this.hasAttribute('type') && this.getAttribute('type') === 'number') {
this.input.setAttribute('inputmode', 'numeric');
this.input.setAttribute('inputmode', 'decimal');
this.input.addEventListener('keydown', this.handleKeydown);
} else {
this.input.removeEventListener('keydown', this.handleKeydown);
}
}
else if (name === 'helper-text') {
@ -431,6 +457,7 @@ customElements.define('sm-input',
}
disconnectedCallback() {
this.input.removeEventListener('input', this.checkInput);
this.clearBtn.removeEventListener('click', this.reset);
this.clearBtn.removeEventListener('click', this.clear);
this.input.removeEventListener('keydown', this.handleKeydown);
}
})

File diff suppressed because one or more lines are too long

View File

@ -1,153 +1,172 @@
//notifications
const smNotifications = document.createElement('template')
smNotifications.innerHTML = `
<style>
*{
padding: 0;
margin: 0;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
:host{
display: -webkit-box;
display: -ms-flexbox;
display: flex;
--accent-color: #4d2588;
--text-color: 17, 17, 17;
--background-color: 255, 255, 255;
--danger-color: red;
--icon-height: 1.5rem;
--icon-width: 1.5rem;
}
.hide{
opacity: 0 !important;
pointer-events: none !important;
}
.notification-panel{
display: grid;
width: 100%;
gap: 0.5rem;
position: fixed;
left: 0;
bottom: 0;
z-index: 100;
max-height: 100%;
padding: 1rem;
overflow: hidden auto;
-ms-scroll-chaining: none;
overscroll-behavior: contain;
}
.notification-panel:empty{
display:none;
}
.notification{
display: -webkit-box;
display: -ms-flexbox;
display: flex;
position: relative;
border-radius: 0.3rem;
background: rgba(var(--background-color), 1);
overflow: hidden;
overflow-wrap: break-word;
word-wrap: break-word;
-ms-word-break: break-all;
word-break: break-all;
word-break: break-word;
-ms-hyphens: auto;
-webkit-hyphens: auto;
hyphens: auto;
max-width: 100%;
padding: 1rem;
align-items: center;
}
.icon-container:not(:empty){
margin-right: 0.5rem;
height: var(--icon-height);
width: var(--icon-width);
}
h4:first-letter,
p:first-letter{
text-transform: uppercase;
}
h4{
font-weight: 400;
}
p{
line-height: 1.6;
-webkit-box-flex: 1;
-ms-flex: 1;
flex: 1;
color: rgba(var(--text-color), 0.9);
overflow-wrap: break-word;
overflow-wrap: break-word;
word-wrap: break-word;
-ms-word-break: break-all;
word-break: break-all;
word-break: break-word;
-ms-hyphens: auto;
-webkit-hyphens: auto;
hyphens: auto;
max-width: 100%;
}
.notification:last-of-type{
margin-bottom: 0;
}
.icon {
height: 100%;
width: 100%;
fill: rgba(var(--text-color), 0.7);
}
.icon--success {
fill: var(--green);
}
.icon--failure,
.icon--error {
fill: var(--danger-color);
}
.close{
height: 2rem;
width: 2rem;
border: none;
cursor: pointer;
margin-left: 1rem;
border-radius: 50%;
padding: 0.3rem;
transition: background-color 0.3s, transform 0.3s;
background-color: transparent;
}
.close:active{
transform: scale(0.9);
}
@media screen and (min-width: 640px){
.notification-panel{
max-width: 28rem;
width: max-content;
}
.notification{
width: auto;
border: solid 1px rgba(var(--text-color), 0.2);
}
}
@media (any-hover: hover){
::-webkit-scrollbar{
width: 0.5rem;
}
::-webkit-scrollbar-thumb{
background: rgba(var(--text-color), 0.3);
border-radius: 1rem;
&:hover{
background: rgba(var(--text-color), 0.5);
<style>
*{
padding: 0;
margin: 0;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
:host{
display: flex;
--icon-height: 1.5rem;
--icon-width: 1.5rem;
}
}
.close:hover{
background-color: rgba(var(--text-color), 0.1);
}
}
</style>
<div class="notification-panel"></div>
`;
.hide{
opacity: 0 !important;
pointer-events: none !important;
}
.notification-panel{
display: grid;
width: 100%;
gap: 0.5rem;
position: fixed;
left: 0;
top: 0;
z-index: 100;
max-height: 100%;
padding: 1rem;
overflow: hidden auto;
-ms-scroll-chaining: none;
overscroll-behavior: contain;
touch-action: none;
}
.notification-panel:empty{
display:none;
}
.notification{
display: -webkit-box;
display: -ms-flexbox;
display: flex;
position: relative;
border-radius: 0.3rem;
background: rgba(var(--foreground-color, (255,255,255)), 1);
overflow: hidden;
overflow-wrap: break-word;
word-wrap: break-word;
-ms-word-break: break-all;
word-break: break-all;
word-break: break-word;
-ms-hyphens: auto;
-webkit-hyphens: auto;
hyphens: auto;
max-width: 100%;
padding: 1rem;
align-items: center;
box-shadow: 0 0.5rem 1rem 0 rgba(0,0,0,0.14);
touch-action: none;
}
.icon-container:not(:empty){
margin-right: 0.5rem;
height: var(--icon-height);
width: var(--icon-width);
}
h4:first-letter,
p:first-letter{
text-transform: uppercase;
}
h4{
font-weight: 400;
}
p{
line-height: 1.6;
-webkit-box-flex: 1;
-ms-flex: 1;
flex: 1;
color: rgba(var(--text-color, (17,17,17)), 0.9);
overflow-wrap: break-word;
overflow-wrap: break-word;
word-wrap: break-word;
-ms-word-break: break-all;
word-break: break-all;
word-break: break-word;
-ms-hyphens: auto;
-webkit-hyphens: auto;
hyphens: auto;
max-width: 100%;
}
.notification:last-of-type{
margin-bottom: 0;
}
.icon {
height: 100%;
width: 100%;
fill: rgba(var(--text-color, (17,17,17)), 0.7);
}
.icon--success {
fill: var(--green);
}
.icon--failure,
.icon--error {
fill: var(--danger-color);
}
.close{
height: 2rem;
width: 2rem;
border: none;
cursor: pointer;
margin-left: 1rem;
border-radius: 50%;
padding: 0.3rem;
transition: background-color 0.3s, transform 0.3s;
background-color: transparent;
flex-shrink: 0;
}
.close:active{
transform: scale(0.9);
}
.action{
display: flex;
align-items: center;
justify-content: center;
padding: 0.5rem 0.8rem;
border-radius: 0.2rem;
border: none;
background-color: rgba(var(--text-color, (17,17,17)), 0.03);
font-family: inherit;
font-size: inherit;
color: var(--accent-color, teal);
font-weight: 500;
cursor: pointer;
}
@media screen and (max-width: 640px){
.notification-panel:not(:empty){
padding-bottom: 3rem;
}
}
@media screen and (min-width: 640px){
.notification-panel{
max-width: 28rem;
width: max-content;
top: auto;
bottom: 0;
}
.notification{
width: auto;
border: solid 1px rgba(var(--text-color, (17,17,17)), 0.2);
}
}
@media (any-hover: hover){
::-webkit-scrollbar{
width: 0.5rem;
}
::-webkit-scrollbar-thumb{
background: rgba(var(--text-color, (17,17,17)), 0.3);
border-radius: 1rem;
&:hover{
background: rgba(var(--text-color, (17,17,17)), 0.5);
}
}
.close:hover{
background-color: rgba(var(--text-color, (17,17,17)), 0.1);
}
}
</style>
<div class="notification-panel"></div>
`;
customElements.define('sm-notifications', class extends HTMLElement {
constructor() {
super();
@ -166,7 +185,23 @@ customElements.define('sm-notifications', class extends HTMLElement {
this.createNotification = this.createNotification.bind(this)
this.removeNotification = this.removeNotification.bind(this)
this.clearAll = this.clearAll.bind(this)
this.handlePointerMove = this.handlePointerMove.bind(this)
this.startX = 0;
this.currentX = 0;
this.endX = 0;
this.swipeDistance = 0;
this.swipeDirection = '';
this.swipeThreshold = 0;
this.startTime = 0;
this.swipeTime = 0;
this.swipeTimeThreshold = 200;
this.currentTarget = null;
this.mediaQuery = window.matchMedia('(min-width: 640px)')
this.handleOrientationChange = this.handleOrientationChange.bind(this)
this.isLandscape = false
}
randString(length) {
@ -178,22 +213,27 @@ customElements.define('sm-notifications', class extends HTMLElement {
}
createNotification(message, options = {}) {
const { pinned = false, icon = '' } = options;
const notification = document.createElement('output')
const { pinned = false, icon = '', action } = options;
const notification = document.createElement('div')
notification.id = this.randString(8)
notification.classList.add('notification');
let composition = ``;
composition += `
<div class="icon-container">${icon}</div>
<p>${message}</p>
`;
<div class="icon-container">${icon}</div>
<output>${message}</output>
`;
if (action) {
composition += `
<button class="action">${action.label}</button>
`
}
if (pinned) {
notification.classList.add('pinned');
composition += `
<button class="close">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 10.586l4.95-4.95 1.414 1.414-4.95 4.95 4.95 4.95-1.414 1.414-4.95-4.95-4.95 4.95-1.414-1.414 4.95-4.95-4.95-4.95L7.05 5.636z"/></svg>
</button>
`;
<button class="close">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 10.586l4.95-4.95 1.414 1.414-4.95 4.95 4.95 4.95-1.414 1.414-4.95-4.95-4.95 4.95-1.414-1.414 4.95-4.95-4.95-4.95L7.05 5.636z"/></svg>
</button>
`;
}
notification.innerHTML = composition;
return notification;
@ -201,28 +241,48 @@ customElements.define('sm-notifications', class extends HTMLElement {
push(message, options = {}) {
const notification = this.createNotification(message, options);
this.notificationPanel.append(notification);
if (this.isLandscape)
this.notificationPanel.append(notification);
else
this.notificationPanel.prepend(notification);
this.notificationPanel.animate(
[
{
transform: `translateY(${this.isLandscape ? '' : '-'}${notification.clientHeight}px)`,
},
{
transform: `none`,
},
], this.animationOptions
)
notification.animate([
{
transform: `translateY(1rem)`,
transform: `translateY(-1rem)`,
opacity: '0'
},
{
transform: `none`,
opacity: '1'
},
], this.animationOptions);
], this.animationOptions).onfinish = (e) => {
e.target.commitStyles()
e.target.cancel()
}
if (notification.querySelector('.action'))
notification.querySelector('.action').addEventListener('click', options.action.callback)
return notification.id;
}
removeNotification(notification) {
removeNotification(notification, direction = 'left') {
if (!notification) return;
const sign = direction === 'left' ? '-' : '+';
notification.animate([
{
transform: `none`,
transform: this.currentX ? `translateX(${this.currentX}px)` : `none`,
opacity: '1'
},
{
transform: `translateY(0.5rem)`,
transform: `translateX(calc(${sign}${Math.abs(this.currentX)}px ${sign} 1rem))`,
opacity: '0'
}
], this.animationOptions).onfinish = () => {
@ -236,13 +296,72 @@ customElements.define('sm-notifications', class extends HTMLElement {
});
}
handlePointerMove(e) {
this.currentX = e.clientX - this.startX;
this.currentTarget.style.transform = `translateX(${this.currentX}px)`;
}
handleOrientationChange(e) {
this.isLandscape = e.matches
if (e.matches) {
// landscape
} else {
// portrait
}
}
connectedCallback() {
this.notificationPanel.addEventListener('click', e => {
this.handleOrientationChange(this.mediaQuery);
this.mediaQuery.addEventListener('change', this.handleOrientationChange);
this.notificationPanel.addEventListener('pointerdown', e => {
if (e.target.closest('.close')) {
this.removeNotification(e.target.closest('.notification'));
} else if (e.target.closest('.notification')) {
this.swipeThreshold = e.target.closest('.notification').getBoundingClientRect().width / 2;
this.currentTarget = e.target.closest('.notification');
this.currentTarget.setPointerCapture(e.pointerId);
this.startTime = Date.now();
this.startX = e.clientX;
this.startY = e.clientY;
this.notificationPanel.addEventListener('pointermove', this.handlePointerMove);
}
});
this.notificationPanel.addEventListener('pointerup', e => {
this.endX = e.clientX;
this.endY = e.clientY;
this.swipeDistance = Math.abs(this.endX - this.startX);
this.swipeTime = Date.now() - this.startTime;
if (this.endX > this.startX) {
this.swipeDirection = 'right';
} else {
this.swipeDirection = 'left';
}
if (this.swipeTime < this.swipeTimeThreshold) {
if (this.swipeDistance > 50)
this.removeNotification(this.currentTarget, this.swipeDirection);
} else {
if (this.swipeDistance > this.swipeThreshold) {
this.removeNotification(this.currentTarget, this.swipeDirection);
} else {
this.currentTarget.animate([
{
transform: `translateX(${this.currentX}px)`,
},
{
transform: `none`,
},
], this.animationOptions).onfinish = (e) => {
e.target.commitStyles()
e.target.cancel()
}
}
}
this.notificationPanel.removeEventListener('pointermove', this.handlePointerMove)
this.notificationPanel.releasePointerCapture(e.pointerId);
this.currentX = 0;
});
const observer = new MutationObserver(mutationList => {
mutationList.forEach(mutation => {
if (mutation.type === 'childList') {
@ -258,4 +377,7 @@ customElements.define('sm-notifications', class extends HTMLElement {
childList: true,
});
}
disconnectedCallback() {
mediaQueryList.removeEventListener('change', handleOrientationChange);
}
});

File diff suppressed because one or more lines are too long

232
components/dist/pin-input.js vendored Normal file
View File

@ -0,0 +1,232 @@
const pinInput = document.createElement('template');
pinInput.innerHTML = `
<style>
*{
padding:0;
margin:0;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
input::-ms-reveal,
input::-ms-clear {
display: none;
}
input:invalid{
outline: none;
-webkit-box-shadow: none;
box-shadow: none;
}
::-moz-focus-inner{
border: none;
}
:host{
--border-radius: 0.5rem;
--pin-length: 4;
}
.component{
display: flex;
align-items: center;
}
.pin-container{
display: grid;
grid-template-columns: repeat(var(--pin-length), 3rem);
width: auto;
gap: 0.5rem;
}
input{
width: 100%;
display: flex;
padding: 0.8rem 0.6rem;
border: none;
font-size: 1.5rem;
text-align: center;
color: rgba(var(--text-color), 1);
background: rgba(var(--text-color), 0.1);
border-radius: var(--border-radius);
}
input:valid{
background-color: transparent;
}
input:focus,
button:focus{
outline: none;
box-shadow: 0 0 0 0.2rem var(--accent-color) inset;
}
button{
display: flex;
align-items: center;
background: none;
border: none;
cursor: pointer;
color: inherit;
font-family: inherit;
margin: 0 1rem;
}
svg{
margin: 0 0.5rem 0 0;
height: 1.5rem;
width: 1.5rem;
fill: rgba(var(--text-color), 1);
}
</style>
<div class="component">
<div class="pin-container"></div>
<button>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><circle cx="32" cy="32" r="9.95"/><path d="M32,12.28C11.7,12.28,0,32,0,32S11.7,51.72,32,51.72,64,32,64,32,52.3,12.28,32,12.28Zm0,33.35A13.63,13.63,0,1,1,45.63,32,13.64,13.64,0,0,1,32,45.63Z"/></svg>
Show
</button>
</div>
`;
customElements.define('pin-input',
class extends HTMLElement {
constructor() {
super()
this.attachShadow({
mode: 'open'
}).append(pinInput.content.cloneNode(true))
this.pinDigits = 4
this.arrayOfInput = [];
this.container = this.shadowRoot.querySelector('.pin-container');
this.toggleButton = this.shadowRoot.querySelector('button')
}
set value(val) {
this.arrayOfInput.forEach((input, index) => input.value = val[index] ? val[index] : '')
}
get value() {
return this.getValue()
}
set pinLength(val) {
this.pinDigits = val
this.setAttribute('pin-length', val)
this.style.setProperty('--pin-length', val)
this.render()
}
get isValid() {
return this.arrayOfInput.every(input => input.value.trim().length)
}
clear = () => {
this.value = ''
}
focusIn = () => {
this.arrayOfInput[0].focus();
}
getValue = () => {
return this.arrayOfInput.reduce((acc, val) => {
return acc += val.value
}, '')
}
render = () => {
this.container.innerHTML = ''
const frag = document.createDocumentFragment();
for (let i = 0; i < this.pinDigits; i++) {
const inputBox = document.createElement('input')
inputBox.setAttribute('type', 'password')
inputBox.setAttribute('inputmode', 'numeric')
inputBox.setAttribute('maxlength', '1')
inputBox.setAttribute('required', '')
this.arrayOfInput.push(inputBox);
frag.append(inputBox);
}
this.container.append(frag);
}
handleKeydown = (e) => {
const activeInput = e.target.closest('input')
if (/[0-9]/.test(e.key)) {
if (activeInput.value.trim().length > 2) {
e.preventDefault();
}
else {
if (activeInput.value.trim().length === 1) {
activeInput.value = e.key
}
if (activeInput.nextElementSibling) {
setTimeout(() => {
activeInput.nextElementSibling.focus();
}, 0)
}
}
}
else if (e.key === "Backspace") {
if (activeInput.previousElementSibling)
setTimeout(() => {
activeInput.previousElementSibling.focus();
}, 0)
}
else if (e.key.length === 1 && !/[0-9]/.test(e.key)) {
e.preventDefault();
}
}
handleInput = () => {
if (this.isValid) {
this.fireEvent(this.getValue())
}
}
fireEvent = (value) => {
let event = new CustomEvent('pincomplete', {
bubbles: true,
cancelable: true,
composed: true,
detail: {
value
}
});
this.dispatchEvent(event);
}
toggleVisibility = () => {
if (this.arrayOfInput[0].getAttribute('type') === 'password') {
this.toggleButton.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><path d="M22.05,31.44a10.12,10.12,0,0,0,.1,1.36L33.36,21.59a10.12,10.12,0,0,0-1.36-.1A10,10,0,0,0,22.05,31.44Z"/><path d="M19.11,35.84A13.6,13.6,0,0,1,36.4,18.55l5.28-5.27A31,31,0,0,0,32,11.72c-20.3,0-32,19.72-32,19.72A48.48,48.48,0,0,0,11.27,43.69Z"/><path d="M52.73,19.2l6.14-6.14L54.63,8.81l-7,7h0l-6,6h0L39,24.41h0l-7,7L20.09,43.35,16.4,47h0l-7,7,4.25,4.24,8.71-8.71A31.15,31.15,0,0,0,32,51.16c20.3,0,32-19.72,32-19.72A48.54,48.54,0,0,0,52.73,19.2ZM32,45.07a13.63,13.63,0,0,1-4.4-.74l3-3a10.12,10.12,0,0,0,1.36.1,10,10,0,0,0,10-9.95,10.12,10.12,0,0,0-.1-1.36l3-3A13.6,13.6,0,0,1,32,45.07Z"/></svg>
Hide
`
this.arrayOfInput.forEach(input => input.setAttribute('type', 'text'))
}
else {
this.toggleButton.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><circle cx="32" cy="32" r="9.95"/><path d="M32,12.28C11.7,12.28,0,32,0,32S11.7,51.72,32,51.72,64,32,64,32,52.3,12.28,32,12.28Zm0,33.35A13.63,13.63,0,1,1,45.63,32,13.64,13.64,0,0,1,32,45.63Z"/></svg>
Show
`
this.arrayOfInput.forEach(input => input.setAttribute('type', 'password'))
}
}
connectedCallback() {
if (this.hasAttribute('pin-length')) {
const pinLength = parseInt(this.getAttribute('pin-length'))
this.pinDigits = pinLength
this.style.setProperty('--pin-length', pinLength)
}
this.render()
this.toggleButton.addEventListener('click', this.toggleVisibility)
this.container.addEventListener('input', this.handleInput);
this.container.addEventListener('keydown', this.handleKeydown);
}
disconnectedCallback() {
this.toggleButton.removeEventListener('click', this.toggleVisibility)
this.container.removeEventListener('input', this.handleInput);
this.container.removeEventListener('keydown', this.handleKeydown);
}
})

View File

@ -1,3 +1,4 @@
//popup
class Stack {
constructor() {
this.items = [];
@ -30,9 +31,6 @@ smPopup.innerHTML = `
display: -ms-grid;
display: grid;
z-index: 10;
--accent-color: #4d2588;
--text-color: 17, 17, 17;
--background-color: 255, 255, 255;
--width: 100%;
--height: auto;
--min-width: auto;
@ -87,7 +85,7 @@ smPopup.innerHTML = `
min-height: var(--min-height);
max-height: 90vh;
border-radius: var(--border-radius);
background: rgba(var(--background-color), 1);
background: rgba(var(--background-color, (255,255,255)), 1);
-webkit-box-shadow: 0 -1rem 2rem #00000020;
box-shadow: 0 -1rem 2rem #00000020;
}
@ -147,7 +145,7 @@ smPopup.innerHTML = `
.handle{
height: 0.3rem;
width: 2rem;
background: rgba(var(--text-color), .4);
background: rgba(var(--text-color, (17,17,17)), .4);
border-radius: 1rem;
margin: 0.5rem 0;
}
@ -158,10 +156,10 @@ smPopup.innerHTML = `
}
::-webkit-scrollbar-thumb{
background: rgba(var(--text-color), 0.3);
background: rgba(var(--text-color, (17,17,17)), 0.3);
border-radius: 1rem;
&:hover{
background: rgba(var(--text-color), 0.5);
background: rgba(var(--text-color, (17,17,17))), 0.5);
}
}
}
@ -201,7 +199,7 @@ customElements.define('sm-popup', class extends HTMLElement {
this.popupContainer = this.shadowRoot.querySelector('.popup-container');
this.backdrop = this.shadowRoot.querySelector('.background');
this.popup = this.shadowRoot.querySelector('.popup');
this.dialogBox = this.shadowRoot.querySelector('.popup');
this.popupBodySlot = this.shadowRoot.querySelector('.popup-body slot');
this.popupHeader = this.shadowRoot.querySelector('.popup-top');
@ -235,7 +233,7 @@ customElements.define('sm-popup', class extends HTMLElement {
resumeScrolling() {
const scrollY = document.body.style.top;
window.scrollTo(0, parseInt(scrollY || '0') * -1);
document.body.style.overflow = 'auto';
document.body.style.overflow = '';
document.body.style.top = 'initial';
}
@ -246,7 +244,7 @@ customElements.define('sm-popup', class extends HTMLElement {
easing: 'ease'
}
const initialAnimation = (window.innerWidth > 640) ? 'scale(1.1)' : `translateY(${this.offset ? `${this.offset}px` : '100%'})`
this.animateTo(this.popup, [
this.animateTo(this.dialogBox, [
{
opacity: this.offset ? 1 : 0,
transform: initialAnimation
@ -311,7 +309,7 @@ customElements.define('sm-popup', class extends HTMLElement {
{ opacity: 1 },
{ opacity: 0 }
], animOptions)
this.animateTo(this.popup, [
this.animateTo(this.dialogBox, [
{
opacity: 1,
transform: (window.innerWidth > 640) ? 'none' : `translateY(${this.offset ? `${this.offset}px` : '0'})`
@ -323,7 +321,7 @@ customElements.define('sm-popup', class extends HTMLElement {
], animOptions).finished
.finally(() => {
this.popupContainer.classList.add('hide');
this.popup.style = ''
this.dialogBox.style = ''
this.removeAttribute('open');
if (this.forms.length) {
@ -363,7 +361,7 @@ customElements.define('sm-popup', class extends HTMLElement {
if (this.touchStartY < e.changedTouches[0].clientY) {
this.offset = e.changedTouches[0].clientY - this.touchStartY;
this.touchEndAnimation = window.requestAnimationFrame(() => {
this.popup.style.transform = `translateY(${this.offset}px)`;
this.dialogBox.style.transform = `translateY(${this.offset}px)`;
});
}
}
@ -372,7 +370,7 @@ customElements.define('sm-popup', class extends HTMLElement {
this.touchEndTime = e.timeStamp;
cancelAnimationFrame(this.touchEndAnimation);
this.touchEndY = e.changedTouches[0].clientY;
this.threshold = this.popup.getBoundingClientRect().height * 0.3;
this.threshold = this.dialogBox.getBoundingClientRect().height * 0.3;
if (this.touchEndTime - this.touchStartTime > 200) {
if (this.touchEndY - this.touchStartY > this.threshold) {
if (this.pinned) {
@ -412,7 +410,7 @@ customElements.define('sm-popup', class extends HTMLElement {
}
updateFocusableList() {
this.focusable = this.querySelectorAll('sm-button:not([disabled]), button:not([disabled]), [href], sm-input, input, sm-select, select, sm-checkbox, sm-textarea, textarea, [tabindex]:not([tabindex="-1"])')
this.focusable = this.querySelectorAll('sm-button:not([disabled]), button:not([disabled]), [href], sm-input, input:not([readonly]), sm-select, select, sm-checkbox, sm-textarea, textarea, [tabindex]:not([tabindex="-1"])')
this.autoFocus = this.querySelector('[autofocus]')
}

File diff suppressed because one or more lines are too long

View File

@ -8,9 +8,6 @@ smRadio.innerHTML = `
box-sizing: border-box;
}
:host{
--accent-color: #4d2588;
--text-color: 17, 17, 17;
--background-color: 255, 255, 255;
--gap: 0.5rem;
--height: 1.4rem;
}
@ -36,16 +33,16 @@ smRadio.innerHTML = `
.outer-disc{
fill: none;
stroke-width: 3;
stroke: rgba(var(--text-color), 0.7);
stroke: rgba(var(--text-color, (17,17,17)), 0.7);
}
.inner-disc{
fill: var(--accent-color);
fill: var(--accent-color, teal);
transition: transform 0.3s;
transform: scale(0);
transform-origin: center;
}
:host([checked]) .outer-disc{
stroke: var(--accent-color);
stroke: var(--accent-color, teal);
}
:host([checked]) .inner-disc{
transform: scale(1);
@ -128,7 +125,7 @@ window.customElements.define('sm-radio', class extends HTMLElement {
this.dispatchEvent(new CustomEvent(`changed${this.getAttribute('name')}`, this.options))
}
}
handleKeyDown(e){
handleKeyDown(e) {
if (e.code === "Space") {
e.preventDefault()
this.handleClick()
@ -139,7 +136,7 @@ window.customElements.define('sm-radio', class extends HTMLElement {
this.setAttribute('checked', '')
this.dispatchGroupEvent()
}
}
handleRadioGroup(e) {
if (e.detail.uid !== this.uniqueId) {

View File

@ -1 +1 @@
const smRadio=document.createElement("template");smRadio.innerHTML='\n<style>\n *{\n padding: 0;\n margin: 0;\n -webkit-box-sizing: border-box;\n box-sizing: border-box;\n } \n :host{\n --accent-color: #4d2588;\n --text-color: 17, 17, 17;\n --background-color: 255, 255, 255;\n --gap: 0.5rem;\n --height: 1.4rem;\n }\n :host([disabled]) {\n opacity: 0.6;\n user-select: none;\n pointer-events: none;\n }\n .hide{\n display: none !important;\n }\n .radio{\n display: flex;\n cursor: pointer;\n }\n .radio__button{\n position: relative;\n height: var(--height);\n width: var(--height);\n overflow: visible;\n padding: 0.1rem;\n }\n .outer-disc{\n fill: none;\n stroke-width: 3;\n stroke: rgba(var(--text-color), 0.7);\n }\n .inner-disc{\n fill: var(--accent-color);\n transition: transform 0.3s;\n transform: scale(0);\n transform-origin: center;\n }\n :host([checked]) .outer-disc{\n stroke: var(--accent-color);\n }\n :host([checked]) .inner-disc{\n transform: scale(1);\n }\n\n @media (any-hover: hover){\n }\n</style>\n<div class="radio">\n <slot name="left"></slot>\n <svg class="radio__button" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><circle class="outer-disc" cx="12" cy="12" r="11"/><circle class="inner-disc" cx="12" cy="12" r="6"/></svg>\n <slot></slot>\n</div>\n',window.customElements.define("sm-radio",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smRadio.content.cloneNode(!0)),this.radio=this.shadowRoot.querySelector(".radio"),this.reset=this.reset.bind(this),this.dispatchChangeEvent=this.dispatchChangeEvent.bind(this),this.dispatchGroupEvent=this.dispatchGroupEvent.bind(this),this.handleKeyDown=this.handleKeyDown.bind(this),this.handleClick=this.handleClick.bind(this),this.handleRadioGroup=this.handleRadioGroup.bind(this),this.uniqueId,this.options}static get observedAttributes(){return["value","disabled","checked"]}get disabled(){return this.hasAttribute("disabled")}set disabled(t){t?this.setAttribute("disabled",""):this.removeAttribute("disabled")}get checked(){return this.hasAttribute("checked")}set checked(t){t?this.setAttribute("checked",""):this.removeAttribute("checked")}set value(t){this.setAttribute("value",t)}get value(){return this.getAttribute("value")}reset(){this.removeAttribute("checked")}dispatchChangeEvent(){this.dispatchEvent(new CustomEvent("change",this.options))}dispatchGroupEvent(){this.hasAttribute("name")&&""!==this.getAttribute("name").trim()&&this.dispatchEvent(new CustomEvent(`changed${this.getAttribute("name")}`,this.options))}handleKeyDown(t){"Space"===t.code&&(t.preventDefault(),this.handleClick())}handleClick(){this.hasAttribute("checked")||(this.setAttribute("checked",""),this.dispatchGroupEvent())}handleRadioGroup(t){t.detail.uid!==this.uniqueId&&this.reset()}randString(t){let e="";const i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";for(let n=0;n<t;n++)e+=i.charAt(Math.floor(Math.random()*i.length));return e}connectedCallback(){this.uniqueId=this.randString(8),this.options={bubbles:!0,composed:!0,detail:{uid:this.uniqueId,value:this.value}},this.hasAttribute("disabled")||this.setAttribute("tabindex","0"),this.setAttribute("role","radio"),this.hasAttribute("checked")||this.setAttribute("aria-checked","false"),this.addEventListener("keydown",this.handleKeyDown),this.addEventListener("click",this.handleClick),this.hasAttribute("name")&&""!==this.getAttribute("name").trim()&&document.addEventListener(`changed${this.getAttribute("name")}`,this.handleRadioGroup)}attributeChangedCallback(t,e,i){e!==i&&("checked"===t?this.dispatchChangeEvent():"disabled"===t&&(this.hasAttribute("disabled")?this.removeAttribute("tabindex"):this.setAttribute("tabindex","0")))}disconnectedCallback(){this.removeEventListener("keydown",this.handleKeyDown),this.removeEventListener("change",this.handleClick)}});
const smRadio=document.createElement("template");smRadio.innerHTML='\n<style>\n *{\n padding: 0;\n margin: 0;\n -webkit-box-sizing: border-box;\n box-sizing: border-box;\n } \n :host{\n --gap: 0.5rem;\n --height: 1.4rem;\n }\n :host([disabled]) {\n opacity: 0.6;\n user-select: none;\n pointer-events: none;\n }\n .hide{\n display: none !important;\n }\n .radio{\n display: flex;\n cursor: pointer;\n }\n .radio__button{\n position: relative;\n height: var(--height);\n width: var(--height);\n overflow: visible;\n padding: 0.1rem;\n }\n .outer-disc{\n fill: none;\n stroke-width: 3;\n stroke: rgba(var(--text-color, (17,17,17)), 0.7);\n }\n .inner-disc{\n fill: var(--accent-color, teal);\n transition: transform 0.3s;\n transform: scale(0);\n transform-origin: center;\n }\n :host([checked]) .outer-disc{\n stroke: var(--accent-color, teal);\n }\n :host([checked]) .inner-disc{\n transform: scale(1);\n }\n\n @media (any-hover: hover){\n }\n</style>\n<div class="radio">\n <slot name="left"></slot>\n <svg class="radio__button" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><circle class="outer-disc" cx="12" cy="12" r="11"/><circle class="inner-disc" cx="12" cy="12" r="6"/></svg>\n <slot></slot>\n</div>\n',window.customElements.define("sm-radio",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smRadio.content.cloneNode(!0)),this.radio=this.shadowRoot.querySelector(".radio"),this.reset=this.reset.bind(this),this.dispatchChangeEvent=this.dispatchChangeEvent.bind(this),this.dispatchGroupEvent=this.dispatchGroupEvent.bind(this),this.handleKeyDown=this.handleKeyDown.bind(this),this.handleClick=this.handleClick.bind(this),this.handleRadioGroup=this.handleRadioGroup.bind(this),this.uniqueId,this.options}static get observedAttributes(){return["value","disabled","checked"]}get disabled(){return this.hasAttribute("disabled")}set disabled(t){t?this.setAttribute("disabled",""):this.removeAttribute("disabled")}get checked(){return this.hasAttribute("checked")}set checked(t){t?this.setAttribute("checked",""):this.removeAttribute("checked")}set value(t){this.setAttribute("value",t)}get value(){return this.getAttribute("value")}reset(){this.removeAttribute("checked")}dispatchChangeEvent(){this.dispatchEvent(new CustomEvent("change",this.options))}dispatchGroupEvent(){this.hasAttribute("name")&&""!==this.getAttribute("name").trim()&&this.dispatchEvent(new CustomEvent(`changed${this.getAttribute("name")}`,this.options))}handleKeyDown(t){"Space"===t.code&&(t.preventDefault(),this.handleClick())}handleClick(){this.hasAttribute("checked")||(this.setAttribute("checked",""),this.dispatchGroupEvent())}handleRadioGroup(t){t.detail.uid!==this.uniqueId&&this.reset()}randString(t){let e="";const i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";for(let n=0;n<t;n++)e+=i.charAt(Math.floor(Math.random()*i.length));return e}connectedCallback(){this.uniqueId=this.randString(8),this.options={bubbles:!0,composed:!0,detail:{uid:this.uniqueId,value:this.value}},this.hasAttribute("disabled")||this.setAttribute("tabindex","0"),this.setAttribute("role","radio"),this.hasAttribute("checked")||this.setAttribute("aria-checked","false"),this.addEventListener("keydown",this.handleKeyDown),this.addEventListener("click",this.handleClick),this.hasAttribute("name")&&""!==this.getAttribute("name").trim()&&document.addEventListener(`changed${this.getAttribute("name")}`,this.handleRadioGroup)}attributeChangedCallback(t,e,i){e!==i&&("checked"===t?this.dispatchChangeEvent():"disabled"===t&&(this.hasAttribute("disabled")?this.removeAttribute("tabindex"):this.setAttribute("tabindex","0")))}disconnectedCallback(){this.removeEventListener("keydown",this.handleKeyDown),this.removeEventListener("change",this.handleClick)}});

View File

@ -11,10 +11,7 @@ smSelect.innerHTML = `
display: -webkit-box;
display: -ms-flexbox;
display: flex;
--accent-color: #4d2588;
--text-color: 17, 17, 17;
--background-color: 255, 255, 255;
--min-width: 100%;
--min-width: max-content;
}
:host([disabled]) .select{
opacity: 0.6;
@ -37,7 +34,7 @@ smSelect.innerHTML = `
height: 1.2rem;
width: 1.2rem;
margin-left: 0.5rem;
fill: rgba(var(--text-color), 0.7);
fill: rgba(var(--text-color, (17,17,17)), 0.7);
}
.selected-option-text{
font-size: inherit;
@ -55,7 +52,7 @@ smSelect.innerHTML = `
grid-template-columns: 1fr auto;
grid-template-areas: 'heading heading' '. .';
padding: var(--padding,0.6rem 0.8rem);
background: rgba(var(--text-color), 0.06);
background: var(--background, rgba(var(--text-color,(17,17,17)), 0.06));
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
@ -63,8 +60,8 @@ smSelect.innerHTML = `
z-index: 2;
}
.selection:focus{
-webkit-box-shadow: 0 0 0 0.1rem var(--accent-color);
box-shadow: 0 0 0 0.1rem var(--accent-color)
-webkit-box-shadow: 0 0 0 0.1rem var(--accent-color, teal);
box-shadow: 0 0 0 0.1rem var(--accent-color, teal)
}
:host([align-select="left"]) .options{
left: 0;
@ -88,14 +85,14 @@ smSelect.innerHTML = `
flex-direction: column;
min-width: var(--min-width);
max-height: var(--max-height, auto);
background: rgba(var(--background-color), 1);
border: solid 1px rgba(var(--text-color), 0.2);
background: rgba(var(--foreground-color,(255,255,255)), 1);
border: solid 1px rgba(var(--text-color,(17,17,17)), 0.2);
border-radius: var(--border-radius, 0.5rem);
z-index: 1;
-webkit-box-shadow: 0.4rem 0.8rem 1.2rem #00000030;
box-shadow: 0.4rem 0.8rem 1.2rem #00000030;
}
.rotate{
:host([open]) .toggle-icon{
-webkit-transform: rotate(180deg);
-ms-transform: rotate(180deg);
transform: rotate(180deg)
@ -110,10 +107,10 @@ smSelect.innerHTML = `
}
::-webkit-scrollbar-thumb{
background: rgba(var(--text-color), 0.3);
background: rgba(var(--text-color,(17,17,17)), 0.3);
border-radius: 1rem;
&:hover{
background: rgba(var(--text-color), 0.5);
background: rgba(var(--text-color,(17,17,17)), 0.5);
}
}
}
@ -121,7 +118,7 @@ smSelect.innerHTML = `
<div class="select">
<div class="selection">
<div class="selected-option-text"></div>
<svg class="icon toggle" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 13.172l4.95-4.95 1.414 1.414L12 16 5.636 9.636 7.05 8.222z"/></svg>
<svg class="icon toggle-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 13.172l4.95-4.95 1.414 1.414L12 16 5.636 9.636 7.05 8.222z"/></svg>
</div>
<div part="options" class="options hide">
<slot></slot>
@ -143,9 +140,11 @@ customElements.define('sm-select', class extends HTMLElement {
this.handleOptionSelection = this.handleOptionSelection.bind(this)
this.handleKeydown = this.handleKeydown.bind(this)
this.handleClickOutside = this.handleClickOutside.bind(this)
this.selectOption = this.selectOption.bind(this)
this.availableOptions
this.previousOption
this._value = undefined;
this.isOpen = false;
this.label = ''
this.slideDown = [{
@ -173,7 +172,6 @@ customElements.define('sm-select', class extends HTMLElement {
}
this.optionList = this.shadowRoot.querySelector('.options')
this.chevron = this.shadowRoot.querySelector('.toggle')
this.selection = this.shadowRoot.querySelector('.selection')
this.selectedOptionText = this.shadowRoot.querySelector('.selected-option-text')
}
@ -187,12 +185,7 @@ customElements.define('sm-select', class extends HTMLElement {
const selectedOption = this.availableOptions.find(option => option.getAttribute('value') === val)
if (selectedOption) {
this.setAttribute('value', val)
this.selectedOptionText.textContent = `${this.label}${selectedOption.textContent}`;
if (this.previousOption) {
this.previousOption.classList.remove('check-selected')
}
selectedOption.classList.add('check-selected')
this.previousOption = selectedOption
this.selectOption(selectedOption)
} else {
console.warn(`There is no option with ${val} as value`)
}
@ -200,19 +193,25 @@ customElements.define('sm-select', class extends HTMLElement {
reset(fire = true) {
if (this.availableOptions[0] && this.previousOption !== this.availableOptions[0]) {
const firstElement = this.availableOptions[0];
if (this.previousOption) {
this.previousOption.classList.remove('check-selected')
}
firstElement.classList.add('check-selected')
this.value = firstElement.getAttribute('value')
this.selectedOptionText.textContent = `${this.label}${firstElement.textContent}`
this.previousOption = firstElement;
const selectedOption = this.availableOptions.find(option => option.hasAttribute('selected')) || this.availableOptions[0];
this.value = selectedOption.getAttribute('value')
if (fire) {
this.fireEvent()
}
}
}
selectOption(selectedOption) {
if (this.previousOption) {
this.previousOption.classList.remove('check-selected')
this.previousOption.removeAttribute('selected')
}
if (this.previousOption !== selectedOption) {
selectedOption.classList.add('check-selected')
selectedOption.setAttribute('selected', '')
this.selectedOptionText.textContent = `${this.label}${selectedOption.textContent}`;
this.previousOption = selectedOption
}
}
focusIn() {
this.selection.focus()
@ -221,11 +220,11 @@ customElements.define('sm-select', class extends HTMLElement {
open() {
this.optionList.classList.remove('hide')
this.optionList.animate(this.slideDown, this.animationOptions)
this.chevron.classList.add('rotate')
this.setAttribute('open', '')
this.isOpen = true
}
collapse() {
this.chevron.classList.remove('rotate')
this.removeAttribute('open')
this.optionList.animate(this.slideUp, this.animationOptions)
.onfinish = () => {
this.optionList.classList.add('hide')
@ -317,6 +316,11 @@ customElements.define('sm-select', class extends HTMLElement {
let slot = this.shadowRoot.querySelector('slot')
slot.addEventListener('slotchange', e => {
this.availableOptions = slot.assignedElements()
this.availableOptions.forEach(elem => {
if (elem.hasAttribute('selected')) {
this._value = elem.value;
}
});
this.reset(false)
});
this.addEventListener('click', this.handleClick)
@ -374,13 +378,13 @@ smOption.innerHTML = `
}
:host(:focus){
outline: none;
background: rgba(var(--text-color), 0.1);
background: rgba(var(--text-color,(17,17,17)), 0.1);
}
.icon {
opacity: 0;
height: 1.2rem;
width: 1.2rem;
fill: rgba(var(--text-color), 0.8);
fill: rgba(var(--text-color,(17,17,17)), 0.8);
}
:host(:focus) .option .icon{
opacity: 0.4
@ -390,7 +394,7 @@ smOption.innerHTML = `
}
@media (hover: hover){
.option:hover{
background: rgba(var(--text-color), 0.1);
background: rgba(var(--text-color,(17,17,17)), 0.1);
}
:host(:not(.check-selected):hover) .icon{
opacity: 0.4

File diff suppressed because one or more lines are too long

View File

@ -7,17 +7,12 @@ spinner.innerHTML = `
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
:host{
--accent-color: #4d2588;
--height: 1.6rem;
--width: 1.6rem;
}
.loader {
height: var(--height);
width: var(--weight);
height: var(--size, 1.5rem);
width: var(--size, 1.5rem);
stroke-width: 8;
overflow: visible;
stroke: var(--accent-color);
stroke: var(--accent-color, teal);
fill: none;
stroke-dashoffset: 180;
stroke-dasharray: 180;

View File

@ -1 +1 @@
const spinner=document.createElement("template");spinner.innerHTML='\n<style> \n*{\n padding: 0;\n margin: 0;\n -webkit-box-sizing: border-box;\n box-sizing: border-box;\n}\n:host{\n --accent-color: #4d2588;\n --height: 1.6rem;\n --width: 1.6rem;\n}\n.loader {\n height: var(--height);\n width: var(--weight);\n stroke-width: 8;\n overflow: visible;\n stroke: var(--accent-color);\n fill: none;\n stroke-dashoffset: 180;\n stroke-dasharray: 180;\n animation: load 2s infinite, spin 1s linear infinite;\n}\n@keyframes load {\n 50% {\n stroke-dashoffset: 0;\n }\n 100%{\n stroke-dashoffset: -180;\n }\n}\n\n@keyframes spin {\n 100% {\n transform: rotate(360deg);\n }\n}\n</style>\n<svg viewBox="0 0 64 64" class="loader"><circle cx="32" cy="32" r="32" /></svg>\n\n';class SpinnerLoader extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(spinner.content.cloneNode(!0))}}window.customElements.define("sm-spinner",SpinnerLoader);
const spinner=document.createElement("template");spinner.innerHTML='\n<style> \n*{\n padding: 0;\n margin: 0;\n -webkit-box-sizing: border-box;\n box-sizing: border-box;\n}\n.loader {\n height: var(--size, 1.5rem);\n width: var(--size, 1.5rem);\n stroke-width: 8;\n overflow: visible;\n stroke: var(--accent-color, teal);\n fill: none;\n stroke-dashoffset: 180;\n stroke-dasharray: 180;\n animation: load 2s infinite, spin 1s linear infinite;\n}\n@keyframes load {\n 50% {\n stroke-dashoffset: 0;\n }\n 100%{\n stroke-dashoffset: -180;\n }\n}\n\n@keyframes spin {\n 100% {\n transform: rotate(360deg);\n }\n}\n</style>\n<svg viewBox="0 0 64 64" class="loader"><circle cx="32" cy="32" r="32" /></svg>\n\n';class SpinnerLoader extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(spinner.content.cloneNode(!0))}}window.customElements.define("sm-spinner",SpinnerLoader);

View File

@ -8,9 +8,6 @@ stripSelect.innerHTML = `
box-sizing: border-box;
}
:host{
--accent-color: #4d2588;
--text-color: 17, 17, 17;
--background-color: 255, 255, 255;
padding: 1rem 0;
}
.hide{
@ -50,7 +47,7 @@ stripSelect.innerHTML = `
cursor: pointer;
position: absolute;
align-items: center;
background: rgba(var(--background-color), 1);
background: rgba(var(--background-color,(255,255,255)), 1);
transform: translateY(-50%);
}
.nav-button--right{
@ -69,7 +66,7 @@ stripSelect.innerHTML = `
.icon{
height: 1.5rem;
width: 1.5rem;
fill: rgba(var(--text-color), .8);
fill: rgba(var(--text-color,(17,17,17)), .8);
}
@media (hover: none){
::-webkit-scrollbar {
@ -85,11 +82,11 @@ stripSelect.innerHTML = `
width: 2rem;
}
.cover--left{
background: linear-gradient(90deg, rgba(var(--background-color), 1), transparent);
background: linear-gradient(90deg, rgba(var(--background-color,(255,255,255)), 1), transparent);
}
.cover--right{
right: 0;
background: linear-gradient(90deg, transparent, rgba(var(--background-color), 1));
background: linear-gradient(90deg, transparent, rgba(var(--background-color,(255,255,255)), 1));
}
}
@media (hover: hover){
@ -104,11 +101,11 @@ stripSelect.innerHTML = `
overflow: hidden;
}
.cover--left{
background: linear-gradient(90deg, rgba(var(--background-color), 1) 60%, transparent);
background: linear-gradient(90deg, rgba(var(--background-color,(255,255,255)), 1) 60%, transparent);
}
.cover--right{
right: 0;
background: linear-gradient(90deg, transparent 0%, rgba(var(--background-color), 1) 40%);
background: linear-gradient(90deg, transparent 0%, rgba(var(--background-color,(255,255,255)), 1) 40%);
}
}
</style>
@ -137,14 +134,19 @@ customElements.define('strip-select', class extends HTMLElement {
this.slottedOptions = undefined;
this._value = undefined;
this.scrollDistance = 0;
this.assignedElements = [];
this.scrollLeft = this.scrollLeft.bind(this);
this.scrollRight = this.scrollRight.bind(this);
this.fireEvent = this.fireEvent.bind(this);
this.setSelectedOption = this.setSelectedOption.bind(this);
}
get value() {
return this._value;
}
set value(val) {
this.setSelectedOption(val);
}
scrollLeft() {
this.stripSelect.scrollBy({
left: -this.scrollDistance,
@ -158,6 +160,19 @@ customElements.define('strip-select', class extends HTMLElement {
behavior: 'smooth'
});
}
setSelectedOption(value) {
if (this._value === value) return
this._value = value;
this.assignedElements.forEach(elem => {
if (elem.value === value) {
elem.setAttribute('active', '');
elem.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "center" });
}
else
elem.removeAttribute('active')
});
}
fireEvent() {
this.dispatchEvent(
new CustomEvent("change", {
@ -178,17 +193,17 @@ customElements.define('strip-select', class extends HTMLElement {
const navButtonLeft = this.shadowRoot.querySelector('.nav-button--left');
const navButtonRight = this.shadowRoot.querySelector('.nav-button--right');
slot.addEventListener('slotchange', e => {
const assignedElements = slot.assignedElements();
assignedElements.forEach(elem => {
this.assignedElements = slot.assignedElements();
this.assignedElements.forEach(elem => {
if (elem.hasAttribute('selected')) {
elem.setAttribute('active', '');
this._value = elem.value;
}
});
if (!this.hasAttribute('multiline')) {
if (assignedElements.length > 0) {
firstOptionObserver.observe(slot.assignedElements()[0]);
lastOptionObserver.observe(slot.assignedElements()[slot.assignedElements().length - 1]);
if (this.assignedElements.length > 0) {
firstOptionObserver.observe(this.assignedElements[0]);
lastOptionObserver.observe(this.assignedElements[this.assignedElements.length - 1]);
}
else {
navButtonLeft.classList.add('hide');
@ -215,10 +230,7 @@ customElements.define('strip-select', class extends HTMLElement {
resObs.observe(this);
this.stripSelect.addEventListener('option-clicked', e => {
if (this._value !== e.target.value) {
this._value = e.target.value;
slot.assignedElements().forEach(elem => elem.removeAttribute('active'));
e.target.setAttribute('active', '');
e.target.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "center" });
this.setSelectedOption(e.target.value);
this.fireEvent();
}
});
@ -273,9 +285,6 @@ stripOption.innerHTML = `
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
:host{
--background-color: inherit;
}
.strip-option{
display: flex;
flex-shrink: 0;
@ -287,17 +296,17 @@ stripOption.innerHTML = `
-webkit-tap-highlight-color: transparent;
}
:host([active]) .strip-option{
color: var(--active-option-color, inherit);
background-color: var(--active-background-color, rgba(var(--text-color), 0.06));
color: var(--active-option-color, rgba(var(--background-color,white)));
background-color: var(--active-background-color, var(--accent-color,teal));
}
:host(:focus-within){
outline: none;
}
:host(:focus-within) .strip-option{
box-shadow: 0 0 0 0.1rem var(--accent-color) inset;
box-shadow: 0 0 0 0.1rem var(--accent-color,teal) inset;
}
:host(:hover:not([active])) .strip-option{
background-color: rgba(var(--text-color), 0.06);
background-color: rgba(var(--text-color,(17,17,17)), 0.06);
}
</style>
<label class="strip-option">

File diff suppressed because one or more lines are too long

View File

@ -1,3 +1,5 @@
//switch
const smSwitch = document.createElement('template')
smSwitch.innerHTML = `
<style>
@ -12,9 +14,6 @@ smSwitch.innerHTML = `
display: -webkit-inline-box;
display: -ms-inline-flexbox;
display: inline-flex;
--accent-color: #4d2588;
--text-color: 17, 17, 17;
--background-color: 255, 255, 255;
}
label{
display: -webkit-box;
@ -61,7 +60,7 @@ smSwitch.innerHTML = `
-webkit-transition: background 0.3s;
-o-transition: background 0.3s;
transition: background 0.3s;
background: rgba(var(--text-color), 0.4);
background: rgba(var(--text-color,inherit), 0.4);
-webkit-box-shadow: 0 0.1rem 0.3rem #00000040 inset;
box-shadow: 0 0.1rem 0.3rem #00000040 inset;
border-radius: 1rem;
@ -80,7 +79,7 @@ smSwitch.innerHTML = `
position: absolute;
height: 2.6rem;
width: 2.6rem;
background: rgba(var(--text-color), 0.2);
background: rgba(var(--text-color,inherit), 0.2);
border-radius: 2rem;
opacity: 0;
-webkit-transition: opacity 0.3s;
@ -119,7 +118,7 @@ smSwitch.innerHTML = `
}
input:checked ~ .track {
background: var(--accent-color);
background: var(--accent-color, teal);
}
</style>
<label tabindex="0">
@ -173,6 +172,9 @@ customElements.define('sm-switch', class extends HTMLElement {
this.removeAttribute('checked')
}
}
get value() {
return this.isChecked
}
reset() {

View File

@ -1 +1 @@
const smSwitch=document.createElement("template");smSwitch.innerHTML='\t\n<style>\n *{\n -webkit-box-sizing: border-box;\n box-sizing: border-box;\n padding: 0;\n margin: 0;\n }\n \n :host{\n display: -webkit-inline-box;\n display: -ms-inline-flexbox;\n display: inline-flex;\n --accent-color: #4d2588;\n --text-color: 17, 17, 17;\n --background-color: 255, 255, 255;\n }\n label{\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex;\n -webkit-box-align: center;\n -ms-flex-align: center;\n align-items: center;\n width: 100%;\n outline: none;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n }\n :host([disabled]) {\n cursor: not-allowed;\n opacity: 0.6;\n pointer-events: none;\n }\n .switch {\n position: relative;\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex;\n -webkit-box-align: center;\n -ms-flex-align: center;\n align-items: center;\n width: 2.4rem;\n flex-shrink: 0;\n margin-left: auto;\n padding: 0.2rem;\n cursor: pointer;\n border-radius: 2rem;\n }\n \n input {\n display: none;\n }\n \n .track {\n position: absolute;\n left: 0;\n right: 0;\n height: 1.4rem;\n -webkit-transition: background 0.3s;\n -o-transition: background 0.3s;\n transition: background 0.3s;\n background: rgba(var(--text-color), 0.4);\n -webkit-box-shadow: 0 0.1rem 0.3rem #00000040 inset;\n box-shadow: 0 0.1rem 0.3rem #00000040 inset;\n border-radius: 1rem;\n }\n \n label:active .thumb::after,\n label:focus-within .thumb::after{\n opacity: 1;\n }\n \n .thumb::after{\n content: \'\';\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex;\n position: absolute;\n height: 2.6rem;\n width: 2.6rem;\n background: rgba(var(--text-color), 0.2);\n border-radius: 2rem;\n opacity: 0;\n -webkit-transition: opacity 0.3s;\n -o-transition: opacity 0.3s;\n transition: opacity 0.3s;\n }\n \n .thumb {\n position: relative;\n display: -webkit-inline-box;\n display: -ms-inline-flexbox;\n display: inline-flex;\n height: 1rem;\n width: 1rem;\n -webkit-box-pack: center;\n -ms-flex-pack: center;\n justify-content: center;\n -webkit-box-align: center;\n -ms-flex-align: center;\n align-items: center;\n border-radius: 1rem;\n -webkit-box-shadow: 0 0.1rem 0.4rem #00000060;\n box-shadow: 0 0.1rem 0.4rem #00000060;\n -webkit-transition: -webkit-transform 0.3s;\n transition: -webkit-transform 0.3s;\n -o-transition: transform 0.3s;\n transition: transform 0.3s;\n transition: transform 0.3s, -webkit-transform 0.3s;\n border: solid 0.3rem white;\n }\n \n input:checked ~ .thumb {\n -webkit-transform: translateX(100%);\n -ms-transform: translateX(100%);\n transform: translateX(100%);\n }\n \n input:checked ~ .track {\n background: var(--accent-color);\n }\n</style>\n<label tabindex="0">\n <slot name="left"></slot>\n <div part="switch" class="switch">\n <input type="checkbox">\n <div class="track"></div>\n <div class="thumb"></div>\n </div>\n <slot name="right"></slot>\n</label>',customElements.define("sm-switch",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smSwitch.content.cloneNode(!0)),this.switch=this.shadowRoot.querySelector(".switch"),this.input=this.shadowRoot.querySelector("input"),this.isChecked=!1,this.isDisabled=!1,this.dispatch=this.dispatch.bind(this)}static get observedAttributes(){return["disabled","checked"]}get disabled(){return this.isDisabled}set disabled(n){n?this.setAttribute("disabled",""):this.removeAttribute("disabled")}get checked(){return this.isChecked}set checked(n){n?this.setAttribute("checked",""):this.removeAttribute("checked")}reset(){}dispatch(){this.dispatchEvent(new CustomEvent("change",{bubbles:!0,composed:!0,detail:{value:this.isChecked}}))}connectedCallback(){this.addEventListener("keydown",n=>{" "!==n.key||this.isDisabled||(n.preventDefault(),this.input.click())}),this.input.addEventListener("click",n=>{this.input.checked?this.checked=!0:this.checked=!1,this.dispatch()})}attributeChangedCallback(n,t,e){t!==e&&("disabled"===n?this.hasAttribute("disabled")?this.disabled=!0:this.disabled=!1:"checked"===n&&(this.hasAttribute("checked")?(this.isChecked=!0,this.input.checked=!0):(this.isChecked=!1,this.input.checked=!1)))}});
const smSwitch=document.createElement("template");smSwitch.innerHTML='\t\n<style>\n *{\n -webkit-box-sizing: border-box;\n box-sizing: border-box;\n padding: 0;\n margin: 0;\n }\n \n :host{\n display: -webkit-inline-box;\n display: -ms-inline-flexbox;\n display: inline-flex;\n }\n label{\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex;\n -webkit-box-align: center;\n -ms-flex-align: center;\n align-items: center;\n width: 100%;\n outline: none;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n }\n :host([disabled]) {\n cursor: not-allowed;\n opacity: 0.6;\n pointer-events: none;\n }\n .switch {\n position: relative;\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex;\n -webkit-box-align: center;\n -ms-flex-align: center;\n align-items: center;\n width: 2.4rem;\n flex-shrink: 0;\n margin-left: auto;\n padding: 0.2rem;\n cursor: pointer;\n border-radius: 2rem;\n }\n \n input {\n display: none;\n }\n \n .track {\n position: absolute;\n left: 0;\n right: 0;\n height: 1.4rem;\n -webkit-transition: background 0.3s;\n -o-transition: background 0.3s;\n transition: background 0.3s;\n background: rgba(var(--text-color,inherit), 0.4);\n -webkit-box-shadow: 0 0.1rem 0.3rem #00000040 inset;\n box-shadow: 0 0.1rem 0.3rem #00000040 inset;\n border-radius: 1rem;\n }\n \n label:active .thumb::after,\n label:focus-within .thumb::after{\n opacity: 1;\n }\n \n .thumb::after{\n content: \'\';\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex;\n position: absolute;\n height: 2.6rem;\n width: 2.6rem;\n background: rgba(var(--text-color,inherit), 0.2);\n border-radius: 2rem;\n opacity: 0;\n -webkit-transition: opacity 0.3s;\n -o-transition: opacity 0.3s;\n transition: opacity 0.3s;\n }\n \n .thumb {\n position: relative;\n display: -webkit-inline-box;\n display: -ms-inline-flexbox;\n display: inline-flex;\n height: 1rem;\n width: 1rem;\n -webkit-box-pack: center;\n -ms-flex-pack: center;\n justify-content: center;\n -webkit-box-align: center;\n -ms-flex-align: center;\n align-items: center;\n border-radius: 1rem;\n -webkit-box-shadow: 0 0.1rem 0.4rem #00000060;\n box-shadow: 0 0.1rem 0.4rem #00000060;\n -webkit-transition: -webkit-transform 0.3s;\n transition: -webkit-transform 0.3s;\n -o-transition: transform 0.3s;\n transition: transform 0.3s;\n transition: transform 0.3s, -webkit-transform 0.3s;\n border: solid 0.3rem white;\n }\n \n input:checked ~ .thumb {\n -webkit-transform: translateX(100%);\n -ms-transform: translateX(100%);\n transform: translateX(100%);\n }\n \n input:checked ~ .track {\n background: var(--accent-color, teal);\n }\n</style>\n<label tabindex="0">\n <slot name="left"></slot>\n <div part="switch" class="switch">\n <input type="checkbox">\n <div class="track"></div>\n <div class="thumb"></div>\n </div>\n <slot name="right"></slot>\n</label>',customElements.define("sm-switch",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smSwitch.content.cloneNode(!0)),this.switch=this.shadowRoot.querySelector(".switch"),this.input=this.shadowRoot.querySelector("input"),this.isChecked=!1,this.isDisabled=!1,this.dispatch=this.dispatch.bind(this)}static get observedAttributes(){return["disabled","checked"]}get disabled(){return this.isDisabled}set disabled(n){n?this.setAttribute("disabled",""):this.removeAttribute("disabled")}get checked(){return this.isChecked}set checked(n){n?this.setAttribute("checked",""):this.removeAttribute("checked")}get value(){return this.isChecked}reset(){}dispatch(){this.dispatchEvent(new CustomEvent("change",{bubbles:!0,composed:!0,detail:{value:this.isChecked}}))}connectedCallback(){this.addEventListener("keydown",n=>{" "!==n.key||this.isDisabled||(n.preventDefault(),this.input.click())}),this.input.addEventListener("click",n=>{this.input.checked?this.checked=!0:this.checked=!1,this.dispatch()})}attributeChangedCallback(n,e,t){e!==t&&("disabled"===n?this.hasAttribute("disabled")?this.disabled=!0:this.disabled=!1:"checked"===n&&(this.hasAttribute("checked")?(this.isChecked=!0,this.input.checked=!0):(this.isChecked=!1,this.input.checked=!1)))}});

View File

@ -11,9 +11,6 @@ smTabHeader.innerHTML = `
display: -webkit-box;
display: -ms-flexbox;
display: flex;
--accent-color: #4d2588;
--text-color: 17, 17, 17;
--background-color: 255, 255, 255;
--gap: 1rem;
--justify-content: flex-start;
--tab-indicator-border-radius: 0.3rem;
@ -41,7 +38,7 @@ smTabHeader.innerHTML = `
bottom: 0;
height: 0.15rem;
border-radius: 1rem 1rem 0 0;
background: var(--accent-color);
background: var(--accent-color, tea);
-webkit-transition: width 0.3s, -webkit-transform 0.3s;
transition: width 0.3s, -webkit-transform 0.3s;
-o-transition: transform 0.3s, width 0.3s;
@ -67,10 +64,10 @@ smTabHeader.innerHTML = `
border-radius: 0.3rem;
}
:host([variant="tab"]) slot::slotted(.active){
color: rgba(var(--background-color), 1);
color: rgba(var(--background-color, (255,255,255)), 1);
}
slot::slotted(.active){
color: var(--accent-color);
color: var(--accent-color, tea);
opacity: 1;
}
@media (any-hover: none){

File diff suppressed because one or more lines are too long

View File

@ -7,12 +7,9 @@ tagsInput.innerHTML = `
box-sizing: border-box;
}
:host{
--accent-color: #4d2588;
--text-color: 17, 17, 17;
--background-color: 255, 255, 255;
--danger-color: red;
--danger-color: red;
--border-radius: 0.3rem;
--background: rgba(var(--text-color), 0.06);
--background: rgba(var(--text-color,(17,17,17)), 0.06);
}
.hide{
display: none !important;
@ -29,7 +26,7 @@ tagsInput.innerHTML = `
background: var(--background);
}
.tags-wrapper:focus-within{
box-shadow: 0 0 0 0.1rem var(--accent-color) inset !important;
box-shadow: 0 0 0 0.1rem var(--accent-color,teal) inset !important;
}
.tag {
@ -41,14 +38,14 @@ tagsInput.innerHTML = `
border-radius: 0.3rem;
padding: 0.3rem 0.5rem;
margin: 0 0.5rem 0.5rem 0;
background-color: rgba(var(--text-color), 0.06);
background-color: rgba(var(--text-color,(17,17,17)), 0.06);
}
.icon {
height: 1.2rem;
width: 1.2rem;
margin-left: 0.3rem;
fill: rgba(var(--text-color), 0.8);
fill: rgba(var(--text-color,(17,17,17)), 0.8);
}
input,
@ -74,7 +71,7 @@ tagsInput.innerHTML = `
top: 50%;
font-weight: 500;
transform: translateY(-50%);
color: rgba(var(--text-color), 0.6);
color: rgba(var(--text-color,(17,17,17)), 0.6);
}
</style>
<div class="tags-wrapper">
@ -161,7 +158,7 @@ customElements.define('tags-input', class extends HTMLElement {
backgroundColor: 'initial'
},
{
backgroundColor: 'var(--accent-color)'
backgroundColor: 'var(--accent-color,teal)'
},
{
backgroundColor: 'initial'

File diff suppressed because one or more lines are too long

View File

@ -5,17 +5,13 @@ textField.innerHTML = `
padding: 0;
margin: 0;
box-sizing: border-box;
}
:host{
--accent-color: #4d2588;
--text-color: 17, 17, 17;
--background-color: 255, 255, 255;
}
}
.text-field{
display: flex;
align-items: center;
}
.text{
padding: 0.6rem 0;
transition: background-color 0.3s;
border-bottom: 0.15rem solid transparent;
overflow-wrap: break-word;
@ -37,33 +33,41 @@ textField.innerHTML = `
.editable{
border-bottom: 0.15rem solid rgba(var(--text-color), 0.6);
}
.edit-button{
display: grid;
.icon-container{
position: relative;
margin-left: 0.5rem;
background-color: transparent;
border: none;
}
:host([disabled]) .edit-button{
display: none;
height: 1.8rem;
width: 1.8rem;
}
.icon{
grid-area: 1/-1;
position: absolute;
cursor: pointer;
height: 1.2rem;
width: 1.2rem;
fill: rgba(var(--text-color), 1);
fill: none;
stroke-width: 8;
stroke: rgba(var(--text-color), 1);
height: 1.8rem;
width: 1.8rem;
padding: 0.4rem;
overflow: visible;
stroke-linecap: round;
stroke-linejoin: round;
}
.hide{
visibility: hidden;
display: none;
}
</style>
<div class="text-field">
<div class="text" part="text"></div>
<button class="edit-button">
<svg class="icon" title="edit" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0z" fill="none"/><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"/></svg>
<svg class="icon hide" title="Save" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0z" fill="none"/><path d="M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z"/></svg>
</button>
<div class="icon-container">
<svg class="edit-button icon" viewBox="0 0 64 64">
<title>Edit</title>
<path d="M46.73,14.81l7,7,7.65-7.6A7.15,7.15,0,0,0,61.39,4L60.11,2.77a7.23,7.23,0,0,0-10.19,0L3.87,48.57a5,5,0,0,0-1.39,2.6L.53,61.27a1.74,1.74,0,0,0,2,2l10.15-1.94A5.06,5.06,0,0,0,15.34,60L49.6,25.9"/>
</svg>
<svg class="save-button icon hide" viewBox="0 0 64 64">
<title>Save</title>
<polyline points="0.35 31.82 21.45 52.98 63.65 10.66"/>
</svg>
</div>
</div>
`
@ -78,35 +82,32 @@ customElements.define('text-field', class extends HTMLElement {
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 = false
this.isDisabled = false
this.fireEvent = this.fireEvent.bind(this)
this.setEditable = this.setEditable.bind(this)
this.setNonEditable = this.setNonEditable.bind(this)
this.toggleEditable = this.toggleEditable.bind(this)
this.revert = this.revert.bind(this)
}
static get observedAttributes() {
return ['disabled', 'value']
return ['disable']
}
get value() {
return this.text
}
set value(val) {
this.text = val
this.textContainer.textContent = val
this.setAttribute('value', val)
}
set disabled(val) {
this.isDisabled = val
if (this.isDisabled)
this.setAttribute('disabled', '')
this.setAttribute('disable', '')
else
this.removeAttribute('disabled')
this.removeAttribute('disable')
}
fireEvent(value) {
let event = new CustomEvent('change', {
fireEvent = (value) => {
let event = new CustomEvent('contentchanged', {
bubbles: true,
cancelable: true,
composed: true,
@ -117,50 +118,42 @@ customElements.define('text-field', class extends HTMLElement {
this.dispatchEvent(event);
}
setEditable() {
setEditable = () => {
if (this.isTextEditable) return
this.textContainer.contentEditable = true
this.textContainer.classList.add('editable')
this.textContainer.focus()
document.execCommand('selectAll', false, null);
this.editButton.children[0].animate(this.rotateOut, this.animOptions).onfinish = () => {
this.editButton.children[0].classList.add('hide')
this.editButton.animate(this.rotateOut, this.animOptions).onfinish = () => {
this.editButton.classList.add('hide')
}
setTimeout(() => {
this.editButton.children[1].classList.remove('hide')
this.editButton.children[1].animate(this.rotateIn, this.animOptions)
this.saveButton.classList.remove('hide')
this.saveButton.animate(this.rotateIn, this.animOptions)
}, 100);
this.isTextEditable = true
}
setNonEditable() {
setNonEditable = () => {
if (!this.isTextEditable) return
this.textContainer.contentEditable = false
this.textContainer.classList.remove('editable')
const newValue = this.textContainer.textContent.trim()
if (this.text !== newValue && newValue !== '') {
if (this.text !== this.textContainer.textContent.trim()) {
this.setAttribute('value', this.textContainer.textContent)
this.text = this.textContainer.textContent.trim()
this.fireEvent(this.text)
} else {
this.value = this.text
}
this.editButton.children[1].animate(this.rotateOut, this.animOptions).onfinish = () => {
this.editButton.children[1].classList.add('hide')
this.saveButton.animate(this.rotateOut, this.animOptions).onfinish = () => {
this.saveButton.classList.add('hide')
}
setTimeout(() => {
this.editButton.children[0].classList.remove('hide')
this.editButton.children[0].animate(this.rotateIn, this.animOptions)
this.editButton.classList.remove('hide')
this.editButton.animate(this.rotateIn, this.animOptions)
}, 100);
this.isTextEditable = false
}
toggleEditable() {
if (this.isTextEditable)
this.setNonEditable()
else
this.setEditable()
}
revert() {
revert = () => {
if (this.textContainer.isContentEditable) {
this.value = this.text
this.setNonEditable()
@ -173,7 +166,7 @@ customElements.define('text-field', class extends HTMLElement {
this.text = this.getAttribute('value')
this.textContainer.textContent = this.text
}
if (this.hasAttribute('disabled'))
if (this.hasAttribute('disable'))
this.isDisabled = true
else
this.isDisabled = false
@ -206,27 +199,30 @@ customElements.define('text-field', class extends HTMLElement {
if (!this.isDisabled) {
this.iconsContainer.classList.remove('hide')
this.textContainer.addEventListener('dblclick', this.setEditable)
this.editButton.addEventListener('click', this.toggleEditable)
this.editButton.addEventListener('click', this.setEditable)
this.saveButton.addEventListener('click', this.setNonEditable)
}
}
attributeChangedCallback(name, oldValue, newValue) {
if (name === 'disabled') {
if (this.hasAttribute('disabled')) {
attributeChangedCallback(name) {
if (name === 'disable') {
if (this.hasAttribute('disable')) {
this.iconsContainer.classList.add('hide')
this.textContainer.removeEventListener('dblclick', this.setEditable)
this.editButton.removeEventListener('click', this.toggleEditable)
this.editButton.removeEventListener('click', this.setEditable)
this.saveButton.removeEventListener('click', this.setNonEditable)
this.revert()
}
else {
this.iconsContainer.classList.remove('hide')
this.textContainer.addEventListener('dblclick', this.setEditable)
this.editButton.addEventListener('click', this.toggleEditable)
this.editButton.addEventListener('click', this.setEditable)
this.saveButton.addEventListener('click', this.setNonEditable)
}
} else if (name === 'value') {
this.text = newValue
this.textContainer.textContent = newValue
}
}
disconnectedCallback() {
this.textContainer.removeEventListener('dblclick', this.setEditable)
this.editButton.removeEventListener('click', this.toggleEditable)
this.editButton.removeEventListener('click', this.setEditable)
this.saveButton.removeEventListener('click', this.setNonEditable)
}
})

View File

@ -1,114 +1,111 @@
const smTextarea = document.createElement('template')
smTextarea.innerHTML = `
<style>
*,
*::before,
*::after {
padding: 0;
margin: 0;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
::-moz-focus-inner{
border: none;
}
.hide{
opacity: 0 !important;
}
:host{
display: grid;
--accent-color: #4d2588;
--text-color: 17, 17, 17;
--background-color: 255, 255, 255;
--danger-color: red;
--border-radius: 0.3rem;
--background: rgba(var(--text-color), 0.06);
--padding: initial;
--max-height: 8rem;
}
:host([variant="outlined"]) .textarea {
box-shadow: 0 0 0 0.1rem rgba(var(--text-color), 0.4) inset;
background: rgba(var(--background-color), 1);
}
.textarea{
display: grid;
position: relative;
cursor: text;
min-width: 0;
text-align: left;
overflow: hidden auto;
grid-template-columns: 1fr;
align-items: stretch;
max-height: var(--max-height);
background: var(--background);
border-radius: var(--border-radius);
padding: var(--padding);
}
.textarea::after,
textarea{
padding: 0.7rem 1rem;
width: 100%;
min-width: 1em;
font: inherit;
color: inherit;
resize: none;
grid-area: 2/1;
justify-self: stretch;
background: none;
appearance: none;
border: none;
outline: none;
line-height: 1.5;
overflow: hidden;
}
.textarea::after{
content: attr(data-value) ' ';
visibility: hidden;
white-space: pre-wrap;
overflow-wrap: break-word;
word-wrap: break-word;
hyphens: auto;
}
.readonly{
pointer-events: none;
}
.textarea:focus-within:not(.readonly){
box-shadow: 0 0 0 0.1rem var(--accent-color) inset;
}
.placeholder{
position: absolute;
margin: 0.7rem 1rem;
opacity: .7;
font-weight: inherit;
font-size: inherit;
line-height: 1.5;
pointer-events: none;
user-select: none;
}
:host([disabled]) .textarea{
cursor: not-allowed;
opacity: 0.6;
}
@media (any-hover: hover){
::-webkit-scrollbar{
width: 0.5rem;
height: 0.5rem;
<style>
*,
*::before,
*::after {
padding: 0;
margin: 0;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
::-moz-focus-inner{
border: none;
}
::-webkit-scrollbar-thumb{
background: rgba(var(--text-color), 0.3);
border-radius: 1rem;
&:hover{
background: rgba(var(--text-color), 0.5);
.hide{
opacity: 0 !important;
}
:host{
display: grid;
--danger-color: red;
--border-radius: 0.3rem;
--background: rgba(var(--text-color,(17,17,17)), 0.06);
--padding: initial;
--max-height: 8rem;
}
:host([variant="outlined"]) .textarea {
box-shadow: 0 0 0 0.1rem rgba(var(--text-color,(17,17,17)), 0.4) inset;
background: rgba(var(--background-color,(255,255,255)), 1);
}
.textarea{
display: grid;
position: relative;
cursor: text;
min-width: 0;
text-align: left;
overflow: hidden auto;
grid-template-columns: 1fr;
align-items: stretch;
max-height: var(--max-height);
background: var(--background);
border-radius: var(--border-radius);
padding: var(--padding);
}
.textarea::after,
textarea{
padding: 0.7rem 1rem;
width: 100%;
min-width: 1em;
font: inherit;
color: inherit;
resize: none;
grid-area: 2/1;
justify-self: stretch;
background: none;
appearance: none;
border: none;
outline: none;
line-height: 1.5;
overflow: hidden;
}
.textarea::after{
content: attr(data-value) ' ';
visibility: hidden;
white-space: pre-wrap;
overflow-wrap: break-word;
word-wrap: break-word;
hyphens: auto;
}
.readonly{
pointer-events: none;
}
.textarea:focus-within:not(.readonly){
box-shadow: 0 0 0 0.1rem var(--accent-color,teal) inset;
}
.placeholder{
position: absolute;
margin: 0.7rem 1rem;
opacity: .7;
font-weight: inherit;
font-size: inherit;
line-height: 1.5;
pointer-events: none;
user-select: none;
}
:host([disabled]) .textarea{
cursor: not-allowed;
opacity: 0.6;
}
@media (any-hover: hover){
::-webkit-scrollbar{
width: 0.5rem;
height: 0.5rem;
}
::-webkit-scrollbar-thumb{
background: rgba(var(--text-color,(17,17,17)), 0.3);
border-radius: 1rem;
&:hover{
background: rgba(var(--text-color,(17,17,17)), 0.5);
}
}
}
}
</style>
<label class="textarea" part="textarea">
<span class="placeholder"></span>
<textarea rows="1"></textarea>
</label>
`;
</style>
<label class="textarea" part="textarea">
<span class="placeholder"></span>
<textarea rows="1"></textarea>
</label>
`;
customElements.define('sm-textarea',
class extends HTMLElement {
constructor() {

View File

@ -1 +1 @@
const smTextarea=document.createElement("template");smTextarea.innerHTML='\n<style>\n*,\n*::before,\n*::after { \n padding: 0;\n margin: 0;\n -webkit-box-sizing: border-box;\n box-sizing: border-box;\n} \n::-moz-focus-inner{\n border: none;\n}\n.hide{\n opacity: 0 !important;\n}\n:host{\n display: grid;\n --accent-color: #4d2588;\n --text-color: 17, 17, 17;\n --background-color: 255, 255, 255;\n --danger-color: red;\n --border-radius: 0.3rem;\n --background: rgba(var(--text-color), 0.06);\n --padding: initial;\n --max-height: 8rem;\n}\n:host([variant="outlined"]) .textarea {\n box-shadow: 0 0 0 0.1rem rgba(var(--text-color), 0.4) inset;\n background: rgba(var(--background-color), 1);\n}\n.textarea{\n display: grid;\n position: relative;\n cursor: text;\n min-width: 0;\n text-align: left;\n overflow: hidden auto;\n grid-template-columns: 1fr;\n align-items: stretch;\n max-height: var(--max-height);\n background: var(--background);\n border-radius: var(--border-radius);\n padding: var(--padding);\n}\n.textarea::after,\ntextarea{\n padding: 0.7rem 1rem;\n width: 100%;\n min-width: 1em;\n font: inherit;\n color: inherit;\n resize: none;\n grid-area: 2/1;\n justify-self: stretch;\n background: none;\n appearance: none;\n border: none;\n outline: none;\n line-height: 1.5;\n overflow: hidden;\n}\n.textarea::after{\n content: attr(data-value) \' \';\n visibility: hidden;\n white-space: pre-wrap;\n overflow-wrap: break-word;\n word-wrap: break-word;\n hyphens: auto;\n}\n.readonly{\n pointer-events: none;\n}\n.textarea:focus-within:not(.readonly){\n box-shadow: 0 0 0 0.1rem var(--accent-color) inset;\n}\n.placeholder{\n position: absolute;\n margin: 0.7rem 1rem;\n opacity: .7;\n font-weight: inherit;\n font-size: inherit;\n line-height: 1.5;\n pointer-events: none;\n user-select: none;\n}\n:host([disabled]) .textarea{\n cursor: not-allowed;\n opacity: 0.6;\n}\n@media (any-hover: hover){\n ::-webkit-scrollbar{\n width: 0.5rem;\n height: 0.5rem;\n }\n \n ::-webkit-scrollbar-thumb{\n background: rgba(var(--text-color), 0.3);\n border-radius: 1rem;\n &:hover{\n background: rgba(var(--text-color), 0.5);\n }\n }\n}\n</style>\n<label class="textarea" part="textarea">\n <span class="placeholder"></span>\n <textarea rows="1"></textarea>\n</label>\n',customElements.define("sm-textarea",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smTextarea.content.cloneNode(!0)),this.textarea=this.shadowRoot.querySelector("textarea"),this.textareaBox=this.shadowRoot.querySelector(".textarea"),this.placeholder=this.shadowRoot.querySelector(".placeholder"),this.reflectedAttributes=["disabled","required","readonly","rows","minlength","maxlength"],this.reset=this.reset.bind(this),this.focusIn=this.focusIn.bind(this),this.fireEvent=this.fireEvent.bind(this),this.checkInput=this.checkInput.bind(this)}static get observedAttributes(){return["disabled","value","placeholder","required","readonly","rows","minlength","maxlength"]}get value(){return this.textarea.value}set value(e){this.setAttribute("value",e),this.fireEvent()}get disabled(){return this.hasAttribute("disabled")}set disabled(e){e?this.setAttribute("disabled",""):this.removeAttribute("disabled")}get isValid(){return this.textarea.checkValidity()}reset(){this.setAttribute("value","")}focusIn(){this.textarea.focus()}fireEvent(){let e=new Event("input",{bubbles:!0,cancelable:!0,composed:!0});this.dispatchEvent(e)}checkInput(){this.hasAttribute("placeholder")&&""!==this.getAttribute("placeholder")&&(""!==this.textarea.value?this.placeholder.classList.add("hide"):this.placeholder.classList.remove("hide"))}connectedCallback(){this.textarea.addEventListener("input",e=>{this.textareaBox.dataset.value=this.textarea.value,this.checkInput()})}attributeChangedCallback(e,t,n){this.reflectedAttributes.includes(e)?this.hasAttribute(e)?this.textarea.setAttribute(e,this.getAttribute(e)?this.getAttribute(e):""):this.textContent.removeAttribute(e):"placeholder"===e?this.placeholder.textContent=this.getAttribute("placeholder"):"value"===e&&(this.textarea.value=n,this.textareaBox.dataset.value=n,this.checkInput())}});
const smTextarea=document.createElement("template");smTextarea.innerHTML='\n <style>\n *,\n *::before,\n *::after { \n padding: 0;\n margin: 0;\n -webkit-box-sizing: border-box;\n box-sizing: border-box;\n } \n ::-moz-focus-inner{\n border: none;\n }\n .hide{\n opacity: 0 !important;\n }\n :host{\n display: grid;\n --danger-color: red;\n --border-radius: 0.3rem;\n --background: rgba(var(--text-color,(17,17,17)), 0.06);\n --padding: initial;\n --max-height: 8rem;\n }\n :host([variant="outlined"]) .textarea {\n box-shadow: 0 0 0 0.1rem rgba(var(--text-color,(17,17,17)), 0.4) inset;\n background: rgba(var(--background-color,(255,255,255)), 1);\n }\n .textarea{\n display: grid;\n position: relative;\n cursor: text;\n min-width: 0;\n text-align: left;\n overflow: hidden auto;\n grid-template-columns: 1fr;\n align-items: stretch;\n max-height: var(--max-height);\n background: var(--background);\n border-radius: var(--border-radius);\n padding: var(--padding);\n }\n .textarea::after,\n textarea{\n padding: 0.7rem 1rem;\n width: 100%;\n min-width: 1em;\n font: inherit;\n color: inherit;\n resize: none;\n grid-area: 2/1;\n justify-self: stretch;\n background: none;\n appearance: none;\n border: none;\n outline: none;\n line-height: 1.5;\n overflow: hidden;\n }\n .textarea::after{\n content: attr(data-value) \' \';\n visibility: hidden;\n white-space: pre-wrap;\n overflow-wrap: break-word;\n word-wrap: break-word;\n hyphens: auto;\n }\n .readonly{\n pointer-events: none;\n }\n .textarea:focus-within:not(.readonly){\n box-shadow: 0 0 0 0.1rem var(--accent-color,teal) inset;\n }\n .placeholder{\n position: absolute;\n margin: 0.7rem 1rem;\n opacity: .7;\n font-weight: inherit;\n font-size: inherit;\n line-height: 1.5;\n pointer-events: none;\n user-select: none;\n }\n :host([disabled]) .textarea{\n cursor: not-allowed;\n opacity: 0.6;\n }\n @media (any-hover: hover){\n ::-webkit-scrollbar{\n width: 0.5rem;\n height: 0.5rem;\n }\n \n ::-webkit-scrollbar-thumb{\n background: rgba(var(--text-color,(17,17,17)), 0.3);\n border-radius: 1rem;\n &:hover{\n background: rgba(var(--text-color,(17,17,17)), 0.5);\n }\n }\n }\n </style>\n <label class="textarea" part="textarea">\n <span class="placeholder"></span>\n <textarea rows="1"></textarea>\n </label>\n ',customElements.define("sm-textarea",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smTextarea.content.cloneNode(!0)),this.textarea=this.shadowRoot.querySelector("textarea"),this.textareaBox=this.shadowRoot.querySelector(".textarea"),this.placeholder=this.shadowRoot.querySelector(".placeholder"),this.reflectedAttributes=["disabled","required","readonly","rows","minlength","maxlength"],this.reset=this.reset.bind(this),this.focusIn=this.focusIn.bind(this),this.fireEvent=this.fireEvent.bind(this),this.checkInput=this.checkInput.bind(this)}static get observedAttributes(){return["disabled","value","placeholder","required","readonly","rows","minlength","maxlength"]}get value(){return this.textarea.value}set value(e){this.setAttribute("value",e),this.fireEvent()}get disabled(){return this.hasAttribute("disabled")}set disabled(e){e?this.setAttribute("disabled",""):this.removeAttribute("disabled")}get isValid(){return this.textarea.checkValidity()}reset(){this.setAttribute("value","")}focusIn(){this.textarea.focus()}fireEvent(){let e=new Event("input",{bubbles:!0,cancelable:!0,composed:!0});this.dispatchEvent(e)}checkInput(){this.hasAttribute("placeholder")&&""!==this.getAttribute("placeholder")&&(""!==this.textarea.value?this.placeholder.classList.add("hide"):this.placeholder.classList.remove("hide"))}connectedCallback(){this.textarea.addEventListener("input",e=>{this.textareaBox.dataset.value=this.textarea.value,this.checkInput()})}attributeChangedCallback(e,t,n){this.reflectedAttributes.includes(e)?this.hasAttribute(e)?this.textarea.setAttribute(e,this.getAttribute(e)?this.getAttribute(e):""):this.textContent.removeAttribute(e):"placeholder"===e?this.placeholder.textContent=this.getAttribute("placeholder"):"value"===e&&(this.textarea.value=n,this.textareaBox.dataset.value=n,this.checkInput())}});

View File

@ -31,7 +31,7 @@ themeToggle.innerHTML = `
pointer-events: none;
transition: transform 0.3s, opacity 0.3s;
transform: translate(-50%, -50%) scale(1.2);
background-color: rgba(var(--text-color), 0.12);
background-color: rgba(var(--text-color,inherit), 0.12);
}
:host(:focus-within) .theme-toggle{
outline: none;
@ -44,7 +44,7 @@ themeToggle.innerHTML = `
position: absolute;
height: 100%;
width: 100%;
fill: rgba(var(--text-color), 1);
fill: rgba(var(--text-color,inherit), 1);
transition: transform 0.3s, opacity 0.1s;
}

File diff suppressed because one or more lines are too long

View File

@ -1620,7 +1620,7 @@
the number of lines textarea should expand or let the textarea expand according to user input until
a max-height is reached.</p>
<h2>Interactive demo</h2>
<sm-textarea id="my_textarea" placeholder="Add some text here..." rows="2"></sm-textarea>
<sm-textarea id="my_textarea" placeholder="Add some text here..." rows="4"></sm-textarea>
<pre>
<code>
&lt;sm-textarea id="my_textarea" placeholder="Add some text here..." rows="4"&gt;&lt;/sm-textarea&gt;
@ -2160,12 +2160,12 @@
const rippleAnimation = circle.animate(
[
{
transform: "scale(3)",
transform: "scale(4)",
opacity: 0,
},
],
{
duration: 1000,
duration: 600,
fill: "forwards",
easing: "ease-out",
}

View File

@ -255,7 +255,7 @@
console.log(getTags.value); /* returns an array of string that are user input */
&lt;/script&gt;
</code>
</pre></section><section id="textarea_page" class="page hide-completely"><h1 class="page__title">Textarea</h1><p>Textarea is suitable component where multiline input is required. you can either specify the number of lines textarea should expand or let the textarea expand according to user input until a max-height is reached.</p><h2>Interactive demo</h2><sm-textarea id="my_textarea" placeholder="Add some text here..." rows="2"></sm-textarea><pre>
</pre></section><section id="textarea_page" class="page hide-completely"><h1 class="page__title">Textarea</h1><p>Textarea is suitable component where multiline input is required. you can either specify the number of lines textarea should expand or let the textarea expand according to user input until a max-height is reached.</p><h2>Interactive demo</h2><sm-textarea id="my_textarea" placeholder="Add some text here..." rows="4"></sm-textarea><pre>
<code>
&lt;sm-textarea id="my_textarea" placeholder="Add some text here..." rows="4"&gt;&lt;/sm-textarea&gt;
</code>
@ -549,12 +549,12 @@
const rippleAnimation = circle.animate(
[
{
transform: "scale(3)",
transform: "scale(4)",
opacity: 0,
},
],
{
duration: 1000,
duration: 600,
fill: "forwards",
easing: "ease-out",
}