Skip to content

Commit

Permalink
Implement infoLabel/infoMessage tooltip
Browse files Browse the repository at this point in the history
  • Loading branch information
MajaZarkova committed May 27, 2024
1 parent d0a6bef commit 9e2933b
Show file tree
Hide file tree
Showing 11 changed files with 247 additions and 6 deletions.
15 changes: 13 additions & 2 deletions apps/alpha-test-app/src/views/HomeView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import {
OnyxSwitch,
OnyxTable,
OnyxTag,
OnyxTextarea,
OnyxTimer,
OnyxTooltip,
type ListboxOption,
type SelectOption,
Expand Down Expand Up @@ -183,7 +185,12 @@ timerEndDate.setHours(timerEndDate.getHours() + 2);
:skeleton="useSkeleton"
/>

<OnyxInput v-if="show('OnyxInput')" label="Input" :skeleton="useSkeleton" />
<OnyxInput
v-if="show('OnyxInput')"
label="Input"
:skeleton="useSkeleton"
info-label="More information tooltip"
/>

<OnyxLink v-if="show('OnyxLink')" href="#" :skeleton="useSkeleton">Link</OnyxLink>

Expand Down Expand Up @@ -287,7 +294,11 @@ timerEndDate.setHours(timerEndDate.getHours() + 2);

<OnyxTag v-if="show('OnyxTag')" label="Example tag" :icon="emojiHappy2" />

<OnyxTextarea v-if="show('OnyxTextarea')" label="Example textarea" />
<OnyxTextarea
v-if="show('OnyxTextarea')"
label="Example textarea"
info-label="More information tooltip"
/>

<OnyxTimer v-if="show('OnyxTimer')" label="Timer" :end-time="timerEndDate" />

Expand Down
34 changes: 34 additions & 0 deletions packages/sit-onyx/src/components/OnyxInput/OnyxInput.ct.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,40 @@ test.describe("Screenshot tests", () => {
},
});

executeMatrixScreenshotTest({
name: "Input (infoLabel/infoMessage)",
columns: ["default", "long-text"],
rows: ["infoLabel", "infoMessage"],
// TODO: remove when contrast issues are fixed in https://github.com/SchwarzIT/onyx/issues/410
disabledAccessibilityRules: ["color-contrast"],
component: (column, row) => {
const label =
column === "long-text" ? "Very long label that should be truncated" : "Test label";
const message =
column === "long-text" ? "Very long message that should be truncated" : "Test message";
const infoLabel = "More information";
const infoMessage = "Additional info message";

return (
<OnyxInput
style="width: 12rem"
label={label}
message={row === "infoMessage" ? message : undefined}
infoLabel={row === "infoLabel" ? infoLabel : undefined}
infoMessage={row === "infoMessage" ? infoMessage : undefined}
/>
);
},
beforeScreenshot: async (component, page, _column, _row) => {
const tooltip = page.getByRole("tooltip");
await component.evaluate((element) => {
element.style.height = `10rem`;
});

await tooltip.hover();
},
});

executeMatrixScreenshotTest({
name: "Input (readonly, disabled, loading)",
columns: ["readonly", "disabled", "loading"],
Expand Down
27 changes: 27 additions & 0 deletions packages/sit-onyx/src/components/OnyxInput/OnyxInput.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,3 +152,30 @@ export const CustomError = {
placeholder: "Interact with me to show error",
},
} satisfies Story;

/**
* This example shows an input with info label tooltip.
*/
export const WithInfoLabel: Story = {
args: {
label: "Label",
infoLabel: "More information",
},
decorators: [
(story) => ({
components: { story },
template: `<div style="padding-top: 2rem"> <story /> </div>`,
}),
],
};

/**
* This example shows an input with info message / additional text.
*/
export const WithInfoMessage = {
args: {
...Default.args,
message: "Example message",
infoMessage: "Additional info message",
},
} satisfies Story;
46 changes: 45 additions & 1 deletion packages/sit-onyx/src/components/OnyxInput/OnyxInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ import { useRequired } from "../../composables/required";
import { useCustomValidity } from "../../composables/useCustomValidity";
import OnyxLoadingIndicator from "../OnyxLoadingIndicator/OnyxLoadingIndicator.vue";
import OnyxSkeleton from "../OnyxSkeleton/OnyxSkeleton.vue";
import OnyxTooltip from "../OnyxTooltip/OnyxTooltip.vue";
import OnyxIcon from "../OnyxIcon/OnyxIcon.vue";
import circleInformation from "@sit-onyx/icons/circle-information.svg?raw";
import type { OnyxInputProps } from "./types";
import { injectI18n } from "../../i18n";
const props = withDefaults(defineProps<OnyxInputProps>(), {
modelValue: "",
Expand Down Expand Up @@ -65,6 +69,7 @@ const patternSource = computed(() => {
});
const shouldShowCounter = computed(() => props.withCounter && props.maxlength);
const { t } = injectI18n();
</script>

<template>
Expand All @@ -79,7 +84,18 @@ const shouldShowCounter = computed(() => props.withCounter && props.maxlength);
v-if="!props.hideLabel"
:class="['onyx-input__label', 'onyx-text--small', requiredMarkerClass]"
>
<div class="onyx-truncation-ellipsis">{{ props.label }}</div>
<div class="onyx-input__info-label">
<div class="onyx-truncation-ellipsis">{{ props.label }}</div>
<OnyxTooltip v-if="props.infoLabel" open="hover" :text="props.infoLabel">
<button
:aria-label="t('infoTooltip')"
role="tooltip"
class="onyx-input__tooltip-trigger"
>
<OnyxIcon :icon="circleInformation" color="neutral" size="12px" />
</button>
</OnyxTooltip>
</div>
</div>

<div class="onyx-input__wrapper">
Expand Down Expand Up @@ -117,6 +133,17 @@ const shouldShowCounter = computed(() => props.withCounter && props.maxlength);

<div v-if="props.message || shouldShowCounter" class="onyx-input__footer onyx-text--small">
<span v-if="props.message" class="onyx-truncation-ellipsis">{{ props.message }}</span>
<OnyxTooltip
v-if="props.infoMessage"
class="onyx-input__info-message"
open="hover"
position="bottom"
:text="props.infoMessage"
>
<button :aria-label="t('infoTooltip')" role="tooltip" class="onyx-input__tooltip-trigger">
<OnyxIcon :icon="circleInformation" color="neutral" size="12px" />
</button>
</OnyxTooltip>
<span v-if="shouldShowCounter" class="onyx-input__counter">
{{ value.length }}/{{ props.maxlength }}
</span>
Expand Down Expand Up @@ -178,6 +205,23 @@ const shouldShowCounter = computed(() => props.withCounter && props.maxlength);
$vertical-padding: var(--onyx-input-padding-vertical)
);
&__info-label {
display: flex;
gap: var(--onyx-spacing-2xs);
max-width: 100%;
}
&__info-message {
height: 1rem;
align-self: center;
}
&__tooltip-trigger {
border: none;
background-color: transparent;
padding: 0;
}
&__wrapper {
&:has(.onyx-input__native:read-write) {
&:has(#{get-autofill-selectors(".onyx-input__native")}) {
Expand Down
9 changes: 9 additions & 0 deletions packages/sit-onyx/src/components/OnyxInput/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ export type OnyxInputProps = DensityProp &
* If you want to visually hide the label, use the `hideLabel` property.
*/
label: string;
/**
* Info text to pop up inside a tooltip, next to the label.
* The tooltip will be hidden if `hideLabel` property is set to true.
*/
infoLabel?: string;
/**
* Current value of the input.
*/
Expand Down Expand Up @@ -84,6 +89,10 @@ export type OnyxInputProps = DensityProp &
* Message / help text to display below the input.
*/
message?: string;
/**
* Info message / additional text to display inside a tooltip next to the message.
*/
infoMessage?: string;
/**
* If `true`, the label will be visually hidden and the `title` attribute will be set.
* For accessibility / screen readers, the aria-label will still be set.
Expand Down
32 changes: 32 additions & 0 deletions packages/sit-onyx/src/components/OnyxTextarea/OnyxTextarea.ct.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,38 @@ test.describe("Screenshot tests", () => {
}
},
});

executeMatrixScreenshotTest({
name: "Textarea (infoLabel/infoMessage)",
columns: ["default", "long-text"],
rows: ["infoLabel", "infoMessage"],
component: (column, row) => {
const label =
column === "long-text" ? "Very long label that should be truncated" : "Test label";
const message =
column === "long-text" ? "Very long message that should be truncated" : "Test message";
const infoLabel = "More information";
const infoMessage = "Additional info message";

return (
<OnyxTextarea
style="width: 12rem"
label={label}
message={row === "infoMessage" ? message : undefined}
infoLabel={row === "infoLabel" ? infoLabel : undefined}
infoMessage={row === "infoMessage" ? infoMessage : undefined}
/>
);
},
beforeScreenshot: async (component, page, _column, _row) => {
const tooltip = page.getByRole("tooltip");
await component.evaluate((element) => {
element.style.height = `15rem`;
});

await tooltip.hover();
},
});
});

test("should emit events", async ({ mount, makeAxeBuilder }) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,30 @@ export const Autosize = {
},
},
} satisfies Story;

/**
* This example shows a textarea with info tooltip.
*/
export const WithInfoLabel: Story = {
args: {
label: "Label",
infoLabel: "More Information",
},
decorators: [
(story) => ({
components: { story },
template: `<div style="padding-top: 2rem"> <story /> </div>`,
}),
],
};

/**
* This example shows a textarea with info message / additional text.
*/
export const WithInfoMessage = {
args: {
...Default.args,
message: "Example message",
infoMessage: "Additional info message",
},
} satisfies Story;
55 changes: 54 additions & 1 deletion packages/sit-onyx/src/components/OnyxTextarea/OnyxTextarea.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ import { useDensity } from "../../composables/density";
import { useRequired } from "../../composables/required";
import { useCustomValidity } from "../../composables/useCustomValidity";
import OnyxSkeleton from "../OnyxSkeleton/OnyxSkeleton.vue";
import OnyxTooltip from "../OnyxTooltip/OnyxTooltip.vue";
import OnyxIcon from "../OnyxIcon/OnyxIcon.vue";
import circleInformation from "@sit-onyx/icons/circle-information.svg?raw";
import type { OnyxTextareaProps } from "./types";
import { injectI18n } from "../../i18n";
const props = withDefaults(defineProps<OnyxTextareaProps>(), {
modelValue: "",
Expand Down Expand Up @@ -57,6 +61,7 @@ const handleChange = (event: Event) => {
emit("change", inputValue);
};
const { t } = injectI18n();
const shouldShowCounter = computed(() => props.withCounter && props.maxlength);
/**
Expand Down Expand Up @@ -99,7 +104,23 @@ const handleInput = (event: Event) => {
v-if="!props.hideLabel"
:class="['onyx-textarea__label', 'onyx-text--small', requiredMarkerClass]"
>
<div class="onyx-truncation-ellipsis">{{ props.label }}</div>
<div class="onyx-textarea__info-label">
<div class="onyx-truncation-ellipsis">{{ props.label }}</div>
<OnyxTooltip
v-if="props.infoLabel"
class="onyx-textarea__info-label-text"
open="hover"
:text="props.infoLabel"
>
<button
:aria-label="t('infoTooltip')"
role="tooltip"
class="onyx-input__tooltip-trigger"
>
<OnyxIcon :icon="circleInformation" color="neutral" size="12px" />
</button>
</OnyxTooltip>
</div>
</div>

<div class="onyx-textarea__wrapper" :data-autosize-value="value">
Expand Down Expand Up @@ -134,6 +155,21 @@ const handleInput = (event: Event) => {

<div v-if="props.message || shouldShowCounter" class="onyx-textarea__footer onyx-text--small">
<span v-if="props.message" class="onyx-truncation-ellipsis">{{ props.message }}</span>
<OnyxTooltip
v-if="props.infoMessage"
class="onyx-textarea__info-message"
open="hover"
position="bottom"
:text="props.infoMessage"
>
<button
:aria-label="t('infoTooltip')"
role="tooltip"
class="onyx-textarea__tooltip-trigger"
>
<OnyxIcon :icon="circleInformation" color="neutral" size="12px" />
</button>
</OnyxTooltip>
<span v-if="shouldShowCounter" class="onyx-textarea__counter">
{{ value.length }}/{{ props.maxlength }}
</span>
Expand Down Expand Up @@ -199,6 +235,23 @@ const handleInput = (event: Event) => {
$vertical-padding: var(--onyx-textarea-padding-vertical)
);
&__info-label {
display: flex;
gap: var(--onyx-spacing-2xs);
max-width: 100%;
}
&__info-message {
height: 1rem;
align-self: center;
}
&__tooltip-trigger {
border: none;
background-color: transparent;
padding: 0;
}
&__wrapper {
padding: 0;
height: unset;
Expand Down
2 changes: 2 additions & 0 deletions packages/sit-onyx/src/components/OnyxTextarea/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export type OnyxTextareaProps = DensityProp &
Pick<
OnyxInputProps,
| "label"
| "infoLabel"
| "hideLabel"
| "modelValue"
| "placeholder"
Expand All @@ -21,6 +22,7 @@ export type OnyxTextareaProps = DensityProp &
| "maxlength"
| "withCounter"
| "message"
| "infoMessage"
| "skeleton"
> & {
/**
Expand Down
3 changes: 2 additions & 1 deletion packages/sit-onyx/src/i18n/locales/de-DE.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,6 @@
"goToHome": "Gehe zur Startseite",
"goBack": "Zurück",
"userMenuLabel": "Benutzeroptionen"
}
},
"infoTooltip": "Info Tooltip"
}
Loading

0 comments on commit 9e2933b

Please sign in to comment.