Skip to content

Commit

Permalink
fix(List): forward all events including child components
Browse files Browse the repository at this point in the history
fix(List.Item.Leading.Avatar): added graceful fail
  • Loading branch information
N00nDay committed Oct 14, 2022
1 parent 9814724 commit fcc2508
Show file tree
Hide file tree
Showing 10 changed files with 280 additions and 12 deletions.
122 changes: 118 additions & 4 deletions src/lib/components/list/Avatar.svelte
Original file line number Diff line number Diff line change
@@ -1,9 +1,123 @@
<script lang="ts" context="module">
export const LIST_ITEM_LEADING_AVATAR_CONTEXT_ID = 'list-item-leading-avatar-context-id';
</script>

<script lang="ts">
import Avatar from '../avatar';
import { setContext, onMount } from 'svelte/internal';
import { twMerge } from 'tailwind-merge';
import Placeholder from './Placeholder.svelte';
import { get_current_component } from 'svelte/internal';
import { forwardEventsBuilder, useActions, type ActionArray } from '../../actions';
export let use: ActionArray = [];
import { exclude } from '../../utils/exclude';
const forwardEvents = forwardEventsBuilder(get_current_component());
export let src: string;
export let alt = 'user-avatar';
export let src: string | undefined = undefined;
export let alt = 'avatar';
export let shape: 'circle' | 'rounded' | 'square' = 'circle';
export let size: 'xs' | 'sm' | 'md' | 'lg' | 'xl' = 'md';
export let initials: string | undefined = undefined;
let loaded = false;
let failed = false;
let loading = true;
setContext(LIST_ITEM_LEADING_AVATAR_CONTEXT_ID, {
avatar: true,
src,
alt,
shape,
size
});
let defaultClass = '';
let containerDefaultClass = '';
if (src) {
defaultClass = 'inline-block absolute';
containerDefaultClass = 'inline-block relative align-middle';
} else if (initials) {
defaultClass =
'inline-flex items-center justify-center align-middle bg-light-icon-background dark:bg-dark-icon-background text-light-content dark:text-dark-content';
}
if (size === 'xs') {
defaultClass += ' h-6 w-6';
containerDefaultClass += ' h-6 w-6';
} else if (size === 'sm') {
defaultClass += ' h-8 w-8';
containerDefaultClass += ' h-8 w-8';
} else if (size === 'md') {
defaultClass += ' h-10 w-10';
containerDefaultClass += ' h-10 w-10';
} else if (size === 'lg') {
defaultClass += ' h-12 w-12';
containerDefaultClass += ' h-12 w-12';
} else if (size === 'xl') {
defaultClass += ' h-16 w-16';
containerDefaultClass += ' h-16 w-16';
}
if (shape === 'circle') {
defaultClass += ' rounded-full';
containerDefaultClass += ' rounded-full';
} else if (shape === 'rounded') {
defaultClass += ' rounded-md';
containerDefaultClass += ' rounded-md';
}
$: finalClass = twMerge(defaultClass, $$props.class);
$: finalContainerClass = twMerge(containerDefaultClass, $$props.class);
onMount(() => {
if (src) {
const image = new Image();
image.src = src;
loading = true;
image.onload = () => {
loading = false;
loaded = true;
};
image.onerror = () => {
loading = false;
failed = true;
};
}
});
</script>

<Avatar {src} {alt} {size} />
{#if src}
<span
class={finalContainerClass}
use:useActions={use}
use:forwardEvents
{...exclude($$props, ['use', 'class'])}
>
{#if loaded}
<img class={finalClass} style={$$props.style} src={src || ''} {alt} />
{:else if failed}
{#if $$slots.placeholder}
<slot name="placeholder" />
{:else}
<Placeholder />
{/if}
{:else if loading}
<Placeholder loading />
{/if}

<slot name="indicator" />
</span>
{:else if initials}
<span
class={finalClass}
use:useActions={use}
use:forwardEvents
{...exclude($$props, ['use', 'class'])}
>
<span
class="font-bold leading-none text-current"
class:text-xs={size === 'xs'}
class:text-sm={size === 'sm'}
class:text-xl={size === 'lg'}
class:text-2xl={size === 'xl'}>{initials}</span
>
</span>
{/if}
12 changes: 11 additions & 1 deletion src/lib/components/list/Content.svelte
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
<script lang="ts">
import { twMerge } from 'tailwind-merge';
import { get_current_component } from 'svelte/internal';
import { forwardEventsBuilder, useActions, type ActionArray } from '../../actions';
export let use: ActionArray = [];
import { exclude } from '../../utils/exclude';
const forwardEvents = forwardEventsBuilder(get_current_component());
const defaultClass = 'ml-3 flex flex-grow flex-col justify-center items-start';
$: finalClass = twMerge(defaultClass, $$props.class);
</script>

<div class={finalClass} style={$$props.style}>
<div
class={finalClass}
use:useActions={use}
use:forwardEvents
{...exclude($$props, ['use', 'class'])}
>
<slot name="title" />
<slot name="description" />
<slot />
Expand Down
12 changes: 11 additions & 1 deletion src/lib/components/list/Description.svelte
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
<script lang="ts">
import { twMerge } from 'tailwind-merge';
import { get_current_component } from 'svelte/internal';
import { forwardEventsBuilder, useActions, type ActionArray } from '../../actions';
export let use: ActionArray = [];
import { exclude } from '../../utils/exclude';
const forwardEvents = forwardEventsBuilder(get_current_component());
const defaultClass = 'text-sm mb-0 text-light-secondary-content dark:text-dark-secondary-content';
$: finalClass = twMerge(defaultClass, $$props.class);
</script>

<p class={finalClass} style={$$props.style}>
<p
class={finalClass}
use:useActions={use}
use:forwardEvents
{...exclude($$props, ['use', 'class'])}
>
<slot />
</p>
9 changes: 8 additions & 1 deletion src/lib/components/list/Extra.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
<script lang="ts">
import { twMerge } from 'tailwind-merge';
import { get_current_component } from 'svelte/internal';
import { forwardEventsBuilder, useActions, type ActionArray } from '../../actions';
export let use: ActionArray = [];
import { exclude } from '../../utils/exclude';
const forwardEvents = forwardEventsBuilder(get_current_component());
export let placement: 'start' | 'center' | 'end' = 'start';
Expand All @@ -12,7 +17,9 @@
class:items-start={placement === 'start'}
class:items-center={placement === 'center'}
class:items-end={placement === 'end'}
style={$$props.style}
use:useActions={use}
use:forwardEvents
{...exclude($$props, ['use', 'class'])}
>
<slot />
</div>
12 changes: 11 additions & 1 deletion src/lib/components/list/Icon.svelte
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
<script lang="ts">
import type { MaterialIcon } from '../../types';
import { twMerge } from 'tailwind-merge';
import { get_current_component } from 'svelte/internal';
import { forwardEventsBuilder, useActions, type ActionArray } from '../../actions';
export let use: ActionArray = [];
import { exclude } from '../../utils/exclude';
const forwardEvents = forwardEventsBuilder(get_current_component());
export let icon: MaterialIcon;
const defaultClass = 'material-icons text-2xl text-white bg-primary';
$: finalClass = twMerge(defaultClass, $$props.class);
</script>

<span class={finalClass} style={$$props.style}>{icon}</span>
<span
class={finalClass}
use:useActions={use}
use:forwardEvents
{...exclude($$props, ['use', 'class'])}>{icon}</span
>
12 changes: 11 additions & 1 deletion src/lib/components/list/Item.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
import { LIST_CONTEXT_ID } from './List.svelte';
import { useContext } from '../../utils/useContext';
import { getContext } from 'svelte';
import { get_current_component } from 'svelte/internal';
import { forwardEventsBuilder, useActions, type ActionArray } from '../../actions';
export let use: ActionArray = [];
import { exclude } from '../../utils/exclude';
const forwardEvents = forwardEventsBuilder(get_current_component());
useContext({
context_id: LIST_CONTEXT_ID,
Expand All @@ -18,7 +23,12 @@
$: finalClass = twMerge(defaultClass, $$props.class);
</script>

<li class={finalClass} style={$$props.style}>
<li
class={finalClass}
use:useActions={use}
use:forwardEvents
{...exclude($$props, ['use', 'class'])}
>
<slot name="leading" />
<slot name="content" />
<slot name="extra" />
Expand Down
12 changes: 11 additions & 1 deletion src/lib/components/list/Leading.svelte
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
<script lang="ts">
import { twMerge } from 'tailwind-merge';
import { get_current_component } from 'svelte/internal';
import { forwardEventsBuilder, useActions, type ActionArray } from '../../actions';
export let use: ActionArray = [];
import { exclude } from '../../utils/exclude';
const forwardEvents = forwardEventsBuilder(get_current_component());
const defaultClass = 'h-10 w-10';
$: finalClass = twMerge(defaultClass, $$props.class);
</script>

<div class={finalClass} style={$$props.style}>
<div
class={finalClass}
use:useActions={use}
use:forwardEvents
{...exclude($$props, ['use', 'class'])}
>
<slot name="icon" />
<slot name="avatar" />
<slot />
Expand Down
12 changes: 11 additions & 1 deletion src/lib/components/list/List.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
<script lang="ts">
import { twMerge } from 'tailwind-merge';
import { setContext } from 'svelte';
import { get_current_component } from 'svelte/internal';
import { forwardEventsBuilder, useActions, type ActionArray } from '../../actions';
export let use: ActionArray = [];
import { exclude } from '../../utils/exclude';
const forwardEvents = forwardEventsBuilder(get_current_component());
export let divided = true;
export let bordered = false;
Expand All @@ -29,6 +34,11 @@
$: finalClass = twMerge(defaultClass, $$props.class);
</script>

<ul class={finalClass} style={$$props.style}>
<ul
class={finalClass}
use:useActions={use}
use:forwardEvents
{...exclude($$props, ['use', 'class'])}
>
<slot />
</ul>
77 changes: 77 additions & 0 deletions src/lib/components/list/Placeholder.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<script lang="ts">
import { fade } from 'svelte/transition';
import { LIST_ITEM_LEADING_AVATAR_CONTEXT_ID } from './Avatar.svelte';
import { useContext } from '../../utils/useContext';
import { getContext } from 'svelte/internal';
import { twMerge } from 'tailwind-merge';
import Icon from './Icon.svelte';
import { get_current_component } from 'svelte/internal';
import { forwardEventsBuilder, useActions, type ActionArray } from '../../actions';
export let use: ActionArray = [];
import { exclude } from '../../utils/exclude';
const forwardEvents = forwardEventsBuilder(get_current_component());
export let loading = false;
useContext({
context_id: LIST_ITEM_LEADING_AVATAR_CONTEXT_ID,
parent: 'List.Item.Leading.Avatar',
component: 'List.Item.Leading.Avatar.Placeholder'
});
const { shape }: { shape: 'circle' | 'rounded' | 'square' } = getContext(
LIST_ITEM_LEADING_AVATAR_CONTEXT_ID
);
let defaultClass =
'absolute inset-0 h-full w-full flex items-center justify-center overflow-hidden bg-light-icon-background dark:bg-dark-icon-background';
if (shape === 'circle') {
defaultClass += ' rounded-full';
} else if (shape === 'rounded') {
defaultClass += ' rounded-md';
}
if (loading) {
defaultClass += ' loading';
}
$: finalClass = twMerge(defaultClass, $$props.class);
</script>

<div
transition:fade|local
class={finalClass}
use:useActions={use}
use:forwardEvents
{...exclude($$props, ['use', 'class'])}
>
{#if $$slots.icon || $$slots.default}
<slot name="icon" />
<slot />
{:else}
<Icon class="text-light-icon dark:text-dark-icon" icon="person" />
{/if}
</div>

<style>
.loading::after {
position: absolute;
transform: translateX(-100%);
background: linear-gradient(
90deg,
rgba(190, 190, 190, 0.2) 25%,
rgba(129, 129, 129, 0.24) 37%,
rgba(190, 190, 190, 0.2) 63%
);
inset: 0 -150%;
animation: shimmer 2s infinite;
content: '';
}
@keyframes shimmer {
0% {
transform: translate(-37.5%);
}
to {
transform: translate(37.5%);
}
}
</style>
12 changes: 11 additions & 1 deletion src/lib/components/list/Title.svelte
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
<script lang="ts">
import { twMerge } from 'tailwind-merge';
import { get_current_component } from 'svelte/internal';
import { forwardEventsBuilder, useActions, type ActionArray } from '../../actions';
export let use: ActionArray = [];
import { exclude } from '../../utils/exclude';
const forwardEvents = forwardEventsBuilder(get_current_component());
const defaultClass = 'text-sm font-semibold text-light-content dark:text-dark-content';
$: finalClass = twMerge(defaultClass, $$props.class);
</script>

<h3 class={finalClass} style={$$props.style}>
<h3
class={finalClass}
use:useActions={use}
use:forwardEvents
{...exclude($$props, ['use', 'class'])}
>
<slot />
</h3>

0 comments on commit fcc2508

Please sign in to comment.