diff --git a/docs/examples/avatar/colorExample.tsx b/docs/examples/avatar/colorExample.tsx new file mode 100644 index 0000000000..35f48ea951 --- /dev/null +++ b/docs/examples/avatar/colorExample.tsx @@ -0,0 +1,35 @@ +import { Avatar, Box, Flex } from 'gestalt'; + +type Color = '01' | '02' | '03' | '04' | '05' | '06' | '07' | '08' | '09' | '10'; + +interface AvatarProps { + name: string; + color: Color; +} + +const avatars: AvatarProps[] = [ + { name: 'Alberto', color: '01' }, + { name: 'Andy', color: '02' }, + { name: 'Alexandra', color: '03' }, + { name: 'Alexi', color: '04' }, + { name: 'Alonso', color: '05' }, + { name: 'Arturo', color: '06' }, + { name: 'Amanda', color: '07' }, + { name: 'Angelina', color: '08' }, + { name: 'Adrian', color: '09' }, + { name: 'Amelia', color: '10' }, +]; + +export default function Example() { + return ( + + + {avatars.map(({ name, color }) => ( + + + + ))} + + + ); +} diff --git a/docs/examples/avatar/containerExample.tsx b/docs/examples/avatar/containerExample.tsx index d3a9a28c40..988f6a3a97 100644 --- a/docs/examples/avatar/containerExample.tsx +++ b/docs/examples/avatar/containerExample.tsx @@ -5,10 +5,10 @@ export default function Example() { - + - + diff --git a/docs/examples/avatar/ideasExample.tsx b/docs/examples/avatar/ideasExample.tsx index fe33b89fff..048d7cf630 100644 --- a/docs/examples/avatar/ideasExample.tsx +++ b/docs/examples/avatar/ideasExample.tsx @@ -1,10 +1,19 @@ -import { Avatar, Flex, Text } from 'gestalt'; +import { Avatar, Flex, Text, useDangerouslyInGestaltExperiment } from 'gestalt'; export default function Example() { + const isInVRExperiment = useDangerouslyInGestaltExperiment({ + webExperimentName: 'web_gestalt_visualRefresh', + mwebExperimentName: 'web_gestalt_visualRefresh', + }); + + const src = isInVRExperiment + ? 'https://i.pinimg.com/564x/b9/f0/56/b9f0561e2d7927fa427f2306a41bce11.jpg' + : 'https://i.ibb.co/jVR29XV/stock5.jpg'; + return ( - + Explore Typographic Art diff --git a/docs/examples/avatar/mainExample.tsx b/docs/examples/avatar/mainExample.tsx index afb4e0a8d5..3d0d807b0e 100644 --- a/docs/examples/avatar/mainExample.tsx +++ b/docs/examples/avatar/mainExample.tsx @@ -1,7 +1,39 @@ -import { Avatar, Flex } from 'gestalt'; +import { Avatar, Flex, useDangerouslyInGestaltExperiment } from 'gestalt'; export default function Example() { - return ( + const isInVRExperiment = useDangerouslyInGestaltExperiment({ + webExperimentName: 'web_gestalt_visualRefresh', + mwebExperimentName: 'web_gestalt_visualRefresh', + }); + + return isInVRExperiment ? ( + + + + + + + + ) : ( - + - + ); diff --git a/docs/examples/avatar/nameExample.tsx b/docs/examples/avatar/nameExample.tsx index 25884b486e..c102d7b773 100644 --- a/docs/examples/avatar/nameExample.tsx +++ b/docs/examples/avatar/nameExample.tsx @@ -1,6 +1,16 @@ -import { Avatar, Flex, Text } from 'gestalt'; +import { Avatar, Flex, Text, useDangerouslyInGestaltExperiment } from 'gestalt'; export default function Example() { + const isInVRExperiment = useDangerouslyInGestaltExperiment({ + webExperimentName: 'web_gestalt_visualRefresh', + mwebExperimentName: 'web_gestalt_visualRefresh', + }); + + const name = isInVRExperiment ? 'Ayesha Rashad' : 'Shanice Byles'; + const src = isInVRExperiment + ? 'https://i.pinimg.com/originals/c5/5c/ac/c55caca43a7c16766215ec165b649c1c.jpg' + : 'https://i.ibb.co/7tGKGvb/shanice.jpg'; + return ( - - Shanice Byles + + {name} ); } diff --git a/docs/examples/avatar/noEmojiExample.tsx b/docs/examples/avatar/noEmojiExample.tsx index aaa3c41662..768f0d1ffc 100644 --- a/docs/examples/avatar/noEmojiExample.tsx +++ b/docs/examples/avatar/noEmojiExample.tsx @@ -1,9 +1,18 @@ -import { Avatar, Flex } from 'gestalt'; +import { Avatar, Flex, useDangerouslyInGestaltExperiment } from 'gestalt'; export default function Example() { + const isInVRExperiment = useDangerouslyInGestaltExperiment({ + webExperimentName: 'web_gestalt_visualRefresh', + mwebExperimentName: 'web_gestalt_visualRefresh', + }); + return ( - + ); } diff --git a/docs/examples/avatar/noImageSourceExample.tsx b/docs/examples/avatar/noImageSourceExample.tsx index d4bae7a1fd..9956b0e9de 100644 --- a/docs/examples/avatar/noImageSourceExample.tsx +++ b/docs/examples/avatar/noImageSourceExample.tsx @@ -1,9 +1,18 @@ -import { Avatar, Flex } from 'gestalt'; +import { Avatar, Flex, useDangerouslyInGestaltExperiment } from 'gestalt'; export default function Example() { + const isInVRExperiment = useDangerouslyInGestaltExperiment({ + webExperimentName: 'web_gestalt_visualRefresh', + mwebExperimentName: 'web_gestalt_visualRefresh', + }); + return ( - + ); } diff --git a/docs/examples/avatar/overExample.tsx b/docs/examples/avatar/overExample.tsx index cb99691b9d..768899b427 100644 --- a/docs/examples/avatar/overExample.tsx +++ b/docs/examples/avatar/overExample.tsx @@ -1,11 +1,20 @@ -import { Avatar, Box, Flex, Mask, Text } from 'gestalt'; +import { Avatar, Box, Flex, Mask, Text, useDangerouslyInGestaltExperiment } from 'gestalt'; export default function Example() { + const isInVRExperiment = useDangerouslyInGestaltExperiment({ + webExperimentName: 'web_gestalt_visualRefresh', + mwebExperimentName: 'web_gestalt_visualRefresh', + }); + + const src = isInVRExperiment + ? 'https://i.pinimg.com/564x/8e/fb/f7/8efbf75008c34394104ef9568c038d2d.jpg' + : 'https://i.ibb.co/jVR29XV/stock5.jpg'; + return ( - + Explore Typographic Art diff --git a/docs/examples/avatar/personExample.tsx b/docs/examples/avatar/personExample.tsx index 9a29f0ca7d..61376e7b20 100644 --- a/docs/examples/avatar/personExample.tsx +++ b/docs/examples/avatar/personExample.tsx @@ -1,6 +1,17 @@ -import { Avatar, Flex, Text } from 'gestalt'; +import { Avatar, Flex, Text, useDangerouslyInGestaltExperiment } from 'gestalt'; export default function Example() { + const isInVRExperiment = useDangerouslyInGestaltExperiment({ + webExperimentName: 'web_gestalt_visualRefresh', + mwebExperimentName: 'web_gestalt_visualRefresh', + }); + + const firstName = isInVRExperiment ? 'Sora' : 'Keerthi'; + const fullName = isInVRExperiment ? 'Sora Suzuki' : 'Keerthi Singh'; + const src = isInVRExperiment + ? 'https://i.pinimg.com/originals/ab/c5/4a/abc54abd85df131e90ca6b372368b738.jpg' + : 'https://i.ibb.co/ZfCZrY8/keerthi.jpg'; + return ( - - Keerthi Singh + + {fullName} ); } diff --git a/docs/examples/avatar/shapeExample.tsx b/docs/examples/avatar/shapeExample.tsx index 3f62fa782a..9ea69deae6 100644 --- a/docs/examples/avatar/shapeExample.tsx +++ b/docs/examples/avatar/shapeExample.tsx @@ -1,17 +1,20 @@ -import { Flex, Image, Mask } from 'gestalt'; +import { Flex, Image, Mask, useDangerouslyInGestaltExperiment } from 'gestalt'; export default function Example() { + const isInVRExperiment = useDangerouslyInGestaltExperiment({ + webExperimentName: 'web_gestalt_visualRefresh', + mwebExperimentName: 'web_gestalt_visualRefresh', + }); + + const alt = isInVRExperiment ? 'Ayesha Avatar' : 'Keerthi Avatar'; + const src = isInVRExperiment + ? 'https://i.pinimg.com/originals/50/ce/c4/50cec4ca4c65131580c540c65548e0a3.jpg' + : 'https://i.ibb.co/ZfCZrY8/keerthi.jpg'; + return ( - Keerthi Avatar + {alt} ); diff --git a/docs/examples/avatar/sizingExample.tsx b/docs/examples/avatar/sizingExample.tsx index 3fe532897c..9f4e8be274 100644 --- a/docs/examples/avatar/sizingExample.tsx +++ b/docs/examples/avatar/sizingExample.tsx @@ -1,13 +1,23 @@ -import { Avatar, Flex } from 'gestalt'; +import { Avatar, Flex, useDangerouslyInGestaltExperiment } from 'gestalt'; export default function Example() { + const isInVRExperiment = useDangerouslyInGestaltExperiment({ + webExperimentName: 'web_gestalt_visualRefresh', + mwebExperimentName: 'web_gestalt_visualRefresh', + }); + + const name = isInVRExperiment ? 'Fatima' : 'Keerthi'; + const src = isInVRExperiment + ? 'https://i.pinimg.com/originals/bf/bc/27/bfbc27685d81eb9a8f65c201ea661f0e.jpg' + : 'https://i.ibb.co/ZfCZrY8/keerthi.jpg'; + return ( - - - - - + + + + + ); } diff --git a/docs/examples/avatar/verifiedExample.tsx b/docs/examples/avatar/verifiedExample.tsx index be1312aff7..473e2348a8 100644 --- a/docs/examples/avatar/verifiedExample.tsx +++ b/docs/examples/avatar/verifiedExample.tsx @@ -1,13 +1,23 @@ -import { Avatar, Flex } from 'gestalt'; +import { Avatar, Flex, useDangerouslyInGestaltExperiment } from 'gestalt'; export default function Example() { + const isInVRExperiment = useDangerouslyInGestaltExperiment({ + webExperimentName: 'web_gestalt_visualRefresh', + mwebExperimentName: 'web_gestalt_visualRefresh', + }); + + const name = isInVRExperiment ? 'Sora' : 'Shanice'; + const src = isInVRExperiment + ? 'https://i.pinimg.com/originals/ab/c5/4a/abc54abd85df131e90ca6b372368b738.jpg' + : 'https://i.ibb.co/7tGKGvb/shanice.jpg'; + return ( diff --git a/docs/examples/avatarGroup/accessibility.tsx b/docs/examples/avatarGroup/accessibility.tsx index 67f5cb9c66..d53ff65a62 100644 --- a/docs/examples/avatarGroup/accessibility.tsx +++ b/docs/examples/avatarGroup/accessibility.tsx @@ -1,5 +1,14 @@ import { useEffect, useRef, useState } from 'react'; -import { AvatarGroup, Box, Flex, Layer, Popover, SearchField, Text } from 'gestalt'; +import { + AvatarGroup, + Box, + Flex, + Layer, + Popover, + SearchField, + Text, + useDangerouslyInGestaltExperiment, +} from 'gestalt'; function SearchCollaboratorsField() { const ref = useRef(null); @@ -23,26 +32,88 @@ function SearchCollaboratorsField() { export default function Example() { const [open, setOpen] = useState(false); const anchorRef = useRef(null); + const isInVRExperiment = useDangerouslyInGestaltExperiment({ + webExperimentName: 'web_gestalt_visualRefresh', + mwebExperimentName: 'web_gestalt_visualRefresh', + }); - return ( + const collaborators = [ + { + name: 'Keerthi', + src: 'https://i.ibb.co/ZfCZrY8/keerthi.jpg', + }, + { + name: 'Alberto', + src: 'https://i.ibb.co/NsK2w5y/Alberto.jpg', + }, + ...new Array(10), + ]; + + const collaboratorsVR = [ + { + name: 'Fatima', + src: 'https://i.pinimg.com/originals/bf/bc/27/bfbc27685d81eb9a8f65c201ea661f0e.jpg', + }, + { + name: 'Ayesha', + src: 'https://i.pinimg.com/originals/c5/5c/ac/c55caca43a7c16766215ec165b649c1c.jpg', + }, + ...new Array(10), + ]; + + const names = isInVRExperiment ? 'Fatima, Ayesha,' : 'Keerthi, Alberto,'; + + return isInVRExperiment ? ( + + + setOpen((value) => !value)} + role="button" + size="md" + /> + + {open && ( + + setOpen(false)} + positionRelativeToAnchor={false} + size={500} + > + + + + Invite collaborators + + + + + + + )} + + ) : ( setOpen((value) => !value)} role="button" size="md" diff --git a/docs/examples/avatarGroup/ideas.tsx b/docs/examples/avatarGroup/ideas.tsx index f86dcf5fcf..1a0fb00dbc 100644 --- a/docs/examples/avatarGroup/ideas.tsx +++ b/docs/examples/avatarGroup/ideas.tsx @@ -1,24 +1,46 @@ -import { AvatarGroup, Flex } from 'gestalt'; +import { AvatarGroup, Flex, useDangerouslyInGestaltExperiment } from 'gestalt'; export default function Example() { + const isInVRExperiment = useDangerouslyInGestaltExperiment({ + webExperimentName: 'web_gestalt_visualRefresh', + mwebExperimentName: 'web_gestalt_visualRefresh', + }); + + const collaborators = [ + { + name: 'Art 1', + src: 'https://i.ibb.co/d0pQsJz/stock3.jpg', + }, + { + name: 'Art 2', + src: 'https://i.ibb.co/SB0pXgS/stock4.jpg', + }, + { + name: 'Art 3', + src: 'https://i.ibb.co/jVR29XV/stock5.jpg', + }, + ]; + + const collaboratorsVR = [ + { + name: 'Artwork 1', + src: 'https://i.pinimg.com/564x/2e/f4/80/2ef48048ccdb68439ef6a6ef1d842e4f.jpg', + }, + { + name: 'Artwork 2', + src: 'https://i.pinimg.com/564x/2a/37/68/2a3768dd4640aebfe93537ec37b016a6.jpg', + }, + { + name: 'Artwork 3', + src: 'https://i.pinimg.com/564x/49/20/5d/49205d231674daf0ddaadd606dd0f60e.jpg', + }, + ]; + return ( diff --git a/docs/examples/avatarGroup/main.tsx b/docs/examples/avatarGroup/main.tsx index dfd8b39624..12fc87739d 100644 --- a/docs/examples/avatarGroup/main.tsx +++ b/docs/examples/avatarGroup/main.tsx @@ -1,6 +1,41 @@ -import { AvatarGroup, Box, Flex } from 'gestalt'; +import { AvatarGroup, Box, Flex, useDangerouslyInGestaltExperiment } from 'gestalt'; export default function Example() { + const isInVRExperiment = useDangerouslyInGestaltExperiment({ + webExperimentName: 'web_gestalt_visualRefresh', + mwebExperimentName: 'web_gestalt_visualRefresh', + }); + + const collaborators = [ + { + name: 'Keerthi', + src: 'https://i.ibb.co/ZfCZrY8/keerthi.jpg', + }, + { + name: 'Alberto', + src: 'https://i.ibb.co/NsK2w5y/Alberto.jpg', + }, + { + name: 'Shanice', + src: 'https://i.ibb.co/7tGKGvb/shanice.jpg', + }, + ]; + + const collaboratorsVR = [ + { + name: 'Fatima', + src: 'https://i.pinimg.com/originals/bf/bc/27/bfbc27685d81eb9a8f65c201ea661f0e.jpg', + }, + { + name: 'Sora', + src: 'https://i.pinimg.com/originals/ab/c5/4a/abc54abd85df131e90ca6b372368b738.jpg', + }, + { + name: 'Ayesha', + src: 'https://i.pinimg.com/originals/c5/5c/ac/c55caca43a7c16766215ec165b649c1c.jpg', + }, + ]; + return ( diff --git a/docs/examples/avatarGroup/noEmoji.tsx b/docs/examples/avatarGroup/noEmoji.tsx index f99482df44..ad1631e1e2 100644 --- a/docs/examples/avatarGroup/noEmoji.tsx +++ b/docs/examples/avatarGroup/noEmoji.tsx @@ -1,22 +1,48 @@ -import { AvatarGroup, Flex } from 'gestalt'; +import { AvatarGroup, Flex, useDangerouslyInGestaltExperiment } from 'gestalt'; export default function Example() { + const isInVRExperiment = useDangerouslyInGestaltExperiment({ + webExperimentName: 'web_gestalt_visualRefresh', + mwebExperimentName: 'web_gestalt_visualRefresh', + }); + + const collaborators = [ + { + name: 'Keerthi', + }, + { + name: '🎉', + }, + { + name: 'Shanice', + src: 'https://i.ibb.co/7tGKGvb/shanice.jpg', + }, + ]; + + const collaboratorsVR = [ + { + color: '10', + name: 'Sora', + }, + { + color: '04', + name: '🙏🏾', + }, + { + name: 'Fatima', + src: 'https://i.pinimg.com/originals/bf/bc/27/bfbc27685d81eb9a8f65c201ea661f0e.jpg', + }, + ]; + + const accessibilityLabel = isInVRExperiment + ? 'Collaborators: Fatima, Sora, Ayesha.' + : 'Collaborators: Keerthi, Alberto, Shanice.'; + return ( diff --git a/docs/examples/avatarGroup/noImageSource.tsx b/docs/examples/avatarGroup/noImageSource.tsx index d0ca381ee2..998279ecde 100644 --- a/docs/examples/avatarGroup/noImageSource.tsx +++ b/docs/examples/avatarGroup/noImageSource.tsx @@ -1,23 +1,49 @@ -import { AvatarGroup, Flex } from 'gestalt'; +import { AvatarGroup, Flex, useDangerouslyInGestaltExperiment } from 'gestalt'; export default function Example() { + const isInVRExperiment = useDangerouslyInGestaltExperiment({ + webExperimentName: 'web_gestalt_visualRefresh', + mwebExperimentName: 'web_gestalt_visualRefresh', + }); + + const accessibilityLabel = isInVRExperiment + ? 'Collaborators: Fatima, Sora, Ayesha.' + : 'Collaborators: Keerthi, Alberto, Shanice.'; + + const collaborators = [ + { + name: 'Keerthi', + }, + { + name: 'Alberto', + src: 'https://i.ibb.co/NsK2w5y/Alberto.jpg', + }, + { + name: 'Shanice', + src: 'https://i.ibb.co/7tGKGvb/shanice.jpg', + }, + ]; + + const collaboratorsVR = [ + { + name: 'Fatima', + src: 'https://i.pinimg.com/originals/bf/bc/27/bfbc27685d81eb9a8f65c201ea661f0e.jpg', + }, + { + name: 'Sora', + src: 'https://i.pinimg.com/originals/ab/c5/4a/abc54abd85df131e90ca6b372368b738.jpg', + }, + { + name: 'Ayesha', + src: 'https://i.pinimg.com/originals/c5/5c/ac/c55caca43a7c16766215ec165b649c1c.jpg', + }, + ]; + return ( diff --git a/docs/examples/avatarGroup/person.tsx b/docs/examples/avatarGroup/person.tsx index df79134bc4..3b973f37c4 100644 --- a/docs/examples/avatarGroup/person.tsx +++ b/docs/examples/avatarGroup/person.tsx @@ -1,24 +1,50 @@ -import { AvatarGroup, Flex } from 'gestalt'; +import { AvatarGroup, Flex, useDangerouslyInGestaltExperiment } from 'gestalt'; export default function Example() { + const isInVRExperiment = useDangerouslyInGestaltExperiment({ + webExperimentName: 'web_gestalt_visualRefresh', + mwebExperimentName: 'web_gestalt_visualRefresh', + }); + + const accessibilityLabel = isInVRExperiment + ? 'Collaborators: Fatima, Mami Wata, Ayesha.' + : 'Collaborators: Keerthi, Mami Wata, Shanice.'; + + const collaborators = [ + { + name: 'PinAble', + src: 'https://i.pinimg.com/75x75_RS/93/ad/66/93ad660e38e4f4315869424ea90e7ea4.jpg', + }, + { + name: 'Alberto', + src: 'https://i.ibb.co/NsK2w5y/Alberto.jpg', + }, + { + name: 'Shanice', + src: 'https://i.ibb.co/7tGKGvb/shanice.jpg', + }, + ]; + + const collaboratorsVR = [ + { + name: 'Fatima', + src: 'https://i.pinimg.com/originals/bf/bc/27/bfbc27685d81eb9a8f65c201ea661f0e.jpg', + }, + { + name: 'Mami Wata', + src: 'https://i.pinimg.com/564x/52/ed/6a/52ed6a9475eeb7e0133fb6d3a8b6aaa4.jpg', + }, + { + name: 'Ayesha', + src: 'https://i.pinimg.com/originals/c5/5c/ac/c55caca43a7c16766215ec165b649c1c.jpg', + }, + ]; + return ( diff --git a/docs/examples/avatarGroup/roleButton.tsx b/docs/examples/avatarGroup/roleButton.tsx index 590a89db00..c4f0881adc 100644 --- a/docs/examples/avatarGroup/roleButton.tsx +++ b/docs/examples/avatarGroup/roleButton.tsx @@ -1,44 +1,59 @@ import { useRef, useState } from 'react'; -import { Avatar, AvatarGroup, Box, Flex, Layer, Popover, Text } from 'gestalt'; - -const collaborators = [ - { - name: 'Keerthi', - src: 'https://i.ibb.co/ZfCZrY8/keerthi.jpg', - }, - { - name: 'Alberto', - src: 'https://i.ibb.co/NsK2w5y/Alberto.jpg', - }, - { - name: 'Shanice', - src: 'https://i.ibb.co/7tGKGvb/shanice.jpg', - }, -]; - -function List() { - return ( - - {collaborators.map(({ name, src }) => ( - - - {name} - - ))} - - ); -} +import { + Avatar, + AvatarGroup, + Box, + Flex, + Layer, + Popover, + Text, + useDangerouslyInGestaltExperiment, +} from 'gestalt'; export default function Example() { const [open, setOpen] = useState(false); const anchorRef = useRef(null); + const isInVRExperiment = useDangerouslyInGestaltExperiment({ + webExperimentName: 'web_gestalt_visualRefresh', + mwebExperimentName: 'web_gestalt_visualRefresh', + }); + + const collaborators = [ + { + name: 'Keerthi', + src: 'https://i.ibb.co/ZfCZrY8/keerthi.jpg', + }, + { + name: 'Alberto', + src: 'https://i.ibb.co/NsK2w5y/Alberto.jpg', + }, + { + name: 'Shanice', + src: 'https://i.ibb.co/7tGKGvb/shanice.jpg', + }, + ]; + + const collaboratorsVR = [ + { + name: 'Fatima', + src: 'https://i.pinimg.com/originals/bf/bc/27/bfbc27685d81eb9a8f65c201ea661f0e.jpg', + }, + { + name: 'Sora', + src: 'https://i.pinimg.com/originals/ab/c5/4a/abc54abd85df131e90ca6b372368b738.jpg', + }, + { + name: 'Ayesha', + src: 'https://i.pinimg.com/originals/c5/5c/ac/c55caca43a7c16766215ec165b649c1c.jpg', + }, + ]; return ( setOpen((value) => !value)} role="button" size="md" @@ -61,10 +76,25 @@ export default function Example() { width={360} > - + Collaborators - + + {!isInVRExperiment && + collaborators.map(({ name, src }) => ( + + + {name} + + ))} + {isInVRExperiment && + collaboratorsVR.map(({ name, src }) => ( + + + {name} + + ))} + diff --git a/docs/examples/avatarGroup/roleLink.tsx b/docs/examples/avatarGroup/roleLink.tsx index 442f3d4c94..4ab21b029b 100644 --- a/docs/examples/avatarGroup/roleLink.tsx +++ b/docs/examples/avatarGroup/roleLink.tsx @@ -1,6 +1,11 @@ -import { AvatarGroup, Flex } from 'gestalt'; +import { AvatarGroup, Flex, useDangerouslyInGestaltExperiment } from 'gestalt'; export default function Example() { + const isInVRExperiment = useDangerouslyInGestaltExperiment({ + webExperimentName: 'web_gestalt_visualRefresh', + mwebExperimentName: 'web_gestalt_visualRefresh', + }); + const collaborators = [ { name: 'Keerthi', @@ -16,11 +21,26 @@ export default function Example() { }, ]; + const collaboratorsVR = [ + { + name: 'Fatima', + src: 'https://i.pinimg.com/originals/bf/bc/27/bfbc27685d81eb9a8f65c201ea661f0e.jpg', + }, + { + name: 'Sora', + src: 'https://i.pinimg.com/originals/ab/c5/4a/abc54abd85df131e90ca6b372368b738.jpg', + }, + { + name: 'Ayesha', + src: 'https://i.pinimg.com/originals/c5/5c/ac/c55caca43a7c16766215ec165b649c1c.jpg', + }, + ]; + return ( {}} role="link" diff --git a/docs/pages/web/avatar.tsx b/docs/pages/web/avatar.tsx index 3004ee2630..f3904934a3 100644 --- a/docs/pages/web/avatar.tsx +++ b/docs/pages/web/avatar.tsx @@ -1,3 +1,4 @@ +import { useDangerouslyInGestaltExperiment } from 'gestalt'; import AccessibilitySection from '../../docs-components/AccessibilitySection'; import docGen, { DocGen } from '../../docs-components/docgen'; import GeneratedPropTable from '../../docs-components/GeneratedPropTable'; @@ -8,6 +9,7 @@ import Page from '../../docs-components/Page'; import PageHeader from '../../docs-components/PageHeader'; import QualityChecklist from '../../docs-components/QualityChecklist'; import SandpackExample from '../../docs-components/SandpackExample'; +import colorExample from '../../examples/avatar/colorExample'; import containerExample from '../../examples/avatar/containerExample'; import ideasExample from '../../examples/avatar/ideasExample'; import mainExample from '../../examples/avatar/mainExample'; @@ -21,6 +23,11 @@ import sizingExample from '../../examples/avatar/sizingExample'; import verifiedExample from '../../examples/avatar/verifiedExample'; export default function AvatarPage({ generatedDocGen }: { generatedDocGen: DocGen }) { + const isInVRExperiment = useDangerouslyInGestaltExperiment({ + webExperimentName: 'web_gestalt_visualRefresh', + mwebExperimentName: 'web_gestalt_visualRefresh', + }); + return ( } + cardSize="md" + description={` + - To reflect a person, company or brand within the product. + `} + sandpackExample={ + + } + title="When to use" + type="do" /> - } + sandpackExample={} /> + {!isInVRExperiment && ( + + + } + /> + + )} ('md'); + const sizeExamples = ( +
+ + { + if (value === 'md' || value === 'xs' || value === 'sm') { + setAvatarsize(value); + } + }} + size="md" + value={avatarsize} + > + {[ + { label: 'xs', value: 'xs' }, + { label: 'sm', value: 'sm' }, + { label: 'md', value: 'md' }, + ].map(({ label, value }) => ( + + ))} + + + Element; addCollaborators: boolean[]; collaborators: any[][]; hideTitle: true; }' is not assignable to type 'IntrinsicAttributes & Props'. + addCollaborators={[false, true]} + collaborators={[ + [ + { + name: 'Keerthi', + src: 'https://i.ibb.co/ZfCZrY8/keerthi.jpg', + }, + ], + [ + { + name: 'Keerthi', + src: 'https://i.ibb.co/ZfCZrY8/keerthi.jpg', + }, + { + name: 'Alberto', + src: 'https://i.ibb.co/NsK2w5y/Alberto.jpg', + }, + ], + [ + { + name: 'Keerthi', + src: 'https://i.ibb.co/ZfCZrY8/keerthi.jpg', + }, + { + name: 'Alberto', + src: 'https://i.ibb.co/NsK2w5y/Alberto.jpg', + }, + { + name: 'Shanice', + src: 'https://i.ibb.co/7tGKGvb/shanice.jpg', + }, + ], + [ + { + name: 'Keerthi', + src: 'https://i.ibb.co/ZfCZrY8/keerthi.jpg', + }, + { + name: 'Alberto', + src: 'https://i.ibb.co/NsK2w5y/Alberto.jpg', + }, + { + name: 'Shanice', + src: 'https://i.ibb.co/7tGKGvb/shanice.jpg', + }, + ...new Array(10), + ], + [ + { + name: 'Keerthi', + src: 'https://i.ibb.co/ZfCZrY8/keerthi.jpg', + }, + { + name: 'Alberto', + src: 'https://i.ibb.co/NsK2w5y/Alberto.jpg', + }, + { + name: 'Shanice', + src: 'https://i.ibb.co/7tGKGvb/shanice.jpg', + }, + ...new Array(100), + ], + ]} + hideTitle + > + {({ addCollaborators, collaborators }) => { + const accessibilityLabel = + collaborators.length <= 3 + ? // @ts-expect-error - TS7006 - Parameter 'x' implicitly has an 'any' type. + `Collaborators: ${collaborators.map((x) => x?.name).join(', and ')}.` + : `Collaborators: ${collaborators + .slice(0, 2) + // @ts-expect-error - TS7006 - Parameter 'x' implicitly has an 'any' type. + .map((x) => x?.name) + .join(', ')} ${ + collaborators.length > 3 ? `and ${collaborators.length - 2} more.` : '.' + }`; + return addCollaborators ? ( + {}} + role="button" + size={avatarsize} + /> + ) : ( + + ); + }} + +
+ ); + + const staticCollaborators = [ + [ + { + name: 'Sora', + src: 'https://i.pinimg.com/originals/ab/c5/4a/abc54abd85df131e90ca6b372368b738.jpg', + }, + ], + [ + { + name: 'Fatima', + src: 'https://i.pinimg.com/originals/bf/bc/27/bfbc27685d81eb9a8f65c201ea661f0e.jpg', + }, + { + name: 'Sora', + src: 'https://i.pinimg.com/originals/ab/c5/4a/abc54abd85df131e90ca6b372368b738.jpg', + }, + { + name: 'Ayesha', + src: 'https://i.pinimg.com/originals/c5/5c/ac/c55caca43a7c16766215ec165b649c1c.jpg', + }, + ], + [ + { + name: 'Fatima', + src: 'https://i.pinimg.com/originals/bf/bc/27/bfbc27685d81eb9a8f65c201ea661f0e.jpg', + }, + { + color: '08', + name: 'Zola', + }, + { + name: 'Ayesha', + src: 'https://i.pinimg.com/originals/c5/5c/ac/c55caca43a7c16766215ec165b649c1c.jpg', + }, + ], + ]; + + const interactiveCollaborators = [ + [ + { + name: 'Fatima', + src: 'https://i.pinimg.com/originals/bf/bc/27/bfbc27685d81eb9a8f65c201ea661f0e.jpg', + }, + ], + [ + { + color: '10', + name: 'Benito', + }, + { + name: 'Ayesha', + src: 'https://i.pinimg.com/originals/c5/5c/ac/c55caca43a7c16766215ec165b649c1c.jpg', + }, + ...new Array(10), + ], + [ + { + color: '04', + name: 'Alanna', + }, + { + color: '06', + name: 'Elliot', + }, + { + color: '08', + name: 'Ricardo', + }, + { + color: '10', + name: 'Ricardo', + }, + ...new Array(10), + ], + [ + { + name: 'Fatima', + src: 'https://i.pinimg.com/originals/bf/bc/27/bfbc27685d81eb9a8f65c201ea661f0e.jpg', + }, + { + name: 'Sora', + src: 'https://i.pinimg.com/originals/ab/c5/4a/abc54abd85df131e90ca6b372368b738.jpg', + }, + { + name: 'Ayesha', + src: 'https://i.pinimg.com/originals/c5/5c/ac/c55caca43a7c16766215ec165b649c1c.jpg', + }, + ...new Array(100), + ], + ]; + + const staticExamples = ( + Element; addCollaborators: boolean[]; collaborators: any[][]; hideTitle: true; }' is not assignable to type 'IntrinsicAttributes & Props'. + addCollaborators={[false]} + collaborators={staticCollaborators} + hideTitle + > + {({ collaborators }) => { + const accessibilityLabel = + collaborators.length <= 3 + ? // @ts-expect-error - TS7006 - Parameter 'x' implicitly has an 'any' type. + `Collaborators: ${collaborators.map((x) => x?.name).join(', and ')}.` + : `Collaborators: ${collaborators + .slice(0, 2) + // @ts-expect-error - TS7006 - Parameter 'x' implicitly has an 'any' type. + .map((x) => x?.name) + .join(', ')} ${ + collaborators.length > 3 ? `and ${collaborators.length - 2} more.` : '.' + }`; + + return ( + + + + Display Only + + + ); + }} + + ); + + const interactiveExamples = ( + Element; addCollaborators: boolean[]; collaborators: any[][]; hideTitle: true; }' is not assignable to type 'IntrinsicAttributes & Props'. + addCollaborators={[true]} + collaborators={interactiveCollaborators} + hideTitle + > + {({ addCollaborators, collaborators }) => { + const accessibilityLabel = + collaborators.length <= 3 + ? // @ts-expect-error - TS7006 - Parameter 'x' implicitly has an 'any' type. + `Collaborators: ${collaborators.map((x) => x?.name).join(', and ')}.` + : `Collaborators: ${collaborators + .slice(0, 2) + // @ts-expect-error - TS7006 - Parameter 'x' implicitly has an 'any' type. + .map((x) => x?.name) + .join(', ')} ${ + collaborators.length > 3 ? `and ${collaborators.length - 2} more.` : '.' + }`; + + return addCollaborators && collaborators.length > 12 ? ( + + {}} + role="button" + size={avatarsize} + /> + + Interactive + + + ) : ( + + {}} + role="button" + size={avatarsize} + /> + + Interactive + + + ); + }} + + ); + + const sizeExamplesVR = ( + + + { + if (value === 'md' || value === 'xs' || value === 'sm') { + setAvatarsize(value); + } + }} + size="md" + value={avatarsize} + > + {[ + { label: 'xs', value: 'xs' }, + { label: 'sm', value: 'sm' }, + { label: 'md', value: 'md' }, + ].map(({ label, value }) => ( + + ))} + + + {staticExamples} + {interactiveExamples} + + ); + return ( @@ -141,162 +482,68 @@ If AvatarGroup is used as a control button to show/hide Popover-component, we re {({ size }) => ( )}
- - - } - /> - + Resize the width or number of avatars to see the AvatarGroup change to match the width of the Column it's been placed in. + " + title="Responsive sizing" + > + + } + /> + + )} - - { - if (value === 'md' || value === 'xs' || value === 'sm') { - setAvatarsize(value); - } - }} - size="md" - value={avatarsize} - > - {[ - { label: 'xs', value: 'xs' }, - { label: 'sm', value: 'sm' }, - { label: 'md', value: 'md' }, - ].map(({ label, value }) => ( - - ))} - - - Element; addCollaborators: boolean[]; collaborators: any[][]; hideTitle: true; }' is not assignable to type 'IntrinsicAttributes & Props'. - addCollaborators={[false, true]} - collaborators={[ - [ - { - name: 'Keerthi', - src: 'https://i.ibb.co/ZfCZrY8/keerthi.jpg', - }, - ], - [ - { - name: 'Keerthi', - src: 'https://i.ibb.co/ZfCZrY8/keerthi.jpg', - }, - { - name: 'Alberto', - src: 'https://i.ibb.co/NsK2w5y/Alberto.jpg', - }, - ], - [ - { - name: 'Keerthi', - src: 'https://i.ibb.co/ZfCZrY8/keerthi.jpg', - }, - { - name: 'Alberto', - src: 'https://i.ibb.co/NsK2w5y/Alberto.jpg', - }, - { - name: 'Shanice', - src: 'https://i.ibb.co/7tGKGvb/shanice.jpg', - }, - ], - [ - { - name: 'Keerthi', - src: 'https://i.ibb.co/ZfCZrY8/keerthi.jpg', - }, - { - name: 'Alberto', - src: 'https://i.ibb.co/NsK2w5y/Alberto.jpg', - }, - { - name: 'Shanice', - src: 'https://i.ibb.co/7tGKGvb/shanice.jpg', - }, - ...new Array(10), - ], - [ - { - name: 'Keerthi', - src: 'https://i.ibb.co/ZfCZrY8/keerthi.jpg', - }, - { - name: 'Alberto', - src: 'https://i.ibb.co/NsK2w5y/Alberto.jpg', - }, - { - name: 'Shanice', - src: 'https://i.ibb.co/7tGKGvb/shanice.jpg', - }, - ...new Array(100), - ], - ]} - hideTitle - > - {({ addCollaborators, collaborators }) => { - const accessibilityLabel = - collaborators.length <= 3 - ? // @ts-expect-error - TS7006 - Parameter 'x' implicitly has an 'any' type. - `Collaborators: ${collaborators.map((x) => x?.name).join(', and ')}.` - : `Collaborators: ${collaborators - .slice(0, 2) - // @ts-expect-error - TS7006 - Parameter 'x' implicitly has an 'any' type. - .map((x) => x?.name) - .join(', ')} ${ - collaborators.length > 3 ? `and ${collaborators.length - 2} more.` : '.' - }`; - return addCollaborators ? ( - {}} - role="button" - size={avatarsize} - /> - ) : ( - - ); - }} - + {isInVRExperiment ? sizeExamplesVR : sizeExamples} setIsImageLoaded(false); - +function Avatar({ accessibilityLabel, color, name, outline, size, src, verified }: Props) { return ( - - {src && isImageLoaded ? ( - - {accessibilityLabel - - ) : ( - - )} - - {verified && ( - - - - - - )} - + ); } diff --git a/packages/gestalt/src/Avatar/AvatarFoundation.css b/packages/gestalt/src/Avatar/AvatarFoundation.css new file mode 100644 index 0000000000..5051babb1c --- /dev/null +++ b/packages/gestalt/src/Avatar/AvatarFoundation.css @@ -0,0 +1,57 @@ +.container { + border-radius: 50%; + padding-bottom: 100%; + position: relative; +} + +.outline { + border-radius: 50%; + outline: 1px solid rgb(255 255 255); +} + +.outlineVR { + border-radius: var(--sema-rounding-circle); + outline: 2px solid var(--sema-color-border-inverse); +} + +.focused { + border: 2px solid var(--sema-color-border-focus-inner-default); + border-radius: 50%; + outline: 2px solid var(--sema-color-border-focus-outer-default); +} + +.imageHovered { + background: var(--sema-color-hover-background-wash-image-tint); +} + +.imagePressed { + background: var(--sema-color-pressed-background-wash-image-tint); +} + +.innerDiv { + display: flex; + inset: 0; + justify-content: center; + position: absolute; +} + +.text { + composes: antialiased sansSerif fontWeightSemiBold from "../Typography.css"; +} + +.vrText { + composes: lg from "../TextUI.css"; +} + +.icon { + stroke-width: 0; + vertical-align: middle; +} + +.iconFillDefault { + fill: var(--color-icon-avatar-default); +} + +.iconFillDarkMode { + fill: var(--color-icon-light); +} diff --git a/packages/gestalt/src/Avatar/DefaultAvatar.tsx b/packages/gestalt/src/Avatar/DefaultAvatar.tsx index 786fa40093..3a10ccaa66 100644 --- a/packages/gestalt/src/Avatar/DefaultAvatar.tsx +++ b/packages/gestalt/src/Avatar/DefaultAvatar.tsx @@ -2,15 +2,31 @@ import AvatarFoundation from './Foundation'; type Props = { accessibilityLabel?: string; + color?: '01' | '02' | '03' | '04' | '05' | '06' | '07' | '08' | '09' | '10'; + isHovered?: boolean; + isPressed?: boolean; name: string; }; -export default function DefaultAvatar({ accessibilityLabel, name }: Props) { - const firstInitial = (name && Array.from(name)[0]?.toUpperCase()) || ''; +export default function DefaultAvatar({ + accessibilityLabel, + color, + isHovered, + isPressed, + name, +}: Props) { + const firstInitial = name ? Array.from(name)[0]?.toUpperCase() : ''; const title = accessibilityLabel ?? name; return ( - + {firstInitial} ); diff --git a/packages/gestalt/src/Avatar/Foundation.tsx b/packages/gestalt/src/Avatar/Foundation.tsx index 26b8220700..175d69a12a 100644 --- a/packages/gestalt/src/Avatar/Foundation.tsx +++ b/packages/gestalt/src/Avatar/Foundation.tsx @@ -1,30 +1,71 @@ import { ReactNode } from 'react'; import classnames from 'classnames'; -import { TOKEN_COLOR_BORDER_AVATAR, TOKEN_COLOR_TEXT_DEFAULT } from 'gestalt-design-tokens'; -import avatarStyles from '../AvatarGroup.css'; +import { TOKEN_COLOR_TEXT_DEFAULT } from 'gestalt-design-tokens'; +import avatarStyles from './AvatarFoundation.css'; +import getAvatarColorToken from './getAvatarColorToken'; +import avatarGroupStyles from '../AvatarGroup.css'; import Box from '../Box'; -import styles from '../Icon.css'; +import { useColorScheme } from '../contexts/ColorSchemeProvider'; import icons from '../icons/index'; import vrIcons from '../icons-vr-theme/index'; -import typographyStyle from '../Typography.css'; import useInExperiment from '../useInExperiment'; const ICON_SIZE_RATIO = (20 / 48) * 100; // For pixel perfect icon button, we use the icon (20px) to parent container (48px) size ratio type ResponsiveFitSizeBoxProps = { + color?: '01' | '02' | '03' | '04' | '05' | '06' | '07' | '08' | '09' | '10'; children: ReactNode; + content: string; + isCollaboratorCount?: boolean; + isHovered?: boolean; + isPressed?: boolean; outline: boolean; }; -function ResponsiveFitSizeBox({ children, outline }: ResponsiveFitSizeBoxProps) { - return ( +function ResponsiveFitSizeBox({ + color, + content, + children, + isCollaboratorCount, + isHovered, + isPressed, + outline, +}: ResponsiveFitSizeBoxProps) { + const isInVRExperiment = useInExperiment({ + webExperimentName: 'web_gestalt_visualRefresh', + mwebExperimentName: 'web_gestalt_visualRefresh', + }); + + const { colorSchemeName } = useColorScheme(); + const isDarkMode = colorSchemeName === 'darkMode'; + + const avatarBackgroundColor = + content === 'icon' || isCollaboratorCount + ? getAvatarColorToken('default', isHovered, isPressed, isDarkMode) + : getAvatarColorToken(color || 'default', isHovered, isPressed, isDarkMode); + + return isInVRExperiment ? ( +
+
{children}
+
+ ) : ( + {content === 'text' ? ( {title ? {title} : null} {children} @@ -100,7 +158,11 @@ export default function AvatarFoundation({ ) : null} {content === 'icon' ? ( Icon - + ) : null} diff --git a/packages/gestalt/src/Avatar/InternalAvatar.tsx b/packages/gestalt/src/Avatar/InternalAvatar.tsx new file mode 100644 index 0000000000..af4844a838 --- /dev/null +++ b/packages/gestalt/src/Avatar/InternalAvatar.tsx @@ -0,0 +1,119 @@ +import { useState } from 'react'; +import classnames from 'classnames'; +import { TOKEN_COLOR_BACKGROUND_AVATAR_PLACEHOLDER } from 'gestalt-design-tokens'; +import avatarStyles from './AvatarFoundation.css'; +import DefaultAvatar from './DefaultAvatar'; +import Box from '../Box'; +import Icon from '../Icon'; +import Image from '../Image'; +import Mask from '../Mask'; +import useInExperiment from '../useInExperiment'; + +const sizes = { + xs: 24, + sm: 32, + md: 48, + lg: 64, + xl: 120, +} as const; + +type Props = { + accessibilityLabel?: string; + color?: '01' | '02' | '03' | '04' | '05' | '06' | '07' | '08' | '09' | '10'; + isHovered?: boolean; + isPressed?: boolean; + name: string; + outline?: boolean; + size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'fit'; + src?: string; + verified?: boolean; +}; + +function InternalAvatar(props: Props) { + const isInVRExperiment = useInExperiment({ + webExperimentName: 'web_gestalt_visualRefresh', + mwebExperimentName: 'web_gestalt_visualRefresh', + }); + const { + accessibilityLabel, + color, + isHovered, + isPressed, + name, + outline, + size = isInVRExperiment ? 'md' : 'fit', + src, + verified, + } = props; + const [isImageLoaded, setIsImageLoaded] = useState(true); + const handleImageError = () => setIsImageLoaded(false); + const width = size === 'fit' ? '100%' : sizes[size]; + const height = size === 'fit' ? '' : sizes[size]; + + return ( +
+ + {src && isImageLoaded ? ( + +
+ {accessibilityLabel +
+
+ ) : ( + + )} + + {verified && ( + + + + + + )} +
+
+ ); +} + +export default InternalAvatar; diff --git a/packages/gestalt/src/Avatar/getAvatarColorToken.ts b/packages/gestalt/src/Avatar/getAvatarColorToken.ts new file mode 100644 index 0000000000..ab72f4db4c --- /dev/null +++ b/packages/gestalt/src/Avatar/getAvatarColorToken.ts @@ -0,0 +1,175 @@ +interface ColorToken { + base: string; + hover: string; + pressed: string; +} + +interface ColorTokens { + [key: string]: ColorToken; +} + +// Need to replace color tokens +const colorTokensLight: ColorTokens = Object.freeze({ + 'default': { + base: '#E8E7E1', + hover: '#D6D4CD', + pressed: '#C2C1BC', + }, + '01': { + // redWeak + base: '#FFD3D1', + hover: '#FBBEBB', + pressed: '#F4A8A4', + }, + '02': { + // redDefault + base: '#FF9494', + hover: '#F87777', + pressed: '#ED5A5A', + }, + '03': { + // purpleWeak + base: '#FCD8FC', + hover: '#FAC7FA', + pressed: '#F8B5F8', + }, + '04': { + // purpleDefault + base: '#EFADEF', + hover: '#E599E5', + pressed: '#DA86DA', + }, + '05': { + // blueWeak + base: '#C5EAF7', + hover: '#A8DDF0', + pressed: '#8ECFE6', + }, + '06': { + // blueDefault + base: '#7CBEDE', + hover: '#58A9D0', + pressed: '#4096BF', + }, + '07': { + // greenWeak + base: '#D0E2A8', + hover: '#BCD090', + pressed: '#A7B97E', + }, + '08': { + // greenDefault + base: '#A8BB63', + hover: '#93A550', + pressed: '#81904C', + }, + '09': { + // orangeWeak + base: '#FDE7C9', + hover: '#F9D9AE', + pressed: '#F4CC95', + }, + '10': { + // orangeDefault + base: '#FBC55B', + hover: '#F8B430', + pressed: '#F1A613', + }, +}); + +const colorTokensDark: ColorTokens = Object.freeze({ + 'default': { + base: '#757570', + hover: '#757570', + pressed: '#757570', + }, + '01': { + // redWeak + base: '#8A0F0F', + hover: '#8A0F0F', + pressed: '#8A0F0F', + }, + '02': { + // redDefault + base: '#B2001A', + hover: '#B2001A', + pressed: '#B2001A', + }, + '03': { + // purpleWeak + base: '#6D4270', + hover: '#6D4270', + pressed: '#6D4270', + }, + '04': { + // purpleDefault + base: '#8F4696', + hover: '#8F4696', + pressed: '#8F4696', + }, + '05': { + // blueWeak + base: '#215D82', + hover: '#215D82', + pressed: '#215D82', + }, + '06': { + // blueDefault + base: '#007DB8', + hover: '#007DB8', + pressed: '#007DB8', + }, + '07': { + // greenWeak + base: '#265926', + hover: '#265926', + pressed: '#265926', + }, + '08': { + // greenDefault + base: '#517D3B', + hover: '#517D3B', + pressed: '#517D3B', + }, + '09': { + // orangeWeak + base: '#9B4B1C', + hover: '#9B4B1C', + pressed: '#9B4B1C', + }, + '10': { + // orangeDefault + base: '#C66F31', + hover: '#C66F31', + pressed: '#C66F31', + }, +}); + +type BackgroundColorLight = keyof typeof colorTokensLight; +type BackgroundColorDark = keyof typeof colorTokensDark; +type GetAvatarColorToken = ( + color: BackgroundColorLight | BackgroundColorDark, + isHovered?: boolean, + isPressed?: boolean, + isDarkMode?: boolean, +) => string; + +const getAvatarColorToken: GetAvatarColorToken = (color, isHovered, isPressed, isDarkMode) => { + const colorToken = isDarkMode ? colorTokensDark[color] : colorTokensLight[color]; + + if (!colorToken || !color) { + throw new Error(`Invalid background color: ${color}`); + } + + if (isPressed) { + return colorToken.pressed; + } + + if (isHovered) { + return colorToken.hover; + } + + return colorToken.base; +}; + +export default getAvatarColorToken; diff --git a/packages/gestalt/src/AvatarGroup.css b/packages/gestalt/src/AvatarGroup.css index 61c4e86706..edee1df093 100644 --- a/packages/gestalt/src/AvatarGroup.css +++ b/packages/gestalt/src/AvatarGroup.css @@ -31,7 +31,3 @@ html[dir="rtl"] .translateX10 { transform: translateX(10%); } - -.text { - color: var(--color-icon-avatar-default); -} diff --git a/packages/gestalt/src/AvatarGroup.tsx b/packages/gestalt/src/AvatarGroup.tsx index b253ca7a55..f853658fdc 100644 --- a/packages/gestalt/src/AvatarGroup.tsx +++ b/packages/gestalt/src/AvatarGroup.tsx @@ -1,4 +1,4 @@ -import { forwardRef, Fragment, useState } from 'react'; +import { forwardRef, Fragment } from 'react'; import AddCollaboratorsButton from './AvatarGroup/AddCollaboratorsButton'; import CollaboratorAvatar from './AvatarGroup/CollaboratorAvatar'; import CollaboratorsCount from './AvatarGroup/CollaboratorsCount'; @@ -6,6 +6,8 @@ import Box from './Box'; import Flex from './Flex'; import TapArea from './TapArea'; import TapAreaLink from './TapAreaLink'; +import useInExperiment from './useInExperiment'; +import useInteractiveStates from './utils/useInteractiveStates'; const MAX_COLLABORATOR_AVATARS = 3; @@ -43,6 +45,7 @@ type Props = { * The user group data. See the [collaborators display](https://gestalt.pinterest.systems/web/avatargroup#Collaborators-display) variant to learn more. */ collaborators: ReadonlyArray<{ + color?: '01' | '02' | '03' | '04' | '05' | '06' | '07' | '08' | '09' | '10'; name: string; src?: string; }>; @@ -82,7 +85,15 @@ type Props = { * ![AvatarGroup dark mode](https://raw.githubusercontent.com/pinterest/gestalt/master/playwright/visual-test/AvatarGroup-dark.spec.ts-snapshots/AvatarGroup-dark-chromium-darwin.png) */ const AvatarGroupWithForwardRef = forwardRef(function AvatarGroup( - { + props: Props, + ref, +) { + const isInVRExperiment = useInExperiment({ + webExperimentName: 'web_gestalt_visualRefresh', + mwebExperimentName: 'web_gestalt_visualRefresh', + }); + + const { accessibilityLabel, accessibilityControls, accessibilityExpanded, @@ -92,21 +103,22 @@ const AvatarGroupWithForwardRef = forwardRef(function AvatarGr href, onClick, role, - size = 'fit', - }: Props, - ref, -) { - const [hovered, setHovered] = useState(false); + size = isInVRExperiment ? 'md' : 'fit', + } = props; const isDisplayOnly = !role; const isXS = size === 'xs'; - const showCollaboratorsCount = collaborators.length > MAX_COLLABORATOR_AVATARS && !isXS; + const validCollaborators = collaborators.filter( + (collaborator) => collaborator && collaborator.name, + ); + + const showCollaboratorsCount = validCollaborators.length > MAX_COLLABORATOR_AVATARS && !isXS; const showAddCollaboratorsButton = (!isDisplayOnly && addCollaborators && !isXS) ?? false; - const displayedCollaborators = collaborators.slice( + const displayedCollaborators = validCollaborators.slice( 0, showCollaboratorsCount ? 2 : MAX_COLLABORATOR_AVATARS, ); @@ -116,14 +128,27 @@ const AvatarGroupWithForwardRef = forwardRef(function AvatarGr (showCollaboratorsCount ? 1 : 0) + (showAddCollaboratorsButton ? 1 : 0); + const { + handleOnMouseEnter, + handleOnMouseLeave, + handleOnBlur, + handleOnFocus, + handleOnMouseDown, + handleOnMouseUp, + isHovered, + isActive: isPressed, + } = useInteractiveStates(); + const collaboratorStack = ( - {displayedCollaborators.map(({ src, name }, index) => ( + {displayedCollaborators.map(({ src, name, color }, index) => ( (function AvatarGr (function AvatarGr {showAddCollaboratorsButton && ( @@ -161,19 +190,71 @@ const AvatarGroupWithForwardRef = forwardRef(function AvatarGr
); - if (role === 'link' && href) { + if (!isInVRExperiment && role === 'link' && href) { + return ( + | undefined} + accessibilityLabel={accessibilityLabel} + fullWidth={false} + href={href} + onBlur={handleOnBlur} + onFocus={handleOnFocus} + onMouseDown={handleOnMouseDown} + onMouseEnter={handleOnMouseEnter} + onMouseLeave={handleOnMouseLeave} + onMouseUp={handleOnMouseUp} + onTap={({ event, dangerouslyDisableOnNavigation }) => + onClick?.({ event, dangerouslyDisableOnNavigation }) + } + rounding="pill" + tapStyle="compress" + > + {avatarGroupStack} + + ); + } + + if (!isInVRExperiment && role === 'button' && onClick) { + return ( + | undefined} + accessibilityControls={accessibilityControls} + accessibilityExpanded={accessibilityExpanded} + accessibilityHaspopup={accessibilityHaspopup} + accessibilityLabel={accessibilityLabel} + fullWidth={false} + onBlur={handleOnBlur} + onFocus={handleOnFocus} + onMouseDown={handleOnMouseDown} + onMouseEnter={handleOnMouseEnter} + onMouseLeave={handleOnMouseLeave} + onMouseUp={handleOnMouseUp} + // @ts-expect-error - TS2345 - Argument of type '{ event: KeyboardEvent | MouseEvent; }' is not assignable to parameter of type '{ event: MouseEvent | KeyboardEvent | KeyboardEvent<...> | MouseEvent<...>; dangerouslyDisableOnNavigation: () => void; }'. + onTap={({ event }) => onClick({ event })} + rounding="pill" + tapStyle="compress" + > + {avatarGroupStack} + + ); + } + + if (isInVRExperiment && role === 'link' && href) { return ( | undefined} accessibilityLabel={accessibilityLabel} fullWidth={false} href={href} - onMouseEnter={() => setHovered(true)} - onMouseLeave={() => setHovered(false)} + onMouseDown={handleOnMouseDown} + onMouseEnter={handleOnMouseEnter} + onMouseLeave={handleOnMouseLeave} + onMouseUp={handleOnMouseUp} onTap={({ event, dangerouslyDisableOnNavigation }) => onClick?.({ event, dangerouslyDisableOnNavigation }) } rounding="pill" + tabIndex={0} tapStyle="compress" > {avatarGroupStack} @@ -181,7 +262,7 @@ const AvatarGroupWithForwardRef = forwardRef(function AvatarGr ); } - if (role === 'button' && onClick) { + if (isInVRExperiment && role === 'button' && onClick) { return ( | undefined} @@ -190,8 +271,11 @@ const AvatarGroupWithForwardRef = forwardRef(function AvatarGr accessibilityHaspopup={accessibilityHaspopup} accessibilityLabel={accessibilityLabel} fullWidth={false} - onMouseEnter={() => setHovered(true)} - onMouseLeave={() => setHovered(false)} + innerFocusColor="default" + onMouseDown={handleOnMouseDown} + onMouseEnter={handleOnMouseEnter} + onMouseLeave={handleOnMouseLeave} + onMouseUp={handleOnMouseUp} // @ts-expect-error - TS2345 - Argument of type '{ event: KeyboardEvent | MouseEvent; }' is not assignable to parameter of type '{ event: MouseEvent | KeyboardEvent | KeyboardEvent<...> | MouseEvent<...>; dangerouslyDisableOnNavigation: () => void; }'. onTap={({ event }) => onClick({ event })} rounding="pill" diff --git a/packages/gestalt/src/AvatarGroup/AddCollaboratorsButton.tsx b/packages/gestalt/src/AvatarGroup/AddCollaboratorsButton.tsx index 2d88b247ff..27864e2cfe 100644 --- a/packages/gestalt/src/AvatarGroup/AddCollaboratorsButton.tsx +++ b/packages/gestalt/src/AvatarGroup/AddCollaboratorsButton.tsx @@ -3,15 +3,22 @@ import HoverOverlay from './HoverOverlay'; import PositioningWrapper from './PositioningWrapper'; import AvatarFoundation from '../Avatar/Foundation'; +type Props = BaseStackType & { + isHovered: boolean; + isPressed: boolean; +}; + export default function AvatarGroupAddCollaboratorsButton({ hovered, + isHovered, + isPressed, pileCount, size, -}: BaseStackType) { +}: Props) { return ( - + ); diff --git a/packages/gestalt/src/AvatarGroup/CollaboratorAvatar.tsx b/packages/gestalt/src/AvatarGroup/CollaboratorAvatar.tsx index 35f4952847..bc7847e2fd 100644 --- a/packages/gestalt/src/AvatarGroup/CollaboratorAvatar.tsx +++ b/packages/gestalt/src/AvatarGroup/CollaboratorAvatar.tsx @@ -1,26 +1,39 @@ import { BaseStackType } from './constants'; import HoverOverlay from './HoverOverlay'; import PositioningWrapper from './PositioningWrapper'; -import Avatar from '../Avatar'; +import InternalAvatar from '../Avatar/InternalAvatar'; type Props = BaseStackType & { + color?: '01' | '02' | '03' | '04' | '05' | '06' | '07' | '08' | '09' | '10'; index: number; name: string; + isHovered: boolean; + isPressed: boolean; src: string; }; export default function AvatarGroupCollaboratorAvatar({ - hovered, + color, + isHovered, index, name, pileCount, + isPressed, size, src, }: Props) { return ( - - + + ); diff --git a/packages/gestalt/src/AvatarGroup/CollaboratorsCount.tsx b/packages/gestalt/src/AvatarGroup/CollaboratorsCount.tsx index 47fd1c8137..2d751ce443 100644 --- a/packages/gestalt/src/AvatarGroup/CollaboratorsCount.tsx +++ b/packages/gestalt/src/AvatarGroup/CollaboratorsCount.tsx @@ -6,12 +6,16 @@ import AvatarFoundation from '../Avatar/Foundation'; type Props = BaseStackType & { showAddCollaboratorsButton: boolean; count: number; + isHovered: boolean; + isPressed: boolean; }; export default function AvatarGroupCollaboratorsCount({ showAddCollaboratorsButton, pileCount, hovered, + isHovered, + isPressed, count, size, }: Props) { @@ -26,8 +30,16 @@ export default function AvatarGroupCollaboratorsCount({ return ( - {/* @ts-expect-error - TS2322 - Type 'string | undefined' is not assignable to type '"translateX10" | undefined'. */} - + {isAbove99Count ? '99+' : count} diff --git a/packages/gestalt/src/AvatarGroup/HoverOverlay.tsx b/packages/gestalt/src/AvatarGroup/HoverOverlay.tsx index 607d3471c1..970b92f4c9 100644 --- a/packages/gestalt/src/AvatarGroup/HoverOverlay.tsx +++ b/packages/gestalt/src/AvatarGroup/HoverOverlay.tsx @@ -7,7 +7,7 @@ import { FixedZIndex } from '../zIndex'; type Props = { children: ReactNode; - hovered: boolean; + hovered?: boolean; size: Size; }; diff --git a/packages/gestalt/src/AvatarGroup/constants.ts b/packages/gestalt/src/AvatarGroup/constants.ts index 4ef0e4fdb0..ffd1106100 100644 --- a/packages/gestalt/src/AvatarGroup/constants.ts +++ b/packages/gestalt/src/AvatarGroup/constants.ts @@ -3,7 +3,7 @@ export type Size = 'xs' | 'sm' | 'md' | 'fit'; export const SIZE_MAP = { xs: 24, sm: 32, md: 48, fit: '100%' } as const; export type BaseStackType = { - hovered: boolean; + hovered?: boolean; pileCount: number; size: Size; }; diff --git a/packages/gestalt/src/__snapshots__/Avatar.test.tsx.snap b/packages/gestalt/src/__snapshots__/Avatar.test.tsx.snap index f66a4f9c64..14cec8129d 100644 --- a/packages/gestalt/src/__snapshots__/Avatar.test.tsx.snap +++ b/packages/gestalt/src/__snapshots__/Avatar.test.tsx.snap @@ -2,48 +2,52 @@ exports[`Avatar renders an outline 1`] = `
- - - Jenny - - - J - - + + Jenny + + + J + + +
@@ -51,47 +55,52 @@ exports[`Avatar renders an outline 1`] = ` exports[`Avatar renders multi-byte character initial 1`] = `
- - - 💩 astral - - - 💩 - - + + 💩 astral + + + 💩 + + +
@@ -99,82 +108,90 @@ exports[`Avatar renders multi-byte character initial 1`] = ` exports[`Avatar renders the checkmark on verified default 1`] = `
- Strava +
+ Strava +
+
+
-
-
-
- - - + + + +
@@ -182,360 +199,413 @@ exports[`Avatar renders the checkmark on verified default 1`] = ` exports[`Avatar renders the correct size - lg 1`] = `
- Strava +
+ Strava +
+
+
-
`; exports[`Avatar renders the correct size - md 1`] = `
- Strava +
+ Strava +
+
+
-
`; exports[`Avatar renders the correct size - sm 1`] = `
- Strava +
+ Strava +
+
+
-
`; exports[`Avatar renders the correct size - xl 1`] = `
- Strava +
+ Strava +
+
+
-
`; exports[`Avatar renders the correct size - xs 1`] = `
- Strava +
+ Strava +
+
+
-
`; exports[`Avatar renders the correct src 1`] = `
- Strava +
+ Strava +
+
+
-
`; exports[`Avatar renders the verified icon 1`] = `
- - - Jammy - - - J - - + + Jammy + + + J + + +
-
-
- - - + + + +
@@ -543,42 +613,47 @@ exports[`Avatar renders the verified icon 1`] = ` exports[`Avatar renders with an empty name shows default icon 1`] = `
- - - + + + +
diff --git a/packages/gestalt/src/__snapshots__/AvatarGroup.jsdom.test.tsx.snap b/packages/gestalt/src/__snapshots__/AvatarGroup.jsdom.test.tsx.snap index 854d61686f..a64a07ab23 100644 --- a/packages/gestalt/src/__snapshots__/AvatarGroup.jsdom.test.tsx.snap +++ b/packages/gestalt/src/__snapshots__/AvatarGroup.jsdom.test.tsx.snap @@ -23,28 +23,36 @@ exports[`AvatarGroup renders AvatarGroup button with addCollaborators button 1`] class="" >
- Keerthi +
+ Keerthi +
+
+
-
@@ -64,13 +72,13 @@ exports[`AvatarGroup renders AvatarGroup button with addCollaborators button 1`] >
- Keerthi +
+ Keerthi +
+
+
-
@@ -167,13 +183,13 @@ exports[`AvatarGroup renders AvatarGroup link with addCollaborators button 1`] = >
- Keerthi +
+ Keerthi +
+
+
-
@@ -264,28 +288,36 @@ exports[`AvatarGroup renders display-only AvatarGroup with counter 1`] = ` class="" >
- Keerthi +
+ Keerthi +
+
+
-
@@ -305,7 +337,7 @@ exports[`AvatarGroup renders display-only AvatarGroup with counter 1`] = ` >
- - - Keerthi - - - K - - + + Keerthi + + + K + + +
@@ -436,28 +472,36 @@ exports[`AvatarGroup renders fit display-only AvatarGroup with image 1`] = ` class="" >
- Keerthi +
+ Keerthi +
+
+
-
@@ -494,28 +538,36 @@ exports[`AvatarGroup renders md display-only AvatarGroup with image 1`] = ` class="" >
- Keerthi +
+ Keerthi +
+
+
-
@@ -551,28 +603,36 @@ exports[`AvatarGroup renders sm display-only AvatarGroup with image 1`] = ` class="" >
- Keerthi +
+ Keerthi +
+
+
-
@@ -608,28 +668,36 @@ exports[`AvatarGroup renders xs display-only AvatarGroup with image 1`] = ` class="" >
- Keerthi +
+ Keerthi +
+
+
-