Skip to content

Commit

Permalink
feat: [useSnackbar] - related #403 (wip)
Browse files Browse the repository at this point in the history
  • Loading branch information
mattgoud committed Jan 7, 2025
1 parent 745a78e commit 8a300c1
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 0 deletions.
1 change: 1 addition & 0 deletions packages/components/snackbar/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export default PuikSnackbar;

export * from './src/snackbar';
export * from './src/snackbar-provider';
export * from './src/use-snackbar';
32 changes: 32 additions & 0 deletions packages/components/snackbar/src/snackbar.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,40 @@
import '@prestashopcorp/puik-components/snackbar/style/css';
import type Snackbar from './snackbar.vue';
import type { Component } from 'vue';

export enum PuikSnackbarVariants {
Default = 'default',
Danger = 'danger',
Success = 'success',
}
export enum PuikSnackbarActions {
Add = 'add-snackbar',
Update = 'update-snackbar',
Dismiss = 'dismiss-snackbar',
Remove = 'remove-snackbar',
}

export type PuikSnackbarDispatchActions =
| {
type: PuikSnackbarActions.Add
snackbar: SnackbarProps
}
| {
type: PuikSnackbarActions.Update
snackbar: Partial<SnackbarProps>
}
| {
type: PuikSnackbarActions.Dismiss
snackbarId?: SnackbarProps['id']
}
| {
type: PuikSnackbarActions.Remove
snackbarId?: SnackbarProps['id']
};

export interface SnackbarsState {
snackbars: SnackbarProps[]
}

export enum PuikSnackbarSwipeAnimations {
Right = 'slide-right',
Expand All @@ -14,13 +43,16 @@ export enum PuikSnackbarSwipeAnimations {
Down = 'slide-down',
}
export interface SnackbarProps {
id: string
open?: boolean
title?: string
description: string
duration?: number
variant?: `${PuikSnackbarVariants}`
swipeAnimation?: `${PuikSnackbarSwipeAnimations}`
hasCloseButton?: boolean
action?: Component
onOpenChange?: ((value: boolean) => void) | undefined
}

export type SnackbarEmits = {
Expand Down
3 changes: 3 additions & 0 deletions packages/components/snackbar/src/snackbar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<ToastRoot
v-bind="forwarded"
:class="['puik-snackbar-root', `puik-snackbar-root--${variant}`, `puik-snackbar-root--swipe-${swipeAnimation}`]"
@update:open="onOpenChange"
>
<div class="puik-snackbar-message">
<ToastTitle
Expand Down Expand Up @@ -39,12 +40,14 @@ import { useForwardPropsEmits, ToastAction, ToastClose, ToastTitle, ToastRoot, T
import { PuikIcon } from '@prestashopcorp/puik-components';
import { PuikSnackbarVariants, PuikSnackbarSwipeAnimations } from './snackbar';
import { type SnackbarProps, SnackbarEmits } from './snackbar';
import { generateId } from '@prestashopcorp/puik-utils';
defineOptions({
name: 'PuikSnackbar'
});
const props = withDefaults(defineProps<SnackbarProps>(), {
id: `puik-snackbar-${generateId()}`,
variant: PuikSnackbarVariants.Default,
swipeAnimation: PuikSnackbarSwipeAnimations.Right
});
Expand Down
84 changes: 84 additions & 0 deletions packages/components/snackbar/src/use-snackbar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { type SnackbarProps, PuikSnackbarActions, PuikSnackbarDispatchActions, SnackbarsState } from './snackbar';

const SNACKBAR_LIMIT = 1;
const SNACKBAR_REMOVE_DELAY = 5000;

function addToRemoveQueue(snackbarId: string, snackbarTimeouts: Map<string, ReturnType<typeof setTimeout>>, state: SnackbarsState) {
if (snackbarTimeouts.has(snackbarId)) { return; }

const timeout = setTimeout(() => {
snackbarTimeouts.delete(snackbarId);
dispatch({
type: PuikSnackbarActions.Remove,
snackbarId
}, snackbarTimeouts, state);
}, SNACKBAR_REMOVE_DELAY);

snackbarTimeouts.set(snackbarId, timeout);
}

function dispatch(action: PuikSnackbarDispatchActions, snackbarTimeouts: Map<string, ReturnType<typeof setTimeout>>, state: SnackbarsState) {
switch (action.type) {
case PuikSnackbarActions.Add:
state.snackbars = [action.snackbar, ...state.snackbars].slice(0, SNACKBAR_LIMIT);
break;

case PuikSnackbarActions.Update:
state.snackbars = state.snackbars.map(s =>
s.id === action.snackbar.id ? { ...s, ...action.snackbar } : s
);
break;

case PuikSnackbarActions.Dismiss: {
const { snackbarId } = action;

if (snackbarId) {
addToRemoveQueue(snackbarId, snackbarTimeouts, state);
} else {
state.snackbars.forEach((snackbar) => {
addToRemoveQueue(snackbar.id, snackbarTimeouts, state);
});
}

state.snackbars = state.snackbars.map(s =>
s.id === snackbarId
? { ...s, open: false }
: s
);
break;
}

case PuikSnackbarActions.Remove:
state.snackbars = state.snackbars.filter(s => s.id !== action.snackbarId);
break;
}
}

export const useSnackbar = (props: SnackbarProps, snackbarTimeouts: Map<string, ReturnType<typeof setTimeout>>, state: SnackbarsState) => {
const id = props.id;

const update = (props: SnackbarProps) =>
dispatch({
type: PuikSnackbarActions.Update,
snackbar: { ...props }
}, snackbarTimeouts, state);

const dismiss = () => dispatch({ type: PuikSnackbarActions.Dismiss, snackbarId: props.id }, snackbarTimeouts, state);

dispatch({
type: PuikSnackbarActions.Add,
snackbar: {
...props,
open: true,
onOpenChange: (open: boolean) => {
if (!open) { dismiss(); }
}
}
}, snackbarTimeouts, state);

return {
id,
dismiss,
update
};
};

0 comments on commit 8a300c1

Please sign in to comment.