Skip to content

Commit

Permalink
geosolutions-it#10158: tooltip enhancer adds 'aria-label' with l10n
Browse files Browse the repository at this point in the history
Modify tooltip enhancer to also provide `aria-label`-property to wrapped objects
(most commonly glyph-only buttons). Does localization on a best-effort basis, trying
to unwrap messages passed in as tooltip prop.

On Behalf of DB Systel
  • Loading branch information
Florian Kellner committed Apr 4, 2024
1 parent ad29db2 commit 0463e49
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 8 deletions.
18 changes: 18 additions & 0 deletions web/client/components/misc/enhancers/__tests__/tooltip-test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ import React from 'react';
import ReactDOM from 'react-dom';
import tooltip from '../tooltip';
import { Button } from 'react-bootstrap';
import Message from "../../../I18N/HTML";
import Localized from "../../../I18N/Localized";

const messages = {
"testMsg": "my message"
};

describe("tooltip enhancer", () => {
beforeEach((done) => {
document.body.innerHTML = '<div id="container"></div>';
Expand All @@ -38,5 +45,16 @@ describe("tooltip enhancer", () => {
el.click();
expect(el.getAttribute('aria-describedby')).toExist();
});
it('adds an aria-label property with localized content', () => {
const CMP = tooltip(Button);
const tip = <Message msgId="testMsg"/>;
ReactDOM.render(
<Localized locale="it-IT" messages={messages}>
<CMP tooltip={tip} tooltipTrigger={['click', 'focus', 'hover']} id="text-cmp">TEXT</CMP>
</Localized>, document.getElementById("container"));
const el = document.getElementById("text-cmp");
expect(el).toExist();
expect(el.getAttribute('aria-label')).toBe('my message');
});

});
34 changes: 26 additions & 8 deletions web/client/components/misc/enhancers/tooltip.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,15 @@ import { omit } from 'lodash';

/**
* Tooltip enhancer. Enhances an object adding a tooltip (with i18n support).
* It is applied only if props contains `tooltip` or `tooltipId`. It have to be applied to a React (functional) component
* It is applied only if props contains `tooltip` or `tooltipId`. It has to be applied to a React (functional) component.
* The tooltip text will also be added as `aria-label` prop to the object in order to increase a11y.
* Note that if you add an i18n `Message` as a tooltip, it will be reconstructed around the tooltip so that its
* text is also available in the `aria-label` property. Passing other `node`s as tooltips is strongly discouraged,
* since it will result in an `[object Object]` `aria-label` which will help nobody.
* @type {function}
* @name tooltip
* @memberof components.misc.enhancers
* @prop {string|node} [tooltip] if present will add the tooltip. This is the full tooltip content
* @prop {string|node} [tooltip] if present will add the tooltip. This is the full tooltip content.
* @prop {string} [tooltipId] if present will show a localized tooltip using the tooltipId as msgId
* @prop {string} [tooltipPosition="top"]
* @prop {string} tooltipTrigger see react overlay trigger
Expand All @@ -32,12 +36,26 @@ import { omit } from 'lodash';
*/
export default branch(
({tooltip, tooltipId} = {}) => tooltip || tooltipId,
(Wrapped) => ({tooltip, tooltipId, tooltipPosition = "top", tooltipTrigger, keyProp, idDropDown, args, ...props} = {}) => (<OverlayTrigger
trigger={tooltipTrigger}
id={idDropDown}
key={keyProp}
placement={tooltipPosition}
overlay={<Tooltip id={"tooltip-" + keyProp}>{tooltipId ? <Message msgId={tooltipId} msgParams={{data: args}} /> : tooltip}</Tooltip>}><Wrapped {...props}/></OverlayTrigger>),
(Wrapped) => ({tooltip, tooltipId, tooltipPosition = "top", tooltipTrigger, keyProp, idDropDown, args, ...props} = {}) =>
(tooltipId || (tooltip.props && tooltip.props.msgId) // this is not DRY, but constructing the <Message> within the OverlayTrigger prevents it from working
? <Message msgId={tooltipId ? tooltipId : tooltip.props.msgId} msgParams={tooltip && tooltip.props && tooltip.props.msgParams ? tooltip.props.msgParams : {data: args}}>
{ (msg) => <OverlayTrigger
trigger={tooltipTrigger}
id={idDropDown}
key={keyProp}
placement={tooltipPosition}
overlay={<Tooltip id={"tooltip-" + keyProp}>{msg}</Tooltip>}>
<Wrapped {...props}
aria-label={msg}/></OverlayTrigger> }
</Message>
: <OverlayTrigger
trigger={tooltipTrigger}
id={idDropDown}
key={keyProp}
placement={tooltipPosition}
overlay={<Tooltip id={"tooltip-" + keyProp}>{tooltipId ? <Message msgId={tooltipId} msgParams={{data: args}} /> : tooltip}</Tooltip>}>
<Wrapped {...props}
aria-label={tooltip}/></OverlayTrigger>),
// avoid to pass non needed props
(Wrapped) => (props) => <Wrapped {...(omit(props, ["tooltipId", "tooltip", "tooltipPosition"]))}>{props.children}</Wrapped>
);

0 comments on commit 0463e49

Please sign in to comment.