Skip to content

Commit

Permalink
✨ add AsChild to show/hide (#2312)
Browse files Browse the repository at this point in the history
* ✨ add AsChild to show/hide

* 📝 changeset

* 📝 asChild jsdoc

* 📝 show demo

* 📝 hide-demo

* Update aksel.nav.no/website/pages/eksempler/primitive-hide/as-child.tsx

* Update aksel.nav.no/website/pages/eksempler/primitive-show/as-child.tsx

* Update aksel.nav.no/website/pages/eksempler/primitive-hide/as-child.tsx

* 📝 Oppdatert docs

---------

Co-authored-by: Ken <26967723+KenAJoh@users.noreply.github.com>
Co-authored-by: Ken <ken.aleksander@gmail.com>
  • Loading branch information
3 people committed Sep 26, 2023
1 parent 522d136 commit ce837ed
Show file tree
Hide file tree
Showing 15 changed files with 296 additions and 66 deletions.
5 changes: 5 additions & 0 deletions .changeset/serious-months-listen.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@navikt/ds-react": patch
---

Primitives: Show/Hide støtter nå `asChild`-api
36 changes: 16 additions & 20 deletions @navikt/core/css/primitives/responsive.css
Original file line number Diff line number Diff line change
@@ -1,51 +1,47 @@
.navds-responsive {
display: none;
}

@media (min-width: 480px) {
.navds-responsive__above--sm {
display: revert;
.navds-responsive__below--sm {
display: none !important;
}
}

@media (max-width: 479px) {
.navds-responsive__below--sm {
display: revert;
.navds-responsive__above--sm {
display: none !important;
}
}

@media (min-width: 768px) {
.navds-responsive__above--md {
display: revert;
.navds-responsive__below--md {
display: none !important;
}
}

@media (max-width: 767px) {
.navds-responsive__below--md {
display: revert;
.navds-responsive__above--md {
display: none !important;
}
}

@media (min-width: 1024px) {
.navds-responsive__above--lg {
display: revert;
.navds-responsive__below--lg {
display: none !important;
}
}

@media (max-width: 1023px) {
.navds-responsive__below--lg {
display: revert;
.navds-responsive__above--lg {
display: none !important;
}
}

@media (min-width: 1280px) {
.navds-responsive__above--xl {
display: revert;
.navds-responsive__below--xl {
display: none !important;
}
}

@media (max-width: 1279px) {
.navds-responsive__below--xl {
display: revert;
.navds-responsive__above--xl {
display: none !important;
}
}
27 changes: 21 additions & 6 deletions @navikt/core/react/src/layout/responsive/Responsive.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import cl from "clsx";
import React, { forwardRef, HTMLAttributes } from "react";
import { BreakpointsAlias } from "../utilities/css";
import { Slot } from "../../util/Slot";

export interface ResponsiveProps extends HTMLAttributes<HTMLDivElement> {
children: React.ReactNode;
Expand All @@ -19,21 +20,35 @@ export interface ResponsiveProps extends HTMLAttributes<HTMLDivElement> {
* @default "div"
*/
as?: "div" | "span";
/**
* When true, will render element as its child. This merges classes, styles and event handlers.
*/
asChild?: boolean;
}

const Responsive = forwardRef<
HTMLDivElement,
ResponsiveProps & { variant: "show" | "hide" }
>(
(
{ as: Component = "div", className, above, below, variant, ...rest },
{
as: Component = "div",
className,
above,
below,
variant,
asChild,
...rest
},
ref
) => {
const aboveProp = variant === "show" ? above : below;
const belowProp = variant === "show" ? below : above;

const Comp = asChild ? Slot : Component;

return (
<Component
<Comp
{...rest}
ref={ref}
className={cl("navds-responsive", className, {
Expand All @@ -54,14 +69,14 @@ const Responsive = forwardRef<
* @example
* <HGrid columns={{ xs: 1, md: 2 }} gap="4">
* <div/>
* <Hide below="md">
* <Hide below="md" asChild>
* // Only visible above "md"
* </Hide>
* </HGrid>
* @example
* <HGrid columns={{ xs: 1, md: 2 }} gap="4">
* <div/>
* <Hide above="md">
* <Hide above="md" asChild>
* // Only visible below "md"
* </Hide>
* </HGrid>
Expand All @@ -79,14 +94,14 @@ export const Hide = forwardRef<HTMLDivElement, ResponsiveProps>(
* @example
* <HGrid columns={{ xs: 1, md: 2 }} gap="4">
* <div/>
* <Show below="md">
* <Show below="md" asChild>
* // Only visible below "md"
* </Show>
* </HGrid>
* @example
* <HGrid columns={{ xs: 1, md: 2 }} gap="4">
* <div/>
* <Show above="md">
* <Show above="md" asChild>
* // Only visible above "md"
* </Show>
* </HGrid>
Expand Down
35 changes: 35 additions & 0 deletions @navikt/core/react/src/layout/responsive/hide.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,38 @@ export const Default = {
</VStack>
),
};

export const AsChild = {
render: () => (
<VStack gap="12">
<VStack gap="2" align="center">
<Hide above="xl" asChild>
<Tag variant="neutral">Hidden above xl</Tag>
</Hide>
<Hide above="lg" asChild>
<Tag variant="neutral">Hidden above lg</Tag>
</Hide>
<Hide above="md" asChild>
<Tag variant="neutral">Hidden above md</Tag>
</Hide>
<Hide above="sm" asChild>
<Tag variant="neutral">Hidden above sm</Tag>
</Hide>
</VStack>
<VStack gap="2" align="center">
<Hide below="xl" asChild>
<Tag variant="alt3">Hidden below xl</Tag>
</Hide>
<Hide below="lg" asChild>
<Tag variant="alt3">Hidden below lg</Tag>
</Hide>
<Hide below="md" asChild>
<Tag variant="alt3">Hidden below md</Tag>
</Hide>
<Hide below="sm" asChild>
<Tag variant="alt3">Hidden below sm</Tag>
</Hide>
</VStack>
</VStack>
),
};
35 changes: 35 additions & 0 deletions @navikt/core/react/src/layout/responsive/show.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,38 @@ export const Default = {
</VStack>
),
};

export const AsChild = {
render: () => (
<VStack gap="12">
<VStack gap="2" align="center">
<Show above="xl" asChild>
<Tag variant="neutral">Visible above xl</Tag>
</Show>
<Show above="lg" asChild>
<Tag variant="neutral">Visible above lg</Tag>
</Show>
<Show above="md" asChild>
<Tag variant="neutral">Visible above md</Tag>
</Show>
<Show above="sm" asChild>
<Tag variant="neutral">Visible above sm</Tag>
</Show>
</VStack>
<VStack gap="2" align="center">
<Show below="xl" asChild>
<Tag variant="alt3">Visible below xl</Tag>
</Show>
<Show below="lg" asChild>
<Tag variant="alt3">Visible below lg</Tag>
</Show>
<Show below="md" asChild>
<Tag variant="alt3">Visible below md</Tag>
</Show>
<Show below="sm" asChild>
<Tag variant="alt3">Visible below sm</Tag>
</Show>
</VStack>
</VStack>
),
};
57 changes: 57 additions & 0 deletions aksel.nav.no/website/pages/eksempler/primitive-hide/as-child.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Hide, HGrid } from "@navikt/ds-react";
import { withDsExample } from "components/website-modules/examples/withDsExample";
import cl from "clsx";

const Example = () => {
return (
<HGrid columns={{ xs: 1, md: 2 }} gap="4">
<Hide above="md" asChild>
<Placeholder mobil text="Synlig bare på mobil" />
</Hide>
<Placeholder text="Alltid synlig" />
</HGrid>
);
};

export default withDsExample(Example, { showBreakpoints: true });

/* Storybook story */
export const Demo = {
render: Example,
};

export const args = {
index: 0,
desc: "Vi anbefaler å bruke 'asChild'-prop der mulig. Dette reduserer dom-noder og forenkler output. For at Hide + child-komponent skal fungere må child kunne ta inn 'className' som prop.",
};

const Placeholder = ({
text,
noPadding,
mobil,
desktop,
className,
}: {
text?: string;
noPadding?: boolean;
mobil?: boolean;
desktop?: boolean;
className?: string;
}) => {
return (
<div
className={cl(
"min-h-24 text-text-on-action grid aspect-video h-auto w-auto place-content-center rounded p-2",
className,
{
"bg-pink-600": mobil,
"bg-violet-600": desktop,
"bg-teal-600": !desktop && !mobil,
}
)}
style={{ padding: noPadding && 0 }}
>
{text}
</div>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -20,27 +20,27 @@ const Example = () => {
<Button icon={<MenuHamburgerIcon aria-hidden />} variant="tertiary">
Meny
</Button>
<Hide below="md">
<Hide below="md" asChild>
<Button
icon={<MagnifyingGlassIcon aria-hidden />}
variant="tertiary"
>
Søk
</Button>
</Hide>
<Hide below="sm">
<Hide below="sm" asChild>
<Button icon={<BellIcon aria-hidden />} variant="tertiary">
Varsler
</Button>
</Hide>
<Hide below="md">
<Hide below="md" asChild>
<Button icon={<PersonIcon aria-hidden />} variant="tertiary">
<BodyShort weight="semibold" truncate className="max-w-[10vw]">
Ola Aksel Norman
</BodyShort>
</Button>
</Hide>
<Hide below="md">
<Hide below="md" asChild>
<Button icon={<LeaveIcon aria-hidden />} variant="tertiary">
Logg ut
</Button>
Expand Down
5 changes: 4 additions & 1 deletion aksel.nav.no/website/pages/eksempler/primitive-hide/hide.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import cl from "clsx";
const Example = () => {
return (
<HGrid columns="1" gap="4">
<Hide above="md">
<Hide above="md" asChild>
<Placeholder mobil text="Synlig bare på mobil" />
</Hide>
<Placeholder text="Alltid synlig" />
Expand All @@ -30,16 +30,19 @@ const Placeholder = ({
noPadding,
mobil,
desktop,
className,
}: {
text?: string;
noPadding?: boolean;
mobil?: boolean;
desktop?: boolean;
className?: string;
}) => {
return (
<div
className={cl(
"min-h-24 text-text-on-action grid aspect-video h-auto w-auto place-content-center rounded p-2",
className,
{
"bg-pink-600": mobil,
"bg-violet-600": desktop,
Expand Down

0 comments on commit ce837ed

Please sign in to comment.