@fluentui/react-avatar 0.0.0-nightlyfc5cfdc52420220215.1 → 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/CHANGELOG.json +794 -13
  2. package/CHANGELOG.md +324 -133
  3. package/MIGRATION.md +71 -66
  4. package/SPEC-AvatarGroup.md +185 -0
  5. package/SPEC.md +160 -135
  6. package/dist/index.d.ts +306 -0
  7. package/{lib → dist}/tsdoc-metadata.json +0 -0
  8. package/lib/Avatar.js.map +1 -1
  9. package/lib/AvatarGroup.js +2 -0
  10. package/lib/AvatarGroup.js.map +1 -0
  11. package/lib/AvatarGroupItem.js +2 -0
  12. package/lib/AvatarGroupItem.js.map +1 -0
  13. package/lib/components/Avatar/Avatar.js.map +1 -1
  14. package/lib/components/Avatar/Avatar.types.js.map +1 -1
  15. package/lib/components/Avatar/index.js.map +1 -1
  16. package/lib/components/Avatar/renderAvatar.js.map +1 -1
  17. package/lib/components/Avatar/useAvatar.js +7 -10
  18. package/lib/components/Avatar/useAvatar.js.map +1 -1
  19. package/lib/components/Avatar/useAvatarStyles.js +89 -74
  20. package/lib/components/Avatar/useAvatarStyles.js.map +1 -1
  21. package/lib/components/AvatarGroup/AvatarGroup.js +16 -0
  22. package/lib/components/AvatarGroup/AvatarGroup.js.map +1 -0
  23. package/lib/components/AvatarGroup/AvatarGroup.types.js +2 -0
  24. package/lib/components/AvatarGroup/AvatarGroup.types.js.map +1 -0
  25. package/lib/components/AvatarGroup/index.js +6 -0
  26. package/lib/components/AvatarGroup/index.js.map +1 -0
  27. package/lib/components/AvatarGroup/renderAvatarGroup.js +43 -0
  28. package/lib/components/AvatarGroup/renderAvatarGroup.js.map +1 -0
  29. package/lib/components/AvatarGroup/useAvatarGroup.js +91 -0
  30. package/lib/components/AvatarGroup/useAvatarGroup.js.map +1 -0
  31. package/lib/components/AvatarGroup/useAvatarGroupStyles.js +296 -0
  32. package/lib/components/AvatarGroup/useAvatarGroupStyles.js.map +1 -0
  33. package/lib/components/AvatarGroupItem/AvatarGroupItem.js +16 -0
  34. package/lib/components/AvatarGroupItem/AvatarGroupItem.js.map +1 -0
  35. package/lib/components/AvatarGroupItem/AvatarGroupItem.types.js +2 -0
  36. package/lib/components/AvatarGroupItem/AvatarGroupItem.types.js.map +1 -0
  37. package/lib/components/AvatarGroupItem/index.js +6 -0
  38. package/lib/components/AvatarGroupItem/index.js.map +1 -0
  39. package/lib/components/AvatarGroupItem/renderAvatarGroupItem.js +17 -0
  40. package/lib/components/AvatarGroupItem/renderAvatarGroupItem.js.map +1 -0
  41. package/lib/components/AvatarGroupItem/useAvatarGroupItem.js +70 -0
  42. package/lib/components/AvatarGroupItem/useAvatarGroupItem.js.map +1 -0
  43. package/lib/components/AvatarGroupItem/useAvatarGroupItemStyles.js +356 -0
  44. package/lib/components/AvatarGroupItem/useAvatarGroupItemStyles.js.map +1 -0
  45. package/lib/contexts/AvatarGroupContext.js +7 -0
  46. package/lib/contexts/AvatarGroupContext.js.map +1 -0
  47. package/lib/contexts/AvatarGroupContext.types.js +2 -0
  48. package/lib/contexts/AvatarGroupContext.types.js.map +1 -0
  49. package/lib/contexts/index.js +2 -0
  50. package/lib/contexts/index.js.map +1 -0
  51. package/lib/index.js +4 -2
  52. package/lib/index.js.map +1 -1
  53. package/lib/utils/getInitials.js +16 -12
  54. package/lib/utils/getInitials.js.map +1 -1
  55. package/lib/utils/index.js.map +1 -1
  56. package/lib-commonjs/Avatar.js.map +1 -1
  57. package/lib-commonjs/AvatarGroup.js +10 -0
  58. package/lib-commonjs/AvatarGroup.js.map +1 -0
  59. package/lib-commonjs/AvatarGroupItem.js +10 -0
  60. package/lib-commonjs/AvatarGroupItem.js.map +1 -0
  61. package/lib-commonjs/components/Avatar/Avatar.js.map +1 -1
  62. package/lib-commonjs/components/Avatar/Avatar.types.js.map +1 -1
  63. package/lib-commonjs/components/Avatar/index.js.map +1 -1
  64. package/lib-commonjs/components/Avatar/renderAvatar.js.map +1 -1
  65. package/lib-commonjs/components/Avatar/useAvatar.js +7 -10
  66. package/lib-commonjs/components/Avatar/useAvatar.js.map +1 -1
  67. package/lib-commonjs/components/Avatar/useAvatarStyles.js +91 -76
  68. package/lib-commonjs/components/Avatar/useAvatarStyles.js.map +1 -1
  69. package/lib-commonjs/components/AvatarGroup/AvatarGroup.js +27 -0
  70. package/lib-commonjs/components/AvatarGroup/AvatarGroup.js.map +1 -0
  71. package/lib-commonjs/components/AvatarGroup/AvatarGroup.types.js +6 -0
  72. package/lib-commonjs/components/AvatarGroup/AvatarGroup.types.js.map +1 -0
  73. package/lib-commonjs/components/AvatarGroup/index.js +18 -0
  74. package/lib-commonjs/components/AvatarGroup/index.js.map +1 -0
  75. package/lib-commonjs/components/AvatarGroup/renderAvatarGroup.js +57 -0
  76. package/lib-commonjs/components/AvatarGroup/renderAvatarGroup.js.map +1 -0
  77. package/lib-commonjs/components/AvatarGroup/useAvatarGroup.js +105 -0
  78. package/lib-commonjs/components/AvatarGroup/useAvatarGroup.js.map +1 -0
  79. package/lib-commonjs/components/AvatarGroup/useAvatarGroupStyles.js +310 -0
  80. package/lib-commonjs/components/AvatarGroup/useAvatarGroupStyles.js.map +1 -0
  81. package/lib-commonjs/components/AvatarGroupItem/AvatarGroupItem.js +27 -0
  82. package/lib-commonjs/components/AvatarGroupItem/AvatarGroupItem.js.map +1 -0
  83. package/lib-commonjs/components/AvatarGroupItem/AvatarGroupItem.types.js +6 -0
  84. package/lib-commonjs/components/AvatarGroupItem/AvatarGroupItem.types.js.map +1 -0
  85. package/lib-commonjs/components/AvatarGroupItem/index.js +18 -0
  86. package/lib-commonjs/components/AvatarGroupItem/index.js.map +1 -0
  87. package/lib-commonjs/components/AvatarGroupItem/renderAvatarGroupItem.js +28 -0
  88. package/lib-commonjs/components/AvatarGroupItem/renderAvatarGroupItem.js.map +1 -0
  89. package/lib-commonjs/components/AvatarGroupItem/useAvatarGroupItem.js +84 -0
  90. package/lib-commonjs/components/AvatarGroupItem/useAvatarGroupItem.js.map +1 -0
  91. package/lib-commonjs/components/AvatarGroupItem/useAvatarGroupItemStyles.js +370 -0
  92. package/lib-commonjs/components/AvatarGroupItem/useAvatarGroupItemStyles.js.map +1 -0
  93. package/lib-commonjs/contexts/AvatarGroupContext.js +15 -0
  94. package/lib-commonjs/contexts/AvatarGroupContext.js.map +1 -0
  95. package/lib-commonjs/contexts/AvatarGroupContext.types.js +6 -0
  96. package/lib-commonjs/contexts/AvatarGroupContext.types.js.map +1 -0
  97. package/lib-commonjs/contexts/index.js +10 -0
  98. package/lib-commonjs/contexts/index.js.map +1 -0
  99. package/lib-commonjs/index.js +106 -3
  100. package/lib-commonjs/index.js.map +1 -1
  101. package/lib-commonjs/utils/getInitials.js +16 -12
  102. package/lib-commonjs/utils/getInitials.js.map +1 -1
  103. package/lib-commonjs/utils/index.js.map +1 -1
  104. package/package.json +26 -25
  105. package/dist/react-avatar.d.ts +0 -142
  106. package/lib/Avatar.d.ts +0 -1
  107. package/lib/components/Avatar/Avatar.d.ts +0 -3
  108. package/lib/components/Avatar/Avatar.types.d.ts +0 -107
  109. package/lib/components/Avatar/index.d.ts +0 -5
  110. package/lib/components/Avatar/renderAvatar.d.ts +0 -2
  111. package/lib/components/Avatar/useAvatar.d.ts +0 -3
  112. package/lib/components/Avatar/useAvatarStyles.d.ts +0 -3
  113. package/lib/index.d.ts +0 -2
  114. package/lib/utils/getInitials.d.ts +0 -14
  115. package/lib/utils/index.d.ts +0 -1
  116. package/lib-commonjs/Avatar.d.ts +0 -1
  117. package/lib-commonjs/components/Avatar/Avatar.d.ts +0 -3
  118. package/lib-commonjs/components/Avatar/Avatar.types.d.ts +0 -107
  119. package/lib-commonjs/components/Avatar/index.d.ts +0 -5
  120. package/lib-commonjs/components/Avatar/renderAvatar.d.ts +0 -2
  121. package/lib-commonjs/components/Avatar/useAvatar.d.ts +0 -3
  122. package/lib-commonjs/components/Avatar/useAvatarStyles.d.ts +0 -3
  123. package/lib-commonjs/index.d.ts +0 -2
  124. package/lib-commonjs/utils/getInitials.d.ts +0 -14
  125. package/lib-commonjs/utils/index.d.ts +0 -1
package/MIGRATION.md CHANGED
@@ -1,19 +1,15 @@
1
1
  # Avatar Migration
2
2
 
3
- ## STATUS: WIP 🚧
4
-
5
- This Migration guide is a work in progress and is not yet ready for use.
6
-
7
3
  ## Migration from v8
8
4
 
9
- The existing `Persona` control supports many more props than the `Avatar` control: notably the extra display text to the side of the image. As such, Avatar is only a direct replacement for Persona in cases where it was only being used to display the image (`hidePersonaDetails` is true). There is a plan to create a wrapper component EntityLayout (final name TBD) that supports placing text next to an Avatar, which is still being designed.
5
+ The existing `Persona` control supports many more props than the `Avatar` control: notably the extra display text to the side of the image. As such, Avatar is only a direct replacement for `Persona` in cases where it was only being used to display the image (`hidePersonaDetails` is true). To fully replace `Persona`, `Avatar` needs to be used in conjunction with another component that displays additional content.
10
6
 
11
7
  In cases where migration is possible, the following props will need to be renamed:
12
8
 
13
9
  - `text` => `name`
14
10
  - `size` converted from an enum to a number, and not all previous sizes are supported:
15
- - `PersonaSize.size8` => Not Supported. Use the `Badge` component since this size of Persona only displays the badge.
16
- - `PersonaSize.size16` => Not Supported. Can use `size={20} tokens={{ width: '16px', height: '16px' }}`
11
+ - `PersonaSize.size8` => Not Supported. Use the `PresenceBadge` component since this size of Persona only displays the badge.
12
+ - `PersonaSize.size16` => Not Supported. Use `size={20}`, and optionally add `style={{ width: '16px', height: '16px' }}` if the exact size is needed.
17
13
  - `PersonaSize.size24` => `size={24}`
18
14
  - `PersonaSize.size28` => `size={28}`
19
15
  - `PersonaSize.size32` => `size={32}`
@@ -21,31 +17,38 @@ In cases where migration is possible, the following props will need to be rename
21
17
  - `PersonaSize.size48` => `size={48}`
22
18
  - `PersonaSize.size56` => `size={56}`
23
19
  - `PersonaSize.size72` => `size={72}`
24
- - `PersonaSize.size100` => Not Supported. Can use `size={96} tokens={{ width: '100px', height: '100px' }}`
20
+ - `PersonaSize.size100` => Not Supported. Use `size={96}`, and optionally add `style={{ width: '100px', height: '100px' }}` if the exact size is needed.
25
21
  - `PersonaSize.size120` => `size={120}`
26
22
  - `coinSize` => Use `size`
27
- - `imageUrl` => `image`
28
- - `imageAlt` => Set `alt` on the `image` slot
29
- - `imageInitials` => `label` (or remove and have it calculated from `name`)
30
- - `presence` => Use the `Badge` component
31
- - `presenceColors` => Use the `Badge` component
32
- - `presenceTitle` => Use the `Badge` component
33
- - `isOutOfOffice` => Use the `Badge` component
34
- - `showUnknownPersonaCoin` => NOT SUPPORTED - Set the `icon` prop to an appropriate icon
35
- - `initialsColor` => Use `color="colorful"` or specify a color by name like `color="darkRed"`
36
- - `showInitialsUntilImageLoad` => (This is the normal behavior of Avatar)
37
- - `imageShouldFadeIn` => NOT SUPPORTED
38
- - `imageShouldStartVisible` => NOT SUPPORTED
39
- - `onPhotoLoadingStateChange` => NOT SUPPORTED
40
- - `onRender*` => NOT SUPPORTED - add custom components to the slots instead of overriding the rendering
41
- - (Or to render a square image, use the `shape='square` prop)
23
+ - `imageUrl` => `image={{ src: '...' }}`
24
+ - `imageAlt` => The Avatar's `aria-label` can be used.
25
+ - `imageInitials` => `initials`
26
+ - `presence` => `badge` (see the `PresenceBadge` component for more details)
27
+ - `PersonaPresence.none` => (Default)
28
+ - `PersonaPresence.away` => `badge={{ status: 'away' }}`
29
+ - `PersonaPresence.blocked` => Not Supported.
30
+ - `PersonaPresence.busy` => `badge={{ status: 'busy' }}`
31
+ - `PersonaPresence.dnd` => `badge={{ status: 'doNotDisturb' }}`
32
+ - `PersonaPresence.offline` => `badge={{ status: 'offline' }}`
33
+ - `PersonaPresence.online` => `badge={{ status: 'available' }}`
34
+ - `presenceColors` => Not Supported. However, the badge can be styled using CSS. E.g. `badge={{ style: { color: '...' } }}`
35
+ - `presenceTitle` => Not Supported.
36
+ - `isOutOfOffice` => `badge={{ status: ..., outOfOffice: true }}`
37
+ - `showUnknownPersonaCoin` => Not Supported. An approximation is: `icon={<QuestionRegular />}`
38
+ - `initialsColor` => `color="colorful"`, or specify a color by name like `color="darkRed"`
39
+ - `showInitialsUntilImageLoad` => Not Supported. This is always true for `Avatar`.
40
+ - `imageShouldFadeIn` => Not Supported. Add a CSS class to the image if desired: `image={{ className: 'myFadeInClass' }}`
41
+ - `imageShouldStartVisible` => Not Supported. This is always true for `Avatar`.
42
+ - `onPhotoLoadingStateChange` => Add event listeners to the image slot for the `<img>` events: `image={{ onLoad: ..., onError: ... }}`
43
+ - `onRender*` => Avatar's slots allow render functions, such as `image={(Component, props) => <Component {...props} />}`
44
+ - To render a square image, use `shape="square"`.
42
45
 
43
46
  ## Migration from v0
44
47
 
45
48
  The v0 Avatar maps more closely to the converged Avatar.
46
49
 
47
- - `variables` => Replaced by `tokens`
48
- - `design` => Replaced by `tokens`
50
+ - `variables` => Replaced by theme
51
+ - `design` => Replaced by theme
49
52
  - `accessibility` => Not needed
50
53
  - `size` is converted from `SizeValue` to a number:
51
54
  - `size="smallest"` => `size={20}`
@@ -55,47 +58,49 @@ The v0 Avatar maps more closely to the converged Avatar.
55
58
  - `size="large"` => `size={44}`
56
59
  - `size="larger"` => `size={64}`
57
60
  - `size="largest"` => `size={96}`
61
+ - `getInitials` => Set the initials directly: `initials={getInitials(name)}`
62
+ - `as` => Only allows `as="span"` (which is the default)
58
63
 
59
64
  ## Property mapping
60
65
 
61
- | v8 `Persona` | v0 `Avatar` | Converged `Avatar` |
62
- | -------------------------- | ---------------- | ------------------ |
63
- | text | name | name |
64
- | size (PersonaSize enum) | size (SizeValue) | size (number) |
65
- | coinSize | - | - |
66
- | imageUrl | image (slot) | image (slot) |
67
- | imageAlt | - | - |
68
- | imageInitials | label (slot) | label (slot) |
69
- | - | getInitials | getInitials |
70
- | presence | status (slot) | badge (slot) |
71
- | presenceColors | - | - |
72
- | presenceTitle | - | - |
73
- | initialsColor | - | color |
74
- | | - | idForColor |
75
- | - | icon (slot) | icon (slot) |
76
- | showUnknownPersonaCoin | - | - |
77
- | className | className | className |
78
- | - | square | shape |
79
- | - | - | active |
80
- | - | - | activeAppearance |
81
- | - | styles | (tokens) |
82
- | - | variables | (tokens) |
83
- | - | design | (tokens) |
84
- | - | accessibility | - |
85
- | - | as | as |
86
- | secondaryText | - | - |
87
- | showSecondaryText | - | - |
88
- | tertiaryText | - | - |
89
- | optionalText | - | - |
90
- | isOutOfOffice | - | - |
91
- | hidePersonaDetails | - | - |
92
- | showInitialsUntilImageLoad | - | - |
93
- | imageShouldFadeIn | - | - |
94
- | imageShouldStartVisible | - | - |
95
- | onPhotoLoadingStateChange | - | - |
96
- | onRenderInitials | - | - |
97
- | onRenderPersonaCoin | - | - |
98
- | onRenderPrimaryText | - | - |
99
- | onRenderSecondaryText | - | - |
100
- | onRenderTertiaryText | - | - |
101
- | onRenderOptionalText | - | - |
66
+ | v8 `Persona` | v0 `Avatar` | v9 `Avatar` |
67
+ | ---------------------------- | ------------------ | --------------------------------------- |
68
+ | `text` | `name` | `name` |
69
+ | `size` (PersonaSize enum) | `size` (SizeValue) | `size` (number) |
70
+ | `coinSize` | - | - |
71
+ | `imageUrl` | `image` (slot) | `src` prop of the `image` slot |
72
+ | `imageAlt` | - | `aria-label` |
73
+ | `imageInitials` | `label` (slot) | `initials` (slot) |
74
+ | - | `getInitials` | - |
75
+ | `presence` | `status` (slot) | `badge` (slot) |
76
+ | `presenceColors` | - | - |
77
+ | `presenceTitle` | - | - |
78
+ | `initialsColor` | - | `color` |
79
+ | | - | `idForColor` |
80
+ | - | `icon` (slot) | `icon` (slot) |
81
+ | `showUnknownPersonaCoin` | - | - |
82
+ | `className` | `className` | `className` |
83
+ | - | `square` | `shape` |
84
+ | - | - | `active` |
85
+ | - | - | `activeAppearance` |
86
+ | - | `styles` | (theme) |
87
+ | - | `variables` | (theme) |
88
+ | - | `design` | (theme) |
89
+ | - | `accessibility` | - |
90
+ | - | `as` | - |
91
+ | `secondaryText` | - | - |
92
+ | `showSecondaryText` | - | - |
93
+ | `tertiaryText` | - | - |
94
+ | `optionalText` | - | - |
95
+ | `isOutOfOffice` | - | `outOfOffice` prop of the `badge` slot |
96
+ | `hidePersonaDetails` | - | - |
97
+ | `showInitialsUntilImageLoad` | - | - |
98
+ | `imageShouldFadeIn` | - | - |
99
+ | `imageShouldStartVisible` | - | - |
100
+ | `onPhotoLoadingStateChange` | - | `image={{ onLoad: ..., onError: ... }}` |
101
+ | `onRenderInitials` | - | Render function for the `initials` slot |
102
+ | `onRenderPersonaCoin` | - | Render function for the Avatar |
103
+ | `onRenderPrimaryText` | - | - |
104
+ | `onRenderSecondaryText` | - | - |
105
+ | `onRenderTertiaryText` | - | - |
106
+ | `onRenderOptionalText` | - | - |
@@ -0,0 +1,185 @@
1
+ # AvatarGroup Spec
2
+
3
+ ## Background
4
+
5
+ AvatarGroup represents a group of multiple people or entities by taking care of the arrangement of individual Avatars in a spread, stack, or pie layout.
6
+
7
+ ## Prior Art
8
+
9
+ ### OpenUI
10
+
11
+ There's no current research in OpenUI's website.
12
+
13
+ | Library | Name | Notes |
14
+ | ------------------------------------------------------------------------------------- | ------------ | --------------------------------------------------------------------------------------------- |
15
+ | [Fluent UI v8](https://developer.microsoft.com/en-us/fluentui#/controls/web/facepile) | Facepile | Receives list of `IFacepilePersona` to represent each avatar. |
16
+ | [Attlassian](https://atlassian.design/components/avatar-group/examples) | Avatar group | Component uses data prop, which is a list of "entries" to represent each avatar in the group. |
17
+ | [Ant Design](https://ant.design/components/avatar/) | Avatar.Group | Uses subcomponent `<Avatar.Group>` to group the avatars given as children. |
18
+ | [Primer React](https://primer.style/react/AvatarStack) | AvatarStack | Acts similar to a FlexBox, avatars are given as children and grouped. |
19
+
20
+ ### Comparison v8 and v0
21
+
22
+ There's only one existent component similar to AvatarGroup in v8 `Facepile`. v0 doesn't have an equivalent of this component.
23
+
24
+ - v8 [Facepile](https://developer.microsoft.com/en-us/fluentui#/controls/web/facepile): Only offers spread layout and offers three overflow indicator styles.
25
+
26
+ ## Epic issue: [#22240](https://github.com/microsoft/fluentui/issues/22240)
27
+
28
+ ## Sample Code
29
+
30
+ ```jsx
31
+ import { AvatarGroup, Avatar } from '@fluentui/react-avatar';
32
+
33
+ const App = () => {
34
+ return (
35
+ <AvatarGroup layout="spread" size={32}>
36
+ <Avatar color="colorful" name="Katri Athokas" />
37
+ <Avatar color="colorful" name="Elvia Atkins" />
38
+ <Avatar color="colorful" name="Cameron Evans" />
39
+ <Avatar color="colorful" name="Wanda Howard" />
40
+ <Avatar color="colorful" name="Mona Kane" />
41
+ </AvatarGroup>
42
+ );
43
+ };
44
+ ```
45
+
46
+ ## Variants
47
+
48
+ There are three layout variants in AvatarGroup:
49
+
50
+ - Spread layout (Default): Avatars are spaced evenly.
51
+ - Stack layout: Avatars are overlapped evenly.
52
+ - Pie layout: For the pie layout there can be a minimum of two Avatars and a maximum of three. This layout does not overflow and provides a popover for more details.
53
+
54
+ - If the size of the avatar group is `36` or smaller then only the first letter of the initials will be displayed.
55
+ - `maxAvatars` will be ignored when using this layout.
56
+
57
+ - The `spread` and `stack` layouts have a maximum of 5 avatars before overflowing by default, which can be overridden via the `maxAvatars` prop.
58
+
59
+ ## API
60
+
61
+ See [AvatarGroup.types.ts](./src/components/AvatarGroup/AvatarGroup.types.ts) for more details.
62
+
63
+ - `size`: Group size will override the children's current size. This is to ensure that the `AvatarGroup`'s spacing is correct because it changes depending on the group size.
64
+ - `popoverSurface`: All Avatars in `popoverSurface` will have a size of 24 and will be encased in a div to apply stylings.
65
+ - Avatar `color`: AvatarGroup's colors will follow the order below, but they can be overriden by providing a color specific color on a given avatar.
66
+
67
+ #### Color override example:
68
+
69
+ In this example, the first Avatar will have a `darkRed` color, while all the other avatars will follow the default color order.
70
+
71
+ ```jsx
72
+ <AvatarGroup>
73
+ <Avatar color="darkRed" name="Katri Athokas" />
74
+ <Avatar name="Elvia Atkins" />
75
+ <Avatar name="Cameron Evans" />
76
+ <Avatar name="Wanda Howard" />
77
+ <Avatar name="Mona Kane" />
78
+ </AvatarGroup>
79
+ ```
80
+
81
+ #### Color order:
82
+
83
+ | | | |
84
+ | --------------------- | ------------------ | --------------------- |
85
+ | Avatar 1: Red | Avatar 2: Blue | Avatar 3: Purple |
86
+ | Avatar 4: Forest | Avatar 5: Pink | Avatar 6: Lavender |
87
+ | Avatar 7: Teal | Avatar 8: Gold | Avatar 9: Cranberry |
88
+ | Avatar 10: Cornflower | Avatar 11: Lilac | Avatar 12: Anchor |
89
+ | Avatar 13: Dark Green | Avatar 14: Pumpkin | Avatar 15: Dark Red |
90
+ | Avatar 16: Mink | Avatar 17: Grape | Avatar 18: Platinum |
91
+ | Avatar 19: Royal Blue | Avatar 20: Brown | Avatar 21: Peach |
92
+ | Avatar 22: Steel | Avatar 23: Navy | Avatar 24: Seafoam |
93
+ | Avatar 25: Magenta | Avatar 26: Beige | Avatar 27: Light Teal |
94
+ | Avatar 28: Gold | Avatar 29: Plum | Avatar 30: Marigold |
95
+
96
+ ## Structure
97
+
98
+ - _**Public**_
99
+
100
+ ```jsx
101
+ <AvatarGroup layout="spread" size={32}>
102
+ <Avatar name="Katri Athokas" />
103
+ <Avatar name="Elvia Atkins" />
104
+ <Avatar name="Cameron Evans" />
105
+ <Avatar name="Wanda Howard" />
106
+ <Avatar name="Mona Kane" />
107
+ </AvatarGroup>
108
+ ```
109
+
110
+ - _**Internal**_
111
+
112
+ ```jsx
113
+ <slots.root {...slotProps.root}>
114
+ {state.root.children}
115
+ {slots.popoverSurface && slots.popoverTrigger && slotProps.popoverSurface.children && (
116
+ <Popover trapFocus size="small">
117
+ <PopoverTrigger>
118
+ <Tooltip content={state.tooltipContent} relationship="description" appearance="inverted">
119
+ <slots.popoverTrigger {...slotProps.popoverTrigger} />
120
+ </Tooltip>
121
+ </PopoverTrigger>
122
+ <slots.popoverSurface {...slotProps.popoverSurface} />
123
+ </Popover>
124
+ )}
125
+ </slots.root>
126
+ ```
127
+
128
+ - _**DOM** - how the component will be rendered as HTML elements_
129
+
130
+ ```html
131
+ <div className="fui-AvatarGroup" role="group">
132
+ <Avatar />
133
+ <Avatar />
134
+ <Avatar />
135
+ <Avatar />
136
+ <button>+1</button>
137
+ </div>
138
+
139
+ // on document.body
140
+ <div class="fui-AvatarGroup__popoverSurface" role="complementary">
141
+ <div class="fui-AvatarGroup__popoverSurfaceItem">
142
+ <Avatar />
143
+ <label />
144
+ </div>
145
+ <!-- ... -->
146
+ <div class="fui-AvatarGroup__popoverSurfaceItem">
147
+ <Avatar />
148
+ <label />
149
+ </div>
150
+ </div>
151
+ ```
152
+
153
+ ## Migration
154
+
155
+ See [MIGRATION-AvatarGroup.md](MIGRATION-AvatarGroup.md) for details.
156
+
157
+ ## Behaviors
158
+
159
+ _Explain how the component will behave in use, including:_
160
+
161
+ - _Component States_
162
+ - Overflowed state: When there are more Avatars than the `maxAvatars`, an overflow indicator will be rendered that can be clicked to look at the rest of the avatars.
163
+ - `Pie` layout: since `maxAvatars` is ignored, the overflow indicator will be rendered strictly when there's more than three avatars.
164
+ - _Interaction_
165
+ - _Keyboard_: Overflow indicator can be interacted with the keyboard and when enter is pressed a popover that traps focus will be rendered.
166
+ - _Cursor_ and _Touch_: When overflow indicator is clicked, the popover is displayed with the avatars that overflow. When the overflow indicator is hovered, a tooltip will read the number of people overflowed (`{numOverflowAvatars} more people` by default).
167
+ - _Screen readers_:
168
+ - `Avatar`: logic is handled by `Avatar` component.
169
+ - `AvatarGroup`:
170
+ - When a label is used alongside `AvatarGroup` and focused, all Avatars are read. If the overflow indicator is rendered, the popover localized text is read.
171
+ - Avatars can be focused and the name will be read. To get to the Avatars in the overflow menu, the Popover must be triggered, which will in turn set focus on it and let the user traverse through the set of overflowed Avatars.
172
+
173
+ ## Accessibility
174
+
175
+ Base accessibility information is included in the design document. After the spec is filled and reviewed, outcomes from it need to be communicated to design and incorporated in the design document.
176
+
177
+ - There's no native element for this component.
178
+
179
+ - `AvatarGroup` will have a role of `group` and slots will be handled by their respective slot type.
180
+ - Only the overflow indicator will be focusable by the keyboard. After the overflow indicator is pressed, the popover will handle focus using the `trapFocus` prop.
181
+ - There are no live-regions in `AvatarGroup`.
182
+ - A Tooltip will appear when the overflow indicator is hovered or focused.
183
+ - Screen reader: when overflow indicator is rendered and focused, screen reader will read the content of the tooltip.
184
+ - Tooltip cannot be focused itself.
185
+ - Focus will only be trapped when the overflow indicator is triggered.