diff --git a/css/main.css b/css/main.css index a3c5ac2..9bb1a39 100644 --- a/css/main.css +++ b/css/main.css @@ -28,7 +28,7 @@ body { background-color: rgba(var(--foreground-color), 1); } -body[data-theme=dark] { +body[data-theme="dark"] { --accent-color: #92a2ff; --accent-color-rgb: 160, 182, 255; --secondary-color: #d60739; @@ -39,7 +39,7 @@ body[data-theme=dark] { --green: #00e676; --yellow: rgb(255, 213, 5); } -body[data-theme=dark] ::-webkit-calendar-picker-indicator { +body[data-theme="dark"] ::-webkit-calendar-picker-indicator { filter: invert(1); } @@ -63,7 +63,7 @@ strong { img { -o-object-fit: cover; - object-fit: cover; + object-fit: cover; } a:where([class]) { @@ -90,7 +90,7 @@ a:any-link:focus-visible { outline: rgba(var(--text-color), 1) 0.1rem solid; } -input[type=datetime-local] { +input[type="datetime-local"] { width: 100%; padding: 0.8rem 0.6rem; border: none; @@ -101,7 +101,7 @@ input[type=datetime-local] { color: inherit; background-color: rgba(var(--text-color), 0.06); } -input[type=datetime-local]:focus { +input[type="datetime-local"]:focus { outline: none; box-shadow: 0 0 0 0.1rem var(--accent-color); } @@ -109,8 +109,8 @@ input[type=datetime-local]:focus { button, .button { -webkit-user-select: none; - -moz-user-select: none; - user-select: none; + -moz-user-select: none; + user-select: none; position: relative; display: inline-flex; border: none; @@ -224,8 +224,8 @@ a:any-link:focus-visible { details summary { display: flex; -webkit-user-select: none; - -moz-user-select: none; - user-select: none; + -moz-user-select: none; + user-select: none; cursor: pointer; align-items: center; gap: 1rem; @@ -264,8 +264,8 @@ sm-chip { --padding: 0.5rem 0.8rem; --background: rgba(var(--text-color), 0.06); -webkit-user-select: none; - -moz-user-select: none; - user-select: none; + -moz-user-select: none; + user-select: none; font-weight: 500; } sm-chip[selected] { @@ -604,7 +604,11 @@ ul { position: absolute; border-radius: 50%; transform: scale(0); - background: radial-gradient(circle, rgba(var(--text-color), 0.3) 0%, rgba(0, 0, 0, 0) 50%); + background: radial-gradient( + circle, + rgba(var(--text-color), 0.3) 0%, + rgba(0, 0, 0, 0) 50% + ); pointer-events: none; } @@ -699,17 +703,17 @@ ul { justify-self: flex-start; } -ul[type=circle], -menu[type=circle] { +ul[type="circle"], +menu[type="circle"] { padding: 1.5rem 2.5rem; list-style: circle; } -ul[type=circle] li, -menu[type=circle] li { +ul[type="circle"] li, +menu[type="circle"] li { margin-bottom: 1rem; } -ul[type=circle] li:last-of-type, -menu[type=circle] li:last-of-type { +ul[type="circle"] li:last-of-type, +menu[type="circle"] li:last-of-type { margin-bottom: 0; } ul, @@ -773,13 +777,13 @@ menu { #meta_mask_status_button .icon-wrapper > * { grid-area: 1/1; } -#meta_mask_status_button[data-status=connected] { +#meta_mask_status_button[data-status="connected"] { pointer-events: none; } -#meta_mask_status_button[data-status=connected] .icon-wrapper::after { +#meta_mask_status_button[data-status="connected"] .icon-wrapper::after { background-color: var(--green); } -#meta_mask_status_button[data-status=disconnected] .icon-wrapper::after { +#meta_mask_status_button[data-status="disconnected"] .icon-wrapper::after { background-color: var(--danger-color); } @@ -847,7 +851,8 @@ main { transition: transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275); } .nav-item__title { - transition: opacity 0.2s, transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275); + transition: opacity 0.2s, + transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275); } .nav-item--active { color: var(--accent-color); @@ -870,17 +875,17 @@ main { overflow: auto; grid-area: pages; } -#page_container[data-page=home] > :nth-child(2) { +#page_container[data-page="home"] > :nth-child(2) { flex: 1; } -#page_container[data-page=send] { +#page_container[data-page="send"] { align-items: flex-start; } -#page_container[data-page=send] > * { +#page_container[data-page="send"] > * { padding: 1rem; margin: 0 auto; } -#page_container[data-page=create] { +#page_container[data-page="create"] { margin: 0 auto; padding: 4vw 1rem; gap: 2rem; @@ -951,6 +956,19 @@ aside h4 { padding-bottom: 0.5rem; } +#address_transactions { + width: 100%; + max-width: 32rem; +} + +.transaction { + width: 100%; +} + +#transactions_list { + width: 100%; +} + #error_section { display: grid; height: 100%; @@ -978,6 +996,7 @@ aside h4 { position: relative; margin-bottom: 2rem; } + .transaction__phase:not(:last-of-type)::after { content: ""; position: absolute; @@ -1004,7 +1023,7 @@ aside h4 { width: 4rem; border-radius: 5rem; -webkit-animation: popup 1s; - animation: popup 1s; + animation: popup 1s; padding: 1rem; } .user-action-result__icon.pending { @@ -1068,17 +1087,24 @@ aside h4 { padding-bottom: 1rem; border-bottom: solid thin rgba(var(--text-color), 0.3); } - +.create-buttons { + display: flex; + max-width: 400px; + gap: 1rem; +} @media only screen and (max-width: 640px) { .hide-on-small { display: none; } - #page_container[data-page=home] { + #page_container[data-page="home"] { flex-direction: column; } - #page_container[data-page=home] > :first-child { + #page_container[data-page="home"] > :first-child { order: 1; } + .create-buttons { + display: grid; + } } @media only screen and (min-width: 640px) { sm-popup { @@ -1166,9 +1192,384 @@ aside h4 { } @media (prefers-reduced-motion) { ::view-transition-group(*), -::view-transition-old(*), -::view-transition-new(*) { + ::view-transition-old(*), + ::view-transition-new(*) { -webkit-animation: none !important; - animation: none !important; + animation: none !important; } +} + +.tx-details-container { + max-width: 800px; + margin: 1rem auto; + padding: 1rem; + font-family: inherit; +} + +/* Header styling */ +.tx-header { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 0.5rem; + margin-bottom: 1.5rem; + padding-bottom: 1rem; + border-bottom: 1px solid rgba(var(--text-color), 0.1); +} + +.tx-title { + font-size: 1.5rem; + font-weight: 600; + color: rgba(var(--text-color), 0.95); + margin: 0; +} + +.tx-card { + background-color: rgba(var(--foreground-color), 1); + border-radius: 0.75rem; + overflow: hidden; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); + border: 1px solid rgba(var(--text-color), 0.1); + margin-top: 1rem; +} + +.tx-status-header { + display: flex; + align-items: center; + gap: 1rem; + padding: 1.25rem; + background-color: rgba(var(--text-color), 0.03); + border-bottom: 1px solid rgba(var(--text-color), 0.1); +} + +.status-indicator { + width: 12px; + height: 12px; + border-radius: 50%; + flex-shrink: 0; +} + +.status-indicator.confirmed { + background-color: var(--color-success); + box-shadow: 0 0 0 4px rgba(var(--color-success-rgb), 0.2); +} + +.status-indicator.pending { + background-color: var(--color-warning); + box-shadow: 0 0 0 4px rgba(var(--color-warning-rgb), 0.2); +} + +.status-details { + flex-grow: 1; +} + +.status-title { + font-size: 1.15rem; + font-weight: 600; + color: rgba(var(--text-color), 0.95); + margin: 0; +} + +.status-subtext { + font-size: 0.85rem; + color: rgba(var(--text-color), 0.7); + margin: 0.25rem 0 0; +} + +.tx-info-grid { + padding: 1.25rem; + display: flex; + flex-direction: column; + gap: 1.5rem; +} + +.tx-address-section { + display: flex; + align-items: stretch; + gap: 1rem; + background: rgba(var(--text-color), 0.02); + padding: 1rem; + border-radius: 0.5rem; +} + +.address-card { + flex: 1; + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.address-label { + font-size: 0.75rem; + font-weight: 500; + color: rgba(var(--text-color), 0.6); + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.address-value { + font-family: "Roboto Mono", monospace; + font-size: 0.85rem; + color: rgba(var(--text-color), 0.9); + word-break: break-all; + background: rgba(var(--text-color), 0.05); + padding: 0.5rem 0.75rem; + border-radius: 0.25rem; +} + +.tx-arrow { + font-size: 1.5rem; + color: rgba(var(--text-color), 0.4); + display: flex; + align-items: center; + padding: 0 0.5rem; +} + +.tx-hash-section { + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.section-label { + font-size: 0.75rem; + font-weight: 500; + color: rgba(var(--text-color), 0.6); + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.hash-value { + background-color: rgba(var(--text-color), 0.05); + padding: 0.75rem; + border-radius: 0.25rem; + font-family: "Roboto Mono", monospace; + font-size: 0.85rem; + color: rgba(var(--text-color), 0.9); + word-break: break-all; +} + +.tx-metrics-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); + gap: 1rem; +} + +.metric-card { + background-color: rgba(var(--text-color), 0.03); + padding: 1rem; + border-radius: 0.5rem; + text-align: center; + border: 1px solid rgba(var(--text-color), 0.08); + transition: background-color 0.2s ease, transform 0.2s ease; +} + +.metric-card:hover { + background-color: rgba(var(--text-color), 0.06); + transform: translateY(-2px); +} + +.metric-label { + font-size: 0.75rem; + font-weight: 500; + color: rgba(var(--text-color), 0.6); + margin-bottom: 0.5rem; + text-transform: uppercase; + letter-spacing: 0.5px; + display: block; +} + +.metric-value { + font-size: 0.95rem; + font-weight: 500; + color: rgba(var(--text-color), 0.95); + word-break: break-word; +} + +.tx-actions { + display: flex; + justify-content: space-between; + gap: 1rem; + padding: 1.25rem; + border-top: 1px solid rgba(var(--text-color), 0.1); + background-color: rgba(var(--text-color), 0.03); +} + +.tx-actions .button { + flex: 1; +} + +@media (max-width: 768px) { + .tx-address-section { + flex-direction: column; + gap: 0.75rem; + align-items: stretch; + } + + .tx-arrow { + transform: rotate(90deg); + margin: 0.5rem auto; + padding: 0; + } + + .tx-metrics-grid { + grid-template-columns: 1fr 1fr; + } +} + +@media (max-width: 576px) { + .tx-header { + padding-bottom: 0.75rem; + } + + .tx-status-header { + padding: 1rem; + gap: 0.75rem; + } + + .status-title { + font-size: 1.1rem; + } + + .tx-info-grid { + padding: 1rem; + gap: 1.25rem; + } + + .tx-address-section { + padding: 0.75rem; + } + + .tx-metrics-grid { + grid-template-columns: 1fr; + } + + .tx-actions { + flex-direction: column; + padding: 1rem; + } +} + +/* Valuation toggle styles */ +.valuation-toggle { + display: flex; + align-items: center; + gap: 0.5rem; + font-size: 0.85rem; + color: rgba(var(--text-color), 0.8); + margin-top: 0.5rem; + margin-right: 0.5rem; +} + +.toggle-switch { + position: relative; + display: inline-block; + width: 3rem; + height: 1.5rem; +} + +.toggle-switch input { + opacity: 0; + width: 0; + height: 0; +} + +.toggle-slider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(var(--text-color), 0.2); + transition: 0.4s; + border-radius: 1.5rem; +} + +.toggle-slider:before { + position: absolute; + content: ""; + height: 1.1rem; + width: 1.1rem; + left: 0.2rem; + bottom: 0.2rem; + background-color: white; + transition: 0.4s; + border-radius: 50%; +} + +input:checked + .toggle-slider { + background-color: var(--accent-color); +} + +input:checked + .toggle-slider:before { + transform: translateX(1.5rem); +} + +.transaction-controls { + display: flex; + align-items: center; + justify-content: space-between; + gap: 1rem; + margin-bottom: 1rem; + padding: 0.5rem; + background-color: rgba(var(--text-color), 0.03); + border-radius: 0.5rem; + border: 1px solid rgba(var(--text-color), 0.08); +} + +.filter-control { + display: flex; + align-items: center; + gap: 0.5rem; +} + +.filter-control label { + font-size: 0.9rem; + color: rgba(var(--text-color), 0.8); + font-weight: 500; +} + +.filter-control select { + padding: 0.4rem 0.6rem; + border-radius: 0.4rem; + border: 1px solid rgba(var(--text-color), 0.1); + background-color: rgba(var(--foreground-color), 1); + color: rgba(var(--text-color), 0.9); + font-size: 0.9rem; + cursor: pointer; + outline: none; +} +.margin-left-auto + .margin-left-auto { + display: none !important; +} + +.filter-control select:focus { + border-color: var(--accent-color); +} + +/* Loading state for transaction details */ +.loading-state { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + min-height: 300px; + gap: 1rem; +} + +.loading-text { + color: rgba(var(--text-color), 0.7); + font-size: 0.9rem; +} + +#sol_balance_wrapper { + background-color: rgba(var(--text-color), 0.06); + padding: max(1rem, 1.5vw); + border-radius: 0.5rem; + width: 100%; +} +#sol_balance_wrapper li:not(:last-of-type) { + border-bottom: solid thin rgba(var(--text-color), 0.3); + padding-bottom: 0.5rem; } \ No newline at end of file diff --git a/index.html b/index.html index ea1e7b5..30cf3ef 100644 --- a/index.html +++ b/index.html @@ -1,828 +1,1082 @@ - - - - Solana Wallet - - - - - - - - -

-

-
- - + + + + Solana Wallet + + + + + + + + + +

+

+
+ + +
+
+ +
+
+ - - -
-
-
- -
-
- - +
- -
-
- - -
-
-

Did you forget your Solana Address?

-

- If you have your Solana Seed, enter it here and recover your Solana - Address. -

-
- - - - - - - -
- - - - - - - + + + + + + + + + + + + + - + - - - - - - - - - - - + + + + + + + + + + - + - + ); + } + + + \ No newline at end of file diff --git a/scripts/components.min.js b/scripts/components.min.js index 2d0e22a..f2a9560 100644 --- a/scripts/components.min.js +++ b/scripts/components.min.js @@ -28,8 +28,11 @@ const smChips = document.createElement("template"); get value() { return this._value; } - set value(t) { - this.setSelectedOption(t); + set value(val) { + this.setSelectedOption(val); + } + get isValid() { + return void 0 !== this._value; } scrollLeft() { this.chipsWrapper.scrollBy({ @@ -43,18 +46,18 @@ const smChips = document.createElement("template"); behavior: "smooth", }); } - setSelectedOption(t) { - this._value !== t && - ((this._value = t), - this.assignedElements.forEach((e) => { - e.value == t - ? (e.setAttribute("selected", ""), - e.scrollIntoView({ + setSelectedOption(value) { + this._value !== value && + ((this._value = value), + this.assignedElements.forEach((elem) => { + elem.value == value + ? (elem.setAttribute("selected", ""), + elem.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "center", })) - : e.removeAttribute("selected"); + : elem.removeAttribute("selected"); })); } fireEvent() { @@ -68,54 +71,51 @@ const smChips = document.createElement("template"); } connectedCallback() { this.setAttribute("role", "listbox"); - const t = this.shadowRoot.querySelector("slot"); - t.addEventListener("slotchange", (e) => { - n.disconnect(), - i.disconnect(), + const slot = this.shadowRoot.querySelector("slot"); + slot.addEventListener("slotchange", (e) => { + firstOptionObserver.disconnect(), + lastOptionObserver.disconnect(), this.observeSelf.disconnect(), clearTimeout(this.slotChangeTimeout), (this.slotChangeTimeout = setTimeout(() => { - (this.assignedElements = t.assignedElements()), - this.assignedElements.forEach((t) => { - t.hasAttribute("selected") && (this._value = t.value); - }), + (this.assignedElements = slot.assignedElements()), this.observeSelf.observe(this); }, 0)); - }); - const e = new ResizeObserver((t) => { - t.forEach((t) => { - if (t.contentBoxSize) { - const e = Array.isArray(t.contentBoxSize) - ? t.contentBoxSize[0] - : t.contentBoxSize; - this.scrollDistance = 0.6 * e.inlineSize; - } else this.scrollDistance = 0.6 * t.contentRect.width; - }); - }); - e.observe(this), + }), + new ResizeObserver((entries) => { + entries.forEach((entry) => { + if (entry.contentBoxSize) { + const contentBoxSize = Array.isArray(entry.contentBoxSize) + ? entry.contentBoxSize[0] + : entry.contentBoxSize; + this.scrollDistance = 0.6 * contentBoxSize.inlineSize; + } else this.scrollDistance = 0.6 * entry.contentRect.width; + }); + }).observe(this), (this.observeSelf = new IntersectionObserver( - (t, e) => { - t.forEach((t) => { - t.isIntersecting && + (entries, observer) => { + entries.forEach((entry) => { + entry.isIntersecting && !this.hasAttribute("multiline") && this.assignedElements.length > 0 && - (n.observe(this.assignedElements[0]), - i.observe( + (firstOptionObserver.observe(this.assignedElements[0]), + lastOptionObserver.observe( this.assignedElements[this.assignedElements.length - 1] ), - e.unobserve(this)); + observer.unobserve(this)); }); }, { threshold: 1 } )), - this.chipsWrapper.addEventListener("option-clicked", (t) => { - this._value !== t.target.value && - (this.setSelectedOption(t.target.value), this.fireEvent()); + this.chipsWrapper.addEventListener("option-clicked", (e) => { + e.stopPropagation(), + this._value !== e.detail.value && + (this.setSelectedOption(e.detail.value), this.fireEvent()); }); - const n = new IntersectionObserver( - (t) => { - t.forEach((t) => { - t.isIntersecting + const firstOptionObserver = new IntersectionObserver( + (entries) => { + entries.forEach((entry) => { + entry.isIntersecting ? (this.navButtonLeft.classList.add("hide"), this.coverLeft.classList.add("hide")) : (this.navButtonLeft.classList.remove("hide"), @@ -124,10 +124,10 @@ const smChips = document.createElement("template"); }, { threshold: 1, root: this } ), - i = new IntersectionObserver( - (t) => { - t.forEach((t) => { - t.isIntersecting + lastOptionObserver = new IntersectionObserver( + (entries) => { + entries.forEach((entry) => { + entry.isIntersecting ? (this.navButtonRight.classList.add("hide"), this.coverRight.classList.add("hide")) : (this.navButtonRight.classList.remove("hide"), @@ -156,11 +156,14 @@ const smChip = document.createElement("template"); this.attachShadow({ mode: "open" }).append( smChip.content.cloneNode(!0) ), - (this._value = void 0), + (this._value = this.getAttribute("value")), (this.radioButton = this.shadowRoot.querySelector("input")), (this.fireEvent = this.fireEvent.bind(this)), (this.handleKeyDown = this.handleKeyDown.bind(this)); } + static get observedAttributes() { + return ["selected"]; + } get value() { return this._value; } @@ -173,16 +176,25 @@ const smChip = document.createElement("template"); }) ); } - handleKeyDown(t) { - ("Enter" !== t.key && "Space" !== t.key) || this.fireEvent(); + handleKeyDown(e) { + ("Enter" !== e.key && "Space" !== e.key) || this.fireEvent(); } connectedCallback() { this.setAttribute("role", "option"), this.setAttribute("tabindex", "0"), - (this._value = this.getAttribute("value")), + this.hasAttribute("value") || + console.error("sm-chip must have a value attribute"), + this.hasAttribute("selected") && this.fireEvent(), this.addEventListener("click", this.fireEvent), this.addEventListener("keydown", this.handleKeyDown); } + attributeChangedCallback(name, oldValue, newValue) { + "selected" === name + ? this.hasAttribute("selected") + ? (this.fireEvent(), this.setAttribute("aria-selected", "true")) + : this.removeAttribute("aria-selected") + : "value" === name && (this._value = newValue); + } disconnectedCallback() { this.removeEventListener("click", this.fireEvent), this.removeEventListener("keydown", this.handleKeyDown); @@ -354,11 +366,6 @@ const smForm = document.createElement("template"); this.resetButton.addEventListener("click", this.reset), this._checkValidity(); }; - checkIfSupported = (elem) => - 1 === elem.nodeType && - (elem.tagName.includes("-") || - "input" === elem.tagName || - elem.querySelector(this.supportedElements)); connectedCallback() { const updateFormDecedents = this.debounce(this.elementsChanged, 100); this.addEventListener("input", this.debounce(this._checkValidity, 100)), @@ -372,11 +379,15 @@ const smForm = document.createElement("template"); (this.mutationObserver = new MutationObserver((mutations) => { mutations.forEach((mutation) => { (("childList" === mutation.type && - [...mutation.addedNodes].some((node) => - this.checkIfSupported(node) + [...mutation.addedNodes].some( + (node) => + 1 === node.nodeType && + node.querySelector(this.supportedElements) )) || - [...mutation.removedNodes].some((node) => - this.checkIfSupported(node) + [...mutation.removedNodes].some( + (node) => + 1 === node.nodeType && + node.querySelector(this.supportedElements) )) && updateFormDecedents(); }); @@ -384,8 +395,7 @@ const smForm = document.createElement("template"); this.mutationObserver.observe(this, { childList: !0, subtree: !0 }); } attributeChangedCallback(name, oldValue, newValue) { - "skip-submit" === name && - (this.skipSubmit = this.hasAttribute("skip-submit")); + "skip-submit" === name && (this.skipSubmit = null !== newValue); } disconnectedCallback() { this.removeEventListener( @@ -535,7 +545,7 @@ const smInput = document.createElement("template"); let _validity = { isValid: !0, errorText: "" }; return ( this.validationFunction && - (_validity = this.validationFunction(this.input.value)), + (_validity = this.validationFunction(this.input.value, this)), _isValid && _validity.isValid ? (this.setAttribute("valid", ""), this.removeAttribute("invalid"), @@ -1493,6 +1503,362 @@ const popupStack = new Stack(), } } ); +const smSwitch = document.createElement("template"); +(smSwitch.innerHTML = + '\t'), + 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); + } + static get observedAttributes() { + return ["disabled", "checked"]; + } + get disabled() { + return this.isDisabled; + } + set disabled(val) { + val + ? this.setAttribute("disabled", "") + : this.removeAttribute("disabled"); + } + get checked() { + return this.isChecked; + } + set checked(value) { + value + ? 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", (e) => { + " " !== e.key || + this.isDisabled || + (e.preventDefault(), this.input.click()); + }), + this.input.addEventListener("click", (e) => { + this.input.checked ? (this.checked = !0) : (this.checked = !1), + this.dispatch(); + }); + } + attributeChangedCallback(name, oldValue, newValue) { + oldValue !== newValue && + ("disabled" === name + ? this.hasAttribute("disabled") + ? ((this.disabled = !0), (this.inert = !0)) + : ((this.disabled = !1), (this.inert = !1)) + : "checked" === name && + (this.hasAttribute("checked") + ? ((this.isChecked = !0), (this.input.checked = !0)) + : ((this.isChecked = !1), (this.input.checked = !1)))); + } + } + ); +const smSelect = document.createElement("template"); +(smSelect.innerHTML = + '
'), + customElements.define( + "sm-select", + class extends HTMLElement { + constructor() { + super(), + this.attachShadow({ mode: "open" }).append( + smSelect.content.cloneNode(!0) + ), + (this.focusIn = this.focusIn.bind(this)), + (this.reset = this.reset.bind(this)), + (this.open = this.open.bind(this)), + (this.collapse = this.collapse.bind(this)), + (this.toggle = this.toggle.bind(this)), + (this.handleOptionsNavigation = + this.handleOptionsNavigation.bind(this)), + (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.debounce = this.debounce.bind(this)), + (this.elementsChanged = this.elementsChanged.bind(this)), + (this.availableOptions = []), + this.previousOption, + (this.isOpen = !1), + (this.label = ""), + (this.defaultSelected = ""), + (this.isUnderViewport = !1), + (this.animationOptions = { + duration: 300, + fill: "forwards", + easing: "ease", + }), + (this.optionList = this.shadowRoot.querySelector(".options")), + (this.selection = this.shadowRoot.querySelector(".selection")), + (this.selectedOptionText = this.shadowRoot.querySelector( + ".selected-option-text" + )); + } + static get observedAttributes() { + return ["disabled", "label", "readonly"]; + } + get value() { + return this.getAttribute("value"); + } + set value(t) { + const e = this.availableOptions.find( + (e) => e.getAttribute("value") === t + ); + e + ? (this.setAttribute("value", t), this.selectOption(e)) + : console.warn(`There is no option with ${t} as value`); + } + debounce(t, e) { + let n = null; + return (...i) => { + window.clearTimeout(n), + (n = window.setTimeout(() => { + t.apply(null, i); + }, e)); + }; + } + reset(t = !0) { + if ( + this.availableOptions[0] && + this.previousOption !== this.availableOptions[0] + ) { + const e = + this.availableOptions.find((t) => t.hasAttribute("selected")) || + this.availableOptions[0]; + (this.value = e.getAttribute("value")), t && this.fireEvent(); + } + } + selectOption(t) { + this.previousOption !== t && + (this.querySelectorAll("[selected").forEach((t) => + t.removeAttribute("selected") + ), + (this.selectedOptionText.textContent = `${this.label}${t.textContent}`), + t.setAttribute("selected", ""), + (this.previousOption = t)); + } + focusIn() { + this.selection.focus(); + } + open() { + this.availableOptions.forEach((t) => t.setAttribute("tabindex", 0)), + this.optionList.classList.remove("hidden"), + (this.isUnderViewport = + this.getBoundingClientRect().bottom + + this.optionList.getBoundingClientRect().height > + window.innerHeight), + this.isUnderViewport + ? this.setAttribute("isUnder", "") + : this.removeAttribute("isUnder"), + this.optionList.animate( + [ + { + transform: `translateY(${ + this.isUnderViewport ? "" : "-" + }0.5rem)`, + opacity: 0, + }, + { transform: "translateY(0)", opacity: 1 }, + ], + this.animationOptions + ), + this.setAttribute("open", ""), + (this.style.zIndex = 1e3), + ( + this.availableOptions.find((t) => t.hasAttribute("selected")) || + this.availableOptions[0] + ).focus(), + document.addEventListener("mousedown", this.handleClickOutside), + (this.isOpen = !0); + } + collapse() { + this.removeAttribute("open"), + (this.optionList.animate( + [ + { transform: "translateY(0)", opacity: 1 }, + { + transform: `translateY(${ + this.isUnderViewport ? "" : "-" + }0.5rem)`, + opacity: 0, + }, + ], + this.animationOptions + ).onfinish = () => { + this.availableOptions.forEach((t) => t.removeAttribute("tabindex")), + document.removeEventListener( + "mousedown", + this.handleClickOutside + ), + this.optionList.classList.add("hidden"), + (this.isOpen = !1), + (this.style.zIndex = "auto"); + }); + } + toggle() { + this.isOpen || this.hasAttribute("disabled") + ? this.collapse() + : this.open(); + } + fireEvent() { + this.dispatchEvent( + new CustomEvent("change", { + bubbles: !0, + composed: !0, + detail: { value: this.value }, + }) + ); + } + handleOptionsNavigation(t) { + "ArrowUp" === t.key + ? (t.preventDefault(), + document.activeElement.previousElementSibling + ? document.activeElement.previousElementSibling.focus() + : this.availableOptions[this.availableOptions.length - 1].focus()) + : "ArrowDown" === t.key && + (t.preventDefault(), + document.activeElement.nextElementSibling + ? document.activeElement.nextElementSibling.focus() + : this.availableOptions[0].focus()); + } + handleOptionSelection(t) { + this.previousOption !== document.activeElement && + ((this.value = document.activeElement.getAttribute("value")), + this.fireEvent()); + } + handleClick(t) { + t.target === this + ? this.toggle() + : (this.handleOptionSelection(), this.collapse()); + } + handleKeydown(t) { + t.target === this + ? this.isOpen && "ArrowDown" === t.key + ? (t.preventDefault(), + ( + this.availableOptions.find((t) => t.hasAttribute("selected")) || + this.availableOptions[0] + ).focus(), + this.handleOptionSelection(t)) + : " " === t.key && (t.preventDefault(), this.toggle()) + : (this.handleOptionsNavigation(t), + this.handleOptionSelection(t), + ["Enter", " ", "Escape", "Tab"].includes(t.key) && + (t.preventDefault(), this.collapse(), this.focusIn())); + } + handleClickOutside(t) { + this.isOpen && !this.contains(t.target) && this.collapse(); + } + elementsChanged() { + (this.availableOptions = [...this.querySelectorAll("sm-option")]), + this.reset(!1), + (this.defaultSelected = this.value); + } + connectedCallback() { + this.setAttribute("role", "listbox"), + this.hasAttribute("disabled") || + this.hasAttribute("readonly") || + (this.selection.setAttribute("tabindex", "0"), + this.addEventListener("click", this.handleClick), + this.addEventListener("keydown", this.handleKeydown)); + const t = this.debounce(this.elementsChanged, 100); + this.shadowRoot.querySelector("slot").addEventListener("slotchange", t), + (this.mutationObserver = new MutationObserver((e) => { + let n = !1; + if ( + (e.forEach((e) => { + switch (e.type) { + case "childList": + t(); + break; + case "attributes": + n = !0; + } + }), + n) + ) { + const t = + this.availableOptions.find((t) => t.hasAttribute("selected")) || + this.availableOptions[0]; + (this.selectedOptionText.textContent = `${this.label}${t.textContent}`), + this.setAttribute("value", t.getAttribute("value")); + } + })), + this.mutationObserver.observe(this, { + subtree: !0, + childList: !0, + attributeFilter: ["selected"], + }), + new IntersectionObserver((t, e) => { + t.forEach((t) => { + if (t.isIntersecting) { + this.selection.getBoundingClientRect().left < + window.innerWidth / 2 + ? this.setAttribute("align-select", "left") + : this.setAttribute("align-select", "right"); + } + }); + }).observe(this); + } + disconnectedCallback() { + this.removeEventListener("click", this.handleClick), + this.removeEventListener("keydown", this.handleKeydown); + } + attributeChangedCallback(t) { + "disabled" === t || "readonly" === t + ? this.hasAttribute("disabled") || this.hasAttribute("readonly") + ? (this.selection.removeAttribute("tabindex"), + this.removeEventListener("click", this.handleClick), + this.removeEventListener("keydown", this.handleKeydown)) + : (this.selection.setAttribute("tabindex", "0"), + this.addEventListener("click", this.handleClick), + this.addEventListener("keydown", this.handleKeydown)) + : "label" === t && + (this.label = this.hasAttribute("label") + ? `${this.getAttribute("label")} ` + : ""); + } + } + ); +const smOption = document.createElement("template"); +(smOption.innerHTML = + '
'), + customElements.define( + "sm-option", + class extends HTMLElement { + constructor() { + super(), + this.attachShadow({ mode: "open" }).append( + smOption.content.cloneNode(!0) + ); + } + connectedCallback() { + this.setAttribute("role", "option"); + } + } + ); const spinner = document.createElement("template"); spinner.innerHTML = '';