bulma-phlex 0.13.0 → 0.15.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: f8f0cd18b60707a8603252208e2cf70b04e4e8afb43a4c2a62e1c06a0b4e484c
4
- data.tar.gz: d89f7b184d4efb444474b4a1ee59c72beaea257a6d3bc1ad1018ddc9ae1a4c87
3
+ metadata.gz: 8a1d3209d836363da07529fa00c9374618623280e70f3167c409e320b77dd4c4
4
+ data.tar.gz: e078ae57978d967610194b989078d484ad2297d4cdd71b0ae2d65b07d80dc105
5
5
  SHA512:
6
- metadata.gz: 56477bb7d2f9704ad2acdb404d9db20edff939ceb58e942fb90ce7fd4d37696c16bf071f3583b357cbf09d0e9d36859178d32c07242cb24d462814e87712caba
7
- data.tar.gz: 62cf166607ea1826c403d7bb940f020ac3b71ef792ee8ff15a65f61ac9f4787713fe4aed3023cb76229002a0add42c161f20147a3001494c180da05e153d8700
6
+ metadata.gz: c7c0d1e8bbfb69e58e78af757f14b4dde6ab532f085e7ea970cb1addd511f2c5c33ba964df7b80dcfdac878f4475108858ceace18f3e5b52356d3b9b3d7df521
7
+ data.tar.gz: c41d7a84d0a5e5c2c03aafd7ff74764af2e94221c051aa67766815d46805cd153829deb87173b7d73285fcfaf9752433412070effb7755fced7d3e45df388912
data/README.md CHANGED
@@ -20,6 +20,7 @@ This gem provides a set of ready-to-use [Phlex](https://github.com/phlex-ruby/ph
20
20
  - [Hero](#hero)
21
21
  - [Icon](#icon)
22
22
  - [Level](#level)
23
+ - [Message](#message)
23
24
  - [Modal](#modal)
24
25
  - [NavigationBar](#navigationbar)
25
26
  - [Notification](#notification)
@@ -58,7 +59,7 @@ gem install bulma-phlex
58
59
 
59
60
  This gem requires:
60
61
 
61
- - Ruby 3.2.10 or higher
62
+ - Ruby 3.3 or higher
62
63
  - Phlex 2.4.1 or higher
63
64
  - Bulma CSS (which you'll need to include in your application)
64
65
 
@@ -84,11 +85,12 @@ Renders a [Bulma button](https://bulma.io/documentation/elements/button/) elemen
84
85
  The component generates a `<button>` by default. Pass an `href:` attribute to generate an `<a>` element instead. Pass `input: "submit"` (or `"button"` or `"reset"`) to generate an `<input>` element.
85
86
 
86
87
  ```ruby
87
- BulmaPhlex::Button(color: "primary", size: "large", icon: "fas fa-thumbs-up") { "Like" }
88
+ BulmaPhlex::Button("Like", color: "primary", size: "large", icon: "fas fa-thumbs-up")
88
89
  BulmaPhlex::Button(href: "/profile") { "View Profile" }
89
90
  BulmaPhlex::Button(input: "submit", color: "success")
90
91
  ```
91
92
 
93
+ The button label can be passed in as a string or in a block.
92
94
 
93
95
  ### Card
94
96
 
@@ -105,6 +107,9 @@ render BulmaPhlex::Card.new do |card|
105
107
  end
106
108
  ```
107
109
 
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.
112
+
108
113
 
109
114
  ### Columns
110
115
 
@@ -157,7 +162,7 @@ Renders a [Bulma form field](https://bulma.io/documentation/form/general/#form-f
157
162
 
158
163
  ```ruby
159
164
  render BulmaPhlex::FormField.new(help: "We'll never share your email.") do |field|
160
- field.label("Email Address")
165
+ field.label("Email Address", for: "user_email_address")
161
166
  field.control { input(name: "user[email_address]", type: "email") }
162
167
  end
163
168
  ```
@@ -217,6 +222,17 @@ end
217
222
  ```
218
223
 
219
224
 
225
+ ### Message
226
+
227
+ Renders a [Bulma message](https://bulma.io/documentation/components/message/) component with a header, optional delete button, and body.
228
+
229
+ ```ruby
230
+ render BulmaPhlex::Message.new("Hello World", color: "info", delete: true) do
231
+ "Look, it's a deletable message box!"
232
+ end
233
+ ```
234
+
235
+
220
236
  ### Modal
221
237
 
222
238
  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.
@@ -322,6 +338,19 @@ To add pagination to the table, call `paginate` with a block that returns a path
322
338
  table.paginate { |page| products_path(page: page) }
323
339
  ```
324
340
 
341
+ Pass HTML attributes to the `tr` elements via the `row` method, using either keyword arguments or a block
342
+ that receives the record for the row:
343
+
344
+ ```ruby
345
+ table.row(class: "custom-row-class") { |row| { id: "row-id-#{row.id}" } }
346
+ ```
347
+
348
+ Hide columns on smaller screens with the column `hidden` option:
349
+
350
+ ```ruby
351
+ table.column("Email", hidden: { mobile: true }) { |user| user.email }
352
+ ```
353
+
325
354
 
326
355
  ### Tabs
327
356
 
@@ -402,4 +431,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
402
431
 
403
432
  ## Credits
404
433
 
405
- This leverages the [Bulma CSS library](https://bulma.io/documentation/) and [Phlex](https://www.phlex.fun/) but is not endorsed or certified by either. We are fans of both and this makes using them together easier.
434
+ This leverages the [Bulma CSS library](https://bulma.io/documentation/) and [Phlex](https://www.phlex.fun/) but is not endorsed or certified by either. We are fans of both and this makes using them together easier.
@@ -7,6 +7,8 @@ module BulmaPhlex
7
7
  # arguments provided. Supports Bulma options for **color**, **size**, **style mode**,
8
8
  # and **layout** (responsive, fullwidth, outlined, inverted, rounded), as well as
9
9
  # optional **icons** on the left and/or right side of the label.
10
+ #
11
+ # The label can be passed into the component as a string or from a block.
10
12
  class Button < Base
11
13
  # Returns an array of CSS classes for the button based on the provided options.
12
14
  def self.classes_for(color: nil, # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
@@ -31,6 +33,7 @@ module BulmaPhlex
31
33
 
32
34
  # **Parameters**
33
35
  #
36
+ # - `label` (positional) — Optionally pass in button label as a string
34
37
  # - `color` — Button color: `"primary"`, `"link"`, `"info"`, `"success"`, `"warning"`, `"danger"`
35
38
  # - `mode` — Button style mode: `"light"` or `"dark"`
36
39
  # - `size` — Button size: `"small"`, `"normal"`, `"medium"`, `"large"`
@@ -44,7 +47,8 @@ module BulmaPhlex
44
47
  # - `icon_right` — Icon class added to the right of the button text
45
48
  # - `input` — If set, renders an `<input>` element of this type (`"button"`, `"reset"`, `"submit"`)
46
49
  # - `**html_attributes` — Additional HTML attributes for the button element
47
- def self.new(color: nil,
50
+ def self.new(label = nil,
51
+ color: nil,
48
52
  mode: nil,
49
53
  size: nil,
50
54
  responsive: false,
@@ -60,7 +64,8 @@ module BulmaPhlex
60
64
  super
61
65
  end
62
66
 
63
- def initialize(color: nil,
67
+ def initialize(label = nil,
68
+ color: nil,
64
69
  mode: nil,
65
70
  size: nil,
66
71
  responsive: false,
@@ -73,6 +78,7 @@ module BulmaPhlex
73
78
  icon_right: nil,
74
79
  input: nil,
75
80
  **html_attributes)
81
+ @label = label
76
82
  @classes = self.class.classes_for(color:, mode:, size:, responsive:, fullwidth:, outlined:, inverted:, rounded:)
77
83
  @input = input
78
84
  @icon_left = icon || icon_left
@@ -81,6 +87,8 @@ module BulmaPhlex
81
87
  end
82
88
 
83
89
  def view_template(&)
90
+ block_content = capture(&)
91
+
84
92
  options = mix({ class: @classes }, @html_attributes)
85
93
 
86
94
  if @input
@@ -89,10 +97,23 @@ module BulmaPhlex
89
97
  element_type = @html_attributes.key?(:href) ? :a : :button
90
98
  tag(element_type, **options) do
91
99
  Icon(@icon_left) if @icon_left
92
- yield if block_given?
100
+ button_label(block_content)
93
101
  Icon(@icon_right) if @icon_right
94
102
  end
95
103
  end
96
104
  end
105
+
106
+ private
107
+
108
+ def button_label(block_content)
109
+ value = @label || block_content
110
+ return if value.nil? || value.empty?
111
+
112
+ if @icon_left || @icon_right
113
+ span { value }
114
+ else
115
+ plain value
116
+ end
117
+ end
97
118
  end
98
119
  end
@@ -65,6 +65,12 @@ module BulmaPhlex
65
65
  (@footer_items ||= []) << [text, href, html_attributes]
66
66
  end
67
67
 
68
+ # Delegates full control of the footer item to the block. The top element in the block must include
69
+ # the `card-footer-item` class.
70
+ def footer_item(&block)
71
+ (@footer_items ||= []) << block
72
+ end
73
+
68
74
  private
69
75
 
70
76
  def card_header
@@ -87,20 +93,28 @@ module BulmaPhlex
87
93
  return if @footer_items.nil? || @footer_items.empty?
88
94
 
89
95
  footer(class: "card-footer") do
90
- @footer_items.each do |text, href, html_attributes|
91
- icon = html_attributes.delete(:icon)
92
- html_attributes[:class] = [html_attributes[:class], "card-footer-item"].compact.join(" ")
93
- a(href:, **html_attributes) do
94
- if icon.present?
95
- icon_text(icon, text)
96
- else
97
- plain text
98
- end
96
+ @footer_items.each do |block_or_text, href, html_attributes|
97
+ if block_or_text.is_a?(Proc)
98
+ block_or_text.call
99
+ else
100
+ render_footer_link(block_or_text, href, html_attributes)
99
101
  end
100
102
  end
101
103
  end
102
104
  end
103
105
 
106
+ def render_footer_link(text, href, html_attributes)
107
+ icon = html_attributes.delete(:icon)
108
+ html_attributes[:class] = [html_attributes[:class], "card-footer-item"].compact.join(" ")
109
+ a(href:, **html_attributes) do
110
+ if icon.nil?
111
+ plain text
112
+ else
113
+ icon_text(icon, text)
114
+ end
115
+ end
116
+ end
117
+
104
118
  def icon_text(icon, text)
105
119
  span(class: "icon-text") do
106
120
  span(class: "icon") { i(class: icon) }
@@ -9,6 +9,8 @@ module BulmaPhlex
9
9
  # integrating with Bulma's column and grid systems. The form control content is set via the
10
10
  # `control` method (or a block passed directly to the component).
11
11
  #
12
+ # If the label is passes as a string argument, the any additional html attributes can also be included as arguments.
13
+ #
12
14
  # ## References
13
15
  #
14
16
  # - [Bulma Form Field](https://bulma.io/documentation/form/general/#form-field)
@@ -46,8 +48,9 @@ module BulmaPhlex
46
48
  #
47
49
  # Optionally expects a block that renders a custom label (e.g. with a link or icon inside).
48
50
  # Only one of `label_string` or a block should be provided.
49
- def label(label_string = nil, &block)
51
+ def label(label_string = nil, **html_attributes, &block)
50
52
  @label_string = label_string
53
+ @label_attributes = html_attributes
51
54
  @label_builder = block
52
55
  end
53
56
 
@@ -103,7 +106,7 @@ module BulmaPhlex
103
106
 
104
107
  def render_label
105
108
  if @label_string
106
- html_label(class: "label") { @label_string }
109
+ html_label(**mix({ class: "label" }, **@label_attributes)) { @label_string }
107
110
  elsif @label_builder
108
111
  raw @label_builder&.call
109
112
  end
@@ -3,9 +3,16 @@
3
3
  module BulmaPhlex
4
4
  # Renders a [Bulma Hero](https://bulma.io/documentation/layout/hero/) component.
5
5
  #
6
- # Supports **color** and **size** options. Content can be provided as a title/subtitle pair,
7
- # a single block for the body, or by calling `head`, `body`, and `foot` on the yielded
8
- # component to define each section independently.
6
+ # Supports **color** and **size** options. There are three ways to provide content:
7
+ #
8
+ # 1. **Title/subtitle params** — pass `title:` and/or `subtitle:` to the constructor; no block needed.
9
+ # 2. **Direct body block** — pass a block to `render`; call Phlex HTML methods on the yielded
10
+ # component and they are rendered inside the `hero-body` div.
11
+ # 3. **Building blocks** — call `head`, `body`, and `foot` on the yielded component to
12
+ # populate each of Bulma's three hero regions independently:
13
+ # - `hero-head` — typically a navbar or branding bar
14
+ # - `hero-body` — main content area
15
+ # - `hero-foot` — bottom tabs or action bar
9
16
  class Hero < BulmaPhlex::Base
10
17
  # **Parameters**
11
18
  #
@@ -42,16 +49,16 @@ module BulmaPhlex
42
49
  output = capture(&)
43
50
 
44
51
  section(**mix({ class: hero_classes }, @html_attributes)) do
45
- if @body.present?
46
- building_blocks(&)
47
- else
52
+ if @body.nil?
48
53
  div(class: "hero-body") do
49
- if output.present?
50
- output
51
- else
54
+ if output.empty?
52
55
  title_and_subtitle
56
+ else
57
+ raw safe(output)
53
58
  end
54
59
  end
60
+ else
61
+ building_blocks(&)
55
62
  end
56
63
  end
57
64
  end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BulmaPhlex
4
+ # Renders a [Bulma message](https://bulma.io/documentation/components/message/) component with a
5
+ # header, optional delete button, and body.
6
+ #
7
+ # The component generates an `article` element and supports color and size options, as well as any
8
+ # additional html attributes.
9
+ class Message < BulmaPhlex::Base
10
+ # **Parameters**
11
+ #
12
+ # - `header_text` (positional, optional) — If not provided, the header will be skipped
13
+ # - `delete` — If `true`, includes a delete button to dismiss the message. Can also be a hash of HTML
14
+ # attributes for the button
15
+ # - `color` — Color of the notification (e.g. `"primary"`, `"info"`, `"danger"`)
16
+ # - `size` — `"small"`, `"normal"` (the default), `"medium"` or `"large"`
17
+ # - `**html_attributes` — Additional HTML attributes for the notification element
18
+ def self.new(header_text = nil, delete: nil, color: nil, size: nil, **html_attributes)
19
+ super
20
+ end
21
+
22
+ def initialize(header_text = nil, delete: nil, color: nil, size: nil, **html_attributes)
23
+ @header_text = header_text
24
+ @delete = delete
25
+ @color = color
26
+ @size = size
27
+ @html_attributes = html_attributes
28
+ after_initialize
29
+ end
30
+
31
+ def view_template(&)
32
+ vanish(&)
33
+
34
+ article(**mix({ class: message_classes }, **@html_attributes)) do
35
+ message_header unless @header_text.nil?
36
+ message_body(&)
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ # allows for easy customization
43
+ def after_initialize; end
44
+
45
+ def message_classes
46
+ classes = ["message"]
47
+ classes << "is-#{@color}" unless @color.nil?
48
+ classes << "is-#{@size}" if !@size.nil? && @size.to_s != "normal"
49
+ classes.join(" ")
50
+ end
51
+
52
+ def message_header
53
+ div(class: "message-header") do
54
+ p { @header_text }
55
+ delete_button if @delete
56
+ end
57
+ end
58
+
59
+ def delete_button
60
+ button_attributes = { class: "delete", aria_label: "delete" }
61
+ button_attributes = mix(button_attributes, @delete) if @delete.is_a?(Hash)
62
+ button(**button_attributes)
63
+ end
64
+
65
+ def message_body(&)
66
+ div(class: "message-body", &)
67
+ end
68
+ end
69
+ end
@@ -14,15 +14,17 @@ module BulmaPhlex
14
14
  # - `color` — Color of the notification (e.g. `"primary"`, `"info"`, `"danger"`)
15
15
  # - `mode` — Style mode: `"light"` or `"dark"`
16
16
  # - `**html_attributes` — Additional HTML attributes for the notification element
17
- def self.new(delete: false, color: nil, mode: nil, **html_attributes)
17
+ def self.new(delete: nil, color: nil, mode: nil, **html_attributes)
18
18
  super
19
19
  end
20
20
 
21
- def initialize(delete: false, color: nil, mode: nil, **html_attributes)
21
+ def initialize(delete: nil, color: nil, mode: nil, **html_attributes)
22
22
  @delete = delete
23
23
  @color = color
24
24
  @mode = mode
25
25
  @html_attributes = html_attributes
26
+
27
+ after_initialize
26
28
  end
27
29
 
28
30
  def view_template(&)
@@ -36,10 +38,13 @@ module BulmaPhlex
36
38
 
37
39
  private
38
40
 
41
+ # allows for easy customization
42
+ def after_initialize; end
43
+
39
44
  def notification_classes
40
45
  classes = ["notification"]
41
- classes << "is-#{@color}" if @color.present?
42
- classes << "is-#{@mode}" if @mode.present?
46
+ classes << "is-#{@color}" unless @color.nil?
47
+ classes << "is-#{@mode}" unless @mode.nil?
43
48
  classes.join(" ")
44
49
  end
45
50
 
@@ -8,24 +8,42 @@ module BulmaPhlex
8
8
  # (bordered, striped, hoverable) and **layout** options (narrow, fullwidth). An optional
9
9
  # **pagination** control can be added to the table footer via the `paginate` method.
10
10
  #
11
+ # The `tr` elements can be customized with the `row` method, which accepts static HTML attributes
12
+ # and/or a block that generates dynamic attributes based on the row data.
13
+ #
14
+ # To make the table responsive, use the `hidden` argument to hide certain columns on smaller
15
+ # screens. See the [Bulma documentation](https://bulma.io/documentation/helpers/visibility-helpers/#hide)
16
+ # for the full list, but the most common options are `hidden: "mobile"` and `hidden: "touch"`.
17
+ #
18
+ # The table supports any additional HTML attributes on the `<table>` element, such as `id` or `data-*`
19
+ # attributes, via the `**html_attributes` argument in the constructor.
20
+ #
11
21
  # ## Example
12
22
  #
13
23
  # users = User.all
14
24
  #
15
25
  # render BulmaPhlex::Table.new(users) do |table|
16
- # table.column "Name" do |user|
17
- # user.full_name
18
- # end
19
- #
20
- # table.column "Email" do |user|
21
- # user.email
22
- # end
23
- #
26
+ # table.row(class: "has-background-light") { |user| { id: "user-row-#{user.id}" } }
27
+ # table.column("Name", &:full_name)
28
+ # table.column("Email", hidden: "touch", &:email)
29
+ # table.date_column("Joined", hidden: "mobile", &:created_at, format: "%B %d, %Y")
30
+ # table.conditional_icon("Admin?", &:admin?)
24
31
  # table.column "Actions" do |user|
25
32
  # link_to "Edit", edit_user_path(user), class: "button is-small"
26
33
  # end
27
34
  # end
28
- class Table < BulmaPhlex::Base
35
+ class Table < BulmaPhlex::Base # rubocop:disable Metrics/ClassLength
36
+ # Returns an array of CSS classes for the table based on the provided options.
37
+ def self.classes_for(bordered: false, striped: false, narrow: false, hoverable: false, fullwidth: false)
38
+ classes = ["table"]
39
+ classes << "is-bordered" if bordered
40
+ classes << "is-striped" if striped
41
+ classes << "is-narrow" if narrow
42
+ classes << "is-hoverable" if hoverable
43
+ classes << "is-fullwidth" if fullwidth
44
+ classes
45
+ end
46
+
29
47
  # **Parameters**
30
48
  #
31
49
  # - `rows` — The collection of records to display in the table
@@ -53,11 +71,7 @@ module BulmaPhlex
53
71
  fullwidth: false,
54
72
  **html_attributes)
55
73
  @rows = rows
56
- @bordered = bordered
57
- @striped = striped
58
- @narrow = narrow
59
- @hoverable = hoverable
60
- @fullwidth = fullwidth
74
+ @table_classes = self.class.classes_for(bordered:, striped:, narrow:, hoverable:, fullwidth:)
61
75
  @html_attributes = html_attributes
62
76
  @columns = []
63
77
  end
@@ -65,19 +79,15 @@ module BulmaPhlex
65
79
  def view_template(&)
66
80
  vanish(&)
67
81
 
68
- table(**mix({ class: table_classes }, @html_attributes)) do
82
+ table(**mix({ class: @table_classes }, @html_attributes)) do
69
83
  thead do
70
- @columns.each do |column|
71
- table_header(column)
72
- end
84
+ @columns.each { |column| table_header(column) }
73
85
  end
74
86
 
75
87
  tbody do
76
88
  @rows.each do |row|
77
- tr do
78
- @columns.each do |column|
79
- td(**column[:html_attributes]) { column[:content].call(row) }
80
- end
89
+ tr(**table_row_html_attributes(row)) do
90
+ @columns.each { |column| table_data_cell(column, row) }
81
91
  end
82
92
  end
83
93
  end
@@ -86,14 +96,19 @@ module BulmaPhlex
86
96
  end
87
97
  end
88
98
 
99
+ def row(**html_attributes, &attribute_builder)
100
+ @row_attributes = html_attributes
101
+ @row_attribute_builder = attribute_builder
102
+ end
103
+
89
104
  # Adds a column to the table. Can be called multiple times to define all columns.
90
105
  #
91
106
  # - `header` — The column header text
92
107
  # - `**html_attributes` — Additional HTML attributes for each `<td>` cell in this column
93
108
  #
94
109
  # Expects a block that receives each `row` object and returns the cell content.
95
- def column(header, **html_attributes, &content)
96
- @columns << { header:, html_attributes:, content: }
110
+ def column(header, hidden: false, **html_attributes, &content)
111
+ @columns << { header:, hidden:, html_attributes:, content: }
97
112
  end
98
113
 
99
114
  # Adds a date-formatted column to the table. Can be called multiple times.
@@ -103,8 +118,8 @@ module BulmaPhlex
103
118
  # - `**html_attributes` — Additional HTML attributes for each `<td>` cell in this column
104
119
  #
105
120
  # Expects a block that receives each `row` object and returns a `Date` or `Time` value.
106
- def date_column(header, format: "%Y-%m-%d", **html_attributes, &content)
107
- column(header, **html_attributes) do |row|
121
+ def date_column(header, hidden: false, format: "%Y-%m-%d", **html_attributes, &content)
122
+ column(header, hidden:, **html_attributes) do |row|
108
123
  content.call(row)&.strftime(format)
109
124
  end
110
125
  end
@@ -116,10 +131,10 @@ module BulmaPhlex
116
131
  # - `**html_attributes` — Additional HTML attributes for each `<td>` cell in this column
117
132
  #
118
133
  # Expects a block that receives each `row` object and returns a truthy or falsy value.
119
- def conditional_icon(header, icon_class: "fas fa-check", **html_attributes, &content)
134
+ def conditional_icon(header, hidden: false, icon_class: "fas fa-check", **html_attributes, &content)
120
135
  html_attributes[:class] = [html_attributes[:class], "has-text-centered"].compact.join(" ")
121
136
 
122
- column(header, **html_attributes) do |row|
137
+ column(header, hidden:, **html_attributes) do |row|
123
138
  Icon(icon_class) if content.call(row)
124
139
  end
125
140
  end
@@ -134,35 +149,49 @@ module BulmaPhlex
134
149
 
135
150
  private
136
151
 
137
- def table_classes
138
- classes = ["table"]
139
- classes << "is-bordered" if @bordered
140
- classes << "is-striped" if @striped
141
- classes << "is-narrow" if @narrow
142
- classes << "is-hoverable" if @hoverable
143
- classes << "is-fullwidth" if @fullwidth
144
- classes
152
+ def table_header(column)
153
+ th(class: header_classes(column)) { column[:header] }
145
154
  end
146
155
 
147
- # this derives a th class from the column html attributes
148
- # perhaps a better way would be pre-defined pairs?
149
- def table_header(column)
150
- attributes = {}
151
- attributes[:class] = header_alignment(column[:html_attributes])
152
- th(**attributes) { column[:header] }
156
+ def header_classes(column)
157
+ classes = []
158
+ classes << "is-hidden-#{column[:hidden]}" if column[:hidden]
159
+ classes << header_alignment(column[:html_attributes])
160
+ classes.compact
153
161
  end
154
162
 
155
163
  def header_alignment(html_attributes)
156
164
  classes = html_attributes[:class]
157
165
  return if classes.nil?
158
166
 
159
- if classes&.include?("has-text-right") || classes&.include?("amount-display")
167
+ if classes.include?("has-text-right") || classes.include?("amount-display")
160
168
  "has-text-right"
161
- elsif classes&.include?("has-text-centered")
169
+ elsif classes.include?("has-text-centered")
162
170
  "has-text-centered"
163
171
  end
164
172
  end
165
173
 
174
+ def table_row_html_attributes(row)
175
+ attributes = @row_attributes || {}
176
+ if @row_attribute_builder
177
+ dynamic_attributes = @row_attribute_builder.call(row) || {}
178
+ attributes = attributes.merge(dynamic_attributes)
179
+ end
180
+ attributes
181
+ end
182
+
183
+ def table_data_cell(column, row)
184
+ td(**mix({ class: cell_classes(column) }, column[:html_attributes])) do
185
+ column[:content].call(row)
186
+ end
187
+ end
188
+
189
+ def cell_classes(column)
190
+ return unless column[:hidden]
191
+
192
+ "is-hidden-#{column[:hidden]}"
193
+ end
194
+
166
195
  def pagination
167
196
  return unless @path_builder
168
197
 
@@ -32,7 +32,7 @@ module BulmaPhlex
32
32
  def view_template
33
33
  if @html_attributes.key?(:href)
34
34
  a(class: tag_classes, **@html_attributes) { text_and_optional_delete_button }
35
- elsif @options[:delete] || @html_attributes.dig(:data, :action).present?
35
+ elsif @options[:delete] || !@html_attributes.dig(:data, :action).nil?
36
36
  button(class: tag_classes, **@html_attributes) { text_and_optional_delete_button }
37
37
  else
38
38
  span(class: tag_classes, **@html_attributes) { plain @text }
@@ -51,9 +51,9 @@ module BulmaPhlex
51
51
 
52
52
  def tag_classes
53
53
  classes = ["tag"]
54
- classes << "is-#{@options[:color]}" if @options[:color].present?
54
+ classes << "is-#{@options[:color]}" unless @options[:color].nil?
55
55
  classes << "is-#{@options[:light]} is-light" if @options[:light]
56
- classes << "is-#{@options[:size]}" if @options[:size].present?
56
+ classes << "is-#{@options[:size]}" unless @options[:size].nil?
57
57
  classes << "is-rounded" if @options[:rounded]
58
58
  classes.join(" ")
59
59
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module BulmaPhlex
4
- VERSION = "0.13.0"
4
+ VERSION = "0.15.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.13.0
4
+ version: 0.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Todd Kummer
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2026-03-09 00:00:00.000000000 Z
10
+ date: 2026-04-16 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: phlex
@@ -76,6 +76,7 @@ files:
76
76
  - lib/bulma_phlex/hero.rb
77
77
  - lib/bulma_phlex/icon.rb
78
78
  - lib/bulma_phlex/level.rb
79
+ - lib/bulma_phlex/message.rb
79
80
  - lib/bulma_phlex/modal.rb
80
81
  - lib/bulma_phlex/navigation_bar.rb
81
82
  - lib/bulma_phlex/navigation_bar_dropdown.rb
@@ -102,7 +103,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
102
103
  requirements:
103
104
  - - ">="
104
105
  - !ruby/object:Gem::Version
105
- version: 3.2.10
106
+ version: '3.3'
106
107
  required_rubygems_version: !ruby/object:Gem::Requirement
107
108
  requirements:
108
109
  - - ">="