bulma-phlex 0.13.0 → 0.14.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: fd181a5709227054b3083db9b36cfe6a8ffb88fab99dc12e617df8d2ddb52f0d
4
+ data.tar.gz: 46ccadb18d86c42f3edd41fd565147cc77d959bd8c43e8eb381eb89645ac3cd8
5
5
  SHA512:
6
- metadata.gz: 56477bb7d2f9704ad2acdb404d9db20edff939ceb58e942fb90ce7fd4d37696c16bf071f3583b357cbf09d0e9d36859178d32c07242cb24d462814e87712caba
7
- data.tar.gz: 62cf166607ea1826c403d7bb940f020ac3b71ef792ee8ff15a65f61ac9f4787713fe4aed3023cb76229002a0add42c161f20147a3001494c180da05e153d8700
6
+ metadata.gz: 7ac0afb5c9ffd6b606fdf12bbb6a9f15e3e24fe79aeff856a3ef240d944d89766fb3d164199b1859f0f5ee8088519541079d22f091e20d5cf7a95b81cafb83ee
7
+ data.tar.gz: 68f95fd0ff6e92c14a8b0ae4e3b524bfec47bcfc20cab7db4576aea7c0af131327802bdfe51c201b1455adb9e667cb3a1df3a3176b6cdae8a42602281bcab3c6
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)
@@ -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
 
@@ -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.
@@ -402,4 +418,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
402
418
 
403
419
  ## Credits
404
420
 
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.
421
+ 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) }
@@ -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
 
@@ -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.14.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.14.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-03-30 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