-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7e696a2
commit 20e6dc5
Showing
6 changed files
with
348 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
import {safeText} from "../utils.js"; | ||
|
||
export default class SnackBar { | ||
/** @param {string} - needed in order to be able to create multiple snackbars on a page */ | ||
#snackBarId; | ||
/** @param {number} - needed in order to delete the previous timeout when a new one appears */ | ||
#timeoutId; | ||
/** @param {HTMLElement} */ | ||
#snackBarEl; | ||
|
||
/** @param {string} id */ | ||
constructor(id = 'snackBar') { | ||
this.#snackBarId = id; | ||
} | ||
|
||
/** | ||
* SnackBar is a tiny notification displayed at the bottom of the screen. It's allowed to have only one SnackBar in | ||
* the same time. Creating a new SnackBar will remove the old one. Default living time is 15 sec after which | ||
* SnackBar disappears. | ||
* Properties: | ||
* - msgText - main text (e.g. Smth was deleted) | ||
* - btnText - OK button text (e.g. Undo) | ||
* - btnCb - function to be called when OK btn pressed | ||
* - ttl - aka TimeToLive in milliseconds | ||
* @param {{msgText:string, btnText:string, btnCb:function, ttl:number}} prop | ||
*/ | ||
show(prop) { | ||
SnackBar.#validateProperties(prop); | ||
this.#removeExistingIfNeeded(); | ||
this.#snackBarEl = this.#createSnackBarElement(this.#snackBarId, prop); | ||
this.#addEventListeners(prop.btnCb); | ||
this.#timeoutId = setTimeout(() => { | ||
this.#removeEl() | ||
}, prop.ttl || 15 * 1000); | ||
} | ||
|
||
#removeExistingIfNeeded(){ | ||
const existing = document.getElementById(`${this.#snackBarId}`); | ||
if (existing) | ||
existing.remove(); | ||
if (this.#timeoutId) | ||
window.clearTimeout(this.#timeoutId) | ||
} | ||
|
||
/** @param {Function} callback */ | ||
#addEventListeners(callback) { | ||
const okButton = this.#snackBarEl.querySelector('[js-ok]'); | ||
if (okButton) { | ||
okButton.addEventListener('click', () => { | ||
this.#removeEl(); | ||
callback() | ||
}) | ||
} | ||
const closeButton = this.#snackBarEl.querySelector('[js-close]'); | ||
closeButton.addEventListener('click', () => {this.#removeEl()}) | ||
} | ||
|
||
#removeEl() { | ||
this.#snackBarEl.remove(); | ||
const containerEl = SnackBar.#getSnackBarContainerEl(); | ||
if (containerEl.children.length === 0) | ||
containerEl.remove(); | ||
} | ||
|
||
/** | ||
* @param {string} id | ||
* @param {{msgText:string, btnText:string, btnCb:function, ttl:number}} prop | ||
* @return {HTMLDivElement} | ||
*/ | ||
#createSnackBarElement(id, prop) { | ||
const containerEl = SnackBar.#getSnackBarContainerEl(); | ||
containerEl.insertAdjacentHTML("beforeend", SnackBar.#htmlTemplate(prop.msgText, prop.btnText, this.#snackBarId)); | ||
return containerEl.lastElementChild; | ||
} | ||
|
||
/** | ||
* @param {string} messageText | ||
* @param {string?} buttonText | ||
* @param {string} elementId | ||
* @return {string} | ||
*/ | ||
static #htmlTemplate(messageText, buttonText, elementId) { | ||
return ` | ||
<div id="${elementId}" class="snackbar"> | ||
<div class="snackbar__label">${safeText(messageText)}</div> | ||
<div class="snackbar__buttons"> | ||
${buttonText ? `<button class="snackbar__button-ok" js-ok>${safeText(buttonText)}</button>` : ''} | ||
<button class="snackbar__button-close material-symbols-outlined" js-close title="Close">close</button> | ||
</div> | ||
</div>` | ||
} | ||
|
||
/** @param {{msgText:string, btnText:string, btnCb:function, ttl:number}} prop */ | ||
static #validateProperties(prop) { | ||
if (!prop) throw new Error('No SnackBar properties'); | ||
if (!prop.msgText) throw new Error('Empty SnackBar message text'); | ||
if (prop.btnText && !prop.btnCb) throw new Error('No callback for SnackBar button'); | ||
if (!prop.btnText && prop.btnCb) throw new Error('No SnackBar button text'); | ||
if (prop.btnCb && (typeof prop.btnCb !== "function")) throw new Error('Callback for SnackBar button is not a function'); | ||
if (prop.ttl && (typeof prop.ttl !== "number")) throw new Error('TTL is not a number'); | ||
} | ||
|
||
static #getSnackBarContainerEl(){ | ||
let container = document.body.querySelector(".snackbar-menu"); | ||
if (!container){ | ||
document.body.insertAdjacentHTML("beforeend", "<div class='snackbar-menu'/>"); | ||
container = document.body.lastElementChild; | ||
} | ||
return container; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
|
||
.snackbar-menu { | ||
--snackbar-background-color: rgb(51, 51, 51); | ||
--snackbar-background-color-hover: rgb(84, 84, 84); | ||
--snackbar-text-label-color: rgba(255, 255, 255, 0.87); | ||
--snackbar-text-action-color: rgb(187, 134, 252); | ||
--snackbar-text-action-disabled-color: rgb(140, 140, 140); | ||
z-index : 8; | ||
margin : 0.5rem; | ||
position : fixed; | ||
right : 0; | ||
bottom : 0; | ||
left : 0; | ||
align-items : center; | ||
justify-content : center; | ||
box-sizing : border-box; | ||
display : flex; | ||
flex-direction: column; | ||
} | ||
|
||
.snackbar { | ||
margin: 0.5rem; | ||
background-color : var(--snackbar-background-color); | ||
min-width : 344px; | ||
box-shadow : var(--box-shadow); | ||
max-width : 672px; | ||
border-radius : 4px; | ||
display : flex; | ||
align-items : center; | ||
justify-content : flex-start; | ||
} | ||
|
||
@media (max-width : 480px), (max-width : 344px){ | ||
.snackbar__surface{ | ||
min-width : 100%; | ||
} | ||
} | ||
|
||
.snackbar__label{ | ||
color : var(--snackbar-text-label-color); | ||
} | ||
|
||
.snackbar__label{ | ||
font-size : 0.875rem; | ||
line-height : 1.25rem; | ||
font-weight : 400; | ||
letter-spacing : 0.012rem; | ||
flex-grow : 1; | ||
box-sizing : border-box; | ||
margin : 0; | ||
padding : 1rem; | ||
} | ||
|
||
|
||
.snackbar__buttons { | ||
margin-left : 0.5rem; | ||
margin-right : 0.5rem; | ||
display : flex; | ||
flex-shrink : 0; | ||
align-items : center; | ||
box-sizing : border-box; | ||
} | ||
|
||
.snackbar__button-ok { | ||
background: var(--snackbar-background-color); | ||
color : var(--snackbar-text-action-color); | ||
border: none; | ||
cursor: pointer; | ||
padding: 0.5rem 1rem; | ||
border-radius: 0.25rem; | ||
margin-right: 0.5rem; | ||
} | ||
|
||
.snackbar__button-ok:disabled, .snackbar__button-close:disabled { | ||
border: none; | ||
color: var(--snackbar-text-action-disabled-color); | ||
pointer-events: none; | ||
} | ||
|
||
.snackbar__button-ok:hover, .snackbar__button-close:hover{ | ||
background: var(--snackbar-background-color-hover); | ||
} | ||
|
||
.snackbar__button-close { | ||
background: var(--snackbar-background-color); | ||
color : var(--snackbar-text-label-color); | ||
border: none; | ||
cursor: pointer; | ||
font-size: 1rem; | ||
width: 1.5rem; | ||
height: 1.5rem; | ||
border-radius: 50%; | ||
padding: 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,11 @@ | ||
export { default as TextInput } from './TextInput/TextInput.js'; | ||
export { default as TypeAheadInput } from './TypeAheadInput/TypeAheadInput.js'; | ||
export { default as SelectInput } from './SelectInput/SelectInput.js' | ||
export { default as EditText } from './EditText/EditText.js' | ||
import SnackBar from "./SnackBar/SnackBar.js"; | ||
|
||
export {default as TextInput} from './TextInput/TextInput.js'; | ||
export {default as TypeAheadInput} from './TypeAheadInput/TypeAheadInput.js'; | ||
export {default as SelectInput} from './SelectInput/SelectInput.js'; | ||
export {default as EditText} from './EditText/EditText.js'; | ||
export {default as SnackBar} from './SnackBar/SnackBar.js'; | ||
if (window) | ||
window.ui = { | ||
SnackBar | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.