Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Big v0.10 upgrade #110

Open
wants to merge 31 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
551042b
Update `.gitignore`
zerodevx Oct 6, 2024
a861482
Set default opts from container instead
zerodevx Oct 6, 2024
63c5caf
Decouple `ToastItem` into `Controller` and `View`
zerodevx Oct 7, 2024
652fdac
Remove deprecated `progress` references
zerodevx Oct 7, 2024
e2366bc
Add feat `unsafe` html toast msg
zerodevx Oct 7, 2024
cc10617
Replace `onpop` callback with promise-based impl
zerodevx Oct 7, 2024
b8c3317
Uno reverse the `reversed` setting :)
zerodevx Oct 7, 2024
213be9d
Valid `id` takes precedence over `target`
zerodevx Oct 7, 2024
76f13be
Expose `outro` fade animation settings
zerodevx Oct 7, 2024
610057f
Decouple container and item themes
zerodevx Oct 7, 2024
852f15c
Don't use magical z-index
zerodevx Oct 7, 2024
352a2f2
Use `fly` transition for outro too
zerodevx Oct 10, 2024
16e114b
Add four states of `pausable`
zerodevx Oct 11, 2024
c24a2e3
Typing improvements
zerodevx Oct 11, 2024
b052f6e
Lower CSS specificity
zerodevx Oct 11, 2024
e7a9f67
Add positioning presets
zerodevx Oct 12, 2024
af5f0a9
Move theme spreading into `SvelteToast`
zerodevx Oct 13, 2024
b7e507f
Mirror `class` prop to toast container
zerodevx Oct 13, 2024
f92ef70
Move presets to `index.js`
zerodevx Oct 13, 2024
4a890c2
Deprecate `classes` array into `class` string instead
zerodevx Oct 13, 2024
d8fc28d
Rename `component` opt to `view` instead
zerodevx Oct 13, 2024
8d4c9d9
Clean up toasts on destroy
zerodevx Oct 14, 2024
3a0158f
Better typings
zerodevx Oct 20, 2024
ff93f5e
Deprecate `class` in favour of spread props
zerodevx Oct 22, 2024
e5b66b9
Use `output` element for implicit `role="status"`
zerodevx Oct 23, 2024
62fe355
Use CSS nesting and remove fixed class names
zerodevx Oct 23, 2024
e1993d2
Revert deprecated `class`
zerodevx Oct 24, 2024
7044484
Revert `pointer-events` behaviour
zerodevx Oct 25, 2024
6cdbfcc
Fix `pausable` pointer events
zerodevx Oct 26, 2024
60014c7
Refactor object coercion
zerodevx Oct 27, 2024
16c65cd
Refactor CSS
zerodevx Oct 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ vite.config.js.timestamp-*
vite.config.ts.timestamp-*
/temp
/test-results
/.vscode
.spellignore
73 changes: 73 additions & 0 deletions src/lib/Controller.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<script>
import { onMount, onDestroy } from 'svelte'
import { tweened } from 'svelte/motion'
import { linear } from 'svelte/easing'
import { toast } from './stores.js'

/** @type {import('./stores.js').SvelteToastOptions} */
export let item

let next = item.initial || 0
let prev = next
let paused = false

const progress = tweened(item.initial, { duration: item.duration, easing: linear })

/** @param {CustomEvent} [ev] */
function close(ev) {
const { value } = ev?.detail || {}
toast.pop(item.id, { value })
}

function autoclose() {
if ($progress === 1 || $progress === 0) close()
}

function pause() {
if (!paused && $progress !== next) {
progress.set($progress, { duration: 0 })
paused = true
}
}

function resume() {
if (paused) {
const d = item.duration || 0
const duration = d - d * (($progress - prev) / (next - prev))
progress.set(next, { duration }).then(autoclose)
paused = false
}
}

function handler() {
document.hidden ? ['hidden', 'both'].includes(item.pausable || '') && pause() : resume()
}

function listen() {
document.addEventListener('visibilitychange', handler)
handler()
}

function unlisten() {
document.removeEventListener('visibilitychange', handler)
}

$: if (next !== item.next) {
next = item.next || 0
prev = $progress
paused = false
progress.set(next).then(autoclose)
}

onMount(listen)
onDestroy(unlisten)
</script>

<output
on:mouseenter={() => {
if (['hover', 'both'].includes(item.pausable || '')) pause()
}}
on:mouseleave={resume}
>
<svelte:component this={item.view} {item} {progress} on:close={close} />
</output>
63 changes: 47 additions & 16 deletions src/lib/SvelteToast.svelte
Original file line number Diff line number Diff line change
@@ -1,52 +1,83 @@
<script>
import { fade, fly } from 'svelte/transition'
import { onDestroy } from 'svelte'
import { fly } from 'svelte/transition'
import { flip } from 'svelte/animate'
import { toast } from './stores.js'
import ToastItem from './ToastItem.svelte'
import Controller from './Controller.svelte'
import View from './View.svelte'

/** @type {import('./stores.js').SvelteToastOptions} */
/** @type {import('./stores.js').SvelteToastOptions} - options override */
export let options = {}
/** @type {(string|'default')} */
/** @type {string|'default'} - toast container target name */
export let target = 'default'
/** @type {string|undefined} - toast container class */
let classes = ''
export { classes as class }

/** @type {import('./stores.js').SvelteToastOptions} */
const defaults = {
duration: 4000,
initial: 1,
next: 0,
pausable: 'hidden',
dismissable: true,
reversed: true,
intro: { x: 256 },
view: View
}
/** @type {import('./stores.js').SvelteToastOptions[]} */
let items = []
/** @type {import('./stores.js').SvelteToastOptions} */
let merged
/** @type {Object<string,string|number>|undefined} */
let theme
/** @type {string|undefined} */
let _class

/** @param {Object<string,string|number>} [theme] */
function getCss(theme) {
return theme ? Object.keys(theme).reduce((a, c) => `${a}${c}:${theme[c]};`, '') : undefined
/** @param {Object<string,string|number>} [obj] */
function toStyles(obj) {
return obj ? Object.keys(obj).reduce((a, c) => `${a}${c}:${obj[c]};`, '') : undefined
}

$: toast._init(target, options)
$: {
;({ theme, class: _class, ...merged } = { ...defaults, ...options })
toast._init(target, merged)
}
$: {
const _items = $toast.filter((i) => i.target === target)
if (merged.reversed) _items.reverse()
items = _items
}

$: items = $toast.filter((i) => i.target === target)
onDestroy(() => toast.pop({ target }))
</script>

<ul class="_toastContainer">
<ul class={classes} style={toStyles(theme)}>
{#each items as item (item.id)}
<li
class={item.classes?.join(' ')}
class={[_class, item.class].join(' ')}
style={toStyles(item.theme)}
in:fly={item.intro}
out:fade
out:fly={item.outro}
animate:flip={{ duration: 200 }}
style={getCss(item.theme)}
>
<ToastItem {item} />
<Controller {item} />
</li>
{/each}
</ul>

<style>
._toastContainer {
:where(ul) {
top: var(--toastContainerTop, 1.5rem);
right: var(--toastContainerRight, 2rem);
bottom: var(--toastContainerBottom, auto);
left: var(--toastContainerLeft, auto);
z-index: var(--toastContainerZIndex, auto);
position: fixed;
margin: 0;
padding: 0;
list-style-type: none;
pointer-events: none;
z-index: var(--toastContainerZIndex, 9999);
will-change: contents;
}
</style>
188 changes: 0 additions & 188 deletions src/lib/ToastItem.svelte

This file was deleted.

Loading