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

Tooltip labeling #3094

Merged
merged 16 commits into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
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
5 changes: 5 additions & 0 deletions .changeset/little-files-cough.md
Copy link
Contributor

Choose a reason for hiding this comment

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

Major?

Text should be updated.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

👍 Updated to major and added a TODO. Will write a section for v7 here https://aksel.nav.no/grunnleggende/kode/migrering.

For now i will create a feature-branch we can merge v7 changes into and change the base of this branch to that one.

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@navikt/ds-react": minor
---

Tooltip: New prop 'desribeChild' to better handle elements with no visible labels.
41 changes: 26 additions & 15 deletions @navikt/core/react/src/tooltip/Tooltip.tsx
HalvorHaugan marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ import {
useInteractions,
} from "@floating-ui/react";
import cl from "clsx";
import React, { HTMLAttributes, cloneElement, forwardRef, useRef } from "react";
import React, { HTMLAttributes, forwardRef, useRef } from "react";
import { useModalContext } from "../modal/Modal.context";
import { Portal } from "../portal";
import { Slot } from "../slot/Slot";
import { Detail } from "../typography";
import { useId } from "../util/hooks";
import { useControllableState } from "../util/hooks/useControllableState";
Expand Down Expand Up @@ -80,6 +81,12 @@ export interface TooltipProps extends HTMLAttributes<HTMLDivElement> {
* List of Keyboard-keys for shortcuts.
*/
keys?: string[];
/**
* When false, Tooltip labels the element, and child-elements content will be ignored by screen-readers.
* When true, content is added as additional information to the child element.
* @default false
*/
describesChild?: boolean;
}

/**
Expand All @@ -89,9 +96,9 @@ export interface TooltipProps extends HTMLAttributes<HTMLDivElement> {
* @see 🏷️ {@link TooltipProps}
*
* @example
* ```jsx
* ```jsx Tooltip as only form of labeling
* <Tooltip content="Skriv ut dokument">
* <Button icon={<PrinterLargeIcon title="demo knapp" />} />
* <Button icon={<PrinterLargeIcon aria-hidden />} />
* </Tooltip>
* ```
*/
Expand All @@ -111,6 +118,7 @@ export const Tooltip = forwardRef<HTMLDivElement, TooltipProps>(
id,
keys,
maxChar = 80,
describesChild = false,
...rest
},
ref,
Expand Down Expand Up @@ -164,7 +172,6 @@ export const Tooltip = forwardRef<HTMLDivElement, TooltipProps>(
const ariaId = useId(id);

const mergedRef = useMergeRefs(ref, refs.setFloating);
const childMergedRef = useMergeRefs(children.ref, refs.setReference);

if (
!children ||
Expand All @@ -184,18 +191,22 @@ export const Tooltip = forwardRef<HTMLDivElement, TooltipProps>(
);
}

const labelProps = describesChild
? _open
? { "aria-describedby": ariaId }
: { title: content }
HalvorHaugan marked this conversation as resolved.
Show resolved Hide resolved
: { "aria-label": content };

return (
<>
{cloneElement(
children,
getReferenceProps({
...children.props,
ref: childMergedRef,
"aria-describedby": _open
? cl(ariaId, children?.props["aria-describedby"])
: children?.props["aria-describedby"],
}),
)}
<Slot
ref={refs.setReference}
{...getReferenceProps()}
{...labelProps}
aria-keyshortcuts={keys ? keys.join("+") : undefined}
>
{children}
</Slot>
<Portal rootElement={rootElement} asChild>
{_open && (
<div
Expand All @@ -220,7 +231,7 @@ export const Tooltip = forwardRef<HTMLDivElement, TooltipProps>(
>
{content}
{keys && (
<span className="navds-tooltip__keys">
<span className="navds-tooltip__keys" aria-hidden>
{keys.map((key) => (
<Detail as="kbd" key={key} className="navds-tooltip__key">
{key}
Expand Down
24 changes: 5 additions & 19 deletions @navikt/core/react/src/tooltip/tooltip.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { Meta } from "@storybook/react";
import React from "react";
import { Alert } from "../alert";
import { Button } from "../button";
import { Search } from "../form/search";
import { VStack } from "../layout/stack";
import Tooltip from "./Tooltip";

Expand Down Expand Up @@ -32,20 +30,6 @@ export default {
},
} satisfies Meta<typeof Tooltip>;

export const Demo = () => (
<div>
<Tooltip content="Tooltip example" placement="top">
<Alert variant="info">test</Alert>
</Tooltip>
<Tooltip content="Tooltip example" placement="top">
<Search label="søk" />
</Tooltip>
<Tooltip content="Tooltip example" placement="top">
<Button aria-describedby="test123">Tooltip</Button>
</Tooltip>
</div>
);

export const Default = (props) => {
return (
<Tooltip
Expand All @@ -56,15 +40,17 @@ export const Default = (props) => {
arrow={props?.arrow}
delay={props?.delay}
offset={props?.offset}
describesChild={props?.describesChild}
>
<Button aria-describedby="test123">Tooltip</Button>
<Button>Tooltip</Button>
</Tooltip>
);
};
Default.args = {
keys: false,
arrow: true,
delay: 150,
describesChild: true,
};

export const Placement = () => {
Expand All @@ -90,10 +76,10 @@ export const Keys = () => {
return (
<Tooltip
content="Tooltip example Laboris reprehenderit sit sunt nisi velit mollit esse excepteur. "
open={true}
keys={["CMD", "I"]}
open={true}
>
<div>Element</div>
<button>Element</button>
</Tooltip>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,20 @@ import { withDsExample } from "@/web/examples/withDsExample";
const Example = () => {
return (
<ToggleGroup defaultValue="lest" onChange={console.info}>
<Tooltip content="Uleste meldinger">
<Tooltip content="Uleste meldinger" describesChild>
<ToggleGroup.Item
value="ulest"
icon={<EnvelopeClosedIcon title="Ulest" />}
icon={<EnvelopeClosedIcon aria-hidden />}
/>
</Tooltip>
<Tooltip content="Leste meldinger">
<Tooltip content="Leste meldinger" describesChild>
<ToggleGroup.Item
value="lest"
icon={<EnvelopeOpenIcon title="Lest" />}
icon={<EnvelopeOpenIcon aria-hidden />}
/>
</Tooltip>
<Tooltip content="Sendte meldinger">
<ToggleGroup.Item
value="sendt"
icon={<PaperplaneIcon title="Sendt" />}
/>
<Tooltip content="Sendte meldinger" describesChild>
<ToggleGroup.Item value="sendt" icon={<PaperplaneIcon aria-hidden />} />
</Tooltip>
</ToggleGroup>
);
Expand All @@ -41,4 +38,5 @@ export const Demo = {

export const args = {
index: 6,
desc: "For ToggleGroup uten label med Tooltip bør du bruke 'describesChild'-prop på Tooltip.",
};
2 changes: 1 addition & 1 deletion aksel.nav.no/website/pages/eksempler/tooltip/demo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { withDsExample } from "@/web/examples/withDsExample";
const Example = () => {
return (
<Tooltip content="Skriv ut dokument">
<Button icon={<PrinterLargeIcon title="demo knapp" />} />
<Button icon={<PrinterLargeIcon aria-hidden />} />
</Tooltip>
);
};
Expand Down
29 changes: 29 additions & 0 deletions aksel.nav.no/website/pages/eksempler/tooltip/labeling.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { PrinterLargeIcon } from "@navikt/aksel-icons";
import { Button, HStack, Tooltip } from "@navikt/ds-react";
import { withDsExample } from "@/web/examples/withDsExample";

const Example = () => {
return (
<HStack gap="4">
<Tooltip content="Skriv ut dokument">
<Button icon={<PrinterLargeIcon aria-hidden />} />
</Tooltip>
<Tooltip content="Skriv ut dokument" describesChild>
<Button>Skriv ut</Button>
</Tooltip>
</HStack>
);
};

// EXAMPLES DO NOT INCLUDE CONTENT BELOW THIS LINE
export default withDsExample(Example);

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

export const args = {
index: 4,
desc: "Hvis tooltip ikke er eneste form for tekstlig beskrivelse, kan du sette 'describesChild' til 'true'. Tooltip content blir da satt som 'title' (lukket) og 'aria-describedby' (åpen).",
};
2 changes: 1 addition & 1 deletion aksel.nav.no/website/pages/eksempler/tooltip/no-arrow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { withDsExample } from "@/web/examples/withDsExample";
const Example = () => {
return (
<Tooltip content="Skriv ut dokument" arrow={false}>
<Button icon={<PrinterLargeIcon title="demo knapp" />} />
<Button icon={<PrinterLargeIcon aria-hidden />} />
</Tooltip>
);
};
Expand Down
8 changes: 4 additions & 4 deletions aksel.nav.no/website/pages/eksempler/tooltip/placement.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,16 @@ const Example = () => {
return (
<div className="grid gap-4">
<Tooltip content="Skriv ut dokument">
<Button icon={<ArrowUpIcon title="demo knapp" />} />
<Button icon={<ArrowUpIcon aria-hidden />} />
</Tooltip>
<Tooltip content="Skriv ut dokument" placement="right">
<Button icon={<ArrowRightIcon title="demo knapp" />} />
<Button icon={<ArrowRightIcon aria-hidden />} />
</Tooltip>
<Tooltip content="Skriv ut dokument" placement="bottom">
<Button icon={<ArrowDownIcon title="demo knapp" />} />
<Button icon={<ArrowDownIcon aria-hidden />} />
</Tooltip>
<Tooltip content="Skriv ut dokument" placement="left">
<Button icon={<ArrowLeftIcon title="demo knapp" />} />
<Button icon={<ArrowLeftIcon aria-hidden />} />
</Tooltip>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { withDsExample } from "@/web/examples/withDsExample";
const Example = () => {
return (
<Tooltip content="Skriv ut dokument" keys={["cmd", "p"]}>
<Button icon={<PrinterLargeIcon title="demo knapp" />} />
<Button icon={<PrinterLargeIcon aria-hidden />} />
</Tooltip>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,10 @@ export function extractArgs(
return {};
}

const parsedArgs = JSON5.parse(`{${args}}`);

if (!parsedArgs) {
env !== "test" &&
console.warn(`Unable to parse args for example/template: ${fileName}`);
return {};
try {
return JSON5.parse(`{${args}}`);
} catch (e) {
console.warn(`Unable to parse args for example/template: ${fileName}`);
throw e;
}

return parsedArgs;
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,9 @@ export function extractMetadata(
"utf-8",
);

return JSON5.parse(metadata);
try {
return JSON5.parse(metadata);
} catch (e) {
console.error(`Could not parse JSON5 in ${dirName}`);
}
}
Loading