diff --git a/app/components/DS/tooltip.html.erb b/app/components/DS/tooltip.html.erb index a10c1147f..fe0c04366 100644 --- a/app/components/DS/tooltip.html.erb +++ b/app/components/DS/tooltip.html.erb @@ -1,8 +1,39 @@ - <%= helpers.icon icon_name, size: size, color: color %> + <% if as == :button %> + <%# Wrap the trigger icon in a focusable ` + <% else %> + <%# `as: :span` — used when the tooltip is rendered inside an + already-focusable interactive ancestor (e.g. ``), + where the HTML spec forbids nested interactive content. + Keyboard reveal is wired in the controller, which (in addition + to listening on the outer span for the standalone case) also + binds `focusin/focusout/keydown` on the closest `` + ancestor — because `focusin` only bubbles UP, a listener on + this descendant span would never fire when the ancestor + disclosure receives focus. %> + + <%= helpers.icon icon_name, size: size, color: color %> + + <% end %> - <% elsif ibkr_item.sync_error.present? %>
- <%= render DS::Tooltip.new(text: ibkr_item.sync_error, icon: "alert-circle", size: "sm", color: "destructive") %> + <%= render DS::Tooltip.new(text: ibkr_item.sync_error, icon: "alert-circle", size: "sm", color: "destructive", as: :span) %> <%= tag.span t(".error"), class: "text-destructive" %>
<% else %> diff --git a/app/views/indexa_capital_items/_indexa_capital_item.html.erb b/app/views/indexa_capital_items/_indexa_capital_item.html.erb index e6f608e33..7f90af7bd 100644 --- a/app/views/indexa_capital_items/_indexa_capital_item.html.erb +++ b/app/views/indexa_capital_items/_indexa_capital_item.html.erb @@ -34,7 +34,7 @@ <% elsif indexa_capital_item.sync_error.present? %>
- <%= render DS::Tooltip.new(text: indexa_capital_item.sync_error, icon: "alert-circle", size: "sm", color: "destructive") %> + <%= render DS::Tooltip.new(text: indexa_capital_item.sync_error, icon: "alert-circle", size: "sm", color: "destructive", as: :span) %> <%= tag.span t(".error"), class: "text-destructive" %>
<% else %> diff --git a/app/views/lunchflow_items/_lunchflow_item.html.erb b/app/views/lunchflow_items/_lunchflow_item.html.erb index a1aec313b..0b0fecc76 100644 --- a/app/views/lunchflow_items/_lunchflow_item.html.erb +++ b/app/views/lunchflow_items/_lunchflow_item.html.erb @@ -35,7 +35,7 @@ <% elsif lunchflow_item.sync_error.present? %>
- <%= render DS::Tooltip.new(text: lunchflow_item.sync_error, icon: "alert-circle", size: "sm", color: "destructive") %> + <%= render DS::Tooltip.new(text: lunchflow_item.sync_error, icon: "alert-circle", size: "sm", color: "destructive", as: :span) %> <%= tag.span t(".error"), class: "text-destructive" %>
<% else %> diff --git a/app/views/mercury_items/_mercury_item.html.erb b/app/views/mercury_items/_mercury_item.html.erb index 0159551e8..6485da548 100644 --- a/app/views/mercury_items/_mercury_item.html.erb +++ b/app/views/mercury_items/_mercury_item.html.erb @@ -35,7 +35,7 @@ <% elsif mercury_item.sync_error.present? %>
- <%= render DS::Tooltip.new(text: mercury_item.sync_error, icon: "alert-circle", size: "sm", color: "destructive") %> + <%= render DS::Tooltip.new(text: mercury_item.sync_error, icon: "alert-circle", size: "sm", color: "destructive", as: :span) %> <%= tag.span t(".error"), class: "text-destructive" %>
<% else %> diff --git a/app/views/simplefin_items/_simplefin_item.html.erb b/app/views/simplefin_items/_simplefin_item.html.erb index c6e90e810..d09d9b202 100644 --- a/app/views/simplefin_items/_simplefin_item.html.erb +++ b/app/views/simplefin_items/_simplefin_item.html.erb @@ -52,7 +52,7 @@ <% if has_warnings %>
<% if stats["accounts_skipped"].to_i > 0 %> - <%= render DS::Tooltip.new(text: t(".accounts_skipped_tooltip"), icon: "alert-triangle", size: "sm", color: "warning") %> + <%= render DS::Tooltip.new(text: t(".accounts_skipped_tooltip"), icon: "alert-triangle", size: "sm", color: "warning", as: :span) %> <%= t(".accounts_skipped_label", count: stats["accounts_skipped"].to_i) %> <% end %> @@ -63,14 +63,15 @@ text: (ago ? t(".rate_limited_ago", time: ago) : t(".rate_limited_recently")), icon: "clock", size: "sm", - color: "warning" + color: "warning", + as: :span ) %> <% end %> <% if stats["total_errors"].to_i > 0 || (stats["errors"].is_a?(Array) && stats["errors"].any?) %> <% tooltip_text = simplefin_error_tooltip(stats) %> <% if tooltip_text.present? %> - <%= render DS::Tooltip.new(text: tooltip_text, icon: "alert-octagon", size: "sm", color: "warning") %> + <%= render DS::Tooltip.new(text: tooltip_text, icon: "alert-octagon", size: "sm", color: "warning", as: :span) %> <% end %> <% end %>
@@ -119,7 +120,7 @@ <% elsif simplefin_item.sync_error.present? && !duplicate_only_errors %>
- <%= render DS::Tooltip.new(text: simplefin_item.sync_error, icon: "alert-circle", size: "sm", color: "destructive") %> + <%= render DS::Tooltip.new(text: simplefin_item.sync_error, icon: "alert-circle", size: "sm", color: "destructive", as: :span) %> <%= tag.span t(".error"), class: "text-destructive" %>
<% elsif duplicate_only_errors %> diff --git a/app/views/snaptrade_items/_snaptrade_item.html.erb b/app/views/snaptrade_items/_snaptrade_item.html.erb index f36712ec2..636d09dbe 100644 --- a/app/views/snaptrade_items/_snaptrade_item.html.erb +++ b/app/views/snaptrade_items/_snaptrade_item.html.erb @@ -42,7 +42,7 @@ <% elsif snaptrade_item.sync_error.present? %>
- <%= render DS::Tooltip.new(text: snaptrade_item.sync_error, icon: "alert-circle", size: "sm", color: "destructive") %> + <%= render DS::Tooltip.new(text: snaptrade_item.sync_error, icon: "alert-circle", size: "sm", color: "destructive", as: :span) %> <%= tag.span t(".error"), class: "text-destructive" %>
<% else %> diff --git a/app/views/sophtron_items/_sophtron_item.html.erb b/app/views/sophtron_items/_sophtron_item.html.erb index a8c71d900..d91450a86 100644 --- a/app/views/sophtron_items/_sophtron_item.html.erb +++ b/app/views/sophtron_items/_sophtron_item.html.erb @@ -41,7 +41,7 @@ <% elsif sophtron_item.sync_error.present? %>
- <%= render DS::Tooltip.new(text: sophtron_item.sync_error, icon: "alert-circle", size: "sm", color: "destructive") %> + <%= render DS::Tooltip.new(text: sophtron_item.sync_error, icon: "alert-circle", size: "sm", color: "destructive", as: :span) %> <%= tag.span t(".error"), class: "text-destructive" %>
<% else %> diff --git a/config/locales/views/components/en.yml b/config/locales/views/components/en.yml index 8c49e0461..11d896222 100644 --- a/config/locales/views/components/en.yml +++ b/config/locales/views/components/en.yml @@ -89,6 +89,8 @@ en: default_label: Preview dialog: close: Close + tooltip: + trigger_label: More info link: opens_in_new_tab: (opens in new tab) provider_sync_summary: diff --git a/test/components/previews/tooltip_component_preview.rb b/test/components/previews/tooltip_component_preview.rb index 68bd6c320..a6345ef0b 100644 --- a/test/components/previews/tooltip_component_preview.rb +++ b/test/components/previews/tooltip_component_preview.rb @@ -6,7 +6,8 @@ class TooltipComponentPreview < ViewComponent::Preview # @param icon text # @param size select [xs, sm, md, lg, xl, 2xl] # @param color select [default, white, success, warning, destructive, current] - def default(text: "This is helpful information", placement: "top", offset: 10, cross_axis: 0, icon: "info", size: "sm", color: "default") + # @param as select [button, span] + def default(text: "This is helpful information", placement: "top", offset: 10, cross_axis: 0, icon: "info", size: "sm", color: "default", as: "button") render DS::Tooltip.new( text: text, placement: placement, @@ -14,7 +15,8 @@ class TooltipComponentPreview < ViewComponent::Preview cross_axis: cross_axis, icon: icon, size: size, - color: color + color: color, + as: as.to_sym ) end