markawesome 0.3.0 → 0.4.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: adad1d3e9850c4d1f82b4cbe73eb56ac9c82c413e66ea0adb1291794a3a9a25a
4
- data.tar.gz: 07b7741a6e96f7031d38d1e10d6ca6a0314d5edd05341222f1f7d7964904d1c4
3
+ metadata.gz: 8a3394f03fff9ca20290650589ba70022b2f8ca71b5581f5d06cb4e06ac83f3f
4
+ data.tar.gz: d5af8667249a450c3119641dc38a9f148bbb2b30a1f8c76eae138c3765617fd5
5
5
  SHA512:
6
- metadata.gz: b4af697c90bf1d4a0d7d10de6fac07f784319b01d45b58fdcfb190475e97f4e5164b7b5fe7e7fd7475aece2651c78cd31181059cb7a8c1ec01ea33c05a154f11
7
- data.tar.gz: ecca3f31fb0b27db1572cea1c82a2989434948699fe2125f8020f0cdd04e39f03a7d2426fbacfff8d65eba0252e6cdf0056a05d93ff7587ae85d39652e076553
6
+ metadata.gz: c29d6692c8cd45f5f2a6a544de3505ff3a9af50a0d36468385f71b38daac30465ff23d15b5d94648f48690fae43d652cf495a4c7ea8d282bc96127a7376e22a3
7
+ data.tar.gz: c8134fa3a4a9344efe72ffa5d4a6504763ba9ebce4a4a9c6f7d8b0907de48506ebb9a7ae843bffd0898da5379ba2ebdf9bc100978f2b86add9cec722c4e3281e
data/CHANGELOG.md CHANGED
@@ -4,6 +4,23 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [0.4.0] - 2026-02-09
8
+
9
+ ### Added
10
+
11
+ - **IconSlotParser**: New reusable parser for `icon:name` and `icon:slot:name` syntax across components
12
+ - **ButtonTransformer**: Icon support with `icon:name` (start slot) and `icon:end:name` for start/end icon slots
13
+ - **CalloutTransformer**: Custom icon override with `icon:name` to replace default variant icons
14
+ - **DetailsTransformer**: Custom expand/collapse icons with `icon:expand:name` and `icon:collapse:name`
15
+ - **TagTransformer**: Inline content icons with `icon:name` for both block and inline tag syntax
16
+
17
+ ### Design
18
+
19
+ - IconSlotParser composes with AttributeParser — strips icon tokens first, passes remaining params for attribute parsing
20
+ - Supports slot name mapping (e.g. `expand` → `expand-icon`) for Web Awesome's HTML slot conventions
21
+ - Rightmost-wins semantics consistent with AttributeParser
22
+ - Content slot mode omits `slot=` attribute for inline icon usage (tags)
23
+
7
24
  ## [0.3.0] - 2026-02-08
8
25
 
9
26
  ### Added
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Markawesome
4
+ # Parses icon:... tokens from parameter strings for Web Awesome component icon slots
5
+ # Supports default slot mapping, explicit slot names, and slot name remapping
6
+ #
7
+ # Examples:
8
+ # "icon:gear" → default slot gets "gear"
9
+ # "icon:end:arrow-right" → "end" slot gets "arrow-right"
10
+ # "success icon:gear large" → icons: { 'start' => 'gear' }, remaining: "success large"
11
+ class IconSlotParser
12
+ # Parse icon tokens from a parameter string
13
+ # @param params_string [String] Space-separated parameter string potentially containing icon:... tokens
14
+ # @param slot_config [Hash] Configuration for icon slots
15
+ # :default [String, nil] Default slot name for icon:name tokens (nil = no default)
16
+ # :slots [Array<String>] Allowed slot names
17
+ # :slot_map [Hash] Optional mapping from short slot names to HTML slot attributes
18
+ # @return [Hash] { icons: Hash, remaining: String }
19
+ def self.parse(params_string, slot_config)
20
+ return { icons: {}, remaining: '' } if params_string.nil? || params_string.strip.empty?
21
+
22
+ icons = {}
23
+ remaining_tokens = []
24
+ tokens = params_string.strip.split(/\s+/)
25
+
26
+ tokens.each do |token|
27
+ if token.start_with?('icon:')
28
+ parts = token.split(':', 3) # ["icon", slot_or_name, maybe_name]
29
+
30
+ if parts.length == 3
31
+ # Explicit slot: icon:slot:name
32
+ slot = parts[1]
33
+ name = parts[2]
34
+ icons[slot] = name if slot_config[:slots]&.include?(slot)
35
+ elsif parts.length == 2 && slot_config[:default]
36
+ # Default slot: icon:name
37
+ name = parts[1]
38
+ icons[slot_config[:default]] = name unless name.empty?
39
+ end
40
+ else
41
+ remaining_tokens << token
42
+ end
43
+ end
44
+
45
+ { icons: icons, remaining: remaining_tokens.join(' ') }
46
+ end
47
+
48
+ # Generate <wa-icon> HTML elements for parsed icons
49
+ # @param icons_hash [Hash] Slot name => icon name pairs
50
+ # @param slot_map [Hash, nil] Optional mapping from parsed slot names to HTML slot attributes
51
+ # @return [String] HTML string with <wa-icon> elements
52
+ def self.to_html(icons_hash, slot_map = nil)
53
+ icons_hash.map do |slot, name|
54
+ html_slot = slot_map ? (slot_map[slot] || slot) : slot
55
+ if html_slot == 'content'
56
+ "<wa-icon name=\"#{name}\"></wa-icon>"
57
+ else
58
+ "<wa-icon slot=\"#{html_slot}\" name=\"#{name}\"></wa-icon>"
59
+ end
60
+ end.join
61
+ end
62
+ end
63
+ end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative 'base_transformer'
4
4
  require_relative '../attribute_parser'
5
+ require_relative '../icon_slot_parser'
5
6
 
6
7
  module Markawesome
7
8
  # Transforms button syntax into wa-button elements
@@ -31,6 +32,8 @@ module Markawesome
31
32
  disabled: %w[disabled]
32
33
  }.freeze
33
34
 
35
+ ICON_SLOTS = { default: 'start', slots: %w[start end] }.freeze
36
+
34
37
  def self.transform(content)
35
38
  # Define both regex patterns - capture all space-separated parameters
36
39
  primary_regex = /^%%%([^\n]*)\n(.*?)\n%%%/m
@@ -40,10 +43,11 @@ module Markawesome
40
43
  transform_proc = proc do |params_string, button_content|
41
44
  button_content = button_content.strip
42
45
 
43
- # Parse attributes using AttributeParser
44
- attributes = AttributeParser.parse(params_string, BUTTON_ATTRIBUTES)
46
+ # Parse icon tokens first, then pass remaining to AttributeParser
47
+ icon_result = IconSlotParser.parse(params_string, ICON_SLOTS)
48
+ attributes = AttributeParser.parse(icon_result[:remaining], BUTTON_ATTRIBUTES)
45
49
 
46
- build_button_html(button_content, attributes)
50
+ build_button_html(button_content, attributes, icon_result[:icons])
47
51
  end
48
52
 
49
53
  # Apply both patterns
@@ -54,7 +58,7 @@ module Markawesome
54
58
  class << self
55
59
  private
56
60
 
57
- def build_button_html(content, attributes)
61
+ def build_button_html(content, attributes, icons = {})
58
62
  # Build HTML attributes from parsed attributes
59
63
  html_attrs = []
60
64
 
@@ -67,6 +71,7 @@ module Markawesome
67
71
  html_attrs << 'disabled' if attributes[:disabled]
68
72
 
69
73
  attrs_string = html_attrs.empty? ? '' : " #{html_attrs.join(' ')}"
74
+ icon_html = IconSlotParser.to_html(icons)
70
75
 
71
76
  # Check if content contains a markdown link
72
77
  link_match = content.match(/^\[([^\]]+)\]\(([^)]+)\)$/)
@@ -83,7 +88,7 @@ module Markawesome
83
88
  # Fix whitespace issues like in badges
84
89
  button_html = button_html.gsub(%r{(</\w+>)\s+}, '\1&nbsp;')
85
90
 
86
- "<wa-button#{attrs_string} href=\"#{link_url}\">#{button_html}</wa-button>"
91
+ "<wa-button#{attrs_string} href=\"#{link_url}\">#{icon_html}#{button_html}</wa-button>"
87
92
  else
88
93
  # It's a regular button
89
94
  button_html = markdown_to_html(content).strip
@@ -92,7 +97,7 @@ module Markawesome
92
97
  # Fix whitespace issues like in badges
93
98
  button_html = button_html.gsub(%r{(</\w+>)\s+}, '\1&nbsp;')
94
99
 
95
- "<wa-button#{attrs_string}>#{button_html}</wa-button>"
100
+ "<wa-button#{attrs_string}>#{icon_html}#{button_html}</wa-button>"
96
101
  end
97
102
  end
98
103
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative 'base_transformer'
4
4
  require_relative '../attribute_parser'
5
+ require_relative '../icon_slot_parser'
5
6
 
6
7
  module Markawesome
7
8
  # Transforms callout syntax into wa-callout elements
@@ -17,6 +18,7 @@ module Markawesome
17
18
  appearance: %w[accent filled outlined plain filled-outlined]
18
19
  }.freeze
19
20
  VARIANT_ALIASES = { 'info' => 'brand' }.freeze
21
+ ICON_SLOTS = { default: 'icon', slots: %w[icon] }.freeze
20
22
 
21
23
  def self.transform(content)
22
24
  variant_pattern = VARIANTS.join('|')
@@ -25,13 +27,21 @@ module Markawesome
25
27
 
26
28
  transform_proc = proc do |variant, extra_params, inner_content|
27
29
  actual_variant = VARIANT_ALIASES.fetch(variant, variant)
28
- extra_attrs = AttributeParser.parse(extra_params, CALLOUT_ATTRIBUTES)
30
+
31
+ # Parse icon tokens first, then pass remaining to AttributeParser
32
+ icon_result = IconSlotParser.parse(extra_params, ICON_SLOTS)
33
+ extra_attrs = AttributeParser.parse(icon_result[:remaining], CALLOUT_ATTRIBUTES)
29
34
 
30
35
  attr_parts = ["variant=\"#{actual_variant}\""]
31
36
  attr_parts << "appearance=\"#{extra_attrs[:appearance]}\"" if extra_attrs[:appearance]
32
37
  attr_parts << "size=\"#{extra_attrs[:size]}\"" if extra_attrs[:size]
33
38
 
34
- icon_html = icon_for(actual_variant)
39
+ # Use custom icon if provided, otherwise use default variant icon
40
+ icon_html = if icon_result[:icons]['icon']
41
+ "<wa-icon slot=\"icon\" name=\"#{icon_result[:icons]['icon']}\" variant=\"solid\"></wa-icon>"
42
+ else
43
+ icon_for(actual_variant)
44
+ end
35
45
  html_content = "#{icon_html}#{markdown_to_html(inner_content)}"
36
46
 
37
47
  "<wa-callout #{attr_parts.join(' ')}>#{html_content}</wa-callout>"
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative 'base_transformer'
4
4
  require_relative '../attribute_parser'
5
+ require_relative '../icon_slot_parser'
5
6
 
6
7
  module Markawesome
7
8
  # Transforms summary/details syntax into wa-details elements
@@ -19,6 +20,12 @@ module Markawesome
19
20
  open: %w[open]
20
21
  }.freeze
21
22
 
23
+ ICON_SLOTS = {
24
+ default: nil,
25
+ slots: %w[expand collapse],
26
+ slot_map: { 'expand' => 'expand-icon', 'collapse' => 'collapse-icon' }
27
+ }.freeze
28
+
22
29
  def self.transform(content)
23
30
  # Define both regex patterns - capture parameter string
24
31
  primary_regex = /^\^\^\^?(.*?)\n(.*?)\n^>>>\n(.*?)\n^\^\^\^?/m
@@ -29,11 +36,12 @@ module Markawesome
29
36
  summary_content = summary_content.strip
30
37
  details_content = details_content.strip
31
38
 
32
- # Parse parameters using AttributeParser
33
- attributes = AttributeParser.parse(params_string, COMPONENT_ATTRIBUTES)
39
+ # Parse icon tokens first, then pass remaining to AttributeParser and name extraction
40
+ icon_result = IconSlotParser.parse(params_string, ICON_SLOTS)
41
+ attributes = AttributeParser.parse(icon_result[:remaining], COMPONENT_ATTRIBUTES)
34
42
 
35
43
  # Extract name parameter (format: name:value) - special handling
36
- name_value = extract_name_value(params_string)
44
+ name_value = extract_name_value(icon_result[:remaining])
37
45
 
38
46
  appearance_class = normalize_appearance(attributes[:appearance])
39
47
  icon_placement = attributes[:icon_placement] || 'end'
@@ -46,9 +54,11 @@ module Markawesome
46
54
  attr_parts << 'open' if attributes[:open]
47
55
  attr_parts << "name='#{name_value}'" if name_value
48
56
 
57
+ icon_html = IconSlotParser.to_html(icon_result[:icons], ICON_SLOTS[:slot_map])
58
+
49
59
  "<wa-details #{attr_parts.join(' ')}>" \
50
60
  "<span slot='summary'>#{summary_html}</span>" \
51
- "#{details_html}</wa-details>"
61
+ "#{icon_html}#{details_html}</wa-details>"
52
62
  end
53
63
 
54
64
  # Apply both patterns
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative 'base_transformer'
4
4
  require_relative '../attribute_parser'
5
+ require_relative '../icon_slot_parser'
5
6
 
6
7
  module Markawesome
7
8
  # Transforms tag syntax into wa-tag elements
@@ -25,6 +26,8 @@ module Markawesome
25
26
  'with-remove': %w[with-remove]
26
27
  }.freeze
27
28
 
29
+ ICON_SLOTS = { default: 'content', slots: %w[content] }.freeze
30
+
28
31
  def self.transform(content)
29
32
  # Define regex patterns
30
33
  # Block syntax (multiline with newlines) - supports both LF and CRLF
@@ -51,10 +54,14 @@ module Markawesome
51
54
  params_tokens = []
52
55
  content_tokens = []
53
56
 
54
- # Separate attribute tokens from content tokens
57
+ # Separate attribute and icon tokens from content tokens
55
58
  tokens.each do |token|
56
59
  matched = COMPONENT_ATTRIBUTES.any? { |_attr, values| values.include?(token) }
57
- matched ? params_tokens << token : content_tokens << token
60
+ if matched || token.start_with?('icon:')
61
+ params_tokens << token
62
+ else
63
+ content_tokens << token
64
+ end
58
65
  end
59
66
 
60
67
  # Build params and content strings
@@ -81,8 +88,9 @@ module Markawesome
81
88
  private
82
89
 
83
90
  def build_tag_html(content, params)
84
- # Parse attributes using AttributeParser
85
- attributes = AttributeParser.parse(params, COMPONENT_ATTRIBUTES)
91
+ # Parse icon tokens first, then pass remaining to AttributeParser
92
+ icon_result = IconSlotParser.parse(params, ICON_SLOTS)
93
+ attributes = AttributeParser.parse(icon_result[:remaining], COMPONENT_ATTRIBUTES)
86
94
 
87
95
  # Build HTML attributes
88
96
  html_attrs = []
@@ -93,13 +101,14 @@ module Markawesome
93
101
  html_attrs << 'with-remove' if attributes[:'with-remove']
94
102
 
95
103
  attrs_string = html_attrs.empty? ? '' : " #{html_attrs.join(' ')}"
104
+ icon_html = IconSlotParser.to_html(icon_result[:icons])
96
105
 
97
106
  tag_html = markdown_to_html(content).strip
98
107
 
99
108
  # Remove paragraph tags if the content is just text
100
109
  tag_html = tag_html.gsub(%r{^<p>(.*)</p>$}m, '\1')
101
110
 
102
- "<wa-tag#{attrs_string}>#{tag_html}</wa-tag>"
111
+ "<wa-tag#{attrs_string}>#{icon_html}#{tag_html}</wa-tag>"
103
112
  end
104
113
  end
105
114
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Markawesome
4
- VERSION = '0.3.0'
4
+ VERSION = '0.4.0'
5
5
  end
data/lib/markawesome.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'markawesome/version'
4
+ require_relative 'markawesome/icon_slot_parser'
4
5
  require_relative 'markawesome/transformer'
5
6
 
6
7
  # Main module for Markawesome - framework-agnostic Markdown to Web Awesome component transformer
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: markawesome
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Janne Waren
@@ -92,6 +92,7 @@ files:
92
92
  - README.md
93
93
  - lib/markawesome.rb
94
94
  - lib/markawesome/attribute_parser.rb
95
+ - lib/markawesome/icon_slot_parser.rb
95
96
  - lib/markawesome/transformer.rb
96
97
  - lib/markawesome/transformers.rb
97
98
  - lib/markawesome/transformers/badge_transformer.rb