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

Add tooltip component #2843

Merged
merged 38 commits into from
May 10, 2021
Merged
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
5f87af1
Add Tooltip component to common
davwheat May 7, 2021
c68fd51
Export Tooltip component
davwheat May 7, 2021
7d93c9d
WIP
davwheat May 8, 2021
a38c3f6
Fix import
davwheat May 8, 2021
9835773
Add missing import
davwheat May 8, 2021
80fc860
Move Tooltip jQuery helper types to separate typing file
davwheat May 8, 2021
fdb40e5
Add `delay` attr, update docblocks
davwheat May 8, 2021
b475f5c
Remove undeeded `index` on import
davwheat May 8, 2021
6e13274
Add support for `destroy` option in tooltip function typings
davwheat May 8, 2021
21aa092
Update type import
davwheat May 8, 2021
4e4f898
Recreate tooltip inside `onupdate` if `text` attr has changed
davwheat May 8, 2021
ba0b528
Rewrite Badge to use Tooltip component; remove console.logs
davwheat May 8, 2021
ff17c09
Simplify Tooltip component to use `title` attr
davwheat May 8, 2021
66393ec
Run `extractText` inside Tooltip component
davwheat May 9, 2021
c05badc
Use `inline-block` instead of `<span>` for inline Tooltip component
davwheat May 9, 2021
2203f9b
Use new Tooltip component for Preview post button
davwheat May 9, 2021
14ee976
Use new Tooltip component in TextEditorButton
davwheat May 9, 2021
abd0b56
Use new Tooltip component for DiscussionListItem-author
davwheat May 9, 2021
6f6c185
Allow block, inline-block, and inline container options
davwheat May 9, 2021
db6fc6d
Use `inline-block` for TextEditorButton
davwheat May 9, 2021
84c129b
Add warning when supplying `title` attr to Tooltip component
davwheat May 9, 2021
e3b1864
Abstract away tooltip text auto-updating logic into Tooltip component
davwheat May 9, 2021
a0abbf9
Use new Tooltip component in PostEdited component
davwheat May 9, 2021
23b3830
Add deprecation warning when `$.tooltip` is used outside of the Toolt…
davwheat May 9, 2021
270709f
Fix broken tooltip on Badges
davwheat May 9, 2021
e4ad3d0
Explicitly state default tooltip options
davwheat May 9, 2021
4d13d02
WIP manual show tooltip attr
davwheat May 9, 2021
3c40bd2
Fix deprecation warning
davwheat May 9, 2021
422c08d
Add support for tooltip visibility attr
davwheat May 9, 2021
677968b
Fix prettier
davwheat May 9, 2021
2e5b40d
Call `super.onupdate`
davwheat May 9, 2021
3fe6003
Add attr to disable `title` attr warning
davwheat May 9, 2021
22ebd0b
Modify direct child instead of using container element
davwheat May 10, 2021
674c22c
Use recreated Tooltip component in Badge
davwheat May 10, 2021
6105a46
Add warning about component overwriting `title` attr
davwheat May 10, 2021
a4b6675
Remove unused styles
davwheat May 10, 2021
b8987db
Update previous uses of Tooltip component
davwheat May 10, 2021
25e30bb
Refactor out duplicate logic
davwheat May 10, 2021
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
68 changes: 68 additions & 0 deletions js/@types/tooltips/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/**
* Selection of options accepted by [Bootstrap's tooltips](https://getbootstrap.com/docs/3.3/javascript/#tooltips-options).
*
* ---
*
* Not all options are present from Bootstrap to discourage the use of options
* that will be deprecated in the future.
*
* More commonly used options that will be deprecated remain, but are marked as
* such.
*
* @see https://getbootstrap.com/docs/3.3/javascript/#tooltips-options
*/
export interface TooltipCreationOptions {
/**
* Whether HTML content is allowed in the tooltip.
*
* ---
*
* **Warning:** this is a possible XSS attack vector. This option shouldn't
* be used wherever possible, and will not work when we migrate to CSS-only
* tooltips.
*
* @deprecated
*/
html?: boolean;
/**
* Tooltip position around the target element.
*/
placement?: 'top' | 'bottom' | 'left' | 'right';
/**
* Sets the delay between a trigger state occurring and the tooltip appearing
* on-screen.
*
* ---
*
* **Warning:** this option will be removed when we switch to CSS-only
* tooltips.
*
* @deprecated
*/
delay?: number;
/**
* Value used if no `title` attribute is present on the HTML element.
*
* If a function is given, it will be called with its `this` reference set to
* the element that the tooltip is attached to.
*/
title?: string;
/**
* How the tooltip is triggered.
*
* Either on `hover`, on `hover focus` (either of the two).
*
* ---
*
* **Warning:** `manual`, `click` and `focus` on its own are deprecated options
* which will not be supported in the future.
*/
trigger?: 'hover' | 'hover focus';
}

/**
* Creates a tooltip on a jQuery element reference.
*
* Returns the same jQuery reference to allow for method chaining.
*/
export type TooltipJQueryFunction = (tooltipOptions?: TooltipCreationOptions | 'destroy' | 'show' | 'hide') => JQuery;
11 changes: 3 additions & 8 deletions js/shims.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import * as _$ from 'jquery';
// Globals from flarum/core
import Application from './src/common/Application';

import type { TooltipJQueryFunction } from './@types/tooltips';

/**
* flarum/core exposes several extensions globally:
*
Expand All @@ -25,14 +27,7 @@ declare global {

// Extend JQuery with our custom functions, defined with $.fn
interface JQuery {
/**
* Creates a tooltip on a jQuery element reference.
*
* Optionally accepts placement and delay options.
*
* Returns the same reference to allow for method chaining.
*/
tooltip: (tooltipOptions?: { placement?: 'top' | 'bottom' | 'left' | 'right'; delay?: number }) => JQuery;
tooltip: TooltipJQueryFunction;
}
}

Expand Down
2 changes: 2 additions & 0 deletions js/src/common/compat.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ import GroupBadge from './components/GroupBadge';
import TextEditor from './components/TextEditor';
import TextEditorButton from './components/TextEditorButton';
import EditUserModal from './components/EditUserModal';
import Tooltip from './components/Tooltip';
import Model from './Model';
import Application from './Application';
import fullTime from './helpers/fullTime';
Expand Down Expand Up @@ -141,6 +142,7 @@ export default {
'components/GroupBadge': GroupBadge,
'components/TextEditor': TextEditor,
'components/TextEditorButton': TextEditorButton,
'components/Tooltip': Tooltip,
'components/EditUserModal': EditUserModal,
Model: Model,
Application: Application,
Expand Down
26 changes: 15 additions & 11 deletions js/src/common/components/Badge.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Tooltip from './Tooltip';
import Component from '../Component';
import icon from '../helpers/icon';
import extract from '../utils/extract';
import classList from '../utils/classList';

/**
* The `Badge` component represents a user/discussion badge, indicating some
Expand All @@ -17,19 +18,22 @@ import extract from '../utils/extract';
*/
export default class Badge extends Component {
view() {
const attrs = Object.assign({}, this.attrs);
const type = extract(attrs, 'type');
const iconName = extract(attrs, 'icon');
const { type, icon: iconName, label, ...attrs } = this.attrs;

attrs.className = 'Badge ' + (type ? 'Badge--' + type : '') + ' ' + (attrs.className || '');
attrs.title = extract(attrs, 'label') || '';
const className = classList('Badge', [type && `Badge--${type}`], attrs.className);

return <span {...attrs}>{iconName ? icon(iconName, { className: 'Badge-icon' }) : m.trust('&nbsp;')}</span>;
}
const iconChild = iconName ? icon(iconName, { className: 'Badge-icon' }) : m.trust('&nbsp;');

const badgeAttrs = {
className,
...attrs,
};

const badgeNode = <div {...badgeAttrs}>{iconChild}</div>;

oncreate(vnode) {
super.oncreate(vnode);
// If we don't have a tooltip label, don't render the tooltip component.
if (!label) return badgeNode;

if (this.attrs.label) this.$().tooltip();
return <Tooltip text={label}>{badgeNode}</Tooltip>;
}
}
11 changes: 4 additions & 7 deletions js/src/common/components/TextEditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import listItems from '../helpers/listItems';
import Button from './Button';

import BasicEditorDriver from '../utils/BasicEditorDriver';
import Tooltip from './Tooltip';

/**
* The `TextEditor` component displays a textarea with controls, including a
Expand Down Expand Up @@ -108,13 +109,9 @@ export default class TextEditor extends Component {
if (this.attrs.preview) {
items.add(
'preview',
Button.component({
icon: 'far fa-eye',
className: 'Button Button--icon',
onclick: this.attrs.preview,
title: app.translator.trans('core.forum.composer.preview_tooltip'),
oncreate: (vnode) => $(vnode.dom).tooltip(),
})
<Tooltip text={app.translator.trans('core.forum.composer.preview_tooltip')}>
<Button icon="far fa-eye" className="Button Button--icon" onclick={this.attrs.preview} />
</Tooltip>
);
}

Expand Down
17 changes: 11 additions & 6 deletions js/src/common/components/TextEditorButton.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
import Button from './Button';
import Tooltip from './Tooltip';

/**
* The `TextEditorButton` component displays a button suitable for the text
* editor toolbar.
*/
export default class TextEditorButton extends Button {
static initAttrs(attrs) {
super.initAttrs(attrs);
view(vnode) {
const originalView = super.view(vnode);

attrs.className = attrs.className || 'Button Button--icon Button--link';
// Steal tooltip label from the Button superclass
const tooltipText = originalView.attrs.title;
delete originalView.attrs.title;

return <Tooltip text={tooltipText}>{originalView}</Tooltip>;
}

oncreate(vnode) {
super.oncreate(vnode);
static initAttrs(attrs) {
super.initAttrs(attrs);

this.$().tooltip();
attrs.className = attrs.className || 'Button Button--icon Button--link';
}
}
Loading