Class: BetterUi::Tabs::ContainerComponent

Inherits:
ApplicationComponent show all
Defined in:
app/components/better_ui/tabs/container_component.rb

Overview

A flexible tabs container component with two operating modes.

This component provides a tabbed interface with support for:

  • JS mode: Client-side tab switching (all content in DOM)
  • Turbo mode: Server-rendered content via Turbo Frames

Examples:

Basic JS mode tabs

<%= render BetterUi::Tabs::ContainerComponent.new(mode: :js) do |tabs| %>
  <% tabs.with_tab(id: "profile", label: "Profile", active: true) %>
  <% tabs.with_tab(id: "settings", label: "Settings") %>
  <% tabs.with_panel(id: "profile", active: true) { "Profile content" } %>
  <% tabs.with_panel(id: "settings") { "Settings content" } %>
<% end %>

Turbo mode with Turbo Frames

<%= render BetterUi::Tabs::ContainerComponent.new(mode: :turbo, frame_id: "tab-content") do |tabs| %>
  <% tabs.with_tab(id: "profile", label: "Profile", href: profile_path, active: true) %>
  <% tabs.with_tab(id: "settings", label: "Settings", href: settings_path) %>
<% end %>
<turbo-frame id="tab-content"><%= yield %></turbo-frame>

Constant Summary collapse

MODES =

Valid operating modes

i[js turbo].freeze
STYLES =

Tab visual styles

i[underline pills bordered].freeze
SIZES =

Size configurations with tab-specific styling

i[xs sm md lg xl].freeze
ALIGNMENTS =

Tab alignment options

i[start center end stretch].freeze
POSITIONS =

Tab list positions

i[top bottom left right].freeze

Constants inherited from ApplicationComponent

ApplicationComponent::SHADOWS, ApplicationComponent::VARIANTS, ApplicationComponent::VARIANT_BODY_DIVIDE, ApplicationComponent::VARIANT_DIVIDE, ApplicationComponent::VARIANT_HEADER_BG, ApplicationComponent::VARIANT_HEADER_TEXT, ApplicationComponent::VARIANT_HIGHLIGHTED, ApplicationComponent::VARIANT_HOVERABLE, ApplicationComponent::VARIANT_RING, ApplicationComponent::VARIANT_SORT_ICON, ApplicationComponent::VARIANT_STRIPED

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(mode: :js, style: :underline, variant: :primary, size: :md, alignment: :start, position: :top, frame_id: nil, default_tab: nil, persist: false, persist_key: nil, show_loading: nil, loader_delay: 1000, id: nil, **options) ⇒ ContainerComponent

Initializes a new tabs container component.

Parameters:

  • mode (Symbol) (defaults to: :js) —

    operating mode (:js, :turbo), defaults to :js

  • style (Symbol) (defaults to: :underline) —

    visual style (:underline, :pills, :bordered), defaults to :underline

  • variant (Symbol) (defaults to: :primary) —

    color variant from VARIANTS, defaults to :primary

  • size (Symbol) (defaults to: :md) —

    size (:xs, :sm, :md, :lg, :xl), defaults to :md

  • alignment (Symbol) (defaults to: :start) —

    tab alignment (:start, :center, :end, :stretch), defaults to :start

  • position (Symbol) (defaults to: :top) —

    tab list position (:top, :bottom, :left, :right), defaults to :top

  • frame_id (String, nil) (defaults to: nil) —

    Turbo Frame ID (required for turbo mode)

  • default_tab (String, nil) (defaults to: nil) —

    ID of the default active tab

  • persist (Boolean) (defaults to: false) —

    persist active tab in URL hash or localStorage

  • persist_key (String, nil) (defaults to: nil) —

    localStorage key for persistence

  • show_loading (Boolean, nil) (defaults to: nil) —

    show loading indicator in turbo mode (default: true for turbo)

  • loader_delay (Integer) (defaults to: 1000) —

    delay in milliseconds before showing the loader (default: 1000)

  • id (String, nil) (defaults to: nil) —

    explicit ID for the container (auto-generated if nil)

  • options (Hash) —

    additional HTML attributes

Raises:

  • (ArgumentError) —

    if mode is invalid

  • (ArgumentError) —

    if style is invalid

  • (ArgumentError) —

    if size is invalid

  • (ArgumentError) —

    if alignment is invalid

  • (ArgumentError) —

    if position is invalid

  • (ArgumentError) —

    if turbo mode is used without frame_id



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'app/components/better_ui/tabs/container_component.rb', line 93

def initialize(
  mode: :js,
  style: :underline,
  variant: :primary,
  size: :md,
  alignment: :start,
  position: :top,
  frame_id: nil,
  default_tab: nil,
  persist: false,
  persist_key: nil,
  show_loading: nil,
  loader_delay: 1000,
  id: nil,
  **options
)
  @mode = validate_mode(mode)
  @style = validate_style(style)
  @variant = validate_variant(variant)
  @size = validate_size(size)
  @alignment = validate_alignment(alignment)
  @position = validate_position(position)
  @frame_id = frame_id
  @default_tab = default_tab
  @persist = persist
  @persist_key = persist_key
  @show_loading = show_loading.nil? ? (@mode == :turbo) : show_loading
  @loader_delay = loader_delay
  @explicit_id = id
  @options = options

  validate_turbo_requirements!
end

Instance Attribute Details

#alignment ⇒ Symbol (readonly)

Returns the tab alignment.

Returns:

  • (Symbol) —

    the alignment



145
146
147
# File 'app/components/better_ui/tabs/container_component.rb', line 145

def alignment
  @alignment
end

#default_tab ⇒ String? (readonly)

Returns the default active tab ID.

Returns:

  • (String, nil) —

    the default_tab



157
158
159
# File 'app/components/better_ui/tabs/container_component.rb', line 157

def default_tab
  @default_tab
end

#frame_id ⇒ String? (readonly)

Returns the Turbo Frame ID.

Returns:

  • (String, nil) —

    the frame_id



153
154
155
# File 'app/components/better_ui/tabs/container_component.rb', line 153

def frame_id
  @frame_id
end

#loader_delay ⇒ Integer (readonly)

Returns the loader delay in milliseconds.

Returns:

  • (Integer) —

    the loader_delay value



173
174
175
# File 'app/components/better_ui/tabs/container_component.rb', line 173

def loader_delay
  @loader_delay
end

#mode ⇒ Symbol (readonly)

Returns the operating mode.

Returns:

  • (Symbol) —

    the mode (:js or :turbo)



129
130
131
# File 'app/components/better_ui/tabs/container_component.rb', line 129

def mode
  @mode
end

#persist ⇒ Boolean (readonly)

Returns whether persistence is enabled.

Returns:

  • (Boolean) —

    the persist flag



161
162
163
# File 'app/components/better_ui/tabs/container_component.rb', line 161

def persist
  @persist
end

#persist_key ⇒ String? (readonly)

Returns the persistence key for localStorage.

Returns:

  • (String, nil) —

    the persist_key



165
166
167
# File 'app/components/better_ui/tabs/container_component.rb', line 165

def persist_key
  @persist_key
end

#position ⇒ Symbol (readonly)

Returns the tab list position.

Returns:

  • (Symbol) —

    the position



149
150
151
# File 'app/components/better_ui/tabs/container_component.rb', line 149

def position
  @position
end

#show_loading ⇒ Boolean (readonly)

Returns whether loading indicator is shown in turbo mode.

Returns:

  • (Boolean) —

    the show_loading flag



169
170
171
# File 'app/components/better_ui/tabs/container_component.rb', line 169

def show_loading
  @show_loading
end

#size ⇒ Symbol (readonly)

Returns the size.

Returns:

  • (Symbol) —

    the size



141
142
143
# File 'app/components/better_ui/tabs/container_component.rb', line 141

def size
  @size
end

#style ⇒ Symbol (readonly)

Returns the visual style.

Returns:

  • (Symbol) —

    the style (:underline, :pills, or :bordered)



133
134
135
# File 'app/components/better_ui/tabs/container_component.rb', line 133

def style
  @style
end

#variant ⇒ Symbol (readonly)

Returns the color variant.

Returns:

  • (Symbol) —

    the variant



137
138
139
# File 'app/components/better_ui/tabs/container_component.rb', line 137

def variant
  @variant
end

Instance Method Details

#container_id ⇒ String

Generates a unique container ID.

Returns:

  • (String) —

    the container ID



177
178
179
# File 'app/components/better_ui/tabs/container_component.rb', line 177

def container_id
  @container_id ||= @explicit_id || "tabs-#{SecureRandom.hex(4)}"
end

#with_loader ⇒ Object

Slot for rendering a custom loader (Turbo mode only)

Yield Returns:

  • (String) —

    the HTML content for the custom loader



68
# File 'app/components/better_ui/tabs/container_component.rb', line 68

renders_one :loader

#with_panel {|panel| ... } ⇒ Object

Slot for rendering tab panels (JS mode only)

Yield Parameters:

Yield Returns:

  • (String) —

    the HTML content for the panel



61
62
63
# File 'app/components/better_ui/tabs/container_component.rb', line 61

renders_many :panels, lambda { |**args|
  PanelComponent.new(**args, container_id: container_id)
}

#with_tab {|tab| ... } ⇒ Object

Slot for rendering tab buttons/links

Yield Parameters:

Yield Returns:

  • (String) —

    the HTML content for the tab



45
46
47
48
49
50
51
52
53
54
55
# File 'app/components/better_ui/tabs/container_component.rb', line 45

renders_many :tabs, lambda { |**args|
  TabComponent.new(
    **args,
    mode: @mode,
    style: @style,
    variant: @variant,
    size: @size,
    frame_id: @frame_id,
    container_id: container_id
  )
}