Module: TurboOverlay::Helpers::ViewHelper
- Defined in:
- lib/turbo_overlay/helpers/view_helper.rb
Instance Method Summary collapse
-
#drawer_button_to(name = nil, options = nil, html_options = nil, &block) ⇒ Object
‘button_to` counterpart to `drawer_link_to` — see `modal_button_to`.
-
#drawer_dismiss_link_to(name = nil, options = nil, html_options = nil, &block) ⇒ Object
Inside a drawer, render a link styled as a “dismiss” trigger.
-
#drawer_link_to(name = nil, options = nil, html_options = nil, &block) ⇒ Object
Build a link that opens its target as a drawer overlay.
-
#hint_link_to(name = nil, options = nil, html_options = nil, &block) ⇒ Object
Decorate any ‘<a>` so the gem’s JS shows a hover-hint preview.
-
#modal_button_to(name = nil, options = nil, html_options = nil, &block) ⇒ Object
Render a ‘button_to` form whose POST/DELETE/PATCH/PUT response opens a modal overlay.
-
#modal_dismiss_link_to(name = nil, options = nil, html_options = nil, &block) ⇒ Object
Inside a modal, render a link styled as a “dismiss” trigger.
-
#modal_link_to(name = nil, options = nil, html_options = nil, &block) ⇒ Object
Build a link that opens its target as a modal overlay.
-
#overlay_close(show = true) ⇒ Object
Toggle the chrome’s default close (“×”) button for the current overlay render.
-
#overlay_close? ⇒ Boolean
Whether the chrome should render its default close button.
-
#overlay_footer(value = nil, &block) ⇒ Object
Set the overlay footer content.
-
#overlay_frame_tags(*_types) ⇒ Object
Deprecated.
-
#overlay_response_wrapper(type, &block) ⇒ Object
Wraps the given block in the appropriate response primitive for the current overlay request:.
-
#overlay_stack_tag ⇒ Object
Emit the receiving stack container for overlays.
-
#overlay_title(value = nil, &block) ⇒ Object
Set the overlay header title.
-
#popover_button_to(name = nil, options = nil, html_options = nil, &block) ⇒ Object
‘button_to` counterpart to `popover_link_to` — see `modal_button_to`.
-
#popover_dismiss_link_to(name = nil, options = nil, html_options = nil, &block) ⇒ Object
Inside a popover, render a link styled as a “dismiss” trigger.
-
#popover_link_to(name = nil, options = nil, html_options = nil, &block) ⇒ Object
Build a link that opens its target as a popover overlay anchored to the clicked link.
-
#turbo_overlay_frame_id(type = nil) ⇒ Object
The DOM id of the per-overlay turbo-frame for the current request: ‘turbo_overlay_<type>_<id>`.
Instance Method Details
#drawer_button_to(name = nil, options = nil, html_options = nil, &block) ⇒ Object
‘button_to` counterpart to `drawer_link_to` — see `modal_button_to`. Accepts `position:`, `backdrop:`, `close:`, and `keep_overlay_open_on_redirect:`.
100 101 102 |
# File 'lib/turbo_overlay/helpers/view_helper.rb', line 100 def (name = nil, = nil, = nil, &block) (:drawer, name, , , &block) end |
#drawer_dismiss_link_to(name = nil, options = nil, html_options = nil, &block) ⇒ Object
Inside a drawer, render a link styled as a “dismiss” trigger.
93 94 95 |
# File 'lib/turbo_overlay/helpers/view_helper.rb', line 93 def drawer_dismiss_link_to(name = nil, = nil, = nil, &block) (:drawer, name, , , &block) end |
#drawer_link_to(name = nil, options = nil, html_options = nil, &block) ⇒ Object
Build a link that opens its target as a drawer overlay. Same stacking and ‘overlay_id:` semantics as `modal_link_to`.
<%= drawer_link_to "Filters", filters_path %>
‘position:` overrides the configured drawer side for this one link (`:left`, `:right`, `:top`, `:bottom`). When omitted the drawer opens on the side set by `TurboOverlay.configuration.drawer.position`.
<%= drawer_link_to "Nav", nav_path, position: :left %>
‘backdrop: false` opens the drawer non-modally: no dimmed backdrop, the page stays scrollable, and text on the page remains selectable so users can copy/paste between the page and the drawer. Click outside the drawer is also ignored (no backdrop to click). ESC still closes.
<%= drawer_link_to "Inspector", inspect_path, backdrop: false %>
‘close: false` opens the drawer without the default close (“×”) button. ESC still closes; the backdrop is unaffected.
88 89 90 |
# File 'lib/turbo_overlay/helpers/view_helper.rb', line 88 def drawer_link_to(name = nil, = nil, = nil, &block) (:drawer, name, , , &block) end |
#hint_link_to(name = nil, options = nil, html_options = nil, &block) ⇒ Object
Decorate any ‘<a>` so the gem’s JS shows a hover-hint preview. ‘hint_link_to` is a thin wrapper around `link_to` that sets the two data attributes the JS reads. Compose freely with overlay helpers (`modal_link_to “Edit”, path, hint: true, hint_url: …`) or set the data attributes directly on any `link_to`.
<%= hint_link_to "User", user_path(@user) %>
<%= hint_link_to "User", user_path(@user), hint_url: hint_user_path(@user) %>
Without ‘hint_url:`, the gem extracts a `<template id=“…”>` from the page’s own response when Turbo prefetches it on hover. With ‘hint_url:`, the gem fetches the alternate URL with the `:hint` request variant on hover. Overlay links (`modal_link_to` etc.) are excluded from Turbo’s hover prefetch — provide ‘hint_url:` for them.
‘show_delay:` / `hide_delay:` (ms) override the configured `TurboOverlay.configuration.hint.show_delay_ms` / `hide_delay_ms` for this one link. Useful for dense lists (datatables, menus) where a longer show delay keeps hints from flickering during scroll/keyboard navigation, or for a single high-signal link that wants a near-zero delay.
<%= hint_link_to "User", user_path(@user), show_delay: 600 %>
168 169 170 171 172 173 174 175 176 177 178 179 |
# File 'lib/turbo_overlay/helpers/view_helper.rb', line 168 def hint_link_to(name = nil, = nil, = nil, &block) if block_given? = || {} = name , = _hint_normalize_link_args(, ) link_to(, , &block) else = ( || {}).dup , = _hint_normalize_link_args(, ) link_to(name, , ) end end |
#modal_button_to(name = nil, options = nil, html_options = nil, &block) ⇒ Object
Render a ‘button_to` form whose POST/DELETE/PATCH/PUT response opens a modal overlay. Use this when opening the modal is the result of a non-GET action — creating a record, deleting an item, kicking off a wizard. The form carries the same overlay data attributes a `modal_link_to` link would, so the server sees identical `X-Turbo-Overlay-*` request headers and wraps the response in the modal layout.
<%= modal_button_to "Delete", widget_path(@w), method: :delete %>
<%= modal_button_to "Start wizard", wizards_path, method: :post %>
Accepts the same overlay options as ‘modal_link_to` (`overlay_id:`, `close:`, `keep_overlay_open_on_redirect:`). `advance:` is not exposed — non-GET requests don’t push history.
60 61 62 |
# File 'lib/turbo_overlay/helpers/view_helper.rb', line 60 def (name = nil, = nil, = nil, &block) (:modal, name, , , &block) end |
#modal_dismiss_link_to(name = nil, options = nil, html_options = nil, &block) ⇒ Object
Inside a modal, render a link styled as a “dismiss” trigger. Outside a modal, behaves like a normal ‘link_to`.
<%= modal_dismiss_link_to "Cancel", cancel_path %>
42 43 44 |
# File 'lib/turbo_overlay/helpers/view_helper.rb', line 42 def modal_dismiss_link_to(name = nil, = nil, = nil, &block) (:modal, name, , , &block) end |
#modal_link_to(name = nil, options = nil, html_options = nil, &block) ⇒ Object
Build a link that opens its target as a modal overlay. The response is appended to the host-page stack container, so a modal opened from inside another modal stacks on top rather than replacing.
<%= modal_link_to "New User", new_user_path %>
<%= modal_link_to "Edit", edit_user_path(@user),
overlay_id: "edit_user_#{@user.id}" %>
‘overlay_id:` is optional. When omitted the server generates a random id; supply your own when you want to close the overlay later from server code via `turbo_stream.overlay(:close, id: “…”)`.
‘close: false` opens the modal without the default close (“×”) button rendered by the chrome partial. Useful when the body provides its own dismiss controls (the confirm partial uses this internally). ESC and backdrop click still close.
34 35 36 |
# File 'lib/turbo_overlay/helpers/view_helper.rb', line 34 def modal_link_to(name = nil, = nil, = nil, &block) (:modal, name, , , &block) end |
#overlay_close(show = true) ⇒ Object
Toggle the chrome’s default close (“×”) button for the current overlay render. Defaults to on; call with ‘false` from inside an overlay view to suppress it:
<% overlay_close false %>
Precedence (highest first): partial local ‘close:` on `render “turbo_overlay/modal”`, this helper, the link option `close: false` (carried as a request header and exposed via `turbo_overlay_close?`), then the default `true`.
359 360 361 |
# File 'lib/turbo_overlay/helpers/view_helper.rb', line 359 def (show = true) @_overlay_close = show end |
#overlay_close? ⇒ Boolean
Whether the chrome should render its default close button. Resolves the precedence described on ‘overlay_close`.
365 366 367 368 |
# File 'lib/turbo_overlay/helpers/view_helper.rb', line 365 def return @_overlay_close != false if defined?(@_overlay_close) controller. end |
#overlay_footer(value = nil, &block) ⇒ Object
Set the overlay footer content.
345 346 347 |
# File 'lib/turbo_overlay/helpers/view_helper.rb', line 345 def (value = nil, &block) content_for(:overlay_footer, value, &block) end |
#overlay_frame_tags(*_types) ⇒ Object
Deprecated. Aliased to ‘overlay_stack_tag` for one minor cycle. The previous frame-per-type model has been replaced by a single shared stack container.
291 292 293 294 295 296 |
# File 'lib/turbo_overlay/helpers/view_helper.rb', line 291 def (*_types) ActiveSupport::Deprecation.new("0.4", "turbo_overlay").warn( "overlay_frame_tags is deprecated; use overlay_stack_tag instead." ) end |
#overlay_response_wrapper(type, &block) ⇒ Object
Wraps the given block in the appropriate response primitive for the current overlay request:
-
Initial open (‘X-Turbo-Overlay` header): emits a `<turbo-stream action=“append” target=“<stack_id>”>` whose template contains a `<turbo-frame id=“<frame_id>”>` around the dialog.
-
Form re-render inside an open overlay (‘Turbo-Frame: turbo_overlay_<type>_<id>`): emits a `<turbo-stream action=“replace” method=“morph”>` targeting the open frame. Morphing preserves the `<dialog>` node identity (top-layer membership, popover anchor, stack registration, ESC / outside-click handlers, focus, and scroll position) and just updates the children to show the new markup — the error messages, the populated form fields. Plain frame replacement would tear the dialog down and re-attach a fresh one, which detaches popovers from their anchor and leaks document-level handlers.
Used by the modal/drawer layouts to keep them readable.
327 328 329 330 331 332 333 334 335 336 337 |
# File 'lib/turbo_overlay/helpers/view_helper.rb', line 327 def (type, &block) frame_id = "turbo_overlay_#{type}_#{}" frame_html = turbo_frame_tag(frame_id, class: "turbo-overlay-frame", &block) if controller. turbo_stream.replace(frame_id, method: :morph) { frame_html } else stack_id = TurboOverlay.configuration.stack_id turbo_stream.append(stack_id) { frame_html } end end |
#overlay_stack_tag ⇒ Object
Emit the receiving stack container for overlays. Drop this in your application layout (typically just before ‘</body>`) once.
<%= overlay_stack_tag %>
When the host app has confirm chrome partials in ‘app/views/turbo_overlay/`, emits sibling `<template>` elements per variant the JS confirm hook clones from:
<template id="turbo_overlay_confirm_modal_template">…</template>
<template id="turbo_overlay_confirm_popover_template">…</template>
Partial resolution per variant prefers ‘_confirm.html+<variant>.erb`, then falls back to a shared `_confirm.html.erb`. The shared partial — if it’s the only one present — is rendered once for both modal and popover styles so apps that don’t want chrome-specific variants can ship a single file.
The same shape applies to the loading partials:
<template id="turbo_overlay_loading_modal_template">…</template>
<template id="turbo_overlay_loading_drawer_template">…</template>
<template id="turbo_overlay_loading_popover_template">…</template>
<template id="turbo_overlay_loading_hint_template">…</template>
rendered from ‘_loading.html+<type>.erb` with `_loading.html.erb` as the shared fallback. Cloned by the JS at click time to give users immediate feedback while the real response is in flight.
The configured default confirm style is exposed as a data attribute on the stack container so the JS can read it without a separate config plumbing pass.
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 |
# File 'lib/turbo_overlay/helpers/view_helper.rb', line 216 def stack_id = TurboOverlay.configuration.stack_id confirm_style = TurboOverlay.configuration.confirm.style.to_s hint_cfg = TurboOverlay.configuration.hint data_attrs = { controller: "turbo-overlay-stack", "turbo-overlay-confirm-style": confirm_style, "turbo-overlay-hint-show-delay": hint_cfg.show_delay_ms, "turbo-overlay-hint-hide-delay": hint_cfg.hide_delay_ms, "turbo-overlay-advance-modal": TurboOverlay.configuration.modal.advance.to_s, "turbo-overlay-advance-drawer": TurboOverlay.configuration.drawer.advance.to_s } allowed_click_outside = TurboOverlay.configuration.allowed_click_outside_selectors if allowed_click_outside.any? data_attrs["turbo-overlay-stack-allowed-click-outside-selectors-value"] = allowed_click_outside.to_json end stack = content_tag(:div, "".html_safe, id: stack_id, class: "turbo-overlay-stack", data: data_attrs) return stack unless respond_to?(:lookup_context) && lookup_context parts = [stack] [:modal, :popover].each do |variant| rendered = ( "turbo_overlay/confirm", variant, chrome: variant, locals: { close: false } ) next unless rendered parts << content_tag(:template, rendered, id: "turbo_overlay_confirm_#{variant}_template") end [:modal, :drawer, :popover, :hint].each do |variant| rendered = ( "turbo_overlay/loading", variant, chrome: variant, locals: { loading: true, close: false } ) next unless rendered parts << content_tag(:template, rendered, id: "turbo_overlay_loading_#{variant}_template") end # On a hintable request, render the action's `+hint.erb` # variant template if one exists. Gated on # `_overlay_hintable_request?` so a regular page render # doesn't pay the cost. body = if body hint_body = if lookup_context.exists?("turbo_overlay/hint", [], true) # Render the partial as a layout so the user's body lands # at `<%= yield %>`. Same pattern used by the modal/drawer # /popover layouts. render(layout: "turbo_overlay/hint") { body } else # No chrome partial in the app yet; emit the body unwrapped # so the JS still has something to extract. body end parts << content_tag(:template, hint_body, id: "turbo-overlay-hint") end return stack if parts.size == 1 safe_join(parts) end |
#overlay_title(value = nil, &block) ⇒ Object
Set the overlay header title.
340 341 342 |
# File 'lib/turbo_overlay/helpers/view_helper.rb', line 340 def (value = nil, &block) content_for(:overlay_title, value, &block) end |
#popover_button_to(name = nil, options = nil, html_options = nil, &block) ⇒ Object
‘button_to` counterpart to `popover_link_to` — see `modal_button_to`. Accepts `position:`, `align:`, `offset:`, `close:`. The popover anchors to the rendered form (which wraps the button), so positioning works the same as for a `popover_link_to` link.
138 139 140 |
# File 'lib/turbo_overlay/helpers/view_helper.rb', line 138 def (name = nil, = nil, = nil, &block) (:popover, name, , , &block) end |
#popover_dismiss_link_to(name = nil, options = nil, html_options = nil, &block) ⇒ Object
Inside a popover, render a link styled as a “dismiss” trigger.
129 130 131 |
# File 'lib/turbo_overlay/helpers/view_helper.rb', line 129 def popover_dismiss_link_to(name = nil, = nil, = nil, &block) (:popover, name, , , &block) end |
#popover_link_to(name = nil, options = nil, html_options = nil, &block) ⇒ Object
Build a link that opens its target as a popover overlay anchored to the clicked link. Same stacking and ‘overlay_id:` semantics as `modal_link_to`.
<%= popover_link_to "Edit", edit_user_path(@user) %>
‘position:` overrides the configured side (`:top`, `:bottom`, `:left`, `:right`). `align:` overrides the cross-axis alignment (`:start`, `:center`, `:end`). `offset:` overrides the pixel gap between trigger and popover.
<%= popover_link_to "Info", info_path,
position: :top, align: :center, offset: 8 %>
Popovers are non-modal (no backdrop, page stays interactive) and dismiss on outside click or ESC. Opening a second popover automatically closes any other open popover; modals and drawers still stack on top.
124 125 126 |
# File 'lib/turbo_overlay/helpers/view_helper.rb', line 124 def popover_link_to(name = nil, = nil, = nil, &block) (:popover, name, , , &block) end |
#turbo_overlay_frame_id(type = nil) ⇒ Object
The DOM id of the per-overlay turbo-frame for the current request: ‘turbo_overlay_<type>_<id>`. Used by overlay layouts to tag the wrapping frame.
301 302 303 304 305 |
# File 'lib/turbo_overlay/helpers/view_helper.rb', line 301 def (type = nil) type ||= controller. return nil unless type && "turbo_overlay_#{type}_#{}" end |