Skip to content

Commit 5c05a51

Browse files
committed
chore(avatar): migrate to Svelte 5
1 parent e6452c6 commit 5c05a51

11 files changed

Lines changed: 118 additions & 122 deletions

File tree

.changeset/brave-tips-do.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
"@svelte-put/preprocess-inline-svg": major
33
---
44

5-
switch to using modern Svelte AST
5+
[BREAKING] switch to using modern Svelte AST

.changeset/odd-rules-argue.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
"@svelte-put/clickoutside": major
33
---
44

5-
drop support for Svelte 4 and lower (will still work as of now but no guarantees in the future)
5+
[BREAKING] drop support for Svelte 4 and lower (will still work as of now but no guarantees in the future)

.changeset/soft-countries-add.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@svelte-put/avatar': major
3+
---
4+
5+
[BREAKING] drop support for Svelte 4 and lower; now using runes and snippets

.changeset/tiny-dancers-live.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
"@svelte-put/preprocess-inline-svg": major
33
---
44

5-
support Svelte v5, drop support for v4 and below, now written in JS with JSDocs
5+
[BREAKING] support Svelte v5, drop support for v4 and below, now written in JS with JSDocs

.changeset/twelve-tools-type.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
"@svelte-put/preprocess-auto-slug": major
33
---
44

5-
drop support for Svelte 4 and lower, now using Svelte modern AST and witten in JS with JSDocs
5+
[BREAKING] drop support for Svelte 4 and lower, now using Svelte modern AST and witten in JS with JSDocs

packages/avatar/src/Avatar.svelte

Lines changed: 17 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,20 @@
11
<script>
2-
import { onMount } from 'svelte';
3-
42
import { resolveAlt, resolveSize, resolveSrc, DEFINITIVE_FALLBACK } from './avatar.utils.js';
53
6-
/** @type {import('./Avatar.svelte.d.ts').AvatarProps['src']} */
7-
export let src = undefined;
8-
/** @type {import('./Avatar.svelte.d.ts').AvatarProps['gravatar']} */
9-
export let gravatar = undefined;
10-
/** @type {import('./Avatar.svelte.d.ts').AvatarProps['uiAvatar']} */
11-
export let uiAvatar = undefined;
12-
/** @type {import('./Avatar.svelte.d.ts').AvatarProps['fallback']} */
13-
export let fallback = undefined;
14-
/** @type {import('./Avatar.svelte.d.ts').AvatarProps['size']} */
15-
export let size = undefined;
16-
/** @type {import('./Avatar.svelte.d.ts').AvatarProps['alt']} */
17-
export let alt = undefined;
4+
/** @type {import('./Avatar.svelte.d.ts').AvatarProps} */
5+
let { src, gravatar, uiAvatar, fallback, size, alt, class: cls = '', img, ...rest } = $props();
6+
7+
let rAlt = $derived(resolveAlt(alt, gravatar, uiAvatar, src));
8+
let rSize = $derived(resolveSize(32, size, src, gravatar, uiAvatar));
9+
let sources = $derived(resolveSrc(src, gravatar, uiAvatar, fallback));
10+
let rSrc = $state(DEFINITIVE_FALLBACK);
1811
19-
$: rAlt = resolveAlt(alt, gravatar, uiAvatar, src);
20-
$: rSize = resolveSize(32, size, src, gravatar, uiAvatar);
21-
$: sources = resolveSrc(src, gravatar, uiAvatar, fallback);
22-
let rSrc = DEFINITIVE_FALLBACK;
12+
/** @type {HTMLImageElement | undefined} */
13+
let element = $state(undefined);
2314
24-
/** @type {HTMLImageElement} */
25-
let element;
26-
onMount(async () => {
15+
$effect(() => {
2716
let rElement = element;
28-
if ($$slots.default) {
17+
if (img) {
2918
rElement = new Image();
3019
rElement.style.display = 'none';
3120
document.body.appendChild(rElement);
@@ -50,18 +39,20 @@
5039
Svelte image wrapper component for displaying avatar
5140
@public
5241
-->
53-
<slot src={rSrc} size={rSize} alt={rAlt} {sources}>
42+
{#if img}
43+
{@render img({ src: rSrc, size: rSize, alt: rAlt, sources })}
44+
{:else}
5445
<img
5546
src={rSrc}
5647
alt={rAlt}
5748
height={rSize}
5849
width={rSize}
59-
class="svelte-put-avatar {$$props.class ?? ''}"
50+
class="svelte-put-avatar {cls}"
6051
data-sources={sources.join(',')}
6152
bind:this={element}
62-
{...$$restProps}
53+
{...rest}
6354
/>
64-
</slot>
55+
{/if}
6556
6657
<style>
6758
:global(:where(.svelte-put-avatar)) {
Lines changed: 47 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,6 @@
1-
import type { SvelteComponent } from 'svelte';
1+
import type { Snippet, SvelteComponent } from 'svelte';
22
import type { HTMLImgAttributes } from 'svelte/elements';
33

4-
/**
5-
* Slots of Avatar component
6-
*
7-
*/
8-
export interface AvatarSlots {
9-
default: {
10-
/** The resolved avatar url */
11-
src: string;
12-
/** The resolved alt text, if any */
13-
alt: string;
14-
/** The resolved size, if any */
15-
size: number;
16-
/** All the images source from prop */
17-
sources: string[];
18-
};
19-
}
20-
21-
/**
22-
* Props to Avatar component
23-
*
24-
*/
25-
export interface AvatarProps extends HTMLImgAttributes {
26-
/**
27-
* "src" attribute. This option is of highest priority
28-
*/
29-
src?: string;
30-
/**
31-
* Either the email for {@link https://en.gravatar.com/site/implement/images | Gravatar }
32-
* or {@link GravatarOptions } object. This option take second priority.
33-
*
34-
* By default, the Gravatar `default` query is set to 404, so that if gravatar is not valid,
35-
* the next priority url will be used. Be careful when setting this `default` to other values,
36-
* as gravatar will then always return a valid resource, hence stopping the resolution flow
37-
* (i.e uiAvatar & fallback will never be used).
38-
*/
39-
gravatar?: GravatarOptions | string;
40-
/**
41-
* Either the name for building initials with {@link https://ui-avatars.com | UIAvatar }
42-
* or {@link UIAvatarOptions } object. This option take third priority.
43-
*/
44-
uiAvatar?: string | UIAvatarOptions;
45-
/**
46-
* The fallback url string. This option takes lowest priority.
47-
* It defaults to the internal fallback (https://www.gravatar.com/avatar?d=mp).
48-
* If you provide a different url that is not a valid resource, the internal fallback
49-
* will be used.
50-
*/
51-
fallback?: string;
52-
/**
53-
* value for "width" & "height" attribute of <img>.
54-
* Will have no effect if default slot is overridden
55-
*/
56-
size?: number;
57-
/**
58-
* value for "alt" attribute of <img>.
59-
* Default to uiAvatar.name or gravatar.email if any.
60-
* Will have no effect if default slot is overridden
61-
*/
62-
alt?: string;
63-
class?: string;
64-
}
65-
664
/**
675
* URL or option to fallback when email hash returns no match from Gravatar.
686
* See {@link https://en.gravatar.com/site/implement/images | Gravatar } for
@@ -80,11 +18,6 @@ export type GravatarDefault =
8018
| 'blank'
8119
| `${'http' | 'https'}://${string}.${'png' | 'jpg' | 'jpeg' | 'gif'}`;
8220

83-
/**
84-
* Options for building {@link https://en.gravatar.com/site/implement/images | Gravatar } url.
85-
* Each option should map to a supported Gravatar query param
86-
*
87-
*/
8821
export interface GravatarOptions {
8922
/** email to md5-hash */
9023
email: string;
@@ -126,5 +59,49 @@ export interface UIAvatarOptions {
12659
format?: 'svg' | 'png';
12760
}
12861

129-
// eslint-disable-next-line @typescript-eslint/ban-types
130-
export default class Avatar extends SvelteComponent<AvatarProps, {}, AvatarSlots> {}
62+
/**
63+
* Props to Avatar component
64+
*/
65+
export interface AvatarProps extends HTMLImgAttributes {
66+
/**
67+
* "src" attribute. This option is of highest priority
68+
*/
69+
src?: string;
70+
/**
71+
* Either the email for {@link https://en.gravatar.com/site/implement/images | Gravatar }
72+
* or {@link GravatarOptions } object. This option take second priority.
73+
*
74+
* By default, the Gravatar `default` query is set to 404, so that if gravatar is not valid,
75+
* the next priority url will be used. Be careful when setting this `default` to other values,
76+
* as gravatar will then always return a valid resource, hence stopping the resolution flow
77+
* (i.e uiAvatar & fallback will never be used).
78+
*/
79+
gravatar?: GravatarOptions | string;
80+
/**
81+
* Either the name for building initials with {@link https://ui-avatars.com | UIAvatar }
82+
* or {@link UIAvatarOptions } object. This option take third priority.
83+
*/
84+
uiAvatar?: string | UIAvatarOptions;
85+
/**
86+
* The fallback url string. This option takes lowest priority.
87+
* It defaults to the internal fallback (https://www.gravatar.com/avatar?d=mp).
88+
* If you provide a different url that is not a valid resource, the internal fallback
89+
* will be used.
90+
*/
91+
fallback?: string;
92+
/**
93+
* value for "width" & "height" attribute of <img>.
94+
* Will have no effect if default slot is overridden
95+
*/
96+
size?: number;
97+
/**
98+
* value for "alt" attribute of <img>.
99+
* Default to uiAvatar.name or gravatar.email if any.
100+
* Will have no effect if default slot is overridden
101+
*/
102+
alt?: string;
103+
img?: Snippet<[{ src: string; size: number; alt: string; sources: string[] }]>;
104+
}
105+
106+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
107+
export default class Avatar extends SvelteComponent<AvatarProps, any, any> {}

packages/avatar/src/avatar.helpers.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import md5 from 'md5';
33
/**
44
* Builds a {@link https://ui-avatars.com | UIAvatar } url
55
*
6-
* @param {string | import('./Avatar.svelte.d.ts').UIAvatarOptions} input - name for UIAvatar or object of options
6+
* @param {string | import('./LegacyAvatar.svelte.js').UIAvatarOptions} input - name for UIAvatar or object of options
77
* @returns {string} the constructed UIAvatar URL
88
*/
99
export function uiAvatar(input) {
@@ -25,12 +25,12 @@ export function uiAvatar(input) {
2525
/**
2626
* Builds a {@link https://en.gravatar.com/site/implement/images | Gravatar } url
2727
*
28-
* @param {string | import('./Avatar.svelte.d.ts').GravatarOptions} input - email for Gravatar or object of options
28+
* @param {string | import('./LegacyAvatar.svelte.js').GravatarOptions} input - email for Gravatar or object of options
2929
* @returns {string} the constructed Gravatar URL
3030
*/
3131
export function gravatar(input) {
3232
let email = '';
33-
/** @type {Omit<import('./Avatar.svelte.d.ts').GravatarOptions, 'email'>} */
33+
/** @type {Omit<import('./LegacyAvatar.svelte.js').GravatarOptions, 'email'>} */
3434
let options = {};
3535
if (typeof input === 'string') {
3636
email = input;

packages/avatar/src/avatar.utils.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ function nonNullableFilter(value) {
4646
/**
4747
* @package
4848
* @param {string | undefined} alt
49-
* @param {import('./Avatar.svelte.d.ts').AvatarProps['gravatar'] | undefined} gravatar
50-
* @param {import('./Avatar.svelte.d.ts').AvatarProps['uiAvatar'] | undefined} uiAvatar
49+
* @param {import('./Avatar.svelte').AvatarProps['gravatar'] | undefined} gravatar
50+
* @param {import('./Avatar.svelte').AvatarProps['uiAvatar'] | undefined} uiAvatar
5151
* @param {string | undefined } src
5252
* @returns {string}
5353
*/
@@ -71,8 +71,8 @@ export function resolveAlt(
7171
* @param {number} fallback
7272
* @param {number | undefined} size
7373
* @param {string | undefined} src
74-
* @param {import('./Avatar.svelte.d.ts').AvatarProps['gravatar'] | undefined} gravatar
75-
* @param {import('./Avatar.svelte.d.ts').AvatarProps['uiAvatar'] | undefined} uiAvatar
74+
* @param {import('./Avatar.svelte').AvatarProps['gravatar'] | undefined} gravatar
75+
* @param {import('./Avatar.svelte').AvatarProps['uiAvatar'] | undefined} uiAvatar
7676
* @returns {number}
7777
*/
7878
export function resolveSize(
@@ -98,8 +98,8 @@ export const DEFINITIVE_FALLBACK = 'https://www.gravatar.com/avatar?d=mp';
9898
/**
9999
* @package
100100
* @param {string | undefined} src
101-
* @param {import('./Avatar.svelte.d.ts').AvatarProps['gravatar'] | undefined} gravatar
102-
* @param {import('./Avatar.svelte.d.ts').AvatarProps['uiAvatar'] | undefined} uiAvatar
101+
* @param {import('./Avatar.svelte').AvatarProps['gravatar'] | undefined} gravatar
102+
* @param {import('./Avatar.svelte').AvatarProps['uiAvatar'] | undefined} uiAvatar
103103
* @param {string | undefined} fallback
104104
* @returns {string[]}
105105
*/

sites/docs/src/routes/docs/(package)/avatar/_page/content.md.svelte

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@
1919
let uiAvatarVariant = 'Minimal';
2020
</script>
2121

22+
<!--
23+
TODO add migration docs
24+
- drop support for v4 and below
25+
- no more default slot, use the `img` snippet instead
26+
-->
27+
2228
## Installation
2329

2430
<enhanced-code-block group display="tabs" bind:title={$packageManager}>

0 commit comments

Comments
 (0)