feat: add tooltips for icon buttons

This commit is contained in:
Symon
2026-06-07 18:06:04 +03:00
parent 856768c45e
commit 4a70e995d3
38 changed files with 612 additions and 253 deletions
@@ -5,16 +5,26 @@
import React from 'react';
import PropTypes from 'prop-types';
import { useTranslation } from 'react-i18next';
import { Button, Popup as SemanticUIPopup } from 'semantic-ui-react';
import Tooltip from '../Tooltip';
import styles from './PopupHeader.module.css';
const PopupHeader = React.memo(({ children, onBack }) => (
<SemanticUIPopup.Header className={styles.wrapper}>
{onBack && <Button icon="angle left" onClick={onBack} className={styles.backButton} />}
<div className={styles.content}>{children}</div>
</SemanticUIPopup.Header>
));
const PopupHeader = React.memo(({ children, onBack }) => {
const [t] = useTranslation();
return (
<SemanticUIPopup.Header className={styles.wrapper}>
{onBack && (
<Tooltip content={t('action.goBack')}>
<Button icon="angle left" onClick={onBack} className={styles.backButton} />
</Tooltip>
)}
<div className={styles.content}>{children}</div>
</SemanticUIPopup.Header>
);
});
PopupHeader.propTypes = {
children: PropTypes.node.isRequired,
@@ -0,0 +1,69 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
import React, { useMemo } from 'react';
import PropTypes from 'prop-types';
import { Popup as SemanticUIPopup } from 'semantic-ui-react';
import styles from './Tooltip.module.css';
const callAll =
(...callbacks) =>
(...args) => {
callbacks.forEach((callback) => {
if (callback) {
callback(...args);
}
});
};
const Tooltip = React.forwardRef(
({ children, content, disabled, position, 'aria-label': ariaLabel, onClick, ...props }, ref) => {
const trigger = useMemo(() => {
const contentAriaLabel = typeof content === 'string' ? content : undefined;
return React.cloneElement(children, {
...props,
ref,
'aria-label': children.props['aria-label'] || ariaLabel || contentAriaLabel,
onClick: callAll(children.props.onClick, onClick),
});
}, [children, content, props, ref, ariaLabel, onClick]);
if (disabled || !content) {
return trigger;
}
return (
<SemanticUIPopup
basic
inverted
trigger={trigger}
content={content}
on={['hover', 'focus']}
position={position}
className={styles.wrapper}
/>
);
},
);
Tooltip.propTypes = {
children: PropTypes.element.isRequired,
content: PropTypes.node.isRequired,
disabled: PropTypes.bool,
'aria-label': PropTypes.string,
onClick: PropTypes.func,
position: PropTypes.string,
};
Tooltip.defaultProps = {
disabled: false,
'aria-label': undefined,
onClick: undefined,
position: 'top center',
};
export default React.memo(Tooltip);
@@ -0,0 +1,12 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
:global(#app) .wrapper {
border-radius: 3px;
font-size: 12px;
font-weight: bold;
line-height: 16px;
padding: 6px 8px;
}
@@ -0,0 +1,8 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
import Tooltip from './Tooltip';
export default Tooltip;
+2 -1
View File
@@ -7,5 +7,6 @@ import Input from './components/Input';
import Popup from './components/Popup';
import Masonry from './components/Masonry';
import FilePicker from './components/FilePicker';
import Tooltip from './components/Tooltip';
export { Input, Popup, Masonry, FilePicker };
export { Input, Popup, Masonry, FilePicker, Tooltip };