mirror of
https://github.com/penpot/penpot.git
synced 2025-05-30 04:46:11 +02:00
🎉 Create tooltip DS component (#6340)
* ✨ Add new tooltip DS component * 🎉 Add delay * 🎉 Update docs and stories * 🎉 Add configurable delay * ♻️ Fix comments * ♻️ Fix comments
This commit is contained in:
parent
c45187eedd
commit
e2918f4148
8 changed files with 628 additions and 2 deletions
|
@ -18,6 +18,7 @@ const preview = {
|
||||||
decorators: decorators,
|
decorators: decorators,
|
||||||
parameters: {
|
parameters: {
|
||||||
controls: {
|
controls: {
|
||||||
|
disableSaveFromUI: true,
|
||||||
matchers: {
|
matchers: {
|
||||||
color: /(background|color)$/i,
|
color: /(background|color)$/i,
|
||||||
date: /Date$/i,
|
date: /Date$/i,
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
[app.main.ui.ds.product.loader :refer [loader*]]
|
[app.main.ui.ds.product.loader :refer [loader*]]
|
||||||
[app.main.ui.ds.product.user-milestone :refer [user-milestone*]]
|
[app.main.ui.ds.product.user-milestone :refer [user-milestone*]]
|
||||||
[app.main.ui.ds.storybook :as sb]
|
[app.main.ui.ds.storybook :as sb]
|
||||||
|
[app.main.ui.ds.tooltip.tooltip :refer [tooltip*]]
|
||||||
[app.main.ui.ds.utilities.date :refer [date*]]
|
[app.main.ui.ds.utilities.date :refer [date*]]
|
||||||
[app.main.ui.ds.utilities.swatch :refer [swatch*]]
|
[app.main.ui.ds.utilities.swatch :refer [swatch*]]
|
||||||
[app.util.i18n :as i18n]
|
[app.util.i18n :as i18n]
|
||||||
|
@ -57,6 +58,7 @@
|
||||||
:Text text*
|
:Text text*
|
||||||
:TabSwitcher tab-switcher*
|
:TabSwitcher tab-switcher*
|
||||||
:Toast toast*
|
:Toast toast*
|
||||||
|
:Tooltip tooltip*
|
||||||
:ContextNotification context-notification*
|
:ContextNotification context-notification*
|
||||||
:NotificationPill notification-pill*
|
:NotificationPill notification-pill*
|
||||||
:Actionable actionable*
|
:Actionable actionable*
|
||||||
|
|
|
@ -18,6 +18,7 @@ $sz-200: px2rem(200);
|
||||||
$sz-224: px2rem(224);
|
$sz-224: px2rem(224);
|
||||||
$sz-252: px2rem(252);
|
$sz-252: px2rem(252);
|
||||||
$sz-284: px2rem(284);
|
$sz-284: px2rem(284);
|
||||||
|
$sz-352: px2rem(352);
|
||||||
$sz-400: px2rem(400);
|
$sz-400: px2rem(400);
|
||||||
$sz-480: px2rem(480);
|
$sz-480: px2rem(480);
|
||||||
$sz-964: px2rem(964);
|
$sz-964: px2rem(964);
|
||||||
|
|
202
frontend/src/app/main/ui/ds/tooltip/tooltip.cljs
Normal file
202
frontend/src/app/main/ui/ds/tooltip/tooltip.cljs
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
|
(ns app.main.ui.ds.tooltip.tooltip
|
||||||
|
(:require-macros
|
||||||
|
[app.common.data.macros :as dm]
|
||||||
|
[app.main.style :as stl])
|
||||||
|
(:require
|
||||||
|
[app.common.data :as d]
|
||||||
|
[app.util.dom :as dom]
|
||||||
|
[app.util.keyboard :as kbd]
|
||||||
|
[app.util.timers :as ts]
|
||||||
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
|
(defn- calculate-tooltip-rect [tooltip trigger-rect placement offset]
|
||||||
|
(let [{trigger-top :top
|
||||||
|
trigger-left :left
|
||||||
|
trigger-right :right
|
||||||
|
trigger-bottom :bottom
|
||||||
|
trigger-width :width
|
||||||
|
trigger-height :height} trigger-rect
|
||||||
|
|
||||||
|
{tooltip-width :width
|
||||||
|
tooltip-height :height} (dom/get-bounding-rect tooltip)
|
||||||
|
|
||||||
|
offset (d/nilv offset 2)
|
||||||
|
overlay-offset 32]
|
||||||
|
|
||||||
|
(case placement
|
||||||
|
"bottom"
|
||||||
|
{:top (+ trigger-bottom offset)
|
||||||
|
:left (- (+ trigger-left (/ trigger-width 2)) (/ tooltip-width 2))
|
||||||
|
:right (+ (- (+ trigger-left (/ trigger-width 2)) (/ tooltip-width 2)) tooltip-width)
|
||||||
|
:bottom (+ (- trigger-bottom offset) tooltip-height)
|
||||||
|
:width tooltip-width
|
||||||
|
:height tooltip-height}
|
||||||
|
|
||||||
|
"left"
|
||||||
|
{:top (- (+ trigger-top (/ trigger-height 2) 8) (/ tooltip-height 2))
|
||||||
|
:left (- trigger-left tooltip-width 12)
|
||||||
|
:right (+ (- trigger-left tooltip-width 12) tooltip-width)
|
||||||
|
:bottom (+ (- (+ trigger-top (/ trigger-height 2) 12) (/ tooltip-height 2)) tooltip-height)
|
||||||
|
:width tooltip-width
|
||||||
|
:height tooltip-height}
|
||||||
|
|
||||||
|
"right"
|
||||||
|
{:top (- (+ trigger-top (/ trigger-height 2) 4) (/ tooltip-height 2))
|
||||||
|
:left (+ trigger-right offset 4)
|
||||||
|
:right (+ trigger-right offset tooltip-width 4)
|
||||||
|
:bottom (+ (- (+ trigger-top (/ trigger-height 2) 4) (/ tooltip-height 2)) tooltip-height)
|
||||||
|
:width tooltip-width
|
||||||
|
:height tooltip-height}
|
||||||
|
|
||||||
|
"bottom-right"
|
||||||
|
{:top (+ trigger-bottom offset)
|
||||||
|
:left (- trigger-right overlay-offset)
|
||||||
|
:right (+ (- trigger-right overlay-offset) tooltip-width)
|
||||||
|
:bottom (+ (- trigger-bottom offset) tooltip-height)
|
||||||
|
:width tooltip-width
|
||||||
|
:height tooltip-height}
|
||||||
|
|
||||||
|
"bottom-left"
|
||||||
|
{:top (+ trigger-bottom offset)
|
||||||
|
:left (+ (- trigger-left tooltip-width) overlay-offset)
|
||||||
|
:right (+ (- trigger-left tooltip-width) overlay-offset tooltip-width)
|
||||||
|
:bottom (+ (- trigger-bottom offset) tooltip-height)
|
||||||
|
:width tooltip-width
|
||||||
|
:height tooltip-height}
|
||||||
|
|
||||||
|
"top-right"
|
||||||
|
{:top (- trigger-top offset tooltip-height)
|
||||||
|
:left (- trigger-right overlay-offset)
|
||||||
|
:right (+ (- trigger-right overlay-offset) tooltip-width)
|
||||||
|
:bottom (+ (- trigger-top offset tooltip-height) tooltip-height)
|
||||||
|
:width tooltip-width
|
||||||
|
:height tooltip-height}
|
||||||
|
|
||||||
|
"top-left"
|
||||||
|
{:top (- trigger-top offset tooltip-height)
|
||||||
|
:left (+ (- trigger-left tooltip-width) overlay-offset)
|
||||||
|
:right (+ (- trigger-left tooltip-width) overlay-offset tooltip-width)
|
||||||
|
:bottom (+ (- trigger-top offset tooltip-height) tooltip-height)
|
||||||
|
:width tooltip-width
|
||||||
|
:height tooltip-height}
|
||||||
|
|
||||||
|
{:top (- trigger-top offset tooltip-height)
|
||||||
|
:left (- (+ trigger-left (/ trigger-width 2)) (/ tooltip-width 2))
|
||||||
|
:right (+ (- (+ trigger-left (/ trigger-width 2)) (/ tooltip-width 2)) tooltip-width)
|
||||||
|
:bottom (+ (- trigger-top offset tooltip-height) tooltip-height)
|
||||||
|
:width tooltip-width
|
||||||
|
:height tooltip-height})))
|
||||||
|
|
||||||
|
(defn- get-fallback-order [placement]
|
||||||
|
(case placement
|
||||||
|
"top" ["top" "right" "bottom" "left" "top-right" "bottom-right" "bottom-left" "top-left"]
|
||||||
|
"bottom" ["bottom" "left" "top" "right" "bottom-right" "bottom-left" "top-left" "top-right"]
|
||||||
|
"left" ["left" "top" "right" "bottom" "top-left" "top-right" "bottom-right" "bottom-left"]
|
||||||
|
"right" ["right" "bottom" "left" "top" "bottom-left" "top-left" "top-right" "bottom-right"]
|
||||||
|
"top-right" ["top-right" "right" "bottom" "left" "top" "bottom-right" "bottom-left" "top-left"]
|
||||||
|
"bottom-right" ["bottom-right" "bottom" "left" "top" "right" "bottom-left" "top-left" "top-right"]
|
||||||
|
"bottom-left" ["bottom-left" "left" "top" "right" "bottom" "top-left" "top-right" "bottom-right"]
|
||||||
|
"top-left" ["top-left" "top" "right" "bottom" "left" "bottom-left" "top-right" "bottom-right"]))
|
||||||
|
|
||||||
|
(def ^:private schema:tooltip
|
||||||
|
[:map
|
||||||
|
[:class {:optional true} :string]
|
||||||
|
[:id :string]
|
||||||
|
[:offset {:optional true} :int]
|
||||||
|
[:delay {:optional true} :int]
|
||||||
|
[:placement {:optional true}
|
||||||
|
[:maybe [:enum "top" "bottom" "left" "right" "top-right" "bottom-right" "bottom-left" "top-left"]]]])
|
||||||
|
|
||||||
|
(mf/defc tooltip*
|
||||||
|
{::mf/props :obj
|
||||||
|
::mf/schema schema:tooltip}
|
||||||
|
[{:keys [class id children tooltip-content placement offset delay] :rest props}]
|
||||||
|
(let [placement* (mf/use-state #(d/nilv placement "top"))
|
||||||
|
placement (deref placement*)
|
||||||
|
delay (d/nilv delay 300)
|
||||||
|
|
||||||
|
schedule-ref (mf/use-ref nil)
|
||||||
|
|
||||||
|
position-tooltip
|
||||||
|
(fn [^js tooltip trigger-rect]
|
||||||
|
(let [all-placements (get-fallback-order placement)]
|
||||||
|
(.showPopover ^js tooltip)
|
||||||
|
(loop [[current-placement & remaining-placements] all-placements]
|
||||||
|
(when current-placement
|
||||||
|
(reset! placement* current-placement)
|
||||||
|
(let [tooltip-rect (calculate-tooltip-rect tooltip trigger-rect current-placement offset)]
|
||||||
|
(if (dom/is-bounding-rect-outside? tooltip-rect)
|
||||||
|
(recur remaining-placements)
|
||||||
|
(do (dom/set-css-property! tooltip "display" "grid")
|
||||||
|
(dom/set-css-property! tooltip "top" (dm/str (:top tooltip-rect) "px"))
|
||||||
|
(dom/set-css-property! tooltip "left" (dm/str (:left tooltip-rect) "px")))))))))
|
||||||
|
|
||||||
|
on-show
|
||||||
|
(mf/use-fn
|
||||||
|
(mf/deps id placement)
|
||||||
|
(fn [event]
|
||||||
|
(when-let [schedule (mf/ref-val schedule-ref)]
|
||||||
|
(ts/dispose! schedule)
|
||||||
|
(mf/set-ref-val! schedule-ref nil))
|
||||||
|
(when-let [tooltip (dom/get-element id)]
|
||||||
|
(let [trigger-rect (->> (dom/get-current-target event)
|
||||||
|
(dom/get-bounding-rect))]
|
||||||
|
(mf/set-ref-val!
|
||||||
|
schedule-ref
|
||||||
|
(ts/schedule
|
||||||
|
delay
|
||||||
|
#(position-tooltip tooltip trigger-rect)))))))
|
||||||
|
|
||||||
|
on-hide
|
||||||
|
(mf/use-fn
|
||||||
|
(mf/deps id)
|
||||||
|
(fn [] (when-let [tooltip (dom/get-element id)]
|
||||||
|
(when-let [schedule (mf/ref-val schedule-ref)]
|
||||||
|
(ts/dispose! schedule)
|
||||||
|
(mf/set-ref-val! schedule-ref nil))
|
||||||
|
(dom/set-css-property! tooltip "display" "none")
|
||||||
|
(.hidePopover ^js tooltip))))
|
||||||
|
|
||||||
|
handle-key-down
|
||||||
|
(mf/use-fn
|
||||||
|
(mf/deps on-hide)
|
||||||
|
(fn [event]
|
||||||
|
(when (kbd/esc? event)
|
||||||
|
(on-hide))))
|
||||||
|
|
||||||
|
class (d/append-class class (stl/css-case
|
||||||
|
:tooltip true
|
||||||
|
:tooltip-top (= placement "top")
|
||||||
|
:tooltip-bottom (= placement "bottom")
|
||||||
|
:tooltip-left (= placement "left")
|
||||||
|
:tooltip-right (= placement "right")
|
||||||
|
:tooltip-top-right (= placement "top-right")
|
||||||
|
:tooltip-bottom-right (= placement "bottom-right")
|
||||||
|
:tooltip-bottom-left (= placement "bottom-left")
|
||||||
|
:tooltip-top-left (= placement "top-left")))
|
||||||
|
|
||||||
|
props (mf/spread-props props {:on-mouse-enter on-show
|
||||||
|
:on-mouse-leave on-hide
|
||||||
|
:on-focus on-show
|
||||||
|
:on-blur on-hide
|
||||||
|
:on-key-down handle-key-down
|
||||||
|
:class (stl/css :tooltip-trigger)
|
||||||
|
:aria-describedby id})]
|
||||||
|
[:> :div props
|
||||||
|
children
|
||||||
|
[:div {:class class
|
||||||
|
:id id
|
||||||
|
:popover "auto"
|
||||||
|
:role "tooltip"}
|
||||||
|
[:div {:class (stl/css :tooltip-content)}
|
||||||
|
(if (fn? tooltip-content)
|
||||||
|
(tooltip-content)
|
||||||
|
tooltip-content)]
|
||||||
|
[:div {:class (stl/css :tooltip-arrow)
|
||||||
|
:id "tooltip-arrow"}]]]))
|
74
frontend/src/app/main/ui/ds/tooltip/tooltip.mdx
Normal file
74
frontend/src/app/main/ui/ds/tooltip/tooltip.mdx
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
import { Canvas, Meta } from '@storybook/blocks';
|
||||||
|
import * as Tooltip from "./tooltip.stories";
|
||||||
|
|
||||||
|
|
||||||
|
<Meta title= "Tooltip" />
|
||||||
|
|
||||||
|
# Tooltip
|
||||||
|
|
||||||
|
A tooltip is a floating text area that provides helpful or contextual information on hover and focus.
|
||||||
|
|
||||||
|
<Canvas of={Tooltip.Default} />
|
||||||
|
|
||||||
|
## Technical notes
|
||||||
|
|
||||||
|
The tooltip component accepts a `placement` prop that defines the preferred position of the tooltip relative to its trigger. Possible values are:
|
||||||
|
|
||||||
|
```
|
||||||
|
"top" | "bottom" | "left" | "right" | "top-right" | "bottom-right" | "bottom-left" | "top-left"
|
||||||
|
```
|
||||||
|
The component will attempt to use the specified `placement` but may fall back to others if there isn’t enough space.
|
||||||
|
If `placement` is not provided, the tooltip will default to "top".
|
||||||
|
|
||||||
|
```clj
|
||||||
|
(ns app.main.ui.foo
|
||||||
|
(:require
|
||||||
|
[app.main.ui.ds.tooltip.tooltip :as tlp])
|
||||||
|
|
||||||
|
[:> tlp/tooltip* {:id "test-tooltip"
|
||||||
|
:placement "bottom"
|
||||||
|
:tooltip-content "Tooltip content"}
|
||||||
|
[:div "Trigger component"]])
|
||||||
|
```
|
||||||
|
|
||||||
|
Tooltip content can include HTML elements:
|
||||||
|
```clj
|
||||||
|
(ns app.main.ui.foo
|
||||||
|
(:require
|
||||||
|
[app.main.ui.ds.tooltip.tooltip :as tlp])
|
||||||
|
|
||||||
|
[:> tlp/tooltip* {:id "test-tooltip"
|
||||||
|
:placement "bottom"
|
||||||
|
:tooltip-content (mf/html
|
||||||
|
[:span "Tooltip content"])}
|
||||||
|
[:div "Trigger component"]])
|
||||||
|
```
|
||||||
|
|
||||||
|
### Accessibility
|
||||||
|
|
||||||
|
The tooltip requires an `id` prop, which is used to associate the trigger with the tooltip content via the `aria-describedby` attribute.
|
||||||
|
This ensures screen readers can announce the tooltip content when the trigger is focused.
|
||||||
|
|
||||||
|
Tooltips should not contain interactive elements like buttons, links, or form inputs, since users cannot interact with them via mouse or keyboard.
|
||||||
|
|
||||||
|
|
||||||
|
## Usage guidelines (design)
|
||||||
|
### Where to use
|
||||||
|
|
||||||
|
Use a tooltip as a way for users to see more information before they select an element, go to a new page, or trigger an action on the page.
|
||||||
|
|
||||||
|
### When to use
|
||||||
|
|
||||||
|
- When users need help making a decision
|
||||||
|
- When you need to provide more information for icons or icon buttons without labels
|
||||||
|
- When you need to define new or unfamiliar UI elements that are not described directly in the user interface
|
||||||
|
|
||||||
|
### Interaction / Behaviour
|
||||||
|
|
||||||
|
Tooltips are triggered on hover or keyboard focus
|
||||||
|
|
||||||
|
They automatically disappear on mouse leave or blur
|
||||||
|
|
||||||
|
Tooltip positioning is dynamically adjusted to stay within the viewport
|
||||||
|
|
||||||
|
A small delay is applied before showing the tooltip to avoid accidental triggers, the duration of this delay is configurable by default it is 300ms.
|
152
frontend/src/app/main/ui/ds/tooltip/tooltip.scss
Normal file
152
frontend/src/app/main/ui/ds/tooltip/tooltip.scss
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
//
|
||||||
|
// Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
|
@use "../_sizes.scss" as *;
|
||||||
|
@use "../_borders.scss" as *;
|
||||||
|
@use "../typography.scss" as *;
|
||||||
|
|
||||||
|
// This variable refers to the legs of
|
||||||
|
// an equilateral triangle with base 16px
|
||||||
|
// and height 8px to design of the arrow.
|
||||||
|
|
||||||
|
$arrow-size: 11px;
|
||||||
|
|
||||||
|
.tooltip {
|
||||||
|
position: absolute;
|
||||||
|
max-width: $sz-352;
|
||||||
|
background-color: transparent;
|
||||||
|
overflow: hidden;
|
||||||
|
width: fit-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-arrow {
|
||||||
|
background-color: var(--color-background-primary);
|
||||||
|
border-radius: var(--sp-xs);
|
||||||
|
width: $arrow-size;
|
||||||
|
height: $arrow-size;
|
||||||
|
grid-area: arrow;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-top {
|
||||||
|
grid-template-areas:
|
||||||
|
"content"
|
||||||
|
"arrow";
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-top .tooltip-arrow {
|
||||||
|
justify-self: center;
|
||||||
|
border-radius: 0 0 var(--sp-xs) 0;
|
||||||
|
transform: rotate(45deg) translateX(calc(-1 * var(--sp-s)));
|
||||||
|
border-bottom: $b-1 solid var(--color-accent-primary-muted);
|
||||||
|
border-right: $b-1 solid var(--color-accent-primary-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-bottom {
|
||||||
|
grid-template-areas:
|
||||||
|
"arrow"
|
||||||
|
"content";
|
||||||
|
}
|
||||||
|
.tooltip-bottom .tooltip-arrow {
|
||||||
|
justify-self: center;
|
||||||
|
border-radius: var(--sp-xs) 0;
|
||||||
|
transform: rotate(45deg) translateX(var(--sp-s));
|
||||||
|
border-top: $b-1 solid var(--color-accent-primary-muted);
|
||||||
|
border-left: $b-1 solid var(--color-accent-primary-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-left {
|
||||||
|
grid-template-areas: "content arrow ";
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-left .tooltip-arrow {
|
||||||
|
align-self: center;
|
||||||
|
border-radius: 0 var(--sp-xs);
|
||||||
|
transform: rotate(45deg) translateX(calc(-1 * var(--sp-xs))) translateY(var(--sp-xs));
|
||||||
|
border-top: $b-1 solid var(--color-accent-primary-muted);
|
||||||
|
border-right: $b-1 solid var(--color-accent-primary-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-right {
|
||||||
|
grid-template-areas: " arrow content";
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-right .tooltip-arrow {
|
||||||
|
align-self: center;
|
||||||
|
border-radius: 0 var(--sp-xs);
|
||||||
|
transform: rotate(45deg) translateX(var(--sp-xs)) translateY(calc(-1 * var(--sp-xs)));
|
||||||
|
border-bottom: $b-1 solid var(--color-accent-primary-muted);
|
||||||
|
border-left: $b-1 solid var(--color-accent-primary-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-top-right {
|
||||||
|
grid-template-areas:
|
||||||
|
"content"
|
||||||
|
"arrow";
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-top-right .tooltip-arrow {
|
||||||
|
margin: 0 var(--sp-l);
|
||||||
|
border-radius: var(--sp-xs) 0;
|
||||||
|
transform: rotate(45deg) translateX(calc(-1 * var(--sp-s)));
|
||||||
|
border-bottom: $b-1 solid var(--color-accent-primary-muted);
|
||||||
|
border-right: $b-1 solid var(--color-accent-primary-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-bottom-right {
|
||||||
|
grid-template-areas:
|
||||||
|
"arrow"
|
||||||
|
"content";
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-bottom-right .tooltip-arrow {
|
||||||
|
margin: 0px var(--sp-s);
|
||||||
|
transform: rotate(45deg) translateX(var(--sp-s));
|
||||||
|
border-radius: var(--sp-xs) 0;
|
||||||
|
border-top: $b-1 solid var(--color-accent-primary-muted);
|
||||||
|
border-left: $b-1 solid var(--color-accent-primary-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-bottom-left {
|
||||||
|
grid-template-areas:
|
||||||
|
"arrow"
|
||||||
|
"content";
|
||||||
|
}
|
||||||
|
.tooltip-bottom-left .tooltip-arrow {
|
||||||
|
justify-self: end;
|
||||||
|
margin: 0 var(--sp-s);
|
||||||
|
transform: rotate(45deg) translateY(var(--sp-s));
|
||||||
|
border-radius: var(--sp-xs) 0;
|
||||||
|
border-top: $b-1 solid var(--color-accent-primary-muted);
|
||||||
|
border-left: $b-1 solid var(--color-accent-primary-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-top-left {
|
||||||
|
grid-template-areas:
|
||||||
|
"content"
|
||||||
|
"arrow";
|
||||||
|
}
|
||||||
|
.tooltip-top-left .tooltip-arrow {
|
||||||
|
margin: 0 var(--sp-s);
|
||||||
|
justify-self: end;
|
||||||
|
border-radius: var(--sp-xs) 0;
|
||||||
|
transform: rotate(45deg) translateX(calc(-1 * var(--sp-s)));
|
||||||
|
border-bottom: $b-1 solid var(--color-accent-primary-muted);
|
||||||
|
border-right: $b-1 solid var(--color-accent-primary-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-content {
|
||||||
|
background-color: var(--color-background-primary);
|
||||||
|
color: var(--color-foreground-secondary);
|
||||||
|
border-radius: var(--sp-xs);
|
||||||
|
border: $b-1 solid var(--color-accent-primary-muted);
|
||||||
|
padding: var(--sp-s) var(--sp-m);
|
||||||
|
grid-area: content;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-trigger {
|
||||||
|
width: fit-content;
|
||||||
|
height: fit-content;
|
||||||
|
}
|
193
frontend/src/app/main/ui/ds/tooltip/tooltip.stories.jsx
Normal file
193
frontend/src/app/main/ui/ds/tooltip/tooltip.stories.jsx
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
//
|
||||||
|
// Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
|
import * as React from "react";
|
||||||
|
import Components from "@target/components";
|
||||||
|
|
||||||
|
const { Tooltip } = Components;
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: "Tooltip",
|
||||||
|
component: Tooltip,
|
||||||
|
argTypes: {
|
||||||
|
placement: {
|
||||||
|
description: "Position of the tooltip",
|
||||||
|
control: { type: "select" },
|
||||||
|
options: [
|
||||||
|
"top",
|
||||||
|
"bottom",
|
||||||
|
"left",
|
||||||
|
"right",
|
||||||
|
"top-left",
|
||||||
|
"top-right",
|
||||||
|
"bottom-left",
|
||||||
|
"bottom-right",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
delay: {
|
||||||
|
control: { type: "number" },
|
||||||
|
description: "Delay in milliseconds before showing the tooltip",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
parameters: {
|
||||||
|
controls: { exclude: ["children", "id"] },
|
||||||
|
},
|
||||||
|
args: {
|
||||||
|
children: (
|
||||||
|
<button popovertarget="popover-example">Hover this element</button>
|
||||||
|
),
|
||||||
|
id: "popover-example",
|
||||||
|
tooltipContent: "This is the tooltip content",
|
||||||
|
delay: 300,
|
||||||
|
},
|
||||||
|
render: ({ children, ...args }) => (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Tooltip {...args}>{children}</Tooltip>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Default = {};
|
||||||
|
|
||||||
|
export const Corners = {
|
||||||
|
render: ({}) => (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "grid",
|
||||||
|
gridTemplateColumns: "repeat(3, 1fr)",
|
||||||
|
gridTemplateRows: "repeat(3, 1fr)",
|
||||||
|
gap: "1rem",
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Tooltip
|
||||||
|
id="popover-example10"
|
||||||
|
tooltipContent="This is the tooltip content, and must be shown in two lines."
|
||||||
|
style={{
|
||||||
|
placeSelf: "start start",
|
||||||
|
width: "fit-content",
|
||||||
|
height: "fit-content",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<button popovertarget="popover-example10">Hover here</button>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip
|
||||||
|
id="popover-example2"
|
||||||
|
tooltipContent="This is the tooltip content, and must be shown in two lines."
|
||||||
|
style={{
|
||||||
|
alignSelf: "start",
|
||||||
|
justifySelf: "center",
|
||||||
|
width: "fit-content",
|
||||||
|
height: "fit-content",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
popovertarget="popover-example2"
|
||||||
|
style={{
|
||||||
|
alignSelf: "start",
|
||||||
|
justifySelf: "center",
|
||||||
|
width: "fit-content",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Hover here
|
||||||
|
</button>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip
|
||||||
|
id="popover-example3"
|
||||||
|
tooltipContent="This is the tooltip content, and must be shown in two lines."
|
||||||
|
style={{
|
||||||
|
alignSelf: "start",
|
||||||
|
justifySelf: "end",
|
||||||
|
width: "fit-content",
|
||||||
|
height: "fit-content",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<button popovertarget="popover-example3">Hover here</button>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip
|
||||||
|
id="popover-example4"
|
||||||
|
tooltipContent="This is the tooltip content, and must be shown in two lines."
|
||||||
|
style={{
|
||||||
|
alignSelf: "center",
|
||||||
|
justifySelf: "start",
|
||||||
|
width: "fit-content",
|
||||||
|
height: "fit-content",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<button popovertarget="popover-example4">Hover here</button>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip
|
||||||
|
id="popover-example5"
|
||||||
|
tooltipContent="This is the tooltip content, and must be shown in two lines."
|
||||||
|
style={{
|
||||||
|
alignSelf: "center",
|
||||||
|
justifySelf: "center",
|
||||||
|
width: "fit-content",
|
||||||
|
height: "fit-content",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<button popovertarget="popover-example5">Hover here</button>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip
|
||||||
|
id="popover-example6"
|
||||||
|
tooltipContent="This is the tooltip content, and must be shown in two lines."
|
||||||
|
style={{
|
||||||
|
alignSelf: "center",
|
||||||
|
justifySelf: "end",
|
||||||
|
width: "fit-content",
|
||||||
|
height: "fit-content",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<button popovertarget="popover-example6">Hover here</button>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip
|
||||||
|
id="popover-example7"
|
||||||
|
tooltipContent="This is the tooltip content, and must be shown in two lines."
|
||||||
|
style={{
|
||||||
|
alignSelf: "end",
|
||||||
|
justifySelf: "start",
|
||||||
|
width: "fit-content",
|
||||||
|
height: "fit-content",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<button popovertarget="popover-example7">Hover here</button>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip
|
||||||
|
id="popover-example8"
|
||||||
|
tooltipContent="This is the tooltip content, and must be shown in two lines."
|
||||||
|
style={{
|
||||||
|
alignSelf: "end",
|
||||||
|
justifySelf: "center",
|
||||||
|
width: "fit-content",
|
||||||
|
height: "fit-content",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<button popovertarget="popover-example8">Hover here</button>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip
|
||||||
|
id="popover-example9"
|
||||||
|
tooltipContent="This is the tooltip content, and must be shown in two lines."
|
||||||
|
style={{
|
||||||
|
alignSelf: "end",
|
||||||
|
justifySelf: "end",
|
||||||
|
width: "fit-content",
|
||||||
|
height: "fit-content",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<button popovertarget="popover-example9">Hover here</button>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
};
|
|
@ -240,8 +240,6 @@
|
||||||
(dom/stop-propagation event)
|
(dom/stop-propagation event)
|
||||||
(when (and can-edit? (not (seq errors)) on-click)
|
(when (and can-edit? (not (seq errors)) on-click)
|
||||||
(on-click event))))
|
(on-click event))))
|
||||||
|
|
||||||
;; FIXME: missing deps
|
|
||||||
on-hover
|
on-hover
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps selected-shapes is-viewer? active-theme-tokens token half-applied? no-valid-value ref-not-in-active-set)
|
(mf/deps selected-shapes is-viewer? active-theme-tokens token half-applied? no-valid-value ref-not-in-active-set)
|
||||||
|
@ -266,8 +264,11 @@
|
||||||
:token-pill-invalid-applied-viewer (and is-viewer?
|
:token-pill-invalid-applied-viewer (and is-viewer?
|
||||||
(and full-applied? errors?)))
|
(and full-applied? errors?)))
|
||||||
:type "button"
|
:type "button"
|
||||||
|
:on-focus on-hover
|
||||||
|
|
||||||
:on-click on-click
|
:on-click on-click
|
||||||
:on-mouse-enter on-hover
|
:on-mouse-enter on-hover
|
||||||
|
|
||||||
:on-context-menu on-context-menu}
|
:on-context-menu on-context-menu}
|
||||||
(cond
|
(cond
|
||||||
errors?
|
errors?
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue