diff --git a/playroom/snippets.tsx b/playroom/snippets.tsx index 04a02011b8..bda16fcf20 100644 --- a/playroom/snippets.tsx +++ b/playroom/snippets.tsx @@ -3074,7 +3074,66 @@ const heroSnippets = [ /> ))} /> - + `, + }, + { + group: 'Hero', + name: 'CoverHero', + code: ` + Novedad} + pretitle="Conecta Max" + title="Vuela con la Fibra 1Gb" + description="Para teletrabajar, ver series y películas y además, tener varios dispositivos conectados." + button={Lo quiero} + extra={} + sideExtra={} + /> + `, + }, + { + group: 'Hero', + name: 'CoverHero (video)', + code: ` + Novedad} + pretitle="Conecta Max"poste + title="Vuela con la Fibra 1Gb" + description="Para teletrabajar, ver series y películas y además, tener varios dispositivos conectados." + button={Lo quiero} + extra={} + sideExtra={} + /> + `, + }, + { + group: 'Hero', + name: 'CoverHero (carousel)', + code: ` + ( + Headline} + pretitle="Pretitle" + title={["Title", "Title 2", "Title 3"][idx]} + description={ + [ + "Description", + "This is a long description with a long text to see how this works", + "", + ][idx] + } + extra={} + sideExtra={} + button={Action} + buttonLink={Link} + /> + ))} + /> `, }, ]; diff --git a/src/__acceptance_tests__/__ssr_pages__/cover-hero.tsx b/src/__acceptance_tests__/__ssr_pages__/cover-hero.tsx new file mode 100644 index 0000000000..f760fa92bd --- /dev/null +++ b/src/__acceptance_tests__/__ssr_pages__/cover-hero.tsx @@ -0,0 +1,17 @@ +import * as React from 'react'; +import {CoverHero, Tag, ButtonPrimary, Placeholder} from '../../..'; + +const CarouselTest = (): JSX.Element => ( + Novedad} + pretitle="Conecta Max" + title="Vuela con la Fibra 1Gb" + description="Para teletrabajar, ver series y películas y además, tener varios dispositivos conectados." + button={Lo quiero} + extra={} + sideExtra={} + /> +); + +export default CarouselTest; diff --git a/src/__acceptance_tests__/cover-hero-ssr-acceptance-test.tsx b/src/__acceptance_tests__/cover-hero-ssr-acceptance-test.tsx new file mode 100644 index 0000000000..4d9b5ef55b --- /dev/null +++ b/src/__acceptance_tests__/cover-hero-ssr-acceptance-test.tsx @@ -0,0 +1,5 @@ +import {openSSRPage} from '../test-utils'; + +test('ssr CoverHero', async () => { + await openSSRPage({name: 'cover-hero'}); +}); diff --git a/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-16-9-aspect-ratio-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-16-9-aspect-ratio-1-snap.png new file mode 100644 index 0000000000..613623eb53 Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-16-9-aspect-ratio-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-centered-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-centered-1-snap.png new file mode 100644 index 0000000000..2816df7ae2 Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-centered-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-centered-with-extra-and-side-extra-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-centered-with-extra-and-side-extra-1-snap.png new file mode 100644 index 0000000000..cd2e3ef3fb Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-centered-with-extra-and-side-extra-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-long-text-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-long-text-1-snap.png new file mode 100644 index 0000000000..8fe2072861 Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-long-text-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-long-text-centered-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-long-text-centered-1-snap.png new file mode 100644 index 0000000000..2414ed2e45 Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-long-text-centered-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-long-text-with-side-extra-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-long-text-with-side-extra-1-snap.png new file mode 100644 index 0000000000..e9a651082e Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-long-text-with-side-extra-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-minimal-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-minimal-1-snap.png new file mode 100644 index 0000000000..eb65e89788 Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-minimal-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-one-button-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-one-button-1-snap.png new file mode 100644 index 0000000000..ea8db78f7e Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-one-button-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-one-link-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-one-link-1-snap.png new file mode 100644 index 0000000000..77a47e0ba4 Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-one-link-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-two-buttons-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-two-buttons-1-snap.png new file mode 100644 index 0000000000..6c65bb19ab Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-two-buttons-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-two-buttons-and-link-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-two-buttons-and-link-1-snap.png new file mode 100644 index 0000000000..1d9427b770 Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-two-buttons-and-link-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-with-background-image-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-with-background-image-1-snap.png new file mode 100644 index 0000000000..228c3ea62c Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-with-background-image-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-with-background-video-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-with-background-video-1-snap.png new file mode 100644 index 0000000000..66f418ccf9 Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-with-background-video-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-with-extra-and-side-extra-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-with-extra-and-side-extra-1-snap.png new file mode 100644 index 0000000000..6dd459ed98 Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-with-extra-and-side-extra-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-with-variant-alternative-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-with-variant-alternative-1-snap.png new file mode 100644 index 0000000000..1ad4a18d2a Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-with-variant-alternative-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-with-variant-default-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-with-variant-default-1-snap.png new file mode 100644 index 0000000000..5f22147d69 Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-with-variant-default-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-with-variant-inverse-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-with-variant-inverse-1-snap.png new file mode 100644 index 0000000000..7b395f49e6 Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-desktop-with-variant-inverse-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-inside-a-slideshow-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-inside-a-slideshow-1-snap.png new file mode 100644 index 0000000000..9241e5a6a1 Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-inside-a-slideshow-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-mobile-7-10-aspect-ratio-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-mobile-7-10-aspect-ratio-1-snap.png new file mode 100644 index 0000000000..08303f2959 Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-mobile-7-10-aspect-ratio-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-mobile-centered-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-mobile-centered-1-snap.png new file mode 100644 index 0000000000..3e2458abfd Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-mobile-centered-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-mobile-centered-with-extra-and-side-extra-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-mobile-centered-with-extra-and-side-extra-1-snap.png new file mode 100644 index 0000000000..78d144daf6 Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-mobile-centered-with-extra-and-side-extra-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-mobile-long-text-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-mobile-long-text-1-snap.png new file mode 100644 index 0000000000..8d20e5397f Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-mobile-long-text-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-mobile-min-height-100-vh-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-mobile-min-height-100-vh-1-snap.png new file mode 100644 index 0000000000..8223249e6d Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-mobile-min-height-100-vh-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-mobile-minimal-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-mobile-minimal-1-snap.png new file mode 100644 index 0000000000..9fda20b38e Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-mobile-minimal-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-mobile-with-extra-and-side-extra-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-mobile-with-extra-and-side-extra-1-snap.png new file mode 100644 index 0000000000..aa08217fc7 Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-mobile-with-extra-and-side-extra-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-tablet-with-extra-and-side-extra-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-tablet-with-extra-and-side-extra-1-snap.png new file mode 100644 index 0000000000..83a5cbda7d Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/cover-hero-screenshot-test-tsx-cover-hero-tablet-with-extra-and-side-extra-1-snap.png differ diff --git a/src/__screenshot_tests__/cover-hero-screenshot-test.tsx b/src/__screenshot_tests__/cover-hero-screenshot-test.tsx new file mode 100644 index 0000000000..504598c014 --- /dev/null +++ b/src/__screenshot_tests__/cover-hero-screenshot-test.tsx @@ -0,0 +1,246 @@ +import {openStoryPage, screen} from '../test-utils'; + +const cases = [ + [ + 'desktop with background image', + { + device: 'DESKTOP', + args: {background: 'image'}, + }, + ], + [ + 'desktop with background video', + { + device: 'DESKTOP', + args: {background: 'video'}, + }, + ], + [ + 'desktop with variant inverse', + { + device: 'DESKTOP', + args: {background: 'color from skin', variant: 'inverse'}, + }, + ], + [ + 'desktop with variant alternative', + { + device: 'DESKTOP', + args: {background: 'color from skin', variant: 'alternative'}, + }, + ], + [ + 'desktop with variant default', + { + device: 'DESKTOP', + args: {background: 'color from skin', variant: 'default'}, + }, + ], + [ + 'desktop with extra and sideExtra', + { + device: 'DESKTOP', + args: {withExtra: true, withSideExtra: true}, + }, + ], + [ + 'mobile with extra and sideExtra', + { + device: 'MOBILE_IOS', + args: {withExtra: true, withSideExtra: true}, + }, + ], + [ + 'tablet with extra and sideExtra', + { + device: 'TABLET', + args: {withExtra: true, withSideExtra: true}, + }, + ], + [ + 'desktop centered', + { + device: 'DESKTOP', + args: {centered: true, actions: 'button secondaryButton and link'}, + }, + ], + [ + 'mobile centered', + { + device: 'MOBILE_IOS', + args: {centered: true, actions: 'button secondaryButton and link'}, + }, + ], + [ + 'desktop centered with extra and sideExtra', + { + device: 'DESKTOP', + args: { + centered: true, + withExtra: true, + withSideExtra: true, + actions: 'button secondaryButton and link', + }, + }, + ], + [ + 'mobile centered with extra and sideExtra', + { + device: 'MOBILE_IOS', + args: { + centered: true, + withExtra: true, + withSideExtra: true, + actions: 'button secondaryButton and link', + }, + }, + ], + [ + 'desktop one button', + { + device: 'DESKTOP', + args: {actions: 'button'}, + }, + ], + [ + 'desktop one link', + { + device: 'DESKTOP', + args: {actions: 'link'}, + }, + ], + [ + 'desktop two buttons', + { + device: 'DESKTOP', + args: {actions: 'button and secondaryButton'}, + }, + ], + [ + 'desktop two buttons and link', + { + device: 'DESKTOP', + args: {actions: 'button secondaryButton and link'}, + }, + ], + [ + 'desktop long text', + { + device: 'DESKTOP', + args: { + title: 'Long title '.repeat(10), + description: 'This is a long description with a long text to see how this works'.repeat(10), + }, + }, + ], + [ + 'desktop long text with sideExtra', + { + device: 'DESKTOP', + args: { + title: 'Long title '.repeat(10), + description: 'This is a long description with a long text to see how this works'.repeat(10), + withSideExtra: true, + }, + }, + ], + [ + 'desktop long text centered', + { + device: 'DESKTOP', + args: { + title: 'Long title '.repeat(10), + centered: true, + description: 'This is a long description with a long text to see how this works'.repeat(10), + }, + }, + ], + [ + 'mobile long text', + { + device: 'MOBILE_IOS', + args: { + title: 'Long title '.repeat(10), + description: 'This is a long description with a long text to see how this works'.repeat(10), + }, + }, + ], + [ + 'desktop 16:9 aspect ratio', + { + device: 'DESKTOP', + args: { + aspectRatio: '16 9', + }, + }, + ], + [ + 'mobile 7:10 aspect ratio', + { + device: 'MOBILE_IOS', + args: { + aspectRatio: '7 10', + }, + }, + ], + [ + 'mobile minHeight 100vh', + { + device: 'MOBILE_IOS', + args: { + minHeight: '100vh', + }, + }, + ], + [ + 'desktop minimal', + { + device: 'DESKTOP', + args: { + headline: '', + pretitle: '', + title: 'Title', + description: '', + actions: 'none', + }, + }, + ], + [ + 'mobile minimal', + { + device: 'MOBILE_IOS', + args: { + headline: '', + pretitle: '', + title: 'Title', + description: '', + actions: 'none', + }, + }, + ], +] as const; + +test.each(cases)('CoverHero %s', async (_name, {device, args}) => { + await openStoryPage({ + id: 'components-hero-coverhero--default', + device, + args, + }); + + const coverHero = await screen.findByTestId('cover-hero'); + const image = await coverHero.screenshot(); + expect(image).toMatchImageSnapshot(); +}); + +test('CoverHero inside a Slideshow', async () => { + await openStoryPage({ + id: 'components-hero-coverhero--cover-hero-in-slideshow', + args: { + background: 'image', + }, + }); + + const coverHero = await screen.findByTestId('slideshow'); + const image = await coverHero.screenshot(); + expect(image).toMatchImageSnapshot(); +}); diff --git a/src/__screenshot_tests__/hero-screenshot-test.tsx b/src/__screenshot_tests__/hero-screenshot-test.tsx index 5aeb564d72..4534e7a207 100644 --- a/src/__screenshot_tests__/hero-screenshot-test.tsx +++ b/src/__screenshot_tests__/hero-screenshot-test.tsx @@ -17,7 +17,7 @@ const getCases = () => { test.each(getCases())('Hero - %s (%s)', async (background, device) => { await openStoryPage({ - id: 'components-hero--default', + id: 'components-hero-hero--default', device: device as Device, args: {background}, }); @@ -28,7 +28,7 @@ test.each(getCases())('Hero - %s (%s)', async (background, device) => { test.each(DEVICES)('Hero - no vertical padding (%s)', async (device) => { await openStoryPage({ - id: 'components-hero--default', + id: 'components-hero-hero--default', device, args: {noPaddingY: true}, }); @@ -39,7 +39,7 @@ test.each(DEVICES)('Hero - no vertical padding (%s)', async (device) => { test('Hero - custom height', async () => { await openStoryPage({ - id: 'components-hero--default', + id: 'components-hero-hero--default', device: 'MOBILE_IOS', args: {height: '1000px'}, }); @@ -50,7 +50,7 @@ test('Hero - custom height', async () => { test('Hero - background brand in O2-new skin', async () => { await openStoryPage({ - id: 'components-hero--default', + id: 'components-hero-hero--default', skin: 'O2-new', args: {background: 'brand'}, }); diff --git a/src/__stories__/cover-hero-story.tsx b/src/__stories__/cover-hero-story.tsx new file mode 100644 index 0000000000..66fcc47540 --- /dev/null +++ b/src/__stories__/cover-hero-story.tsx @@ -0,0 +1,226 @@ +import * as React from 'react'; +import { + CoverHero, + ButtonPrimary, + ButtonLink, + Tag, + Placeholder, + skinVars, + Slideshow, + ButtonSecondary, +} from '..'; +import usingVrImg from './images/using-vr.jpg'; +import beachImg from './images/beach.jpg'; +import beachVideo from './videos/beach.mp4'; + +import type {TagType} from '..'; + +export default { + title: 'Components/Hero/CoverHero', + parameters: { + fullScreen: true, + }, +}; + +type Args = { + background: 'image' | 'video' | 'custom color' | 'color from skin'; + backgroundColorCustom: string; + backgroundColorFromSkin: string; + variant: 'default' | 'inverse' | 'alternative'; + headlineType: TagType; + headline: string; + pretitle: string; + title: string; + description: string; + withExtra: boolean; + withSideExtra: boolean; + actions: + | 'none' + | 'button' + | 'link' + | 'button and link' + | 'button and secondaryButton' + | 'secondaryButton and link' + | 'button, secondaryButton and link'; + minHeight: string | undefined; + aspectRatio: '1:1' | '16:9' | '7:10' | '4:3' | 'auto'; + centered: boolean; + noPaddingY: boolean; +}; + +export const Default: StoryComponent = ({ + background, + backgroundColorCustom, + backgroundColorFromSkin, + variant, + headlineType, + headline, + pretitle, + title, + description, + withExtra, + withSideExtra, + actions, + minHeight, + aspectRatio, + centered, + noPaddingY, +}) => { + const backgroundProps = + background === 'image' + ? { + backgroundImage: usingVrImg, + } + : background === 'video' + ? { + backgroundVideo: beachVideo, + poster: beachImg, + } + : { + background: backgroundColorFromSkin || backgroundColorCustom, + variant, + }; + + const button = actions.includes('button') ? Action : undefined; + const buttonLink = actions.includes('link') ? Link : undefined; + const secondaryButton = actions.includes('secondaryButton') ? ( + Secondary + ) : undefined; + + return ( + {headline} : undefined} + pretitle={pretitle} + title={title} + description={description} + extra={withExtra ? : undefined} + sideExtra={withSideExtra ? : undefined} + button={button} + secondaryButton={secondaryButton} + buttonLink={buttonLink} + minHeight={minHeight} + aspectRatio={aspectRatio} + centered={centered} + noPaddingY={noPaddingY} + {...backgroundProps} + /> + ); +}; + +Default.storyName = 'CoverHero'; + +Default.args = { + background: 'image', + backgroundColorCustom: '', + backgroundColorFromSkin: '', + variant: 'default', + headlineType: 'promo', + headline: 'Hero', + pretitle: 'Pretitle', + title: 'Title', + description: 'This is a long description with a long text to see how this works', + withExtra: false, + withSideExtra: false, + actions: 'button and link', + minHeight: undefined, + aspectRatio: 'auto', + centered: false, + noPaddingY: false, +}; + +Default.argTypes = { + headlineType: { + options: ['promo', 'active', 'inactive', 'success', 'warning', 'error'], + control: {type: 'select'}, + }, + background: { + options: ['image', 'video', 'color from skin', 'custom color'], + control: {type: 'select'}, + }, + backgroundColorCustom: { + control: {type: 'color'}, + if: {arg: 'background', eq: 'custom color'}, + }, + backgroundColorFromSkin: { + control: {type: 'select'}, + options: {'none (determined by variant)': '', ...skinVars.colors}, + if: {arg: 'background', eq: 'color from skin'}, + }, + variant: { + options: ['default', 'inverse', 'alternative'], + control: {type: 'select'}, + // This control should only be visible when background is set to 'color from skin' or 'custom color'. + // That could look similar to this in a future storybook version (see https://github.com/ComponentDriven/csf/pull/76): + // if: { + // or: [ + // {arg: 'background', eq: 'color from skin'}, + // {arg: 'background', eq: 'custom color'}, + // ], + // }, + }, + actions: { + options: [ + 'none', + 'button', + 'link', + 'button and link', + 'button and secondaryButton', + 'secondaryButton and link', + 'button secondaryButton and link', + ], + control: { + type: 'select', + labels: { + 'button secondaryButton and link': 'button, secondaryButton and link', + }, + }, + }, + minHeight: { + control: {type: 'text'}, + }, + aspectRatio: { + options: ['1 1', '16 9', '7 10', '4 3', 'auto'], + mapping: { + '1 1': '1:1', + '16 9': '16:9', + '7 10': '7:10', + '4 3': '4:3', + }, + control: { + type: 'select', + labels: { + '1 1': '1:1', + '16 9': '16:9', + '7 10': '7:10', + '4 3': '4:3', + }, + }, + }, +}; + +export const CoverHeroInSlideshow: StoryComponent = () => ( + ( + Headline} + pretitle="Pretitle" + title={['Title', 'Title 2', 'Title 3'][idx]} + description={ + ['Description', 'This is a long description with a long text to see how this works', ''][ + idx + ] + } + extra={} + sideExtra={} + button={Action} + buttonLink={Link} + /> + ))} + /> +); + +CoverHeroInSlideshow.storyName = 'CoverHero in Slideshow'; diff --git a/src/__stories__/grid-layout-story.tsx b/src/__stories__/grid-layout-story.tsx index 16efae1cd0..fda927835a 100644 --- a/src/__stories__/grid-layout-story.tsx +++ b/src/__stories__/grid-layout-story.tsx @@ -2,6 +2,8 @@ import * as React from 'react'; import {GridLayout, ResponsiveLayout} from '..'; import {Placeholder} from '../placeholder'; +import type {VerticalSpace} from '../grid-layout'; + export default { title: 'Layout/Grid layout', parameters: { @@ -9,9 +11,30 @@ export default { }, }; -export const WithoutTemplate: StoryComponent = () => ( +type Args = { + collapseBreakpoint: 'tablet' | 'mobile'; + verticalSpace: VerticalSpace; +}; + +const args = { + collapseBreakpoint: 'tablet', + verticalSpace: 8, +} as const; + +const argTypes = { + collapseBreakpoint: { + options: ['tablet', 'mobile'], + control: {type: 'select'}, + }, + verticalSpace: { + options: [0, 2, 4, 8, 12, 16, 24, 32, 40], + control: {type: 'select'}, + }, +}; + +export const WithoutTemplate: StoryComponent = ({collapseBreakpoint, verticalSpace}) => ( - + @@ -29,43 +52,85 @@ export const WithoutTemplate: StoryComponent = () => ( ); WithoutTemplate.storyName = 'Without template'; +WithoutTemplate.args = args; +WithoutTemplate.argTypes = argTypes; -export const SixAndSix: StoryComponent = () => ( +export const SixAndSix: StoryComponent = ({collapseBreakpoint, verticalSpace}) => ( - } right={} /> + } + right={} + /> ); SixAndSix.storyName = 'Template 6+6'; +SixAndSix.args = args; +SixAndSix.argTypes = argTypes; -export const EightAndFour: StoryComponent = () => ( +export const EightAndFour: StoryComponent = ({collapseBreakpoint, verticalSpace}) => ( - } right={} /> + } + right={} + /> ); EightAndFour.storyName = 'Template 8+4'; +EightAndFour.args = args; +EightAndFour.argTypes = argTypes; -export const FourAndSix: StoryComponent = () => ( +export const FourAndSix: StoryComponent = ({collapseBreakpoint, verticalSpace}) => ( - } right={} /> + } + right={} + /> ); FourAndSix.storyName = 'Template 4+6'; +FourAndSix.args = args; +FourAndSix.argTypes = argTypes; -export const FiveAndFour: StoryComponent = () => ( +export const FiveAndFour: StoryComponent = ({collapseBreakpoint, verticalSpace}) => ( - } right={} /> + } + right={} + /> ); FiveAndFour.storyName = 'Template 5+4'; +FiveAndFour.args = args; +FiveAndFour.argTypes = argTypes; -export const ThreeAndNine: StoryComponent = () => ( +export const ThreeAndNine: StoryComponent = ({collapseBreakpoint, verticalSpace}) => ( - } right={} /> + } + right={} + /> ); ThreeAndNine.storyName = 'Template 3+9'; +ThreeAndNine.args = args; +ThreeAndNine.argTypes = argTypes; diff --git a/src/__stories__/hero-story.tsx b/src/__stories__/hero-story.tsx index d64f3935ea..ad8bd75f9b 100644 --- a/src/__stories__/hero-story.tsx +++ b/src/__stories__/hero-story.tsx @@ -8,7 +8,7 @@ import type {TagType} from '..'; import type {AspectRatio} from '../video'; export default { - title: 'Components/Hero', + title: 'Components/Hero/Hero', parameters: { fullScreen: true, }, diff --git a/src/__stories__/poster-card-story.tsx b/src/__stories__/poster-card-story.tsx index 8e857472cc..4bff363265 100644 --- a/src/__stories__/poster-card-story.tsx +++ b/src/__stories__/poster-card-story.tsx @@ -209,8 +209,14 @@ Default.argTypes = { variant: { options: ['default', 'inverse', 'alternative'], control: {type: 'select'}, - // this control should only be visible when background is set to 'color from skin' or 'custom color' - // if: {arg: 'background', eq: 'color'}, + // This control should only be visible when background is set to 'color from skin' or 'custom color'. + // That could look similar to this in a future storybook version (see https://github.com/ComponentDriven/csf/pull/76): + // if: { + // or: [ + // {arg: 'background', eq: 'color from skin'}, + // {arg: 'background', eq: 'custom color'}, + // ], + // }, }, aspectRatio: { options: ['1:1', '16:9', '7:10', '9:10', 'auto'], diff --git a/src/button-group.css.ts b/src/button-group.css.ts index ae0b0d007a..4bee4667a7 100644 --- a/src/button-group.css.ts +++ b/src/button-group.css.ts @@ -1,5 +1,6 @@ import {style} from '@vanilla-extract/css'; import {sprinkles} from './sprinkles.css'; +import * as mq from './media-queries.css'; const buttonLayoutSpacing = 16; const buttonLinkPadding = 12; @@ -11,6 +12,30 @@ export const inline = style([ }, ]); +export const centerInMobile = style({ + '@media': { + [mq.mobile]: { + justifyContent: 'center', + }, + }, +}); + +export const centerInTablet = style({ + '@media': { + [mq.tablet]: { + justifyContent: 'center', + }, + }, +}); + +export const centerInDesktop = style({ + '@media': { + [mq.desktopOrBigger]: { + justifyContent: 'center', + }, + }, +}); + export const container = style({ marginTop: -buttonLayoutSpacing, marginLeft: -buttonLayoutSpacing - buttonLinkPadding, diff --git a/src/button-group.tsx b/src/button-group.tsx index 3bc957bbe1..b21d22f517 100644 --- a/src/button-group.tsx +++ b/src/button-group.tsx @@ -4,22 +4,46 @@ import {getPrefixedDataAttributes} from './utils/dom'; import * as styles from './button-group.css'; import type {ButtonLink, ButtonPrimary, ButtonSecondary} from './button'; -import type {DataAttributes, RendersNullableElement} from './utils/types'; +import type {ByBreakpoint, DataAttributes, RendersNullableElement} from './utils/types'; export interface ButtonGroupProps { primaryButton?: RendersNullableElement; secondaryButton?: RendersNullableElement; link?: RendersNullableElement; dataAttributes?: DataAttributes; + align?: ByBreakpoint<'center' | 'left'>; } -const ButtonGroup: React.FC = ({primaryButton, secondaryButton, link, dataAttributes}) => { +const ButtonGroup: React.FC = ({ + primaryButton, + secondaryButton, + link, + align = 'left', + dataAttributes, +}) => { const anyAction = !!primaryButton || !!secondaryButton || !!link; const bothButtons = !!primaryButton && !!secondaryButton; + const alignByBreakpoint = + typeof align === 'string' + ? { + mobile: align, + tablet: align, + desktop: align, + } + : { + mobile: align.mobile ?? 'left', + tablet: align.tablet ?? align.mobile ?? 'left', + desktop: align.desktop ?? 'left', + }; + return anyAction ? (
{(primaryButton || secondaryButton) && ( diff --git a/src/card.tsx b/src/card.tsx index d138c35719..e5c911ee27 100644 --- a/src/card.tsx +++ b/src/card.tsx @@ -287,11 +287,14 @@ const CardActionPauseIcon = ({color}: IconProps) => ; -const useVideoWithControls = ( +export const useVideoWithControls = ( videoSrc?: VideoSource, poster?: string, videoRef?: React.RefObject -) => { +): { + video?: React.ReactNode; + videoAction?: CardAction; +} => { const {texts} = useTheme(); const videoController = React.useRef(null); const [videoStatus, dispatch] = React.useReducer(videoReducer, 'loading'); @@ -338,22 +341,24 @@ const useVideoWithControls = ( return {video}; } - const videoAction: CardAction = { - uncheckedProps: { - Icon: - videoStatus === 'loadingTimeout' && !isRunningAcceptanceTest() - ? CardActionSpinner - : CardActionPauseIcon, - label: videoStatus === 'loadingTimeout' ? '' : texts.pauseIconButtonLabel, - }, - checkedProps: { - Icon: CardActionPlayIcon, - label: texts.playIconButtonLabel, - }, - onChange: onVideoControlPress, - disabled: videoStatus === 'loadingTimeout', - checked: videoStatus === 'paused', - }; + const videoAction: CardAction | undefined = video + ? { + uncheckedProps: { + Icon: + videoStatus === 'loadingTimeout' && !isRunningAcceptanceTest() + ? CardActionSpinner + : CardActionPauseIcon, + label: videoStatus === 'loadingTimeout' ? '' : texts.pauseIconButtonLabel, + }, + checkedProps: { + Icon: CardActionPlayIcon, + label: texts.playIconButtonLabel, + }, + onChange: onVideoControlPress, + disabled: videoStatus === 'loadingTimeout', + checked: videoStatus === 'paused', + } + : undefined; return { video, diff --git a/src/carousel.css.ts b/src/carousel.css.ts index 60a6b207de..865f943bbc 100644 --- a/src/carousel.css.ts +++ b/src/carousel.css.ts @@ -84,9 +84,14 @@ export const bulletActiveInverse = style([ ]); const arrowButtonSize = 40; -export const slideshowContainer = sprinkles({ - position: 'relative', -}); +export const slideshowContainer = style([ + sprinkles({ + position: 'relative', + }), + {}, // needed to force vanilla extract to generate a class name (not only sprinkles) +]); + +export const slideshowWithBullets = style({}); const hideScrollbar = style({ scrollbarWidth: 'none', // Hide in FF diff --git a/src/carousel.tsx b/src/carousel.tsx index ef2cb4c0dc..9ed67ab34e 100644 --- a/src/carousel.tsx +++ b/src/carousel.tsx @@ -817,7 +817,9 @@ export const Slideshow = ({
diff --git a/src/cover-hero-media.tsx b/src/cover-hero-media.tsx new file mode 100644 index 0000000000..bcb4907db9 --- /dev/null +++ b/src/cover-hero-media.tsx @@ -0,0 +1,35 @@ +'use client'; +import * as React from 'react'; +import {CardActionsGroup, useVideoWithControls} from './card'; +import * as styles from './cover-hero.css'; +import Image from './image'; + +import type {ExclusifyUnion} from './utils/utility-types'; +import type {VideoElement, VideoSource} from './video'; + +export type ImageProps = { + backgroundImage: string; +}; + +export type VideoProps = { + backgroundVideo: VideoSource; + poster?: string; + backgroundVideoRef?: React.RefObject; +}; + +export const CoverHeroMedia = ({ + backgroundVideo, + backgroundImage, + poster, + backgroundVideoRef, +}: ExclusifyUnion): React.ReactElement => { + const {video, videoAction} = useVideoWithControls(backgroundVideo, poster, backgroundVideoRef); + return ( +
+ {backgroundImage && } + {backgroundVideo && video} +
+ {videoAction && } +
+ ); +}; diff --git a/src/cover-hero.css.ts b/src/cover-hero.css.ts new file mode 100644 index 0000000000..921f992dcc --- /dev/null +++ b/src/cover-hero.css.ts @@ -0,0 +1,128 @@ +import {createVar, globalStyle, style} from '@vanilla-extract/css'; +import {sprinkles} from './sprinkles.css'; +import * as mq from './media-queries.css'; +import {slideshowWithBullets, slideshowContainer} from './carousel.css'; + +const aspectRatio = createVar(); + +export const vars = {aspectRatio}; + +export const coverHero = style([ + sprinkles({ + position: 'relative', + display: 'flex', + flexDirection: 'column', + justifyContent: 'center', + width: '100%', + top: 0, + bottom: 0, + }), + {}, +]); + +export const coverHeroContainer = style([ + sprinkles({ + position: 'relative', + display: 'flex', + width: '100%', + }), + { + selectors: { + [`${slideshowContainer} &`]: { + height: '100%', + }, + }, + }, +]); + +export const withAspectRatio = style({ + ':before': { + float: 'left', + content: '""', + paddingTop: `calc(100% / ${aspectRatio})`, + }, + ':after': { + display: 'block', + content: '""', + clear: 'both', + }, +}); + +export const minHeight = style({ + minHeight: 400, + '@media': { + [mq.tabletOrBigger]: { + minHeight: 460, + }, + }, +}); + +// give some extra space for the slideshow bullets +globalStyle(`${slideshowWithBullets} ${coverHero}:after`, { + '@media': { + [mq.mobile]: { + display: 'block', + content: '""', + height: 24, + }, + }, +}); + +export const hasSideExtra = style({}); + +export const centered = style([ + sprinkles({ + alignItems: 'center', + }), + { + textAlign: 'center', + selectors: { + [`${hasSideExtra}&`]: { + '@media': { + [mq.tabletOrBigger]: { + textAlign: 'left', + }, + }, + }, + }, + }, +]); + +export const mediaLayer = sprinkles({ + position: 'absolute', + objectFit: 'cover', + width: '100%', + height: '100%', +}); + +export const mediaOverlay = style([ + sprinkles({ + position: 'absolute', + top: 0, + left: 0, + width: '100%', + height: '100%', + }), + { + backgroundColor: 'rgba(0, 0, 0, 0.4)', + }, +]); + +export const mainContent = sprinkles({position: 'relative'}); + +// pretitle and description should be 6 grid columns wide, but they are already inside a grid item (the left side of GridLayout) +// so we can't adjust their width to the parent grid columns. 75% is a good approximation. +export const sixColumns = style({ + '@media': { + [mq.tabletOrBigger]: { + width: '75%', + selectors: { + [`${centered}:not(${hasSideExtra}) &`]: { + margin: '0 auto', + }, + }, + }, + }, +}); + +export const sideExtra = sprinkles({position: 'relative'}); diff --git a/src/cover-hero.tsx b/src/cover-hero.tsx new file mode 100644 index 0000000000..9d7c2c94bc --- /dev/null +++ b/src/cover-hero.tsx @@ -0,0 +1,204 @@ +import * as React from 'react'; +import ResponsiveLayout from './responsive-layout'; +import Box from './box'; +import ButtonGroup from './button-group'; +import Stack from './stack'; +import {Text3, Text8} from './text'; +import {vars} from './skins/skin-contract.css'; +import * as styles from './cover-hero.css'; +import classnames from 'classnames'; +import {applyCssVars} from './utils/css'; +import * as mediaStyles from './image.css'; +import GridLayout from './grid-layout'; +import {CoverHeroMedia} from './cover-hero-media'; +import {getPrefixedDataAttributes} from './utils/dom'; + +import type {DataAttributes} from './utils/types'; +import type {ImageProps, VideoProps} from './cover-hero-media'; +import type {AspectRatio} from './image'; +import type {ExclusifyUnion} from './utils/utility-types'; +import type {ButtonLink, ButtonPrimary, ButtonSecondary} from './button'; +import type Tag from './tag'; +import type {RendersNullableElement} from './utils/renders-element'; +import type {Variant} from './theme-variant-context'; + +type BaseProps = { + headline?: RendersNullableElement; + pretitle?: string; + pretitleLinesMax?: number; + title: string; + titleLinesMax?: number; + titleAs?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'; + description?: string; + descriptionLinesMax?: number; + extra?: React.ReactNode; + sideExtra?: React.ReactNode; + button?: RendersNullableElement; + secondaryButton?: RendersNullableElement; + buttonLink?: RendersNullableElement; + minHeight?: string | number; + aspectRatio?: AspectRatio | number | 'auto'; + centered?: boolean; + noPaddingY?: boolean; + /** "data-" prefix is automatically added. For example, use "testid" instead of "data-testid" */ + dataAttributes?: DataAttributes; + 'aria-label'?: string; +}; + +type BackgroundProps = { + background?: string; + variant?: Variant; +}; + +type CoverHeroProps = BaseProps & ExclusifyUnion; + +const aspectRatioToNumber = (aspectRatio?: BaseProps['aspectRatio']): number => { + if (!aspectRatio || aspectRatio === 'auto') { + return 0; + } + if (typeof aspectRatio === 'number') { + return aspectRatio; + } + return { + '1:1': 1, + '16:9': 16 / 9, + '7:10': 7 / 10, + '4:3': 9 / 10, + }[aspectRatio]; +}; + +const CoverHero = React.forwardRef( + ( + { + headline, + pretitle, + pretitleLinesMax, + title, + titleLinesMax, + titleAs = 'h1', + description, + descriptionLinesMax, + extra, + sideExtra, + button, + secondaryButton, + buttonLink, + minHeight, + aspectRatio = 'auto', + variant, + centered, + noPaddingY, + dataAttributes, + 'aria-label': ariaLabel, + ...mediaProps + }, + ref + ) => { + const hasMedia = mediaProps.backgroundVideo || mediaProps.backgroundImage; + + const background = hasMedia + ? 'none' + : mediaProps.background || + { + default: vars.colors.background, + inverse: vars.colors.backgroundBrand, + alternative: vars.colors.backgroundAlternative, + }[variant ?? 'default']; + + const textShadow = hasMedia ? '0 0 15px rgba(0, 0, 0, 0.4)' : undefined; + + const mainContent = ( +
+ {headline && {headline}} + + + {pretitle && ( +
+ + {pretitle} + +
+ )} + + {title} + +
+ {description && ( +
+ + {description} + +
+ )} +
+ {extra} +
+ ); + + const withAspectRatio = aspectRatio && aspectRatio !== 'auto'; + + return ( +
+
+ {hasMedia ? : null} + + + + {centered && !sideExtra ? ( + {mainContent} + ) : ( + {sideExtra}
} + /> + )} + + + + +
+ + ); + } +); + +export default CoverHero; diff --git a/src/grid-layout.css.ts b/src/grid-layout.css.ts index 3f2568e5db..2a400d9f95 100644 --- a/src/grid-layout.css.ts +++ b/src/grid-layout.css.ts @@ -1,4 +1,4 @@ -import {createVar, fallbackVar, style} from '@vanilla-extract/css'; +import {createVar, fallbackVar, globalStyle, style} from '@vanilla-extract/css'; import * as mq from './media-queries.css'; export const desktopSmallColumn = style({}); @@ -6,22 +6,35 @@ export const desktopMediumColumn = style({}); export const desktopLargeColumn = style({}); const verticalSpace = createVar(); + +const collapsedGrid = { + gridTemplateColumns: 'minmax(0, 1fr)', + gridColumnGap: 16, + gap: fallbackVar(verticalSpace, '0px'), +}; + export const grid = style({ display: 'grid', '@media': { [mq.largeDesktop]: { - gridColumnGap: 24, gridTemplateColumns: 'repeat(12, 1fr)', + gridColumnGap: 24, }, [mq.desktop]: { gridTemplateColumns: 'repeat(12, 1fr)', gridColumnGap: 16, }, - [mq.tabletOrSmaller]: { - gridTemplateColumns: 'minmax(0, 1fr)', + [mq.tablet]: { + gridTemplateColumns: 'repeat(12, 1fr)', gridColumnGap: 16, - gap: fallbackVar(verticalSpace, '0px'), }, + [mq.mobile]: collapsedGrid, + }, +}); + +export const collapsedInTablet = style({ + '@media': { + [mq.tablet]: collapsedGrid, }, }); @@ -31,7 +44,18 @@ export const span = style({ [mq.desktopOrBigger]: { gridColumn: `span ${colSpan}`, }, - [mq.tabletOrSmaller]: { + [mq.tablet]: { + gridColumn: `span ${colSpan}`, + }, + [mq.mobile]: { + gridColumn: 'span 1', + }, + }, +}); + +globalStyle(`${collapsedInTablet} ${span}`, { + '@media': { + [mq.tablet]: { gridColumn: 'span 1', }, }, diff --git a/src/grid-layout.tsx b/src/grid-layout.tsx index 19bb864d90..f06d5b068b 100644 --- a/src/grid-layout.tsx +++ b/src/grid-layout.tsx @@ -5,80 +5,83 @@ import classnames from 'classnames'; import DesktopContainerTypeContextProvider from './desktop-container-type-context'; import {applyCssVars} from './utils/css'; +import type {ExclusifyUnion} from './utils/utility-types'; import type {DataAttributes} from './utils/types'; -type VerticalSpace = 0 | 2 | 4 | 8 | 12 | 16 | 24 | 32 | 40 | 48 | 56 | 64 | 72 | 80; +export type VerticalSpace = 0 | 2 | 4 | 8 | 12 | 16 | 24 | 32 | 40 | 48 | 56 | 64 | 72 | 80; -type PropsChildren = { - template?: undefined; - children: React.ReactNode; +type CommonProps = { verticalSpace?: VerticalSpace; + collapseBreakpoint?: 'tablet' | 'mobile'; dataAttributes?: DataAttributes; }; +type PropsChildren = { + children: React.ReactNode; +}; + type PropsTemplate6_6 = { template: '6+6'; left: React.ReactNode; right: React.ReactNode; - children?: undefined; - verticalSpace?: VerticalSpace; - dataAttributes?: DataAttributes; }; type PropsTemplate8_4 = { template: '8+4'; left: React.ReactNode; right: React.ReactNode; - children?: undefined; - verticalSpace?: VerticalSpace; - dataAttributes?: DataAttributes; }; type PropsTemplate4_6 = { template: '4+6'; left: React.ReactNode; right: React.ReactNode; - children?: undefined; - verticalSpace?: VerticalSpace; - dataAttributes?: DataAttributes; }; type PropsTemplate5_4 = { template: '5+4'; left: React.ReactNode; right: React.ReactNode; - children?: undefined; - verticalSpace?: VerticalSpace; - dataAttributes?: DataAttributes; }; type PropsTemplate3_9 = { template: '3+9'; left: React.ReactNode; right: React.ReactNode; - children?: undefined; - verticalSpace?: VerticalSpace; - dataAttributes?: DataAttributes; }; type PropsTemplate10 = { template: '10'; children: React.ReactNode; - verticalSpace?: VerticalSpace; - dataAttributes?: DataAttributes; }; -type Props = - | PropsChildren - | PropsTemplate6_6 - | PropsTemplate8_4 - | PropsTemplate4_6 - | PropsTemplate5_4 - | PropsTemplate3_9 - | PropsTemplate10; +type PropsTemplate8 = { + template: '8'; + children: React.ReactNode; +}; -const GridLayout: React.FC = (props) => { - const dataAttributes = getPrefixedDataAttributes(props.dataAttributes); +type Props = CommonProps & + ExclusifyUnion< + | PropsChildren + | PropsTemplate6_6 + | PropsTemplate8_4 + | PropsTemplate4_6 + | PropsTemplate5_4 + | PropsTemplate3_9 + | PropsTemplate10 + | PropsTemplate8 + >; + +const GridLayout: React.FC = ({ + dataAttributes, + template, + left, + right, + verticalSpace, + collapseBreakpoint = 'tablet', + children, +}) => { + const prefixedDataAttributes = getPrefixedDataAttributes(dataAttributes, 'GridLayout'); const spanStyles = (n: number) => ({ className: classnames(styles.span, { @@ -90,95 +93,107 @@ const GridLayout: React.FC = (props) => { }); const gridStyles = { - className: styles.grid, - style: props.verticalSpace + className: classnames(styles.grid, {[styles.collapsedInTablet]: collapseBreakpoint === 'tablet'}), + style: verticalSpace ? applyCssVars({ - [styles.vars.verticalSpace]: `${props.verticalSpace}px`, + [styles.vars.verticalSpace]: `${verticalSpace}px`, }) : undefined, }; - if (props.template === '6+6') { + if (template === '6+6') { return ( -
+
-
{props.left}
-
{props.right}
+
{left}
+
{right}
); } - if (props.template === '8+4') { + if (template === '8+4') { return ( -
+
-
{props.left}
+
{left}
-
{props.right}
+
{right}
); } - if (props.template === '4+6') { + if (template === '4+6') { return ( -
+
-
{props.left}
+
{left}
-
{props.right}
+
{right}
); } - if (props.template === '5+4') { + if (template === '5+4') { return ( -
+
-
{props.left}
+
{left}
-
{props.right}
+
{right}
); } - if (props.template === '3+9') { + if (template === '3+9') { return ( -
+
-
{props.left}
+
{left}
-
{props.right}
+
{right}
); } - if (props.template === '10') { + if (template === '10') { return ( -
+
-
{props.children}
+
{children}
); } + if (template === '8') { + return ( +
+
+ +
{children}
+
+
+
+ ); + } + return ( -
- {props.children} +
+ {children}
); }; diff --git a/src/image.css.ts b/src/image.css.ts index f7ffb744e4..aec33a15fc 100644 --- a/src/image.css.ts +++ b/src/image.css.ts @@ -27,7 +27,6 @@ export const image = style([ borderRadius: skinVars.borderRadii.container, }), { - zIndex: 1, transition: `opacity ${FADE_IN_DURATION_MS}ms`, }, ]); diff --git a/src/image.tsx b/src/image.tsx index e41539b2ab..2ae26fa9db 100644 --- a/src/image.tsx +++ b/src/image.tsx @@ -286,7 +286,6 @@ export const ImageContent = React.forwardRef( position: 'absolute', width: '100%', height: '100%', - zIndex: 1, }} > diff --git a/src/index.tsx b/src/index.tsx index 0989c42363..62bce1c4d9 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -81,6 +81,7 @@ export { CardActionIconButton, } from './card'; export {default as Hero} from './hero'; +export {default as CoverHero} from './cover-hero'; export {Table} from './table'; export {default as Divider} from './divider'; export {Menu, MenuItem, MenuSection} from './menu';