phlex-icons-bootstrap 2.19.0 → 2.20.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: 9132e7a32afc9c2ff41a25dd7de207f16e02a9f3a655bdfe1eded0fd8a8be1ba
4
- data.tar.gz: 81bc50d824973d237042b925511be98408fdf0d38731f4841113de513fcbe00f
3
+ metadata.gz: 1402a43e6df889d63b04b2422c5c4d2f6f457d43330adba486710b76d1e03cce
4
+ data.tar.gz: 6a85af5e4933722783191a4f7188728ef3f12fb195efda34e8688d79b2e24f74
5
5
  SHA512:
6
- metadata.gz: 6da70c91224b802a0aab3639df440ee888b1e4fe25a3755ebd73ed2fab7301a4395cce00a20705d92a7fa0cf7d2512c14a95796a630f00b4973f9f053b61948a
7
- data.tar.gz: 6e7f10f3c812bea158086b53fab5984577462dd4ea9bb4aa40bd5375fd81536a513131b626ee1ada4e2ac5c546fb9c512497c753e439add208444b1bb6f9b0d0
6
+ metadata.gz: a7849af580a4bc83606a5ca1e1d15c2e48c53991323c4c8fdccca18559358560dd37831fb61662f71278cbe917c8a7eb7453a81400568b17e5a0b542b719eef5
7
+ data.tar.gz: '099cd42e6d2a067e8215bc3a009c2b973f1cc44b53c5ce32d4cc408df3ee67aca909338f47bbdb4aa912605f9ecd80f67b085666f1877f138267db17b7eabab0'
data/.rubocop.yml CHANGED
@@ -25,4 +25,8 @@ Metrics/MethodLength:
25
25
  CountAsOne: ['array', 'method_call']
26
26
 
27
27
  Metrics/ClassLength:
28
- CountAsOne: ['array', 'method_call']
28
+ CountAsOne: ['array', 'method_call']
29
+
30
+ Metrics/BlockLength:
31
+ Exclude:
32
+ - 'spec/**/*'
data/README.md CHANGED
@@ -62,11 +62,15 @@ The gem provides global configuration options, and per icons pack configuration
62
62
  ```ruby
63
63
  PhlexIcons.configure do |config|
64
64
  config.default_classes = 'size-6'
65
+ config.helper_method_name = :phlex_icon # Default: :phlex_icon
66
+ config.default_pack = :hero # Default: nil. Accepts :symbol, "string", or Class (e.g., PhlexIcons::Hero)
65
67
  end
66
68
 
67
69
  # OR
68
70
 
69
71
  PhlexIcons.configuration.default_classes = 'size-6'
72
+ PhlexIcons.configuration.helper_method_name = :phlex_icon
73
+ PhlexIcons.configuration.default_pack = :hero
70
74
  ```
71
75
 
72
76
  ### Bootstrap Icons configuration
@@ -153,6 +157,9 @@ class PhlexIcons < Phlex::HTML
153
157
  Radix::Home(class: 'size-4')
154
158
  Remix::HomeLine(class: 'size-4')
155
159
  Tabler::Home(variant: :filled, class: 'size-4')
160
+
161
+ # or with a string
162
+ Icon('bootstrap/house', class: 'size-4')
156
163
  end
157
164
  end
158
165
  end
@@ -174,11 +181,48 @@ class PhlexIcons < Phlex::HTML
174
181
  render PhlexIcons::Radix::Home.new(class: 'size-4')
175
182
  render PhlexIcons::Remix::HomeLine.new(class: 'size-4')
176
183
  render PhlexIcons::Tabler::Home.new(variant: :filled, class: 'size-4')
184
+
185
+ # or with a string
186
+ render PhlexIcons::Icon('bootstrap/house', class: 'size-4')
177
187
  end
178
188
  end
179
189
  end
180
190
  ```
181
191
 
192
+ ### Rails View Helper
193
+
194
+ `phlex-icons` provides a convenient helper method to render icons directly in your ERB or Phlex views.
195
+
196
+ By default, the helper method is named `phlex_icon`, but is configurable.
197
+
198
+ ```erb
199
+ <%# Render a Bootstrap house icon with default size %>
200
+ <%= phlex_icon 'bootstrap/house' %>
201
+
202
+ <%# Render a Heroicons solid home icon with a specific class %>
203
+ <%= phlex_icon 'hero/home', variant: :solid, class: 'w-5 h-5 text-blue-500' %>
204
+
205
+ <%# Render a Tabler home icon, filled variant %>
206
+ <%= phlex_icon 'tabler/home:filled' %>
207
+
208
+ <%# If default_pack = :hero, render a Heroicons home icon %>
209
+ <%= phlex_icon 'home', class: 'w-6 h-6' %>
210
+
211
+ <%# Render a Flag icon (rectangle variant is default for flags if not configured otherwise) %>
212
+ <%= phlex_icon 'flag/sa' %>
213
+
214
+ <%# Render a custom icon %>
215
+ <%= phlex_icon 'custom/my_awesome_icon:variant_name' %>
216
+ ```
217
+
218
+ The first argument is the icon identifier. Such as: `'pack/icon_name:variant'`.
219
+
220
+ * If `default_pack` is configured, you can omit the pack name (e.g., `'icon_name:variant'` instead of `'pack/icon_name:variant'`).
221
+ * The `:variant` part is optional.
222
+ * Examples: `'hero/house:solid'`, `'house:solid'`, `'house'`
223
+
224
+ Subsequent arguments are passed as options to the icon component, such as `variant`, `class`, etc.
225
+
182
226
  ### Specific icon pack(s)
183
227
 
184
228
  Let's say you want to use only Heroicons and Flag Icons, you can use the following gems:
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rubocop:disable Layout/LineLength
4
+ module PhlexIcons
5
+ module Bootstrap
6
+ class Bluesky < Base
7
+ def view_template
8
+ svg(
9
+ **attrs,
10
+ xmlns: 'http://www.w3.org/2000/svg',
11
+ fill: 'currentColor',
12
+ viewbox: '0 0 16 16'
13
+ ) do |s|
14
+ s.path(
15
+ d:
16
+ 'M3.468 1.948C5.303 3.325 7.276 6.118 8 7.616c.725-1.498 2.698-4.29 4.532-5.668C13.855.955 16 .186 16 2.632c0 .489-.28 4.105-.444 4.692-.572 2.04-2.653 2.561-4.504 2.246 3.236.551 4.06 2.375 2.281 4.2-3.376 3.464-4.852-.87-5.23-1.98-.07-.204-.103-.3-.103-.218 0-.081-.033.014-.102.218-.379 1.11-1.855 5.444-5.231 1.98-1.778-1.825-.955-3.65 2.28-4.2-1.85.315-3.932-.205-4.503-2.246C.28 6.737 0 3.12 0 2.632 0 .186 2.145.955 3.468 1.948'
17
+ )
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ # rubocop:enable Layout/LineLength
@@ -12,9 +12,8 @@ module PhlexIcons
12
12
  viewbox: '0 0 16 16'
13
13
  ) do |s|
14
14
  s.path(
15
- fill_rule: 'evenodd',
16
15
  d:
17
- 'M2 0a2 2 0 0 0-2 2h16a2 2 0 0 0-2-2zM0 14V3h16v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2m12-8a1 1 0 1 0 2 0 1 1 0 0 0-2 0'
16
+ 'M16 14a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V3h16zm-3-9a1 1 0 1 0 0 2 1 1 0 0 0 0-2m1-5a2 2 0 0 1 2 2H0a2 2 0 0 1 2-2z'
18
17
  )
19
18
  end
20
19
  end
@@ -12,9 +12,8 @@ module PhlexIcons
12
12
  viewbox: '0 0 16 16'
13
13
  ) do |s|
14
14
  s.path(
15
- fill_rule: 'evenodd',
16
15
  d:
17
- 'M2 0a2 2 0 0 0-2 2h16a2 2 0 0 0-2-2zM0 8V3h16v2h-6a1 1 0 1 0 0 2h6v7a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-4h6a1 1 0 1 0 0-2z'
16
+ 'M16 5h-6a1 1 0 0 0 0 2h6v7a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-4h6a1 1 0 0 0 0-2H0V3h16zm-2-5a2 2 0 0 1 2 2H0a2 2 0 0 1 2-2z'
18
17
  )
19
18
  end
20
19
  end
@@ -12,9 +12,8 @@ module PhlexIcons
12
12
  viewbox: '0 0 16 16'
13
13
  ) do |s|
14
14
  s.path(
15
- fill_rule: 'evenodd',
16
15
  d:
17
- 'M2 0a2 2 0 0 0-2 2h16a2 2 0 0 0-2-2zM0 14V3h16v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2m12-8a1 1 0 1 0 2 0 1 1 0 0 0-2 0M5 9a1 1 0 1 0 2 0 1 1 0 0 0-2 0m5-2a1 1 0 1 1 0-2 1 1 0 0 1 0 2M2 9a1 1 0 1 0 2 0 1 1 0 0 0-2 0'
16
+ 'M16 14a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V3h16zM3 8a1 1 0 1 0 0 2 1 1 0 0 0 0-2m3 0a1 1 0 1 0 0 2 1 1 0 0 0 0-2m4-3a1 1 0 1 0 0 2 1 1 0 0 0 0-2m3 0a1 1 0 1 0 0 2 1 1 0 0 0 0-2m1-5a2 2 0 0 1 2 2H0a2 2 0 0 1 2-2z'
18
17
  )
19
18
  end
20
19
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module PhlexIcons
4
4
  module Bootstrap # rubocop:disable Metrics/ModuleLength
5
- VERSION = '1.11.3'
5
+ VERSION = '1.12.1'
6
6
  VARIANTS = nil
7
7
 
8
8
  extend Phlex::Kit
@@ -201,6 +201,7 @@ module PhlexIcons
201
201
  autoload :BinocularsFill, 'phlex-icons/bootstrap/binoculars_fill'
202
202
  autoload :BlockquoteLeft, 'phlex-icons/bootstrap/blockquote_left'
203
203
  autoload :BlockquoteRight, 'phlex-icons/bootstrap/blockquote_right'
204
+ autoload :Bluesky, 'phlex-icons/bootstrap/bluesky'
204
205
  autoload :Bluetooth, 'phlex-icons/bootstrap/bluetooth'
205
206
  autoload :BodyText, 'phlex-icons/bootstrap/body_text'
206
207
  autoload :Book, 'phlex-icons/bootstrap/book'
@@ -2,10 +2,33 @@
2
2
 
3
3
  module PhlexIcons
4
4
  class Configuration
5
- attr_accessor :default_variant, :default_classes
5
+ attr_accessor :default_variant, :default_classes, :helper_method_name
6
+ attr_reader :default_pack
6
7
 
7
8
  def initialize(default_classes: 'size-6')
8
9
  @default_classes = default_classes
10
+ @helper_method_name = :phlex_icon
11
+ @default_pack = nil
12
+ end
13
+
14
+ # Custom setter for default_pack
15
+ # Accepts Class (PhlexIcons::Hero), String ('hero'), or Symbol (:hero)
16
+ #
17
+ # @param value [Class, String, Symbol, nil] The value to set the default pack to.
18
+ # @raise [ArgumentError] If the value is not a Class, String, Symbol, or nil.
19
+ def default_pack=(value)
20
+ @default_pack = case value
21
+ when Class
22
+ # Extract 'Hero' from PhlexIcons::Hero, lowercase, symbolize
23
+ value.name.split('::').last&.downcase&.to_sym
24
+ when String, Symbol
25
+ value.to_sym
26
+ when nil
27
+ nil
28
+ else
29
+ raise ArgumentError,
30
+ "Invalid type for default_pack: #{value.class}. Expected Class, String, Symbol, or nil."
31
+ end
9
32
  end
10
33
  end
11
34
  end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'name_parser'
4
+
5
+ module PhlexIcons
6
+ extend Phlex::Kit
7
+
8
+ class Icon < Phlex::SVG
9
+ # Factory method to create an icon component instance.
10
+ # Parses the name string, finds the corresponding class, and initializes it with options.
11
+ # @param name [String] Icon identifier (e.g., "hero/house:solid", "lucide/arrow-right").
12
+ # @param options [Hash] HTML attributes and options for the icon component.
13
+ # @return [Phlex::SVG] An instance of the resolved icon component.
14
+ # @raise [ArgumentError] If the name format is invalid or default pack is missing.
15
+ # @raise [NameError] If the corresponding icon class cannot be found.
16
+ def initialize(name, **options)
17
+ @name = name
18
+ @options = options&.transform_keys(&:to_sym) || {}
19
+ super()
20
+ end
21
+
22
+ def view_template
23
+ parser = PhlexIcons::NameParser.new(@name)
24
+
25
+ # Prioritize variant from the name string over options hash
26
+ @options[:variant] = parser.variant_name if parser.variant_name
27
+
28
+ render parser.klass.new(**@options)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PhlexIcons
4
+ class NameParser
5
+ attr_reader :pack_name, :icon_name, :variant_name, :identifier, :klass
6
+
7
+ # Initializes the parser with the full icon identifier string (e.g., "hero/arrow-right:solid").
8
+ # Parses the string into pack, icon, and variant components.
9
+ # Determines and validates the corresponding icon component class.
10
+ # @param identifier [String] The full icon identifier.
11
+ # @raise [ArgumentError] If the name format is invalid or default pack is missing.
12
+ # @raise [NameError] If the corresponding icon class cannot be found.
13
+ def initialize(identifier)
14
+ @identifier = identifier.to_s
15
+ @pack_name, @icon_name, @variant_name = parse(@identifier)
16
+ @klass = find_icon_class(@pack_name, @icon_name)
17
+ end
18
+
19
+ private
20
+
21
+ # Performs the core parsing logic.
22
+ # @param identifier [String] The full icon identifier.
23
+ # @return [Array<String, String, Symbol, nil>] An array containing [pack_name, icon_name, variant_name].
24
+ def parse(identifier)
25
+ name_part, variant = identifier.split(':', 2)
26
+
27
+ # Check if the part before ':' (or the whole string if no ':') is empty
28
+ if name_part.nil? || name_part.strip.empty?
29
+ raise ArgumentError,
30
+ "Invalid icon name format. Could not determine pack or icon name from '#{identifier}'."
31
+ end
32
+
33
+ parsed_variant = variant&.empty? ? nil : variant&.to_sym
34
+ pack, icon = parse_pack_and_icon(name_part)
35
+
36
+ validate_identifier_parts(pack, icon, identifier)
37
+
38
+ [pack, icon, parsed_variant]
39
+ end
40
+
41
+ # Extracts the pack and icon names from the part before the variant separator (':').
42
+ # @param name_part [String] The part of the name string before ':'.
43
+ # @return [Array<String, String>] An array containing [pack_name, icon_name].
44
+ def parse_pack_and_icon(name_part)
45
+ if name_part.include?('/')
46
+ # If split results in empty parts, they will be caught by validate_identifier_parts later
47
+ name_part.split('/', 2)
48
+ else
49
+ # If name_part is just the icon, it cannot be empty (checked in `parse`)
50
+ [get_default_pack_name_or_raise(name_part), name_part]
51
+ end
52
+ end
53
+
54
+ # Retrieves the configured default pack name or raises an error if not set.
55
+ # @param icon_name_part [String] The icon name used when the pack prefix is missing (for error message).
56
+ # @return [String] The default pack name.
57
+ # @raise [ArgumentError] If PhlexIcons.configuration.default_pack is not configured.
58
+ def get_default_pack_name_or_raise(icon_name_part)
59
+ # Assumes PhlexIcons.configuration is available.
60
+ # Consider requiring 'phlex_icons/configuration' explicitly if needed outside Rails context.
61
+ default_pack_name = defined?(PhlexIcons.configuration) ? PhlexIcons.configuration&.default_pack&.to_s : nil
62
+ unless default_pack_name && !default_pack_name.empty?
63
+ raise ArgumentError,
64
+ "Icon name '#{icon_name_part}' is missing the pack name prefix (e.g., 'hero/'), " \
65
+ 'and no `default_pack` is configured in PhlexIcons.'
66
+ end
67
+ default_pack_name
68
+ end
69
+
70
+ # Validates that both pack and icon name parts were successfully extracted.
71
+ # @param pack [String, nil] The extracted pack name.
72
+ # @param icon [String, nil] The extracted icon name.
73
+ # @param identifier [String] The original full identifier (for error message).
74
+ # @raise [ArgumentError] If either pack or icon is missing or empty.
75
+ def validate_identifier_parts(pack, icon, identifier)
76
+ return if pack && !pack.empty? && icon && !icon.empty?
77
+
78
+ raise ArgumentError,
79
+ "Invalid icon name format. Could not determine pack or icon name from '#{identifier}'."
80
+ end
81
+
82
+ # Finds the PhlexIcon component class based on pack and icon names.
83
+ # @param pack_name [String] The kebab-case pack name (e.g., "hero").
84
+ # @param icon_name [String] The kebab-case icon name (e.g., "arrow-right").
85
+ # @return [Class] The icon component class.
86
+ # @raise [NameError] If the corresponding icon class cannot be found.
87
+ def find_icon_class(pack_name, icon_name)
88
+ class_name = build_icon_class_name(pack_name, icon_name)
89
+ find_and_validate_icon_class(class_name, pack_name, icon_name)
90
+ end
91
+
92
+ # Constructs the full Ruby class name for an icon component.
93
+ # @param pack_name [String] The kebab-case pack name (e.g., "hero").
94
+ # @param icon_name [String] The kebab-case icon name (e.g., "arrow-right").
95
+ # @return [String] The CamelCase class name (e.g., "PhlexIcons::Hero::ArrowRight").
96
+ def build_icon_class_name(pack_name, icon_name)
97
+ pack_module_name = pack_name.split('-').map(&:capitalize).join
98
+ icon_class_name = icon_name.split('-').map(&:capitalize).join
99
+ "PhlexIcons::#{pack_module_name}::#{icon_class_name}"
100
+ end
101
+
102
+ # Attempts to find the icon class by its name and validates its existence.
103
+ # @param class_name [String] The full class name to find.
104
+ # @param pack_name [String] Original pack name (for error message).
105
+ # @param icon_name [String] Original icon name (for error message).
106
+ # @return [Class] The found icon component class.
107
+ # @raise [NameError] If the class cannot be found.
108
+ def find_and_validate_icon_class(class_name, pack_name, icon_name)
109
+ Object.const_get(class_name)
110
+ rescue NameError
111
+ raise NameError,
112
+ "Could not find icon component class '#{class_name}'. " \
113
+ "Make sure the pack ('#{pack_name}') and name ('#{icon_name}') " \
114
+ 'are correct and the corresponding file is loaded.'
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'configuration'
4
+
5
+ module PhlexIcons
6
+ class Railtie < ::Rails::Railtie
7
+ initializer 'phlex_icons.view_helpers' do
8
+ ActiveSupport.on_load(:action_view) do
9
+ helper_method_name = PhlexIcons.configuration.helper_method_name
10
+
11
+ define_method helper_method_name do |name, **options|
12
+ PhlexIcons::Icon.call(name, **options)&.html_safe
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PhlexIcons
4
- VERSION = '2.19.0'
4
+ VERSION = '2.20.0'
5
5
  end
@@ -12,6 +12,9 @@ require_relative 'phlex-icons/version'
12
12
  require_relative 'phlex-icons/bootstrap'
13
13
  require_relative 'phlex-icons/material'
14
14
 
15
+ require_relative 'phlex-icons/icon'
16
+ require_relative 'phlex-icons/railtie' if defined?(Rails)
17
+
15
18
  module PhlexIcons
16
19
  class << self
17
20
  def configuration
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: phlex-icons-bootstrap
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.19.0
4
+ version: 2.20.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ali Hamdi Ali Fadel
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-04-25 00:00:00.000000000 Z
11
+ date: 2025-05-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: phlex
@@ -245,6 +245,7 @@ files:
245
245
  - lib/phlex-icons/bootstrap/binoculars_fill.rb
246
246
  - lib/phlex-icons/bootstrap/blockquote_left.rb
247
247
  - lib/phlex-icons/bootstrap/blockquote_right.rb
248
+ - lib/phlex-icons/bootstrap/bluesky.rb
248
249
  - lib/phlex-icons/bootstrap/bluetooth.rb
249
250
  - lib/phlex-icons/bootstrap/body_text.rb
250
251
  - lib/phlex-icons/bootstrap/book.rb
@@ -2105,6 +2106,7 @@ files:
2105
2106
  - lib/phlex-icons/bootstrap/zoom_in.rb
2106
2107
  - lib/phlex-icons/bootstrap/zoom_out.rb
2107
2108
  - lib/phlex-icons/configuration.rb
2109
+ - lib/phlex-icons/icon.rb
2108
2110
  - lib/phlex-icons/material.rb
2109
2111
  - lib/phlex-icons/material/abc.rb
2110
2112
  - lib/phlex-icons/material/abc_filled.rb
@@ -14829,6 +14831,8 @@ files:
14829
14831
  - lib/phlex-icons/material/zoom_out_round.rb
14830
14832
  - lib/phlex-icons/material/zoom_out_sharp.rb
14831
14833
  - lib/phlex-icons/material/zoom_out_two_tone.rb
14834
+ - lib/phlex-icons/name_parser.rb
14835
+ - lib/phlex-icons/railtie.rb
14832
14836
  - lib/phlex-icons/version.rb
14833
14837
  - phlex-icons.png
14834
14838
  - sig/phlex/icons.rbs