Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 10 additions & 0 deletions libs/core/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,11 @@ export namespace Components {
* @defaultValue null
*/
"image"?: string | null;
/**
* The initials to display in the avatar when no image is provided.
* @defaultValue null
*/
"initials"?: string | null;
/**
* Size of the avatar. Value can be preset or custom.
* @defaultValue lg
Expand Down Expand Up @@ -2870,6 +2875,11 @@ declare namespace LocalJSX {
* @defaultValue null
*/
"image"?: string | null;
/**
* The initials to display in the avatar when no image is provided.
* @defaultValue null
*/
"initials"?: string | null;
/**
* Size of the avatar. Value can be preset or custom.
* @defaultValue lg
Expand Down
24 changes: 24 additions & 0 deletions libs/core/src/components/pds-avatar/docs/pds-avatar.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,30 @@ An avatar that displays a user's profile image. If no image is provided, a defau
<pds-avatar alt="Customer Profile" image={sampleImg}></pds-avatar>
</DocCanvas>

### Initials

An avatar that displays user initials when no profile image is available. This is useful for representing users with their initials as a fallback.

<DocCanvas
mdxSource={{
react: '<PdsAvatar initials="KJ"></PdsAvatar>',
webComponent: '<pds-avatar initials="KJ"></pds-avatar>'
}}>
<pds-avatar initials="KJ"></pds-avatar>
</DocCanvas>

### Initials with Badge

An avatar displaying initials along with a badge indicator.

<DocCanvas
mdxSource={{
react: '<PdsAvatar initials="KJ" badge={true}></PdsAvatar>',
webComponent: '<pds-avatar initials="KJ" badge="true"></pds-avatar>'
}}>
<pds-avatar initials="KJ" badge="true"></pds-avatar>
</DocCanvas>

## Playground

<Canvas of={stories.Default} />
Expand Down
14 changes: 14 additions & 0 deletions libs/core/src/components/pds-avatar/pds-avatar.scss
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,17 @@ img {
object-fit: cover;
width: 100%;
}

.pds-avatar__initials {
color: var(--pine-color-brand);
fill: var(--pine-color-brand);
font-size: var(--pine-font-size-085);
font-weight: var(--pine-font-weight-semi-bold);
height: 100%;
text-align: center;
width: 100%;

text {
text-anchor: middle;
}
}
33 changes: 25 additions & 8 deletions libs/core/src/components/pds-avatar/pds-avatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ export class PdsAvatar {
*/
@Prop() image?: string | null = null;

/**
* The initials to display in the avatar when no image is provided.
* @defaultValue null
*/
@Prop() initials?: string | null = null;

/**
* Size of the avatar. Value can be preset or custom.
* @defaultValue lg
Expand Down Expand Up @@ -108,19 +114,30 @@ export class PdsAvatar {
&& <pds-icon color="var(--pine-color-purple-600)" class="pds-avatar__badge" icon={checkCircleFilled} size="33.53%"></pds-icon>
);

private renderIconOrImage = () => (
this.image
? <img alt={this.alt} src={this.image} />
// Percentage is average size of icon in relation to total avatar size
// of all preset sizes found in Figma.
// Used to allow icons to scale to container size
: <pds-icon color="var(--pine-color-brand)" icon={userFilled} size="33.53%"></pds-icon>
);
private renderIconOrImage = () => {
if (this.image) {
return <img alt={this.alt} src={this.image} />;
}

if (this.initials) {
return (
<svg class="pds-avatar__initials" viewBox="0 0 32 32">
<text x="16" y="20">{this.initials}</text>
</svg>
);
}

// Percentage is average size of icon in relation to total avatar size
// of all preset sizes found in Figma.
// Used to allow icons to scale to container size
return <pds-icon color="var(--pine-color-brand)" icon={userFilled} size="33.53%"></pds-icon>;
};

private classNames = () => (
{
'pds-avatar': true,
[`pds-avatar--has-image`]: this.image !== '' && this.image !== null, // Remove when FF supports :has selector
[`pds-avatar--has-initials`]: this.initials !== '' && this.initials !== null,
[`pds-avatar--${this.variant}`]: this.variant === 'admin'
}
);
Expand Down
1 change: 1 addition & 0 deletions libs/core/src/components/pds-avatar/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
| `componentId` | `component-id` | A unique identifier used for the underlying component `id` attribute. | `string` | `undefined` |
| `dropdown` | `dropdown` | Determines whether the avatar functions as a dropdown trigger. | `boolean` | `false` |
| `image` | `image` | The src for a custom user image. | `string` | `null` |
| `initials` | `initials` | The initials to display in the avatar when no image is provided. | `string` | `null` |
| `size` | `size` | Size of the avatar. Value can be preset or custom. | `string` | `'lg'` |
| `variant` | `variant` | Determines the variant of avatar. Changes appearance accordingly. | `"admin" \| "customer"` | `'customer'` |

Expand Down
15 changes: 15 additions & 0 deletions libs/core/src/components/pds-avatar/stories/pds-avatar.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export default {
componentId: null,
dropdown: false,
image: null,
initials: null,
size: null,
variant: 'customer',
},
Expand All @@ -22,6 +23,7 @@ const BaseTemplate = (args) => html`<pds-avatar
dropdown="${args.dropdown}"
component-id="${args.componentId}"
image="${args.image}"
initials="${args.initials}"
size="${args.size}"
variant="${args.variant}"
>
Expand Down Expand Up @@ -61,3 +63,16 @@ Image.args = {
image: imgFile,
size: 'xl'
}

export const Initials = BaseTemplate.bind();
Initials.args = {
initials: 'KJ',
size: 'lg'
}

export const InitialsWithBadge = BaseTemplate.bind();
InitialsWithBadge.args = {
badge: true,
initials: 'KJ',
size: 'lg'
}
53 changes: 53 additions & 0 deletions libs/core/src/components/pds-avatar/test/pds-avatar.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -185,4 +185,57 @@ describe('pds-avatar', () => {
`);
});

it('renders initials when prop is set', async () => {
const page = await newSpecPage({
components: [PdsAvatar],
html: `<pds-avatar initials="KJ"></pds-avatar>`,
});
expect(page.root).toEqualHtml(`
<pds-avatar class="pds-avatar pds-avatar--has-initials" initials="KJ" size="lg" variant="customer">
<mock:shadow-root>
<div part="asset-wrapper" style="height: 56px; width: 56px;">
<svg class="pds-avatar__initials" viewBox="0 0 32 32">
<text x="16" y="20">KJ</text>
</svg>
</div>
</mock:shadow-root>
</pds-avatar>
`);
});

it('renders image over initials when both are provided', async () => {
const page = await newSpecPage({
components: [PdsAvatar],
html: `<pds-avatar image="https://placehold.co/64x64" initials="KJ"></pds-avatar>`,
});
expect(page.root).toEqualHtml(`
<pds-avatar class="pds-avatar pds-avatar--has-image pds-avatar--has-initials" image="https://placehold.co/64x64" initials="KJ" size="lg" variant="customer">
<mock:shadow-root>
<div part="asset-wrapper" style="height: 56px; width: 56px;">
<img src="https://placehold.co/64x64"/>
</div>
</mock:shadow-root>
</pds-avatar>
`);
});

it('renders initials with badge when both props are set', async () => {
const page = await newSpecPage({
components: [PdsAvatar],
html: `<pds-avatar initials="KJ" badge="true"></pds-avatar>`,
});
expect(page.root).toEqualHtml(`
<pds-avatar class="pds-avatar pds-avatar--has-initials" initials="KJ" badge="true" size="lg" variant="customer">
<mock:shadow-root>
<div part="asset-wrapper" style="height: 56px; width: 56px;">
<svg class="pds-avatar__initials" viewBox="0 0 32 32">
<text x="16" y="20">KJ</text>
</svg>
<pds-icon class="pds-avatar__badge" color="var(--pine-color-purple-600)" icon="${checkCircleFilled}" size="33.53%"></pds-icon>
</div>
</mock:shadow-root>
</pds-avatar>
`);
});

});
Loading