Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<script setup lang="ts">
const getOverflowTooltip = (hiddenCount: number) => `${hiddenCount} more teammates`
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟑 Minor

Pluralize the tooltip label for the single-hidden-avatar case.

With the current example data, this renders 1 more teammates.

Suggested copy fix
-const getOverflowTooltip = (hiddenCount: number) => `${hiddenCount} more teammates`
+const getOverflowTooltip = (hiddenCount: number) => `${hiddenCount} more teammate${hiddenCount === 1 ? '' : 's'}`
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const getOverflowTooltip = (hiddenCount: number) => `${hiddenCount} more teammates`
const getOverflowTooltip = (hiddenCount: number) => `${hiddenCount} more teammate${hiddenCount === 1 ? '' : 's'}`
πŸ€– Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@docs/app/components/content/examples/avatar-group/AvatarGroupOverflowTooltipExample.vue`
at line 2, The tooltip string returned by getOverflowTooltip always uses the
plural "teammates", causing "1 more teammates" for a single hidden avatar;
update getOverflowTooltip to return a singular label when hiddenCount is 1
(e.g., "1 more teammate") and the plural for all other counts (e.g., "{n} more
teammates") so the tooltip grammatically matches the count.

</script>

<template>
<UAvatarGroup :max="2">
<UAvatar
src="https://github.com/benjamincanac.png"
alt="Benjamin Canac"
loading="lazy"
/>

<UAvatar
src="https://github.com/romhml.png"
alt="Romain Hamel"
loading="lazy"
/>

<UAvatar
src="https://github.com/noook.png"
alt="Neil Richter"
loading="lazy"
/>

<template #overflow="{ hiddenCount, avatarProps }">
<UTooltip :text="getOverflowTooltip(hiddenCount)">
<UAvatar v-bind="avatarProps" />
</UTooltip>
</template>
</UAvatarGroup>
</template>
6 changes: 6 additions & 0 deletions docs/content/docs/2.components/avatar-group.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@ slots:
:u-avatar{src="https://github.com/noook.png" alt="Neil Richter" loading="lazy"}
::

### Overflow tooltip
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟑 Minor

Add the unreleased-feature badge to this new docs heading.

This section documents a new slot API, so the heading should carry the Soon badge until the feature ships in the next npm release.

Suggested docs fix
-### Overflow tooltip
+### Overflow tooltip :badge{label="Soon" class="align-text-top"}

As per coding guidelines, docs/**/*.md: Add :badge{label="Soon" class="align-text-top"} to docs headings when introducing new features or fixes, as the docs deploy on merge but features ship on next npm release.

πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
### Overflow tooltip
### Overflow tooltip :badge{label="Soon" class="align-text-top"}
πŸ€– Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/content/docs/2.components/avatar-group.md` at line 72, Update the new
docs heading "### Overflow tooltip" to include the unreleased-feature badge by
appending :badge{label="Soon" class="align-text-top"} to that heading so it
reads "### Overflow tooltip :badge{label=\"Soon\" class=\"align-text-top\"}" in
docs/content/docs/2.components/avatar-group.md.


Use the `overflow` slot to customize the `+X` avatar. The slot receives the hidden count and the default avatar props, so you can wrap the overflow avatar with a [Tooltip](/docs/components/tooltip) and provide either a static string or a helper function that derives the label from the count.

:component-example{name="avatar-group-overflow-tooltip-example"}

## Examples

### With tooltip
Expand Down
10 changes: 9 additions & 1 deletion src/runtime/components/AvatarGroup.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export interface AvatarGroupProps {

export interface AvatarGroupSlots {
default?(props?: {}): VNode[]
overflow?(props: { hiddenCount: number, avatarProps: { text: string, class: any } }): VNode[]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟑 Minor

Expose the overflow slot marker through avatarProps.

The fallback overflow avatar is still marked as data-slot="base", so consumers/tests can’t distinguish the new overflow content when using the provided avatarProps. Consider carrying the marker in avatarProps so both the default fallback and custom slot examples keep the same identifier.

Proposed fix
-  overflow?(props: { hiddenCount: number, avatarProps: { text: string, class: any } }): VNode[]
+  overflow?(props: { hiddenCount: number, avatarProps: { text: string, class: any, 'data-slot': string } }): VNode[]
 const overflowAvatarProps = computed(() => ({
   text: `+${hiddenCount.value}`,
-  class: ui.value.base({ class: uiProp.value?.base })
+  class: ui.value.base({ class: uiProp.value?.base }),
+  'data-slot': 'overflow'
 }))
     <slot v-if="hiddenCount > 0" name="overflow" :hidden-count="hiddenCount" :avatar-props="overflowAvatarProps">
-      <UAvatar v-bind="overflowAvatarProps" data-slot="base" />
+      <UAvatar v-bind="overflowAvatarProps" />
     </slot>

As per coding guidelines, src/runtime/components/**/*.vue: β€œAdd data-slot="name" attributes on all template elements to identify slot content”.

Also applies to: 94-108

πŸ€– Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/runtime/components/AvatarGroup.vue` at line 29, The overflow fallback
avatar is still tagged as data-slot="base" and the overflow slot marker must be
carried through avatarProps so consumers/tests can identify overflow content;
update the overflow slot signature (the overflow?(props: { hiddenCount: number,
avatarProps: { text: string, class: any } }): VNode[] type) and the code that
builds/passes avatarProps in AvatarGroup.vue so that avatarProps includes the
data-slot attribute (e.g., data-slot="overflow") and ensure the default fallback
avatar element binds that avatarProps, and also apply the same change for the
other overflow usage block around the ~94-108 region so both default and custom
slot renderings expose the same data-slot marker.

}
</script>

Expand Down Expand Up @@ -90,14 +91,21 @@ const hiddenCount = computed(() => {
return children.value.length - visibleAvatars.value.length
})

const overflowAvatarProps = computed(() => ({
text: `+${hiddenCount.value}`,
class: ui.value.base({ class: uiProp.value?.base })
}))

provide(avatarGroupInjectionKey, computed(() => ({
size: props.size
})))
</script>

<template>
<Primitive :as="as" data-slot="root" :class="ui.root({ class: [uiProp?.root, props.class] })">
<UAvatar v-if="hiddenCount > 0" :text="`+${hiddenCount}`" data-slot="base" :class="ui.base({ class: uiProp?.base })" />
<slot v-if="hiddenCount > 0" name="overflow" :hidden-count="hiddenCount" :avatar-props="overflowAvatarProps">
<UAvatar v-bind="overflowAvatarProps" data-slot="base" />
</slot>
<component :is="avatar" v-for="(avatar, count) in visibleAvatars" :key="count" data-slot="base" :class="ui.base({ class: uiProp?.base })" />
</Primitive>
</template>
23 changes: 23 additions & 0 deletions test/components/AvatarGroup.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,23 @@ const AvatarGroupWrapper = defineComponent({
</UAvatarGroup>`
})

const AvatarGroupOverflowTooltipWrapper = defineComponent({
components: {
UAvatar: Avatar,
UAvatarGroup: AvatarGroup
},
template: `<UAvatarGroup :max="2">
<UAvatar src="https://github.com/benjamincanac.png" alt="Benjamin Canac" />
<UAvatar src="https://github.com/romhml.png" alt="Romain Hamel" />
<UAvatar src="https://github.com/noook.png" alt="Neil Richter" />
<template #overflow="{ hiddenCount, avatarProps }">
<span :data-hidden-count="hiddenCount">
<UAvatar v-bind="avatarProps" />
</span>
</template>
</UAvatarGroup>`
})

describe('AvatarGroup', () => {
const sizes = Object.keys(theme.variants.size) as any

Expand All @@ -33,6 +50,12 @@ describe('AvatarGroup', () => {
['with default slot', {}]
])

it('exposes the hidden count to the overflow slot', async () => {
const wrapper = await mountSuspended(AvatarGroupOverflowTooltipWrapper)

expect(wrapper.find('[data-hidden-count="1"]').exists()).toBe(true)
})

it('passes accessibility tests', async () => {
const wrapper = await mountSuspended(AvatarGroupWrapper, {
props: {
Expand Down
Loading