Skip to content

Commit

Permalink
cleanup props
Browse files Browse the repository at this point in the history
  • Loading branch information
huntabyte committed Dec 29, 2023
1 parent 0e3ae47 commit 93f282c
Show file tree
Hide file tree
Showing 9 changed files with 301 additions and 55 deletions.
9 changes: 9 additions & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,15 @@ module.exports = {
parser: 'svelte-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser'
},
rules: {
'@typescript-eslint/no-unused-vars': [
'warn',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^\\$\\$(Props|Events|Slots|Generic)$'
}
]
}
}
]
Expand Down
2 changes: 1 addition & 1 deletion src/lib/Loader.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<div class="sonner-loading-wrapper" data-visible={visible}>
<div class="sonner-spinner">
{#each bars as _bar, i (i)}
{#each bars as _, i (i)}
<div class="sonner-loading-bar" />
{/each}
</div>
Expand Down
91 changes: 70 additions & 21 deletions src/lib/Toast.svelte
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
<script lang="ts">
import { onMount } from 'svelte';
import type { ToastT, Position } from './types.js';
import type { ToastClassnames, ToastProps } from './types.js';
import Loader from './Loader.svelte';
import Icon from './Icon.svelte';
import { toastState, useEffect } from './state.js';
import { cn } from './internal/helpers.js';
import type { Expand } from './internal/types.js';
type $$Props = Expand<ToastProps>;
// Default lifetime of a toasts (in ms)
const TOAST_LIFETIME = 4000;
Expand All @@ -15,21 +19,41 @@
const TIME_BEFORE_UNMOUNT = 200;
const defaultClasses: ToastClassnames = {
toast: '',
title: '',
description: '',
loader: '',
closeButton: '',
cancelButton: '',
actionButton: '',
action: '',
warning: '',
error: '',
success: '',
default: '',
info: '',
loading: '',
normal: ''
};
const { toasts, heights, removeHeight, addHeight, dismiss } = toastState;
export let toast: ToastT;
export let index: number;
export let expanded: boolean;
export let invert: boolean;
export let position: Position;
export let visibleToasts: number;
export let expandByDefault: boolean;
export let closeButton: boolean;
export let interacting: boolean;
export let cancelButtonStyle = '';
export let actionButtonStyle = '';
export let duration: number | null;
export let descriptionClass = '';
export let toast: $$Props['toast'];
export let index: $$Props['index'];
export let expanded: $$Props['expanded'];
export let invert: $$Props['invert'];
export let position: $$Props['position'];
export let visibleToasts: $$Props['visibleToasts'];
export let expandByDefault: $$Props['expandByDefault'];
export let closeButton: $$Props['closeButton'];
export let interacting: $$Props['interacting'];
export let cancelButtonStyle: $$Props['cancelButtonStyle'] = '';
export let actionButtonStyle: $$Props['actionButtonStyle'] = '';
export let duration: $$Props['duration'] = 4000;
export let descriptionClass: $$Props['descriptionClass'] = '';
export let classes: $$Props['classes'] = {};
export let unstyled: $$Props['unstyled'] = false;
let mounted = false;
let removed = false;
Expand All @@ -39,21 +63,25 @@
let initialHeight = 0;
let toastRef: HTMLLIElement;
$: classes = { ...defaultClasses, ...classes };
$: isFront = index === 0;
$: isVisible = index + 1 <= visibleToasts;
$: toastType = toast.type;
$: toastType = toast.type ?? 'default';
$: toastClass = toast.class || '';
$: toastDescriptionClass = toast.descriptionClass || '';
// Height index is used to calculate the offset as it gets updated before the toast array, which means we can calculate the new layout faster.
$: heightIndex =
$heights.findIndex((height) => height.toastId === toast.id) || 0;
let offset = 0;
let closeTimerStartTimeRef = 0;
let closeTimerRemainingTimeRef =
toast.duration || duration || TOAST_LIFETIME;
let lastCloseTimerStartTimeRef = 0;
let pointerStartRef: { x: number; y: number } | null = null;
$: coords = position.split('-');
$: toastsHeightBefore = $heights.reduce((prev, curr, reducerIndex) => {
// Calculate offset up untill current toast
Expand Down Expand Up @@ -149,9 +177,10 @@
}
offsetBeforeRemove = offset;
const target = event.target as HTMLElement;
// Ensure we maintain correct pointer capture even when going outside of the toast (e.g. when swiping)
(event.target as HTMLElement).setPointerCapture(event.pointerId);
if ((event.target as HTMLElement).tagName === 'BUTTON') {
target.setPointerCapture(event.pointerId);
if (target.tagName === 'BUTTON') {
return;
}
swiping = true;
Expand Down Expand Up @@ -212,9 +241,16 @@
aria-atomic="true"
role="status"
tabIndex={0}
class={`${$$props.class} ${toastClass}`}
class={cn(
$$props.class,
toastClass,
classes?.toast,
toast?.classes?.toast,
classes?.[toastType],
toast?.classes?.[toastType]
)}
data-sonner-toast=""
data-styled={!toast.component}
data-styled={!(toast.component || toast?.unstyled || unstyled)}
data-mounted={mounted}
data-promise={Boolean(toast.promise)}
data-removed={removed}
Expand Down Expand Up @@ -249,6 +285,7 @@
deleteToast();
toast.onDismiss?.(toast);
}}
class={cn(classes?.closeButton, toast?.classes?.closeButton)}
>
<svg
xmlns="http://www.w3.org/2000/svg"
Expand Down Expand Up @@ -290,11 +327,21 @@
</div>
{/if}
<div data-content="">
<div data-title="">{toast.title}</div>
<div
data-title=""
class={cn(classes?.title, toast?.classes?.title)}
>
{toast.title}
</div>
{#if toast.description}
<div
data-description=""
class={descriptionClass + toastDescriptionClass}
class={cn(
descriptionClass,
toastDescriptionClass,
classes?.description,
toast.classes?.description
)}
>
{toast.description}
</div>
Expand All @@ -305,6 +352,7 @@
data-button
data-cancel
style={cancelButtonStyle}
class={cn(classes?.cancelButton, toast?.classes?.cancelButton)}
on:click={() => {
deleteToast();
if (toast.cancel?.onClick) {
Expand All @@ -319,6 +367,7 @@
<button
data-button=""
style={actionButtonStyle}
class={cn(classes?.actionButton, toast?.classes?.actionButton)}
on:click={(event) => {
toast.action?.onClick(event);
if (event.defaultPrevented) return;
Expand Down
43 changes: 19 additions & 24 deletions src/lib/Toaster.svelte
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
<script lang="ts">
import { onDestroy, onMount } from 'svelte';
import type { Position } from './types.js';
import type { Position, ToastOptions } from './types.js';
import { toastState } from './state.js';
import Toast from './Toast.svelte';
import type { ToasterProps } from './types.js';
type $$Props = ToasterProps;
// Visible toasts amount
const VISIBLE_TOASTS_AMOUNT = 3;
Expand All @@ -16,15 +20,6 @@
// Default gap between toasts
const GAP = 14;
interface ToastOptions {
class?: string;
descriptionClass?: string;
style?: string;
cancelButtonStyle?: string;
actionButtonStyle?: string;
}
// TODO: move to mode watcher for SSR theme
function getInitialTheme(t: string) {
if (t !== 'system') {
return t;
Expand All @@ -45,16 +40,15 @@
}
export let invert = false;
export let theme: 'light' | 'dark' | 'system' = 'light';
export let position: Position = 'bottom-right';
export let theme: Exclude<$$Props['theme'], undefined> = 'light';
export let position = 'bottom-right';
export let hotkey: string[] = ['altKey', 'KeyT'];
export let richColors = false;
export let expand = false;
export let duration: number | null = null;
export let visibleToasts: number = VISIBLE_TOASTS_AMOUNT;
export let visibleToasts = VISIBLE_TOASTS_AMOUNT;
export let closeButton = false;
export let toastOptions: ToastOptions = {};
export let offset: string | number | null = null;
export let offset: $$Props['offset'] = null;
const { toasts, heights } = toastState;
Expand All @@ -73,10 +67,11 @@
let interacting = false;
let actualTheme = getInitialTheme(theme);
let listRef: HTMLOListElement;
$: hotkeyLabel = hotkey.join('+').replace(/Key/g, '').replace(/Digit/g, '');
let lastFocusedElementRef: HTMLElement | null = null;
let isFocusWithinRef = false;
$: hotkeyLabel = hotkey.join('+').replace(/Key/g, '').replace(/Digit/g, '');
$: if ($toasts.length <= 1) {
expanded = false;
}
Expand Down Expand Up @@ -207,21 +202,21 @@
<Toast
{index}
{toast}
{duration}
class={toastOptions?.class}
descriptionClass={toastOptions?.descriptionClass}
invert={Boolean(invert)}
{visibleToasts}
closeButton={Boolean(closeButton)}
{interacting}
{position}
style={toastOptions?.style ?? ''}
cancelButtonStyle={toastOptions?.cancelButtonStyle}
actionButtonStyle={toastOptions?.actionButtonStyle}
{toasts}
{heights}
expandByDefault={Boolean(expand)}
{expanded}
actionButtonStyle={toastOptions?.actionButtonStyle ||
''}
cancelButtonStyle={toastOptions?.cancelButtonStyle ||
''}
descriptionClass={toastOptions?.descriptionClass || ''}
classes={toastOptions.classes || {}}
duration={toastOptions.duration || 4000}
unstyled={toastOptions.unstyled || false}
/>
{/each}
</ol>
Expand Down
3 changes: 3 additions & 0 deletions src/lib/internal/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function cn(...classes: (string | undefined)[]) {
return classes.filter(Boolean).join(' ');
}
2 changes: 2 additions & 0 deletions src/lib/internal/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './types.js';
export * from './helpers.js';
5 changes: 5 additions & 0 deletions src/lib/internal/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export type Expand<T> = T extends object
? T extends infer O
? { [K in keyof O]: O[K] }
: never
: T;
5 changes: 3 additions & 2 deletions src/lib/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ function createToastState() {
typeof data?.id === 'number' || (data.id && data.id?.length > 0)
? data.id
: toastsCounter++;
const dismissable = data.dismissable === undefined ? true : data.dismissable;

const $toasts = get(toasts);

Expand All @@ -37,13 +38,13 @@ function createToastState() {
toasts.update((prev) =>
prev.map((toast) => {
if (toast.id === id) {
return { ...toast, ...data, id, title: message };
return { ...toast, ...data, id, title: message, dismissable };
}
return toast;
})
);
} else {
addToast({ title: message, ...rest, id });
addToast({ ...rest, id, title: message, dismissable });
}

return id;
Expand Down
Loading

0 comments on commit 93f282c

Please sign in to comment.