From 023835cdadcdd2572696b971ad6890999c2f608a Mon Sep 17 00:00:00 2001 From: Andrei Prigorshnev Date: Thu, 28 Jul 2022 18:33:20 +0400 Subject: [PATCH] DEV: a new `d-tooltip` component (#17513) --- .../discourse/app/components/d-tooltip.js | 35 ++++++++++++++ .../app/templates/components/d-tooltip.hbs | 3 ++ .../integration/components/d-tooltip-test.js | 47 +++++++++++++++++++ .../stylesheets/common/components/_index.scss | 1 + .../common/components/d-tooltip.scss | 11 +++++ .../styleguide/molecules/rich-tooltip.hbs | 9 ++++ .../styleguide/config/locales/client.en.yml | 5 ++ 7 files changed, 111 insertions(+) create mode 100644 app/assets/javascripts/discourse/app/components/d-tooltip.js create mode 100644 app/assets/javascripts/discourse/app/templates/components/d-tooltip.hbs create mode 100644 app/assets/javascripts/discourse/tests/integration/components/d-tooltip-test.js create mode 100644 app/assets/stylesheets/common/components/d-tooltip.scss create mode 100644 plugins/styleguide/assets/javascripts/discourse/templates/styleguide/molecules/rich-tooltip.hbs diff --git a/app/assets/javascripts/discourse/app/components/d-tooltip.js b/app/assets/javascripts/discourse/app/components/d-tooltip.js new file mode 100644 index 00000000000..90d654c8333 --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/d-tooltip.js @@ -0,0 +1,35 @@ +import Component from "@ember/component"; +import { schedule } from "@ember/runloop"; +import tippy from "tippy.js"; + +export default class DiscourseTooltip extends Component { + tagName = ""; + + didInsertElement() { + this._super(...arguments); + this._initTippy(); + } + + willDestroyElement() { + this._super(...arguments); + this._tippyInstance.destroy(); + } + + _initTippy() { + schedule("afterRender", () => { + // Ember.ViewUtils.getViewBounds is a private API, + // but it's not going to be dropped without a public deprecation warning, + // see: https://stackoverflow.com/a/50125938/3206146 + // eslint-disable-next-line no-undef + const viewBounds = Ember.ViewUtils.getViewBounds(this); + const element = viewBounds.firstNode; + const parent = viewBounds.parentElement; + this._tippyInstance = tippy(parent, { + content: element, + theme: "d-tooltip", + arrow: false, + placement: "bottom-start", + }); + }); + } +} diff --git a/app/assets/javascripts/discourse/app/templates/components/d-tooltip.hbs b/app/assets/javascripts/discourse/app/templates/components/d-tooltip.hbs new file mode 100644 index 00000000000..896794b84d0 --- /dev/null +++ b/app/assets/javascripts/discourse/app/templates/components/d-tooltip.hbs @@ -0,0 +1,3 @@ +
+ {{yield}} +
diff --git a/app/assets/javascripts/discourse/tests/integration/components/d-tooltip-test.js b/app/assets/javascripts/discourse/tests/integration/components/d-tooltip-test.js new file mode 100644 index 00000000000..d775130913a --- /dev/null +++ b/app/assets/javascripts/discourse/tests/integration/components/d-tooltip-test.js @@ -0,0 +1,47 @@ +import { module, test } from "qunit"; +import { render, triggerEvent } from "@ember/test-helpers"; +import { setupRenderingTest } from "discourse/tests/helpers/component-test"; +import { hbs } from "ember-cli-htmlbars"; +import { query } from "discourse/tests/helpers/qunit-helpers"; + +async function mouseenter() { + await triggerEvent(query("button"), "mouseenter"); +} + +module("Integration | Component | d-tooltip", function (hooks) { + setupRenderingTest(hooks); + + test("doesn't show tooltip if it wasn't expanded", async function (assert) { + await render(hbs` + + `); + assert.notOk(document.querySelector("[data-tippy-root]")); + }); + + test("it shows tooltip on mouseenter", async function (assert) { + await render(hbs` + + `); + + await mouseenter(); + assert.ok( + document.querySelector("[data-tippy-root]"), + "the tooltip is added to the page" + ); + assert.equal( + document + .querySelector("[data-tippy-root] .tippy-content") + .textContent.trim(), + "Tooltip text", + "the tooltip content is correct" + ); + }); +}); diff --git a/app/assets/stylesheets/common/components/_index.scss b/app/assets/stylesheets/common/components/_index.scss index 553b77e74aa..66f90063d82 100644 --- a/app/assets/stylesheets/common/components/_index.scss +++ b/app/assets/stylesheets/common/components/_index.scss @@ -6,6 +6,7 @@ @import "color-input"; @import "conditional-loading-section"; @import "convert-to-public-topic-modal"; +@import "d-tooltip"; @import "date-input"; @import "date-picker"; @import "date-time-input-range"; diff --git a/app/assets/stylesheets/common/components/d-tooltip.scss b/app/assets/stylesheets/common/components/d-tooltip.scss new file mode 100644 index 00000000000..3ca748420bf --- /dev/null +++ b/app/assets/stylesheets/common/components/d-tooltip.scss @@ -0,0 +1,11 @@ +// ".tippy-box" is one of the classes tippy.js uses for creating tooltips +// see https://atomiks.github.io/tippyjs/v6/themes/#tippy-elements +// +// Using `data-theme~="d-tooltip"` scopes down these styles +// to tooltips created using the d-tooltip component +.tippy-box[data-theme~="d-tooltip"] { + color: var(--primary); + background: var(--secondary); + border: 1px solid var(--primary-low); + box-shadow: shadow("menu-panel"); +} diff --git a/plugins/styleguide/assets/javascripts/discourse/templates/styleguide/molecules/rich-tooltip.hbs b/plugins/styleguide/assets/javascripts/discourse/templates/styleguide/molecules/rich-tooltip.hbs new file mode 100644 index 00000000000..16e31ae418f --- /dev/null +++ b/plugins/styleguide/assets/javascripts/discourse/templates/styleguide/molecules/rich-tooltip.hbs @@ -0,0 +1,9 @@ + + + {{i18n "styleguide.sections.rich_tooltip.hover_to_see"}} + +

{{i18n "styleguide.sections.rich_tooltip.header"}}

+ {{i18n "styleguide.sections.rich_tooltip.description"}} +
+
+
diff --git a/plugins/styleguide/config/locales/client.en.yml b/plugins/styleguide/config/locales/client.en.yml index 2578ff9a2f7..f6f3506b691 100644 --- a/plugins/styleguide/config/locales/client.en.yml +++ b/plugins/styleguide/config/locales/client.en.yml @@ -83,3 +83,8 @@ en: title: "Spinners" empty_state: title: "Empty State" + rich_tooltip: + title: "Rich Tooltip" + description: "Description" + header: "Header" + hover_to_see: "Hover to see a tooltip"