From 072dc3c27f5f454388b9acff4fa55ee8c5901008 Mon Sep 17 00:00:00 2001 From: Daniel Knights Date: Sun, 14 Feb 2021 19:08:32 +0000 Subject: [PATCH] Code cleanup --- src/lib/render.ts | 145 ++++++++++++++++++++++++---------------------- src/lib/styles.ts | 6 +- src/lib/toast.ts | 5 +- todo.txt | 4 +- 4 files changed, 84 insertions(+), 76 deletions(-) diff --git a/src/lib/render.ts b/src/lib/render.ts index 4667e6e..185a649 100644 --- a/src/lib/render.ts +++ b/src/lib/render.ts @@ -5,33 +5,71 @@ import { validateLocalOptions } from './validate' const toastQueue: Array<[Element, Element]> = [] -function renderToast(app: App, options: Options): void { - // Render toast container - const container = document.createElement('div') - const mobileContainer = document.createElement('div') +function formatAndMountContainer(el: Element, className: string, target: Element): void { + const attributes = [ + ['role', 'status'], + ['aria-live', 'polite'], + ['aria-atomic', 'false'] + ] + + attributes.forEach((attr) => { + el.setAttribute(attr[0], attr[1]) + }) + + el.className = className + target.appendChild(el) +} - // Set container attributes - container.className = 'dk__toast-container' - container.setAttribute('role', 'status') - container.setAttribute('aria-live', 'polite') - container.setAttribute('aria-atomic', 'false') +function formatToastFromOptions( + text: string, + options: Options, + localOptions: LocalOptions, + duration?: number | false +): Element { + const toast = document.createElement('div') + const left = localOptions.slotLeft + const right = localOptions.slot || localOptions.slotRight + + // Add classes + toast.className = 'dk__toast' + if (options.class) toast.classList.add(options.class) + if (localOptions.class) toast.classList.add(localOptions.class) + if (localOptions.type) toast.classList.add(`dk__${localOptions.type}`) + + // If text + if (text) toast.textContent = text + // If left slot + if (left) { + toast.innerHTML = `
${left}
` + toast.innerHTML + } + // If right slot + if (right) { + toast.innerHTML += `
${right}
` + } + // If slot only + if (!text && (left || right)) toast.classList.add('dk__icon-only') - mobileContainer.className = 'dk__toast-mobile-container' - mobileContainer.setAttribute('role', 'status') - mobileContainer.setAttribute('aria-live', 'polite') - mobileContainer.setAttribute('aria-atomic', 'false') + const styles = localOptions.styles ? localOptions.styles : options.styles + toast.setAttribute('style', formatCssProperties(styles, duration)) - // Append - document.body.appendChild(container) - document.body.appendChild(mobileContainer) + if (localOptions.disableClick) { + // Prevent hover styling + toast.style.cursor = 'default' + toast.style.opacity = '1' + } - function DKToast(text: string, localOptions?: LocalOptions): void { - if (!localOptions) localOptions = {} - const toast = document.createElement('div') - const left = localOptions.slotLeft - const right = localOptions.slot || localOptions.slotRight - let clicked: boolean + return toast +} + +function toastPlugin(app: App, options: Options): void { + const container = document.createElement('div') + const mobileContainer = document.createElement('div') + + formatAndMountContainer(container, 'dk__toast-container', document.body) + formatAndMountContainer(mobileContainer, 'dk__toast-mobile-container', document.body) + function renderToast(text: string, localOptions?: LocalOptions): void { + if (!localOptions) localOptions = {} if (!validateLocalOptions(text, localOptions)) return const positions = { @@ -39,63 +77,40 @@ function renderToast(app: App, options: Options): void { x: localOptions.positionX || options.positionX } - // Render toast section const section = document.querySelector(`.dk__toast-${positions.y}-${positions.x}`) || document.createElement('div') const toastCount = document.querySelectorAll('.dk__toast').length / 2 + // Remove oldest toast if max limit is reached if (options.max && toastCount >= options.max) { toastQueue[0][0].parentElement?.removeChild(toastQueue[0][0]) toastQueue[0][1].parentElement?.removeChild(toastQueue[0][1]) toastQueue.shift() } + // If section doesn't exist, format and mount if (!section.className) { - // Set section attributes - section.className = `dk__toast-section dk__toast-${positions.y}-${positions.x}` - section.setAttribute('role', 'status') - section.setAttribute('aria-live', 'polite') - section.setAttribute('aria-atomic', 'false') - - // Append - container.appendChild(section) - } - - toast.className = 'dk__toast' - if (options.class) toast.classList.add(options.class) - if (localOptions.class) toast.classList.add(localOptions.class) - if (localOptions.type) toast.classList.add(`dk__${localOptions.type}`) + const className = `dk__toast-section dk__toast-${positions.y}-${positions.x}` - // If text - if (text) toast.textContent = text - // If left slot - if (left) { - toast.innerHTML = `
${left}
` + toast.innerHTML + formatAndMountContainer(section, className, container) } - // If right slot - if (right) { - toast.innerHTML += `
${right}
` - } - // If slot only - if (!text && (left || right)) toast.classList.add('dk__icon-only') + // Determine if duration is a number or false, local or global const duration = localOptions.duration || localOptions.duration === false ? localOptions.duration : options.duration - const styles = localOptions.styles ? localOptions.styles : options.styles - toast.setAttribute('style', formatCssProperties(styles, duration)) + const toast = formatToastFromOptions(text, options, localOptions, duration) + const mobileClone = toast.cloneNode(true) - if (localOptions.disableClick) { - toast.style.cursor = 'default' - toast.style.opacity = '1' - } + // Prevent attempting to remove toast if it's been removed by click + let clicked: boolean - const mobileClone = toast.cloneNode(true) + function removeToastPair(e?: Event): void { + if (e) clicked = true - function removeToastPair(): void { if ([...section.children].includes(toast)) { section.removeChild(toast) } @@ -104,16 +119,10 @@ function renderToast(app: App, options: Options): void { } } - function clickHandler(): void { - clicked = true - - removeToastPair() - } - - // Remove toast on click if (!options.disableClick && !localOptions.disableClick) { - toast.addEventListener('click', clickHandler) - mobileClone.addEventListener('click', clickHandler) + // Remove toast on click + toast.addEventListener('click', removeToastPair) + mobileClone.addEventListener('click', removeToastPair) } toastQueue.push([toast, mobileClone as Element]) @@ -129,8 +138,8 @@ function renderToast(app: App, options: Options): void { }, duration) } - app.config.globalProperties.$toast = DKToast - app.provide('$toast', DKToast) + app.config.globalProperties.$toast = renderToast + app.provide('$toast', renderToast) } -export default renderToast +export default toastPlugin diff --git a/src/lib/styles.ts b/src/lib/styles.ts index f8aa92b..2d836ee 100644 --- a/src/lib/styles.ts +++ b/src/lib/styles.ts @@ -1,6 +1,6 @@ import type { Options } from './types' -// Minify CSS +/** Minify CSS */ function minify(styles: string): string { let selector = false let value = false @@ -33,7 +33,7 @@ function minify(styles: string): string { return minified } -// Format CSS from camelCase +/** Format CSS from camelCase */ export function formatCssProperties( styles?: Record, duration?: number | false @@ -72,7 +72,7 @@ export function formatCssProperties( return formatted } -// Append minified stylesheet to document head +/** Append minified stylesheet to document head */ export function appendStylesheet(options: Options): void { const { duration, styles, positionY } = options // Format style properties/values diff --git a/src/lib/toast.ts b/src/lib/toast.ts index 0d5d885..00150dc 100644 --- a/src/lib/toast.ts +++ b/src/lib/toast.ts @@ -9,12 +9,13 @@ import renderToast from './render' * * --- * **Options:** + * @property `class` - CSS class to be added to every toast. + * @property `disableClick?: boolean` * @property `duration` - Time in milliseconds before hiding the toast notification. + * @property `max` - Max number of toasts allowed per-section at any one time. * @property `positionX` - 'left', 'right' or 'center'. * @property `positionY` - 'top' or 'bottom'. * @property `styles` - CSS key/value pairs. - * @property `class` - CSS class to be added to every toast. - * @property `max` - Max number of toasts allowed per-section at any one time. */ const toastPlugin = { install: (app: App, options: Options): void => { diff --git a/todo.txt b/todo.txt index 27c24e5..d3c442d 100644 --- a/todo.txt +++ b/todo.txt @@ -1,4 +1,2 @@ -disable click option check local options has priority over global options -unit-tests -code cleanup \ No newline at end of file +unit-tests \ No newline at end of file