bulma-phlex 0.15.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8a1d3209d836363da07529fa00c9374618623280e70f3167c409e320b77dd4c4
4
- data.tar.gz: e078ae57978d967610194b989078d484ad2297d4cdd71b0ae2d65b07d80dc105
3
+ metadata.gz: 6a4e33701b1ed15897b743789cc3fb1923fdaf70fd065035f8342836058927ed
4
+ data.tar.gz: 772252cf5d5660a0a926f4d24a2ffd73898947a6db4ce3f8ea880978acdda0bf
5
5
  SHA512:
6
- metadata.gz: c7c0d1e8bbfb69e58e78af757f14b4dde6ab532f085e7ea970cb1addd511f2c5c33ba964df7b80dcfdac878f4475108858ceace18f3e5b52356d3b9b3d7df521
7
- data.tar.gz: c41d7a84d0a5e5c2c03aafd7ff74764af2e94221c051aa67766815d46805cd153829deb87173b7d73285fcfaf9752433412070effb7755fced7d3e45df388912
6
+ metadata.gz: 7ec1799752698497e06b075b7378d18a3b820e80ec9e95c7448eb1999ac93514c785d6a61f95434ba02962edb103aa398bd6994506a0954804af52becb56f9ac
7
+ data.tar.gz: 4071dd6000764651b7a677d1ab6ac94c15b59043692602be997924ec094977f41eaf704222554e89ce33f0a49feadc65eeb680ef8c3d36963034995c7b867570
data/README.md CHANGED
@@ -10,6 +10,7 @@ This gem provides a set of ready-to-use [Phlex](https://github.com/phlex-ruby/ph
10
10
 
11
11
  - [Installation](#installation)
12
12
  - [Usage](#usage)
13
+ - [Breadcrumb](#breadcrumb)
13
14
  - [Button](#button)
14
15
  - [Card](#card)
15
16
  - [Columns](#columns)
@@ -19,7 +20,9 @@ This gem provides a set of ready-to-use [Phlex](https://github.com/phlex-ruby/ph
19
20
  - [Grid](#grid)
20
21
  - [Hero](#hero)
21
22
  - [Icon](#icon)
23
+ - [Image](#image)
22
24
  - [Level](#level)
25
+ - [Media Object](#media-object)
23
26
  - [Message](#message)
24
27
  - [Modal](#modal)
25
28
  - [NavigationBar](#navigationbar)
@@ -73,11 +76,24 @@ This gem requires:
73
76
  require "bulma-phlex"
74
77
  ```
75
78
 
76
-
77
79
  ## Usage
78
80
 
79
81
  Use the Phlex components in your Rails views or any Ruby application that supports Phlex components.
80
82
 
83
+ ### Breadcrumb
84
+
85
+ Renders a [Bulma breadcrumb](https://bulma.io/documentation/components/breadcrumb/) navigation element. Each breadcrumb item is added via the `item` method on the yielded component.
86
+
87
+ ```ruby
88
+ render BulmaPhlex::Breadcrumb.new do |bc|
89
+ bc.item("Bulma", href: "/")
90
+ bc.item("Components", href: "/components")
91
+ bc.item("Breadcrumb")
92
+ end
93
+ ```
94
+
95
+ It supports options for **alignment** (centered, right-aligned), **separator** style (arrow, bullet, dot, or succeeds), and **size** (small, medium, large). Items also support an optional `icon` argument.
96
+
81
97
  ### Button
82
98
 
83
99
  Renders a [Bulma button](https://bulma.io/documentation/elements/button/) element with support for color, size, style modifiers, and left/right icons.
@@ -94,11 +110,12 @@ The button label can be passed in as a string or in a block.
94
110
 
95
111
  ### Card
96
112
 
97
- Renders a [Bulma card](https://bulma.io/documentation/components/card/) with an optional header, content area, and footer links. Each section is populated via builder methods on the yielded component.
113
+ Renders a [Bulma card](https://bulma.io/documentation/components/card/) with an optional header, image, content area, and footer links. Each section is populated via builder methods on the yielded component.
98
114
 
99
115
  ```ruby
100
116
  render BulmaPhlex::Card.new do |card|
101
- card.head("Card Title")
117
+ card.header("Card Title")
118
+ card.image(src: "image.jpg", alt: "Card image")
102
119
  card.content do
103
120
  "This is some card content"
104
121
  end
@@ -107,9 +124,10 @@ render BulmaPhlex::Card.new do |card|
107
124
  end
108
125
  ```
109
126
 
110
- Use method `footer_item` for full control of the footer items. Class `footer-item` must be on the outer element
111
- of the block.
127
+ The `header` method accepts a string, for a simple title, or a block for custom content.
112
128
 
129
+ Use method `footer_item` for full control of the footer items. Class `footer-item` must be on the outer element
130
+ of the block.
113
131
 
114
132
  ### Columns
115
133
 
@@ -125,7 +143,6 @@ end
125
143
 
126
144
  The `gap:` option accepts either an integer (0–8) or a hash keyed by breakpoint for responsive gap sizes.
127
145
 
128
-
129
146
  ### Dropdown
130
147
 
131
148
  Renders a [Bulma dropdown](https://bulma.io/documentation/components/dropdown/) menu. Supports click-to-toggle (default, via a Stimulus controller) and hoverable (no JavaScript) modes.
@@ -142,6 +159,11 @@ end
142
159
 
143
160
  Set `click: false` to use hover mode instead of the Stimulus controller.
144
161
 
162
+ Use method `header` to add a non-clickable header item. The method takes an optional `divider` argument. (This is not in the Bulma library.)
163
+
164
+ ```ruby
165
+ dropdown.header("Actions", divider: true)
166
+ ```
145
167
 
146
168
  ### File Upload
147
169
 
@@ -155,7 +177,6 @@ end
155
177
 
156
178
  Set `name: true` to include a file name display element. When enabled, Stimulus data attributes are wired up automatically. The controller is not included in this gem; an [example implementation](https://github.com/RockSolt/bulma-phlex-rails/blob/main/app/javascript/controllers/bulma_phlex/file_input_display_controller.js) is available in the `bulma-phlex-rails` gem.
157
179
 
158
-
159
180
  ### Form Field
160
181
 
161
182
  Renders a [Bulma form field](https://bulma.io/documentation/form/general/#form-field) grouping a label, control, and optional help text. Set the label via the `label` method (string or block) and the input via the `control` method.
@@ -169,7 +190,6 @@ end
169
190
 
170
191
  The `column:` and `grid:` options integrate the field into Bulma's column and grid layout systems. Both accept `true`, a size string, or a breakpoint hash.
171
192
 
172
-
173
193
  ### Grid
174
194
 
175
195
  Renders a [Bulma smart grid](https://bulma.io/documentation/grid/smart-grid/) layout. Supports fixed column counts, auto-count, minimum column width, and independent gap control.
@@ -182,7 +202,6 @@ render BulmaPhlex::Grid.new(minimum_column_width: 16) do
182
202
  end
183
203
  ```
184
204
 
185
-
186
205
  ### Hero
187
206
 
188
207
  Renders a [Bulma hero](https://bulma.io/documentation/layout/hero/) section with support for color and size options.
@@ -199,7 +218,6 @@ render BulmaPhlex::Hero.new(color: "info", size: "large") do |hero|
199
218
  end
200
219
  ```
201
220
 
202
-
203
221
  ### Icon
204
222
 
205
223
  Renders a [Bulma icon](https://bulma.io/documentation/elements/icon/) element. Supports color, size, optional text alongside the icon, and left/right positioning for use inside form controls.
@@ -209,6 +227,21 @@ render BulmaPhlex::Icon.new("fas fa-user")
209
227
  render BulmaPhlex::Icon.new("fas fa-home", size: :large, color: :primary, text_right: "Home")
210
228
  ```
211
229
 
230
+ ### Image
231
+
232
+ Renders a [Bulma image](https://bulma.io/documentation/elements/image/) element. Supports size, ratio, rounded, and additional HTML attributes (on either the wrapping `figure` element or the `img` element).
233
+
234
+ ```ruby
235
+ render BulmaPhlex::Image.new(src: "image.jpg", size: 64)
236
+
237
+ render BulmaPhlex::Image.new(
238
+ src: "image.jpg",
239
+ alt: "An image",
240
+ rounded: true,
241
+ ratio: "16by9",
242
+ img_attributes: { class: "custom-img-class", id: "image-id" },
243
+ class: "custom-class", id: "figure-image-id")
244
+ ```
212
245
 
213
246
  ### Level
214
247
 
@@ -221,6 +254,26 @@ render BulmaPhlex::Level.new do |level|
221
254
  end
222
255
  ```
223
256
 
257
+ ### Media Object
258
+
259
+ Renders a [Bulma media object](https://bulma.io/documentation/layout/media-object/) with an optional left image/icon, right content, and main body content. Each section is populated via builder methods on the yielded component.
260
+
261
+ ```ruby
262
+ render BulmaPhlex::MediaObject.new do |media|
263
+ media.left { img(src: "/avatar.png", alt: "Avatar") }
264
+ media.content { "This is the main content of the media object." }
265
+ media.right { button(class: "button is-small") { "Action" } }
266
+ end
267
+ ```
268
+
269
+ If the left content is an image, method `image` can be used instead of `left` to automatically build the supporting HTML structure.
270
+
271
+ ```ruby
272
+ render BulmaPhlex::MediaObject.new do |media|
273
+ media.image(src: "/avatar.png", alt: "Avatar", size: 64, rounded: true)
274
+ media.content { "This is the main content of the media object." }
275
+ end
276
+ ```
224
277
 
225
278
  ### Message
226
279
 
@@ -232,7 +285,6 @@ render BulmaPhlex::Message.new("Hello World", color: "info", delete: true) do
232
285
  end
233
286
  ```
234
287
 
235
-
236
288
  ### Modal
237
289
 
238
290
  Renders a [Bulma modal](https://bulma.io/documentation/components/modal/) dialog overlay with a background, content area, and close button. Content is provided via a block.
@@ -248,7 +300,6 @@ end
248
300
 
249
301
  The modal is shown by adding the `is-active` class to the container — nothing in the component does this automatically. The default Stimulus controller (`bulma-phlex--modal`) handles open/close behavior. Pass a custom `data_attributes_builder:` to integrate with a different JavaScript setup.
250
302
 
251
-
252
303
  ### NavigationBar
253
304
 
254
305
  Renders a [Bulma navbar](https://bulma.io/documentation/components/navbar/) with support for branding, left/right nav links, and dropdown menus. Collapses automatically on mobile via the `bulma-phlex--navigation-bar` Stimulus controller (provided by the `bulma-phlex-rails` gem).
@@ -271,7 +322,6 @@ end
271
322
  > [!NOTE]
272
323
  > Setting `container: true` (or a constraint string like `"is-max-desktop"`) wraps the navbar content in a Bulma container for fixed-width layout. The navbar's background color still spans the full viewport width.
273
324
 
274
-
275
325
  ### Notification
276
326
 
277
327
  Renders a [Bulma notification](https://bulma.io/documentation/elements/notification/) alert box with support for color and mode options.
@@ -290,7 +340,6 @@ render BulmaPhlex::Notification.new(color: "warning", delete: { data: { action:
290
340
  end
291
341
  ```
292
342
 
293
-
294
343
  ### Pagination
295
344
 
296
345
  Renders the [Bulma pagination](https://bulma.io/documentation/components/pagination/) component with previous/next links, numbered page links, ellipses for skipped ranges, and an item count summary. Only renders when there is more than one page of results.
@@ -301,7 +350,6 @@ render BulmaPhlex::Pagination.new(@products, ->(page) { products_path(page: page
301
350
 
302
351
  The first argument must be a pager object responding to `current_page`, `total_pages`, `per_page`, `total_count`, `previous_page`, and `next_page`.
303
352
 
304
-
305
353
  ### Progress Bar
306
354
 
307
355
  Renders a [Bulma progress bar](https://bulma.io/documentation/elements/progress/) element. Supports color and size options.
@@ -312,7 +360,6 @@ render BulmaPhlex::ProgressBar.new(color: "success", size: "large", value: 75, m
312
360
 
313
361
  Omitting `value:` and `max:` produces an indeterminate (animated) progress bar.
314
362
 
315
-
316
363
  ### Table
317
364
 
318
365
  Renders a [Bulma table](https://bulma.io/documentation/elements/table/) for a collection of records. Columns are defined via builder methods on the yielded component.
@@ -338,7 +385,7 @@ To add pagination to the table, call `paginate` with a block that returns a path
338
385
  table.paginate { |page| products_path(page: page) }
339
386
  ```
340
387
 
341
- Pass HTML attributes to the `tr` elements via the `row` method, using either keyword arguments or a block
388
+ Pass HTML attributes to the `tr` elements via the `row` method, using either keyword arguments or a block
342
389
  that receives the record for the row:
343
390
 
344
391
  ```ruby
@@ -351,7 +398,6 @@ Hide columns on smaller screens with the column `hidden` option:
351
398
  table.column("Email", hidden: { mobile: true }) { |user| user.email }
352
399
  ```
353
400
 
354
-
355
401
  ### Tabs
356
402
 
357
403
  Renders a [Bulma tabs](https://bulma.io/documentation/components/tabs/) component with tabbed navigation and associated content panels. Supports alignment, size, and style options (boxed, toggle, rounded, fullwidth).
@@ -367,7 +413,6 @@ Tab switching is handled by the `bulma-phlex--tabs` Stimulus controller. The con
367
413
 
368
414
  An optional right-side element (e.g. a button) can be placed alongside the tab bar via `right_content`.
369
415
 
370
-
371
416
  ### Tag
372
417
 
373
418
  Renders the [Bulma tag](https://bulma.io/documentation/elements/tag/) component. Supports color, size, rounded, and an optional inline delete button.
@@ -379,7 +424,6 @@ render BulmaPhlex::Tag.new("Sale", light: "danger")
379
424
 
380
425
  The element type is inferred from the attributes: an `href:` produces an `<a>`, a `data-action` or `delete: true` produces a `<button>`, and otherwise a `<span>` is used.
381
426
 
382
-
383
427
  ### Title and Subtitle
384
428
 
385
429
  Renders a [Bulma title](https://bulma.io/documentation/elements/title/) with an optional subtitle. Supports sizes 1–6 for both elements and a `spaced:` option to increase the gap between them.
@@ -391,13 +435,12 @@ render BulmaPhlex::Title.new("Dr. Strangelove", size: 2, subtitle: "Or: How I Le
391
435
 
392
436
  When `size:` is set but `subtitle_size:` is not, the subtitle size defaults to `size + 2`.
393
437
 
394
-
395
438
  ## Upgrading to 0.8
396
439
 
397
440
  > [!IMPORTANT]
398
441
  > The 0.8.0 release includes breaking changes. The namespace for the components has been changed from `Components::Bulma` to `Components::BulmaPhlex`.
399
442
 
400
- This can generally be handled with a *Find-and-Replace*:
443
+ This can generally be handled with a _Find-and-Replace_:
401
444
 
402
445
  **Find:** `Bulma::`
403
446
  **Replace:** `BulmaPhlex::`
@@ -406,7 +449,6 @@ Note that this change was also applied to the expected Stimulus controllers. Ref
406
449
 
407
450
  Finally, the optional Rails extensions for the Card and Table components have been moved to the `bulma-phlex-rails` gem. If you are using this with Rails, you should use [the `bulma-phlex-rails` gem](https://github.com/RockSolt/bulma-phlex-rails). It provides both the component extensions as well as JavaScript for the Dropdown, Navigation Bar, and Tabs components.
408
451
 
409
-
410
452
  ## Development
411
453
 
412
454
  After checking out the repo, run `bundle install` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BulmaPhlex
4
+ # Renders a [Bulma breadcrumb](https://bulma.io/documentation/components/breadcrumb/) component.
5
+ # It supports options for **alignment** (centered, right-aligned), **separator** style (arrow,
6
+ # bullet, dot, or succeeds (greater than)), and **size** (small, medium, large).
7
+ class Breadcrumb < Base
8
+ # **Parameters**
9
+ #
10
+ # - `align` — Breadcrumb alignment: `"centered"` or `"right"`
11
+ # - `separator` — Breadcrumb separator style: `"arrow"`, `"bullet"`, `"dot"`, or `"succeeds"`
12
+ # - `size` — Alternate size: `"small"`, `"medium"`, or `"large"`
13
+ # - `**html_attributes` — Additional HTML attributes for the `<nav>` element
14
+ def self.new(align: nil, separator: nil, size: nil, **html_attributes)
15
+ super
16
+ end
17
+
18
+ def initialize(align: nil, separator: nil, size: nil, **html_attributes)
19
+ @align = align
20
+ @separator = separator
21
+ @size = size
22
+ @html_attributes = html_attributes
23
+
24
+ @items = []
25
+ end
26
+
27
+ def view_template(&)
28
+ vanish(&)
29
+ return if @items.empty?
30
+
31
+ nav(**mix(@html_attributes, class: nav_classes, aria: { label: "breadcrumbs" })) do
32
+ ul do
33
+ @items[0...-1].each do |item|
34
+ render_item(item)
35
+ end
36
+
37
+ render_last_item
38
+ end
39
+ end
40
+ end
41
+
42
+ # Adds a breadcrumb item to the component. The last item added will be rendered as the active item.
43
+ #
44
+ # **Parameters**
45
+ # - `label` (positional) — The text label for the breadcrumb item
46
+ # - `href` — URL for the breadcrumb item; not required on last item / current page
47
+ # - `icon` — Optional icon class for the breadcrumb item (e.g. `"fa-solid fa-home"`)
48
+ def item(label, href: nil, icon: nil)
49
+ @items << { label:, icon:, html_attributes: { href: href } }
50
+ end
51
+
52
+ private
53
+
54
+ def nav_classes
55
+ classes = ["breadcrumb"]
56
+ classes << "is-#{@align}" if @align
57
+ classes << "has-#{@separator}-separator" if @separator
58
+ classes << "is-#{@size}" if @size
59
+ classes
60
+ end
61
+
62
+ def render_item(item, list_item_attributes: {})
63
+ li(**list_item_attributes) do
64
+ a(**item[:html_attributes]) do
65
+ if item[:icon]
66
+ render BulmaPhlex::Icon.new(item[:icon], size: "small", icon_attributes: { aria: { hidden: "true" } })
67
+ span { item[:label] }
68
+ else
69
+ plain item[:label]
70
+ end
71
+ end
72
+ end
73
+ end
74
+
75
+ def render_last_item
76
+ item = @items.last
77
+
78
+ item[:html_attributes] = mix(item[:html_attributes], aria: { current: "page" })
79
+ render_item(item, list_item_attributes: { class: "is-active" })
80
+ end
81
+ end
82
+ end
@@ -3,7 +3,7 @@
3
3
  module BulmaPhlex
4
4
  # Renders a [Bulma card](https://bulma.io/documentation/components/card/) component.
5
5
  #
6
- # Supports an optional **header** (with title and custom classes), a **content** area, and a
6
+ # Supports an optional **header** (with title and custom classes), an **image**, a **content** area, and a
7
7
  # **footer** with one or more link items (which can include icons). Each section is populated
8
8
  # via builder methods on the yielded component.
9
9
  #
@@ -32,8 +32,9 @@ module BulmaPhlex
32
32
  def view_template(&)
33
33
  vanish(&)
34
34
 
35
- div(**mix(class: "card", **@html_attributes)) do
35
+ div(**mix({ class: "card" }, **@html_attributes)) do
36
36
  card_header
37
+ card_image
37
38
  card_content
38
39
  card_footer
39
40
  end
@@ -44,8 +45,28 @@ module BulmaPhlex
44
45
  # - `title` — The text to display in the card header
45
46
  # - `classes` — Optional additional CSS classes for the header element
46
47
  def head(title, classes: nil)
48
+ warn "[DEPRECATION] `BulmaPhlex::Card#head` is deprecated. Use `header` instead.", category: :deprecated
49
+
50
+ header(title, class: classes)
51
+ end
52
+
53
+ # in order to use the method name `header`, we need to grab a reference to the method on the base class
54
+ # so it is still available to us
55
+ alias html_header header
56
+
57
+ # Sets the card header. Pass in the title as a string and/or provide a block to render custom content
58
+ # in the header.
59
+ #
60
+ # - `title` — The text to display in the card header (optional)
61
+ # - `**html_attributes` — Additional HTML attributes for the header element (optional)
62
+ def header(title = nil, **html_attributes, &block)
47
63
  @header_title = title
48
- @header_classes = classes
64
+ @header_attributes = html_attributes
65
+ @header_content = block
66
+ end
67
+
68
+ def image(src:, alt: nil, size: nil, rounded: false)
69
+ @image = BulmaPhlex::Image.new(src:, alt:, size:, rounded:)
49
70
  end
50
71
 
51
72
  # Sets the card body content.
@@ -74,10 +95,19 @@ module BulmaPhlex
74
95
  private
75
96
 
76
97
  def card_header
77
- return if @header_title.nil?
98
+ return if @header_title.nil? && @header_content.nil?
99
+
100
+ html_header(**mix({ class: "card-header" }, @header_attributes)) do
101
+ p(class: "card-header-title") { plain @header_title } if @header_title
102
+ @header_content&.call
103
+ end
104
+ end
105
+
106
+ def card_image
107
+ return if @image.nil?
78
108
 
79
- header(class: "card-header #{@header_classes}") do
80
- p(class: "card-header-title") { plain @header_title }
109
+ div(class: "card-image") do
110
+ render @image
81
111
  end
82
112
  end
83
113
 
@@ -85,7 +115,7 @@ module BulmaPhlex
85
115
  return if @card_content.nil?
86
116
 
87
117
  div(class: "card-content") do
88
- div(class: "content") { @card_content.call }
118
+ @card_content.call
89
119
  end
90
120
  end
91
121
 
@@ -61,20 +61,28 @@ module BulmaPhlex
61
61
  end
62
62
  end
63
63
 
64
- def item(content = nil, &)
64
+ # Adds a non-clickable header item to the dropdown menu. Optionally add a divider before the header with
65
+ # the `divder: true` parameter.
66
+ def header(label, divider: false)
67
+ self.divider if divider
68
+ div(class: "dropdown-item has-text-weight-semibold is-unselectable") { label }
69
+ end
70
+
71
+ def item(content = nil, **html_attributes, &)
72
+ attributes = mix({ class: "dropdown-item" }, html_attributes)
65
73
  if block_given?
66
- div(class: "dropdown-item", &)
74
+ div(**attributes, &)
67
75
  else
68
- div(class: "dropdown-item") { content }
76
+ div(**attributes) { content }
69
77
  end
70
78
  end
71
79
 
72
- def link(label, path)
73
- a(class: "dropdown-item", href: path) { label }
80
+ def link(label, path, **html_attributes)
81
+ a(**mix({ class: "dropdown-item" }, html_attributes), href: path) { label }
74
82
  end
75
83
 
76
- def divider
77
- hr(class: "dropdown-divider")
84
+ def divider(**html_attributes)
85
+ hr(**mix({ class: "dropdown-divider" }, html_attributes))
78
86
  end
79
87
 
80
88
  private
@@ -5,7 +5,12 @@ module BulmaPhlex
5
5
  # form control positioning.
6
6
  #
7
7
  # Supports **color** and **size** options, optional **text** to the left or right of the icon,
8
- # and **positioning** helpers (`left`/`right`) for use inside form controls.
8
+ # and **positioning** helpers (`left`/`right`) for use inside form controls. When text is provide,
9
+ # the icon and text are wrapped in a container with the `icon-text` class for proper spacing, and
10
+ # the icon includes `aria-hidden="true"` for accessibility.
11
+ #
12
+ # Additional HTML attributes can be passed to the icon's `<span>` element via `**html_attributes`,
13
+ # and to the inner `<i>` by nested them under `icon_attributes`.
9
14
  #
10
15
  # ## Example
11
16
  #
@@ -21,7 +26,8 @@ module BulmaPhlex
21
26
  # - `text_left` — Text to display to the left of the icon
22
27
  # - `left` — If `true`, adds the `is-left` class for use in form controls
23
28
  # - `right` — If `true`, adds the `is-right` class for use in form controls
24
- # - `**html_attributes` — Additional HTML attributes for the icon span element
29
+ # - `**html_attributes` — Additional HTML attributes for the icon span element. Nest attributes under
30
+ # `icon_attributes` to apply them to the inner `<i>` element instead.
25
31
  def self.new(icon,
26
32
  text_right: nil,
27
33
  text_left: nil,
@@ -48,14 +54,15 @@ module BulmaPhlex
48
54
  @color = color
49
55
  @left = left
50
56
  @right = right
51
- @html_attributes = html_attributes
57
+ @html_attributes = html_attributes.clone
58
+ @icon_attributes = @html_attributes.delete(:icon_attributes) || {}
52
59
  end
53
60
 
54
61
  def view_template
55
62
  optional_text_wrapper do
56
63
  span { @text_left } if @text_left
57
64
  span(**mix({ class: icon_classes }, @html_attributes)) do
58
- i(class: @icon)
65
+ i(class: @icon, **@icon_attributes)
59
66
  end
60
67
  span { @text_right } if @text_right
61
68
  end
@@ -65,12 +72,17 @@ module BulmaPhlex
65
72
 
66
73
  def optional_text_wrapper(&)
67
74
  if @text_right || @text_left
75
+ add_aria_hidden_to_icon_attributes
68
76
  span(class: "icon-text", &)
69
77
  else
70
78
  yield
71
79
  end
72
80
  end
73
81
 
82
+ def add_aria_hidden_to_icon_attributes
83
+ @icon_attributes = mix({ aria: { hidden: "true" } }, @icon_attributes)
84
+ end
85
+
74
86
  def icon_classes
75
87
  classes = ["icon"]
76
88
  classes << "is-#{@size}" if @size
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BulmaPhlex
4
+ # Renders a [Bulma image](https://bulma.io/documentation/elements/image/) component.
5
+ class Image < BulmaPhlex::Base
6
+ # **Parameters**
7
+ #
8
+ # - `src:` — The image source URL (required)
9
+ # - `alt:` — The image alt text (optional)
10
+ # - `rounded:` — Whether to apply the `is-rounded` class (optional, default: false)
11
+ # - `size:` — The image size (optional, e.g., 64 for `is-64x64`)
12
+ # - `ratio:` — The image ratio (optional, e.g., "1by1", "4by3", "16by9")
13
+ # - `img_attributes:` — Additional HTML attributes for the img element (optional)
14
+ # - `**html_attributes` — Additional HTML attributes for the figure element (optional)
15
+ def self.new(src:, alt: nil, rounded: false, size: nil, ratio: nil, img_attributes: {}, **html_attributes)
16
+ super
17
+ end
18
+
19
+ def initialize(src:, alt: nil, rounded: false, size: nil, ratio: nil, img_attributes: {}, **html_attributes)
20
+ @src = src
21
+ @alt = alt
22
+ @rounded = rounded
23
+ @size = size
24
+ @ratio = ratio
25
+ @img_attributes = img_attributes
26
+ @html_attributes = html_attributes
27
+ end
28
+
29
+ def view_template
30
+ figure(**mix({ class: figure_classes }, @html_attributes)) do
31
+ img(**mix({ src: @src, alt: @alt, class: img_classes }, @img_attributes))
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def figure_classes
38
+ classes = ["image"]
39
+ classes << "is-#{@size}x#{@size}" if @size
40
+ classes << "is-#{@ratio}" if @ratio
41
+ classes.join(" ")
42
+ end
43
+
44
+ def img_classes
45
+ "is-rounded" if @rounded
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BulmaPhlex
4
+ # Renders a [Bulma media object](https://bulma.io/documentation/components/media-object/) component.
5
+ #
6
+ # Optional HTML attributes can be passed to the constructor as well as any of the three block methods,
7
+ # `left`, `content`, and `right`, to customize the rendered HTML elements.
8
+ #
9
+ # ## Example
10
+ #
11
+ # render BulmaPhlex::MediaObject.new do |media|
12
+ # media.left do
13
+ # p(class: "image is-64x64") do
14
+ # img(src: "/assets/images/placeholders/128x128.png")
15
+ # end
16
+ # end
17
+ #
18
+ # media.content do
19
+ # p { "This is the main content of the media object." }
20
+ # end
21
+ #
22
+ # media.right do
23
+ # button(class: "delete")
24
+ # end
25
+ # end
26
+ class MediaObject < BulmaPhlex::Base
27
+ # **Parameters**
28
+ #
29
+ # - `**html_attributes` — Additional HTML attributes for the wrapping `article` element
30
+ def self.new(**html_attributes)
31
+ super
32
+ end
33
+
34
+ def initialize(**html_attributes)
35
+ @html_attributes = html_attributes
36
+ end
37
+
38
+ def view_template(&)
39
+ vanish(&)
40
+
41
+ article(**mix({ class: "media" }, @html_attributes)) do
42
+ render_media_left if @media_left
43
+ render_media_content if @media_content
44
+ render_media_right if @media_right
45
+ end
46
+ end
47
+
48
+ # Use a block to provide the left content, which will be wrapped in a `figure` element. Additional
49
+ # HTML attributes can be passed to customize the element.
50
+ #
51
+ # <figure class="media-left">
52
+ # <!-- Left content goes here -->
53
+ # </figure>
54
+ def left(**html_attributes, &block)
55
+ @left_attributes = html_attributes
56
+ @media_left = block
57
+ end
58
+
59
+ # If the left content is an image, you can use this method to provide the image source,
60
+ # alt text, size, and whether it should be rounded. Additional HTML attributes can be
61
+ # passed to customize the `figure` element.
62
+ def image(src:, alt: nil, size: nil, rounded: false, **html_attributes)
63
+ left(**html_attributes) do
64
+ p(class: image_classes(size:)) do
65
+ img(src:, alt:, class: ("is-rounded" if rounded))
66
+ end
67
+ end
68
+ end
69
+
70
+ # Use a block to provide the main content, which will be wrapped in a `div` element. Additional
71
+ # HTML attributes can be passed to customize the element.
72
+ #
73
+ # <div class="media-content">
74
+ # <!-- Main content goes here -->
75
+ # </div>
76
+ def content(**html_attributes, &block)
77
+ @content_attributes = html_attributes
78
+ @media_content = block
79
+ end
80
+
81
+ # Use a block to provide the right content, which will be wrapped in a `div` element. Additional
82
+ # HTML attributes can be passed to customize the element.
83
+ #
84
+ # <div class="media-right">
85
+ # <!-- Right content goes here -->
86
+ # </div>
87
+ def right(**html_attributes, &block)
88
+ @right_attributes = html_attributes
89
+ @media_right = block
90
+ end
91
+
92
+ private
93
+
94
+ def render_media_left
95
+ figure(**mix({ class: "media-left" }, @left_attributes)) do
96
+ @media_left.call
97
+ end
98
+ end
99
+
100
+ def render_media_content
101
+ div(**mix({ class: "media-content" }, @content_attributes)) do
102
+ @media_content.call
103
+ end
104
+ end
105
+
106
+ def render_media_right
107
+ div(**mix({ class: "media-right" }, @right_attributes)) do
108
+ @media_right.call
109
+ end
110
+ end
111
+
112
+ def image_classes(size:)
113
+ classes = ["image"]
114
+ classes << "is-#{size}x#{size}" if size
115
+ classes.join(" ")
116
+ end
117
+ end
118
+ end
@@ -26,8 +26,11 @@ module BulmaPhlex
26
26
  div(class: "navbar-dropdown is-right", &)
27
27
  end
28
28
 
29
- def header(label)
30
- div(class: "navbar-item header has-text-weight-medium") { label }
29
+ # Adds a non-clickable header item to the dropdown menu. Optionally add a divider before the header with
30
+ # the `divder: true` parameter.
31
+ def header(label, divider: false)
32
+ self.divider if divider
33
+ div(class: "navbar-item has-text-weight-semibold") { label }
31
34
  end
32
35
 
33
36
  def item(label, path)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module BulmaPhlex
4
- VERSION = "0.15.0"
4
+ VERSION = "0.17.0"
5
5
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bulma-phlex
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.0
4
+ version: 0.17.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Todd Kummer
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2026-04-16 00:00:00.000000000 Z
10
+ date: 2026-07-21 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: phlex
@@ -65,6 +65,7 @@ files:
65
65
  - lib/bulma-phlex.rb
66
66
  - lib/bulma_phlex.rb
67
67
  - lib/bulma_phlex/base.rb
68
+ - lib/bulma_phlex/breadcrumb.rb
68
69
  - lib/bulma_phlex/button.rb
69
70
  - lib/bulma_phlex/card.rb
70
71
  - lib/bulma_phlex/columns.rb
@@ -75,7 +76,9 @@ files:
75
76
  - lib/bulma_phlex/grid.rb
76
77
  - lib/bulma_phlex/hero.rb
77
78
  - lib/bulma_phlex/icon.rb
79
+ - lib/bulma_phlex/image.rb
78
80
  - lib/bulma_phlex/level.rb
81
+ - lib/bulma_phlex/media_object.rb
79
82
  - lib/bulma_phlex/message.rb
80
83
  - lib/bulma_phlex/modal.rb
81
84
  - lib/bulma_phlex/navigation_bar.rb