mirror of
https://github.com/we-promise/sure.git
synced 2026-09-02 05:11:05 +00:00
* fix(ui): resolve DS Drift Patrol findings from #2745 Replace hand-rolled queue status chips and the insights nav tooltip/badge with DS::Pill and DS::Tooltip. Co-authored-by: Cursor <cursoragent@cursor.com> * i18n: use a single key for background job queue pill labels * fix(ui): address gariasf review on insights badge and queue pills Keep the unread insights count on theme-aware inverse tokens (DS::Pill filled neutral is not dark-mode safe). Extend DS::Tooltip with html_class passthrough and a/summary focus ancestors so icon-only links keep full hover + keyboard reveal. Add queue_label locales (de/uk/zh-TW), drop the dead latency keys, and restore mono via DS::Pill mono: true. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
46 lines
1.9 KiB
Ruby
46 lines
1.9 KiB
Ruby
class DS::Tooltip < ApplicationComponent
|
|
AS_OPTIONS = %i[button span].freeze
|
|
|
|
attr_reader :placement, :offset, :cross_axis, :icon_name, :size, :color, :tooltip_id, :as, :html_class
|
|
|
|
# NOTE: tooltip content must be non-interactive — no buttons, links,
|
|
# or form controls inside. Tooltips are exposed via `aria-describedby`,
|
|
# which announces the content as a description but does not expose
|
|
# interactive descendants to AT. Use a popover/menu primitive when
|
|
# the surface needs to host actions.
|
|
#
|
|
# `as:` controls the trigger element.
|
|
# :button (default) — renders `<button type="button">`, focusable on
|
|
# its own. Use for tooltips placed in standalone, non-interactive
|
|
# surrounding markup.
|
|
# :span — renders `<span>` with no `tabindex`. Use when the tooltip
|
|
# sits inside an already-focusable interactive ancestor (`<a>`,
|
|
# `<summary>`, …) where nested interactive content is forbidden or
|
|
# undesirable. The Stimulus controller also binds focus handlers on
|
|
# the closest `a`/`summary` ancestor so keyboard focus on that
|
|
# element reveals the tooltip (`focusin` only bubbles upward).
|
|
#
|
|
# `html_class:` is merged onto the outer controller wrapper. Pass
|
|
# sizing/layout utilities (e.g. `size-full items-center justify-center`)
|
|
# when `as: :span` should fill an icon-only link so hover covers the
|
|
# whole hit target, not just the icon glyph.
|
|
def initialize(text: nil, placement: "top", offset: 10, cross_axis: 0, icon: "info", size: "sm", color: "default", as: :button, html_class: nil)
|
|
raise ArgumentError, "as: must be one of #{AS_OPTIONS.inspect}" unless AS_OPTIONS.include?(as)
|
|
|
|
@text = text
|
|
@placement = placement
|
|
@offset = offset
|
|
@cross_axis = cross_axis
|
|
@icon_name = icon
|
|
@size = size
|
|
@color = color
|
|
@as = as
|
|
@html_class = html_class
|
|
@tooltip_id = "tooltip-#{SecureRandom.hex(4)}"
|
|
end
|
|
|
|
def tooltip_content
|
|
content? ? content : @text
|
|
end
|
|
end
|