Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(MainNavigationBar): add menu #1280

Merged
merged 65 commits into from
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
bbfd2df
poc desktop large menu
marcoskolodny Oct 23, 2024
06ba846
cleanup
marcoskolodny Oct 23, 2024
a1b75d5
fixes and code updats
marcoskolodny Oct 25, 2024
4851682
fix horizontal padding
marcoskolodny Oct 25, 2024
a75ea6f
code cleanup
marcoskolodny Oct 25, 2024
be5d04e
code refactor
marcoskolodny Oct 25, 2024
aed9219
code cleanup
marcoskolodny Oct 25, 2024
05ee333
fix empty columns case
marcoskolodny Oct 28, 2024
5503d0a
scroll to top of content when menu section changes
marcoskolodny Oct 28, 2024
229769d
update burger menu
marcoskolodny Oct 28, 2024
277a240
fix tokens
marcoskolodny Oct 28, 2024
55e00cd
add extra to burger menu sections
marcoskolodny Oct 28, 2024
26a4b7a
code cleanup
marcoskolodny Oct 28, 2024
044d669
Merge branch 'master' of github.com:Telefonica/mistica-web into WEB-2…
marcoskolodny Oct 28, 2024
82f0c6e
fix typo
marcoskolodny Oct 28, 2024
8776802
code cleanup
marcoskolodny Oct 28, 2024
d0f1fef
add burger menu animation
marcoskolodny Oct 28, 2024
ab105cb
avoid menu logic for empty tabs
marcoskolodny Oct 28, 2024
7947d72
code cleanup
marcoskolodny Oct 28, 2024
3eab164
update logic for extra content
marcoskolodny Oct 29, 2024
b5e76aa
add callback to close menu when custom content is rendered
marcoskolodny Oct 29, 2024
d3a8bd0
fix typo
marcoskolodny Oct 29, 2024
9e9538e
code cleanup
marcoskolodny Oct 29, 2024
1dbffaa
implement desktop small menu
marcoskolodny Oct 29, 2024
e2d98f0
cleanup cod
marcoskolodny Oct 29, 2024
6633955
add a11y logic
marcoskolodny Oct 29, 2024
35376e6
rollback logic
marcoskolodny Oct 29, 2024
75cea2d
make scroll logic more stable
marcoskolodny Oct 29, 2024
a848552
refactor main logic for desktop menu, add arrow logic, cleanup code a…
marcoskolodny Oct 30, 2024
aec3ec1
Merge branch 'master' of github.com:Telefonica/mistica-web into WEB-2…
marcoskolodny Oct 31, 2024
8de72ae
add focus navigation with arrows in desktop
marcoskolodny Oct 31, 2024
ae21da3
add possibility of sections without custom interaction
marcoskolodny Oct 31, 2024
57112f7
a11y roles and small fixes
marcoskolodny Oct 31, 2024
7f36041
fix aria expanded in arrow
marcoskolodny Oct 31, 2024
b2fe0bb
code cleanup
marcoskolodny Oct 31, 2024
ea1a148
code cleanup, add snippets and update story
marcoskolodny Oct 31, 2024
b249589
fix role of items and add unit test
marcoskolodny Oct 31, 2024
0974ed5
remove animation from small menu
marcoskolodny Oct 31, 2024
b3e98f4
add screenshot tests
marcoskolodny Oct 31, 2024
a08bfec
update snipper and add extra unit test
marcoskolodny Oct 31, 2024
d2dcb9a
remove portals, fix focus order in small desktop menu
marcoskolodny Nov 4, 2024
e18fee2
fix issues with focus, refactor main logic and add inverse screenshots
marcoskolodny Nov 4, 2024
7332c8b
fix content animation and add threshold to inverse screenshot
marcoskolodny Nov 5, 2024
601b11e
avoid clip-path in small menu
marcoskolodny Nov 5, 2024
7631a9b
add webkit prefixed clip-path to increase browser support
marcoskolodny Nov 5, 2024
7c068e0
optimize unit tests performance
marcoskolodny Nov 5, 2024
90f4593
fix focus logic and right content height
marcoskolodny Nov 5, 2024
fc63e49
fix scroll logic
marcoskolodny Nov 5, 2024
981bbd3
add debounce logic
marcoskolodny Nov 5, 2024
0ac5085
fix tests
marcoskolodny Nov 5, 2024
530e714
fix hover area of sections
marcoskolodny Nov 5, 2024
b4dfb6c
cleanup
marcoskolodny Nov 5, 2024
4e5903a
Merge branch 'master' of github.com:Telefonica/mistica-web into WEB-2…
marcoskolodny Nov 5, 2024
1fb9cc0
update debounce time after review with design
marcoskolodny Nov 5, 2024
577fba5
fix snippet
marcoskolodny Nov 6, 2024
5cb8682
fix scrolling issues in burger menu
marcoskolodny Nov 6, 2024
618b0aa
cleanup code
marcoskolodny Nov 6, 2024
6bdd8a3
cleanup code
marcoskolodny Nov 6, 2024
638fa05
update chevron
marcoskolodny Nov 6, 2024
7e29589
make small menu default
marcoskolodny Nov 6, 2024
0e749dc
fix screenshots
marcoskolodny Nov 6, 2024
b9a0ca8
use imagePlaceholder variable in snippets
marcoskolodny Nov 7, 2024
dd61e23
use requestAnimationFrame for fade-in effect
marcoskolodny Nov 11, 2024
e8aa201
fix initial screen reader focus in mobile and paddings in burger menu…
marcoskolodny Nov 13, 2024
ba95563
fix snippets coding style
marcoskolodny Nov 13, 2024
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
299 changes: 272 additions & 27 deletions playroom/snippets.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2408,33 +2408,278 @@ const navigationBarSnippets = [
group: 'NavigationBar',
name: 'MainNavigationBar',
code: `
<MainNavigationBar
sections={["Start", "Account", "Explore", "Support"].map((title, idx) => ({
title,
onPress: () => setState("index", idx),
}))}
selectedIndex={getState("index", 0)}
right={
<NavigationBarActionGroup>
<NavigationBarAction
onPress={() => {}}
aria-label="shopping cart with 2 items"
>
<Badge value={2}>
<IconShoppingCartRegular color="currentColor" />
</Badge>
</NavigationBarAction>
<NavigationBarAction onPress={() => {}} aria-label="Open profile">
<Avatar
size={isDesktopOrBigger ? 32 : 24}
initials="ML"
src="${imagePlaceholder}"
/>
{isDesktopOrBigger && "María López Serrano"}
</NavigationBarAction>
</NavigationBarActionGroup>
}
/>`,
<MainNavigationBar
sections={[
{
title: "Start",
onPress: () => setState("index", 0),
},
{
title: "Account",
onPress: () => setState("index", 1),
},
{
title: "Explore",
onPress: () => setState("index", 2),
},
{
title: "Support",
onPress: () => setState("index", 3),
},
]}
selectedIndex={getState("index", 0)}
right={
<NavigationBarActionGroup>
<NavigationBarAction
onPress={() => {}}
aria-label="shopping cart with 2 items"
>
<Badge value={2}>
<IconShoppingCartRegular color="currentColor" />
</Badge>
</NavigationBarAction>
<NavigationBarAction onPress={() => {}} aria-label="Open profile">
<Avatar
size={isDesktopOrBigger ? 32 : 24}
initials="ML"
src="${imagePlaceholder}"
/>
{isDesktopOrBigger && "María López Serrano"}
</NavigationBarAction>
</NavigationBarActionGroup>
}
/>`,
},
{
group: 'NavigationBar',
name: 'MainNavigationBar with menu',
code: `
<MainNavigationBar
sections={[
{
onPress: () => setState("index", 0),
title: "Start",
menu: {
columns: [
{
title: "Start 1",
items: [
{
title: "item 1",
onPress: () => {},
},
{
title: "item 2",
href: "https://www.google.com/",
},
{
title: "item 3",
to: "#",
},
],
},
],
},
},
{
onPress: () => setState("index", 1),
title: "Account",
menu: {
columns: [
{
title: "Account 1",
items: [
{
title: "item 1",
onPress: () => {},
},
],
},
],
},
},
{
onPress: () => setState("index", 2),
title: "Explore",
menu: {
columns: [
{
title: "Explore 1",
items: [
{
title: "item 1",
onPress: () => {},
},
{
title: "item 2",
href: "https://www.google.com/",
},
{
title: "item 3",
to: "#",
},
],
},
],
},
},
]}
selectedIndex={getState("index", 0)}
/>`,
},
{
group: 'NavigationBar',
name: 'MainNavigationBar with large menu',
code: `
<MainNavigationBar
desktopLargeMenu
sections={[
{
onPress: () => setState("index", 0),
title: "Start",
menu: {
columns: [
{
title: "Start 1",
items: [
{
title: "item 1",
onPress: () => {},
},
{
title: "item 2",
href: "https://www.google.com/",
},
{
title: "item 3",
to: "#",
},
],
},
{
title: "Start 2",
items: [
{
title: "item 1",
onPress: () => {},
},
{
title: "item 2",
href: "https://www.google.com/",
},
{
title: "item 3",
to: "#",
},
],
},
],
},
},
{
onPress: () => setState("index", 1),
title: "Account",
menu: {
columns: [
{
title: "Account 1",
items: [
{
title: "item 1",
onPress: () => {},
},
],
},
],
},
},
{
onPress: () => setState("index", 2),
title: "Explore",
menu: {
content: ({ closeMenu }) => (
<Stack space={16}>
<Text2 regular>Custom content</Text2>
<Placeholder />
<ButtonPrimary onPress={closeMenu}>Close menu</ButtonPrimary>
</Stack>
),
},
},
{
onPress: () => setState("index", 3),
title: "Support",
menu: {
content: isDesktopOrBigger ? (
<Grid columns={12} gap={24}>
{Array.from({ length: 3 }, (_, index) => (
<GridItem columnSpan={2} key={index}>
<Stack space={24}>
<Title1>Contenidos</Title1>
<Stack space={16}>
{[
"Destacados",
"Todo fútbol",
"#0",
"Cine",
"Oferta comercial",
"Mi Movistar",
"Movistar Cloud",
].map((title, index) => (
<TextLink
key={index}
onPress={() => {}}
style={{ color: colors.textPrimary }}
>
{title}
</TextLink>
))}
</Stack>
</Stack>
</GridItem>
))}

<GridItem columnSpan={5} columnStart={8}>
<DisplayMediaCard
headline={<Tag type="promo">Oferta</Tag>}
title="Movistar Plus+"
onPress={() => {}}
description="Contrata solo TV por 9,99 €"
backgroundImage="${imagePlaceholder}"
/>
</GridItem>
</Grid>
) : (
<Stack space={40}>
{Array.from({ length: 3 }, (_, index) => (
<Stack space={16} key={index}>
<Title1>Title</Title1>
<NegativeBox>
<RowList>
<Row title="Title" onPress={() => {}} />
<Row title="Title" onPress={() => {}} />
<Row title="Title" onPress={() => {}} />
<Row title="Title" onPress={() => {}} />
</RowList>
</NegativeBox>
</Stack>
))}

<DisplayMediaCard
headline={<Tag type="promo">Oferta</Tag>}
title="Movistar Plus+"
aspectRatio="1:1"
onPress={() => {}}
description="Contrata solo TV por 9,99 €"
backgroundImage="${imagePlaceholder}"
/>
</Stack>
),
},
},
]}
selectedIndex={getState("index", 0)}
/>`,
},
{
group: 'NavigationBar',
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
64 changes: 64 additions & 0 deletions src/__screenshot_tests__/navigation-bar-screenshot-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -164,3 +164,67 @@ test.each(DEVICES)('MainNavigationBar without sections (%s)', async (device) =>

expect(image).toMatchImageSnapshot();
});

test.each`
menuType | content
${'large'} | ${'default'}
${'large'} | ${'custom'}
${'small'} | ${'default'}
${'small'} | ${'custom'}
`('MainNavigationBar with $menuType menu and $content content in DESKTOP', async ({menuType, content}) => {
const page = await openStoryPage({
id: 'components-navigation-bars-mainnavigationbar--default',
device: 'DESKTOP',
args: {sections: true, desktopLargeMenu: menuType === 'large', menu: content},
});

// first section opened
await page.click(await screen.findByRole('button', {name: 'Start'}));
expect(await page.screenshot()).toMatchImageSnapshot();

// second section opened
await page.click(await screen.findByRole('button', {name: 'Account'}));
expect(await page.screenshot()).toMatchImageSnapshot();

// close menu with ESC key
await page.keyboard.press('Escape');
expect(await page.screenshot()).toMatchImageSnapshot();
});

test.each(['default', 'custom'])('MainNavigationBar with menu and %s content in MOBILE_IOS', async (menu) => {
const page = await openStoryPage({
id: 'components-navigation-bars-mainnavigationbar--default',
device: 'MOBILE_IOS',
args: {sections: true, menu},
});

await page.click(await screen.findByRole('button', {name: 'Abrir menú de navegación'}));

// open first section
await page.click(await screen.findByRole('button', {name: 'Start'}));
expect(await page.screenshot()).toMatchImageSnapshot();

// go back
await page.click(await screen.findByRole('button', {name: 'Atrás'}));
expect(await page.screenshot()).toMatchImageSnapshot();

// open second section
await page.click(await screen.findByRole('button', {name: 'Account'}));
expect(await page.screenshot()).toMatchImageSnapshot();

// close menu
await page.click(await screen.findByRole('button', {name: 'Cerrar menú de navegación'}));
expect(await page.screenshot()).toMatchImageSnapshot();
});

test.each(['large', 'small'])('MainNavigationBar inverse with %s menu in DESKTOP', async (menuType) => {
const page = await openStoryPage({
id: 'components-navigation-bars-mainnavigationbar--default',
device: 'DESKTOP',
args: {sections: true, desktopLargeMenu: menuType === 'large', menu: 'default', variant: 'inverse'},
});

// first section opened
await page.click(await screen.findByRole('button', {name: 'Start'}));
expect(await page.screenshot()).toMatchImageSnapshot({failureThreshold: 0.00001});
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I had to add a threshold to avoid unstable behavior in the inverse version of the navbar. Same thing was required in other tests of the inverse navbar before. It seems that the small avatar has a very small diff (8 pixels) in the circular image when it's rendered in CI (we've seen this issue in the past several times).

threshold_issue

});
Loading
Loading