Files
WRNexusJS/packages/ui/components/AvatarGroup.wrn
T
2026-07-29 12:51:10 +05:30

122 lines
3.8 KiB
Plaintext

component AvatarGroup {
props {
items = []
size = "md"
color = "primary"
variant = "solid"
shape = "circle"
layout = "stack"
maxVisible = 4
columns = 3
borderColor = ""
showTooltips = true
overflowLabel = "Show remaining members"
class = ""
@event overflow = function
}
state overflowOpen = false
functions {
function visibleMembers() {
return items.slice(0, Number(maxVisible))
}
function hiddenMembers() {
return items.slice(Number(maxVisible))
}
function toggleOverflow(sourceEvent, root, customEvent) {
overflowOpen = !overflowOpen
root = sourceEvent.currentTarget.closest("[data-wrn-avatar-group]")
customEvent = document.createEvent("CustomEvent")
customEvent.initCustomEvent("overflow", true, false, {
component: "AvatarGroup",
open: overflowOpen,
hiddenCount: hiddenMembers().length
})
root.dispatchEvent(customEvent)
}
}
view {
<div
{...attrs}
class="wire-next wire-next--avatar-group {class}"
data-wrn-avatar-group
data-layout="{layout}"
data-shape="{shape}"
data-size="{size}"
style="--wire-avatar-group-columns:{columns}; --wire-avatar-group-ring:{borderColor || 'var(--wire-color-bg)'}"
role="group"
aria-label="Avatar group"
>
<div class="wire-next__avatar-group-members">
{#each visibleMembers() as item}
<span
class="wire-next__avatar-group-member"
data-size="{item.size || size}"
data-shape="{item.shape || shape}"
data-color="{item.color || color}"
data-variant="{item.variant || variant}"
tabindex="{showTooltips && (item.tooltip || item.name) ? '0' : '-1'}"
aria-label="{item.name || item.alt || item.initials || 'Group member'}"
>
<span class="wire-next__avatar-group-avatar">
{#if item.src}
<img src="{item.src}" alt="{item.alt || item.name || ''}" loading="lazy" />
{:else if item.initials}
<span aria-hidden="true">{item.initials}</span>
{:else}
<span class="icon-[lucide--user-round]" aria-hidden="true"></span>
{/if}
</span>
{#if showTooltips && (item.tooltip || item.name)}
<span class="wire-next__avatar-group-tooltip" role="tooltip">
{item.tooltip || item.name}
</span>
{/if}
</span>
{/each}
{#if hiddenMembers().length > 0}
<span class="wire-next__avatar-group-overflow">
<button
type="button"
class="wire-next__avatar-group-overflow-button"
aria-label="{overflowLabel}"
aria-expanded="{overflowOpen ? 'true' : 'false'}"
@click="toggleOverflow(event)"
>
+{hiddenMembers().length}
</button>
<span
class="wire-next__avatar-group-menu"
role="menu"
data-show="overflowOpen"
aria-hidden="{overflowOpen ? 'false' : 'true'}"
>
{#each hiddenMembers() as item}
<span class="wire-next__avatar-group-menu-item" role="menuitem">
<span class="wire-next__avatar-group-menu-avatar">
{#if item.src}
<img src="{item.src}" alt="" loading="lazy" />
{:else}
<span>{item.initials || '?'}</span>
{/if}
</span>
<span>{item.name || item.alt || item.initials || 'Team member'}</span>
</span>
{/each}
</span>
</span>
{/if}
</div>
</div>
}
}