markawesome 0.19.0 → 0.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: fcd58ebaea11af858fd0b4e922bdf4447035df09cc91b9acfa9dea047a908cf8
4
- data.tar.gz: de54c7cb14e781a63d4bc22a132bb637cc62c1ec0383a0404e46b81efd3a3500
3
+ metadata.gz: '09defacfcfa437cfd7c5406b0705161597633880fac312488a7fa29c3055754d'
4
+ data.tar.gz: 369cd9e0d91dc6a423501367f98e2e54391a04aaebc4cf9da9c79d1c3a4267aa
5
5
  SHA512:
6
- metadata.gz: ebbc8bb6f73131839e94bc1b1d79a875bdd2de65e980832c59fb3305b03324b76c6259b800e16be111bdfd6e3c0df14d6f80820052474d635e2a982c1cd5d987
7
- data.tar.gz: 2a768f945ecb99d16b4aa3e60d64dce34e97bf518239344d83a440a9cba0cd0c60caeac5315c8fbfee5545c3212f6d28376dc3dc181b903cfb0a68f1649c640c
6
+ metadata.gz: fa42c7657b0abac3554309763a38a75a8c6bc08d39b8a28e85b9fa0b57ea931207705efa0ff194c097582996986871a382b09872508dad2cfe325fc957350efa
7
+ data.tar.gz: 4a509a216fd0ce3aea3238e85dbf8cfea8fc60c7d55e9209e7e9915862b933708afd896a9582cc8c630bbbaf41caf759285f8687a5bff8df45c386d7a058617a
data/CHANGELOG.md CHANGED
@@ -6,6 +6,19 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.20.0] - 2026-10-09
10
+
11
+ ### Added
12
+
13
+ - **Labeled divider (`<wa-divider>` label, Web Awesome 3.13.0+).** New `DividerTransformer` with a mirrored one-line shorthand, `--- label ---`, and a `:::wa-divider params?` alternative whose body is the label (empty for a bare divider). Leading tokens are consumed from the left: `start`/`center`/`end` → `label-placement`, `horizontal`/`vertical` → `orientation`, `icon:name` → a `<wa-icon>` before the label. The rest is the label, rendered as inline Markdown. Output: `<wa-divider orientation="…" label-placement="…"><wa-icon name="…"></wa-icon> Label</wa-divider>`, attributes only when given. Plain `---` and `--- ---` are untouched and stay `<hr>`, and so is any line made only of `|`, `:`, `-` and whitespace, which keeps pipe-less GFM table separators such as `--- | ---` intact. The plain-Markdown renderer degrades it to `---` followed by the label as its own paragraph (icon dropped), with a leading blank line so the rule can't turn a preceding line into a setext heading. Known limitation, shared with every transformer: only backtick code fences are protected, so a `--- x ---` line inside a `~~~` fence is transformed.
14
+ - **Display-only stepper (`<wa-stepper>` / `<wa-step>`, Web Awesome 3.14.0, experimental).** New `StepperTransformer`: a `>>>>>> params?` fence (or `:::wa-stepper params?`) wrapping a Markdown task list. Each unindented list line is a step: `[x]`/`[X]` → `completed`; leading `active`, `loading`, `disabled`, a variant (`neutral`/`brand`/`success`/`warning`/`danger`), an attention (`none`/`pulse`/`bounce`) and `icon:name` (→ `slot="icon"`) are flags; the rest is the label as inline Markdown. Lines indented two or more spaces under a step are joined into `<span slot="description">`. Steps are named `step-1…N` and the container's `active` is the step flagged `active` (last wins), else the first incomplete step, else the last. Container params: `horizontal`/`vertical`/`auto` → `orientation`, `label:"…"` → `label` (HTML-escaped). Interactivity (`clickable`, `linear`, step invokers) is intentionally omitted — the steps have no content panels to navigate between. The `>>>>>>` fence never collides with the `^>>>$` separator of details/dialog/popover/tooltip/random-content. Plain-Markdown degrade: an ordered task list keeping `[x]`/`[ ]`, the current step in bold, and descriptions as indented continuation lines.
15
+ - Both run **first** in the pipeline (right after code-block protection, before layouts), so a divider or stepper can sit inside layouts, cards, callouts, tabs, accordion and dialog bodies — e.g. `--- vertical vs ---` between two buttons in a `::::cluster`. Same position in `PlainMarkdownRenderer::PIPELINE` (new `:divider` / `:stepper` override keys).
16
+ - Manifest coverage now also guards `wa-divider` `orientation`/`label-placement`, `wa-stepper` `orientation` and `wa-step` `variant`/`attention` (`DIVIDER_ATTRIBUTES`, `STEPPER_ATTRIBUTES`, `STEP_ATTRIBUTES`).
17
+
18
+ ### Internal
19
+
20
+ - **Refreshed the Web Awesome manifest fixture to 3.14.0** (September 24th, 2026; covers 3.13.0 too). `rake wa:manifest[3.14.0]` regenerated `spec/fixtures/webawesome-enums.json` and `WA_VERSION` moved to `3.14.0`. The diff is **purely additive** — three new tags (`wa-step`, `wa-stepper`, `wa-tag-input`) and a `label-placement` enum on `wa-divider` — with **zero DRIFT and zero GAP** against the enums we accept, so no transformer constant changed. `<wa-accordion>` and `<wa-random-content>` are now **stable** in Web Awesome, so the "experimental" wording was dropped from their transformer comments. Fixture remains byte-identical to `markawesome-js`'s copy. Example-site CDN pins bumped to 3.14.0 in `jekyll-webawesome` and `eleventy-plugin-webawesome`.
21
+
9
22
  ## [0.19.0] - 2026-08-26
10
23
 
11
24
  ### Fixed
data/README.md CHANGED
@@ -25,9 +25,11 @@ Used as the transformation engine for the [jekyll-webawesome](https://github.com
25
25
  | **Copy Button** | `<<<placement? tooltip:full\|copy\|none?` | `:::wa-copy-button placement? tooltip:full\|copy\|none?` | `<wa-copy-button value="content" tooltip-placement="top" tooltip="copy"></wa-copy-button>` |
26
26
  | **Details** | `^^^appearance? icon-placement?` | `:::wa-details appearance? icon-placement?` | `<wa-details>content</wa-details>` |
27
27
  | **Dialog** | `???params?` | `:::wa-dialog params?` | `<wa-dialog>` with trigger button and content |
28
+ | **Divider** | `--- label ---` (e.g. `--- start icon:star New ---`) | `:::wa-divider params?` (body is the label) | `<wa-divider label-placement="start"><wa-icon name="star"></wa-icon> New</wa-divider>` |
28
29
  | **Icon** | `$$$icon-name` | `:::wa-icon icon-name` | `<wa-icon name="icon-name"></wa-icon>` |
29
30
  | **Image Dialog** | `![alt](url)` | — | Wraps images in clickable `<wa-dialog>` overlays |
30
31
  | **Popover** | `&&&params?` or inline `&&&trigger >>> content&&&` | `:::wa-popover params?` | `<wa-popover>` with trigger button and content |
32
+ | **Stepper** | `>>>>>> params?` wrapping a task list | `:::wa-stepper params?` | `<wa-stepper active="step-2"><wa-step name="step-1" completed>…</wa-step>…</wa-stepper>` |
31
33
  | **Tab Group** | `++++++` | `:::wa-tabs` | `<wa-tab-group><wa-tab>content</wa-tab></wa-tab-group>` |
32
34
  | **Tag** | `@@@brand` | `:::wa-tag brand` | `<wa-tag variant="brand">content</wa-tag>` |
33
35
 
@@ -38,6 +40,22 @@ Used as the transformation engine for the [jekyll-webawesome](https://github.com
38
40
  > listener (e.g. a single global handler that removes `event.target`). The markup
39
41
  > we emit is valid either way.
40
42
 
43
+ > **Labeled divider:** `--- label ---` needs text between the mirrored dashes,
44
+ > so a plain `---` stays an `<hr>`. Leading `start`/`center`/`end`
45
+ > (label placement), `horizontal`/`vertical` (orientation) and `icon:name`
46
+ > tokens are consumed from the left; the rest is the label, as inline Markdown.
47
+ > A line made only of `|`, `:` and `-` (a pipe-less table separator) is left
48
+ > alone. Use `:::wa-divider` when a label must start with one of those words.
49
+
50
+ > **Stepper (display-only):** each unindented list line is a step. `[x]` marks
51
+ > it completed; leading `active`, `loading`, `disabled`, a variant, an attention
52
+ > (`pulse`/`bounce`/`none`) and `icon:name` are flags; lines indented under a
53
+ > step become its description. The active step is the one flagged `active`,
54
+ > else the first incomplete step, else the last. Container params are
55
+ > `horizontal`/`vertical`/`auto` and `label:"…"`. `wa-stepper` is experimental
56
+ > in Web Awesome 3.14.0, and its interactive features (`clickable`, `linear`)
57
+ > are deliberately not exposed.
58
+
41
59
  ## Layout Utilities
42
60
 
43
61
  Layout utilities use `::::` (quadruple colon) syntax to wrap content in CSS layout containers. Inner content is not markdown-converted, so component `:::` syntax inside layouts works normally.
@@ -25,9 +25,9 @@ module Markawesome
25
25
  # component without forking the gem.
26
26
  #
27
27
  # @param component [Symbol] one of :accordion, :callout, :badge, :button,
28
- # :card, :carousel, :comparison, :copy_button, :details, :dialog, :icon,
29
- # :image_dialog, :layout, :popover, :random_content, :tabs, :tag,
30
- # :tooltip.
28
+ # :card, :carousel, :comparison, :copy_button, :details, :dialog,
29
+ # :divider, :icon, :image_dialog, :layout, :popover, :random_content,
30
+ # :stepper, :tabs, :tag, :tooltip, :tree.
31
31
  # @yield [content, options] Proc that receives the full source content
32
32
  # and the renderer options; returns the content with that component
33
33
  # syntax replaced.
@@ -44,6 +44,8 @@ module Markawesome
44
44
  end
45
45
 
46
46
  PIPELINE = %i[
47
+ divider
48
+ stepper
47
49
  layout
48
50
  popover
49
51
  tooltip
@@ -68,6 +70,8 @@ module Markawesome
68
70
  ].freeze
69
71
 
70
72
  TRANSFORMER_MAP = {
73
+ divider: DividerTransformer,
74
+ stepper: StepperTransformer,
71
75
  layout: LayoutTransformer,
72
76
  popover: PopoverTransformer,
73
77
  tooltip: TooltipTransformer,
@@ -10,6 +10,13 @@ module Markawesome
10
10
  def self.process(content, options = {})
11
11
  content, tokens = CodeBlockProtector.protect(content)
12
12
 
13
+ # Divider and stepper run FIRST: their content is inline-only (a label,
14
+ # a list of one-line steps), so emitting them before any container lets
15
+ # them sit inside layouts, cards, callouts, tabs, accordion and dialog
16
+ # bodies — e.g. `--- vertical vs ---` inside a `::::cluster`.
17
+ content = DividerTransformer.transform(content)
18
+ content = StepperTransformer.transform(content)
19
+
13
20
  content = LayoutTransformer.transform(content)
14
21
  content = PopoverTransformer.transform(content)
15
22
  content = TooltipTransformer.transform(content)
@@ -23,7 +23,7 @@ module Markawesome
23
23
  # - expanded -> expanded; disabled -> disabled
24
24
  # - icon:name -> <wa-icon slot="icon" name="name"></wa-icon> as first child
25
25
  #
26
- # wa-accordion is experimental in Web Awesome (added 3.7). expanded/disabled
26
+ # wa-accordion was added in Web Awesome 3.7 (stable since 3.13). expanded/disabled
27
27
  # and the mode/appearance/icon-placement attributes are all static-safe.
28
28
  class AccordionTransformer < BaseTransformer
29
29
  CONTAINER_ATTRIBUTES = {
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base_transformer'
4
+ require_relative '../attribute_parser'
5
+ require_relative '../icon_slot_parser'
6
+
7
+ module Markawesome
8
+ # Transforms labeled-divider syntax into <wa-divider> elements with a label in
9
+ # the default slot (Web Awesome 3.13.0+).
10
+ #
11
+ # Primary syntax (one line, mirrored dashes):
12
+ # --- or ---
13
+ # --- start Release notes ---
14
+ # --- end icon:star New ---
15
+ # --- icon:quote-left ---
16
+ # --- vertical vs ---
17
+ # Alternative syntax (the body is the label, and may be empty):
18
+ # :::wa-divider start icon:star
19
+ # Release **notes**
20
+ # :::
21
+ #
22
+ # Leading tokens (consumed from the left until the first non-token word):
23
+ # - start, center, end -> label-placement
24
+ # - horizontal, vertical -> orientation
25
+ # - icon:name -> <wa-icon name="name"> before the label
26
+ # The rest of the line is the label, rendered as inline Markdown. To start a
27
+ # label with one of those words, use the alternative syntax.
28
+ #
29
+ # A plain `---` (and `--- ---`) is left alone and stays an <hr>. So is a line
30
+ # made only of `|`, `:`, `-` and whitespace (e.g. a pipe-less GFM table
31
+ # separator such as `--- | ---`).
32
+ class DividerTransformer < BaseTransformer
33
+ DIVIDER_ATTRIBUTES = {
34
+ orientation: %w[horizontal vertical],
35
+ label_placement: %w[start center end]
36
+ }.freeze
37
+
38
+ # Content slot: emits <wa-icon name="..."> with no slot attribute.
39
+ ICON_SLOTS = {
40
+ default: 'content',
41
+ slots: %w[content],
42
+ slot_map: { 'content' => 'content' }
43
+ }.freeze
44
+
45
+ PRIMARY_REGEX = /^---[ \t]+(\S[^\n]*?)[ \t]+---[ \t]*$/
46
+ ALTERNATIVE_REGEX = /^:::wa-divider[ \t]*([^\n]*)\n(?:(.*?)\n)?:::[ \t]*$/m
47
+ TABLE_SEPARATOR_REGEX = /\A[|:\-\s]*\z/
48
+
49
+ def self.transform(content)
50
+ content = content.gsub(PRIMARY_REGEX) do |match|
51
+ inner = Regexp.last_match(1)
52
+ next match if inner.match?(TABLE_SEPARATOR_REGEX)
53
+
54
+ lead, label = split_leading_tokens(inner)
55
+ build_html(lead, label)
56
+ end
57
+
58
+ content.gsub(ALTERNATIVE_REGEX) do
59
+ params_string = Regexp.last_match(1)
60
+ body = Regexp.last_match(2).to_s
61
+ build_html(params_string, body.strip)
62
+ end
63
+ end
64
+
65
+ # Degrade to a thematic break followed by the label as its own paragraph
66
+ # (icon dropped). The leading blank line stops `---` from turning a
67
+ # preceding paragraph line into a setext heading.
68
+ def self.render_as_markdown(content, _options = {})
69
+ content = content.gsub(PRIMARY_REGEX) do |match|
70
+ inner = Regexp.last_match(1)
71
+ next match if inner.match?(TABLE_SEPARATOR_REGEX)
72
+
73
+ _lead, label = split_leading_tokens(inner)
74
+ markdown_break(label)
75
+ end
76
+
77
+ content.gsub(ALTERNATIVE_REGEX) do
78
+ markdown_break(Regexp.last_match(2).to_s.strip)
79
+ end
80
+ end
81
+
82
+ class << self
83
+ private
84
+
85
+ # Consume leading placement/orientation/icon tokens; the rest is the label.
86
+ def split_leading_tokens(inner)
87
+ tokens = inner.strip.split(/\s+/)
88
+ lead = []
89
+ lead << tokens.shift while tokens.any? && leading_token?(tokens.first)
90
+ [lead.join(' '), tokens.join(' ')]
91
+ end
92
+
93
+ def leading_token?(token)
94
+ token.start_with?('icon:') || DIVIDER_ATTRIBUTES.values.any? { |values| values.include?(token) }
95
+ end
96
+
97
+ def build_html(params_string, label)
98
+ attributes = AttributeParser.parse(params_string, DIVIDER_ATTRIBUTES)
99
+ icon_result = IconSlotParser.parse(params_string, ICON_SLOTS)
100
+
101
+ attr_parts = []
102
+ attr_parts << "orientation=\"#{attributes[:orientation]}\"" if attributes[:orientation]
103
+ attr_parts << "label-placement=\"#{attributes[:label_placement]}\"" if attributes[:label_placement]
104
+ attrs_string = attr_parts.empty? ? '' : " #{attr_parts.join(' ')}"
105
+
106
+ icon_html = IconSlotParser.to_html(icon_result[:icons], ICON_SLOTS[:slot_map])
107
+ label_html = render_inline(label)
108
+ separator = !icon_html.empty? && !label_html.empty? ? ' ' : ''
109
+
110
+ "<wa-divider#{attrs_string}>#{icon_html}#{separator}#{label_html}</wa-divider>"
111
+ end
112
+
113
+ # Inline Markdown: render, then drop the wrapping <p> (the badge idiom).
114
+ def render_inline(text)
115
+ return '' if text.empty?
116
+
117
+ markdown_to_html(text).strip.sub(%r{\A<p>(.*)</p>\z}m, '\1')
118
+ end
119
+
120
+ def markdown_break(label)
121
+ label.empty? ? "\n---" : "\n---\n\n#{label}\n"
122
+ end
123
+ end
124
+ end
125
+ end
@@ -4,7 +4,7 @@ require_relative 'base_transformer'
4
4
  require_relative '../attribute_parser'
5
5
 
6
6
  module Markawesome
7
- # Transforms random-content syntax into Web Awesome's experimental
7
+ # Transforms random-content syntax into Web Awesome's
8
8
  # <wa-random-content> element, which shows one or more of its direct element
9
9
  # children at random (optionally rotating them) and hides the rest — all in
10
10
  # WA's own runtime, so the author writes zero JavaScript. Ideal for a "little
@@ -0,0 +1,201 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base_transformer'
4
+ require_relative '../attribute_parser'
5
+ require_relative '../icon_slot_parser'
6
+
7
+ module Markawesome
8
+ # Transforms stepper syntax into a display-only <wa-stepper> / <wa-step>
9
+ # progress indicator, written as a Markdown task list.
10
+ #
11
+ # Primary syntax:
12
+ # >>>>>> vertical label:"Checkout progress"
13
+ # - [x] Cart
14
+ # - [x] Shipping
15
+ # Standard, 3–5 days
16
+ # - [ ] pulse icon:credit-card Payment
17
+ # - [ ] Review
18
+ # >>>>>>
19
+ # Alternative syntax: :::wa-stepper params? ...same list... :::
20
+ #
21
+ # Container params:
22
+ # - horizontal, vertical, auto -> orientation
23
+ # - label:"text" -> label (accessible name)
24
+ # Steps are unindented list lines (`-`, `*` or `+`):
25
+ # - [x] / [X] marks the step completed; [ ] or no box means not completed
26
+ # - leading flags: active, loading, disabled, a variant (neutral, brand,
27
+ # success, warning, danger), an attention (none, pulse, bounce), and
28
+ # icon:name (slotted into the step's icon slot)
29
+ # - the rest of the line is the label, rendered as inline Markdown
30
+ # - lines indented by two or more spaces under a step are joined into its
31
+ # description slot, rendered as inline Markdown
32
+ #
33
+ # Steps are named step-1..N and the container's `active` points at the step
34
+ # flagged `active` (last one wins), else the first incomplete step, else the
35
+ # last step. Interactivity (`clickable`, `linear`, step invokers) is omitted
36
+ # on purpose: these steps have no content panels, so there is nothing to
37
+ # navigate between without app JavaScript.
38
+ class StepperTransformer < BaseTransformer
39
+ STEPPER_ATTRIBUTES = {
40
+ orientation: %w[horizontal vertical auto]
41
+ }.freeze
42
+
43
+ STEP_ATTRIBUTES = {
44
+ variant: %w[neutral brand success warning danger],
45
+ attention: %w[none pulse bounce]
46
+ }.freeze
47
+
48
+ STEP_FLAGS = %w[active loading disabled].freeze
49
+
50
+ ICON_SLOTS = {
51
+ default: 'icon',
52
+ slots: %w[icon],
53
+ slot_map: { 'icon' => 'icon' }
54
+ }.freeze
55
+
56
+ PRIMARY_REGEX = /^>{6}([^\n]*)\n(.*?)\n>{6}[ \t]*$/m
57
+ ALTERNATIVE_REGEX = /^:::wa-stepper[ \t]*([^\n]*)\n(.*?)\n:::[ \t]*$/m
58
+ LABEL_REGEX = /label:(?:"([^"]*)"|'([^']*)')/
59
+ STEP_LINE_REGEX = /\A[-*+][ \t]+(.*)\z/
60
+ CONTINUATION_REGEX = /\A[ \t]{2,}(\S.*)\z/
61
+ CHECKBOX_REGEX = /\A\[([ xX])\](?:[ \t]+(.*))?\z/
62
+
63
+ def self.transform(content)
64
+ transform_proc = proc do |params_string, body|
65
+ label, params_string = extract_label(params_string.to_s)
66
+ attributes = AttributeParser.parse(params_string, STEPPER_ATTRIBUTES)
67
+ steps = parse_steps(body)
68
+ active = active_index(steps)
69
+
70
+ attr_parts = []
71
+ attr_parts << "orientation=\"#{attributes[:orientation]}\"" if attributes[:orientation]
72
+ attr_parts << "label=\"#{escape_html(label)}\"" unless label.empty?
73
+ attr_parts << "active=\"step-#{active + 1}\"" if active
74
+ attrs_string = attr_parts.empty? ? '' : " #{attr_parts.join(' ')}"
75
+
76
+ steps_html = steps.each_with_index.map { |step, index| build_step(step, index) }.join
77
+ "<wa-stepper#{attrs_string}>#{steps_html}</wa-stepper>"
78
+ end
79
+
80
+ patterns = dual_syntax_patterns(PRIMARY_REGEX, ALTERNATIVE_REGEX, transform_proc)
81
+ apply_multiple_patterns(content, patterns)
82
+ end
83
+
84
+ # Degrade to an ordered task list: completed steps keep [x], the current
85
+ # step is bold, and a description becomes an indented continuation line.
86
+ def self.render_as_markdown(content, _options = {})
87
+ transform_proc = proc do |_params_string, body|
88
+ steps = parse_steps(body)
89
+ active = active_index(steps)
90
+
91
+ steps.each_with_index.map do |step, index|
92
+ marker = "#{index + 1}. "
93
+ label = index == active && !step[:label].empty? ? "**#{step[:label]}**" : step[:label]
94
+ line = "#{marker}[#{step[:completed] ? 'x' : ' '}]"
95
+ line += " #{label}" unless label.empty?
96
+ line += "\n#{' ' * marker.length}#{step[:description]}" unless step[:description].empty?
97
+ line
98
+ end.join("\n")
99
+ end
100
+
101
+ patterns = dual_syntax_patterns(PRIMARY_REGEX, ALTERNATIVE_REGEX, transform_proc)
102
+ apply_multiple_patterns(content, patterns)
103
+ end
104
+
105
+ class << self
106
+ private
107
+
108
+ # Pull out label:"…" (or label:'…') before the bare tokens are parsed, so
109
+ # words inside the label can't be read as orientation tokens.
110
+ def extract_label(params_string)
111
+ match = LABEL_REGEX.match(params_string)
112
+ return ['', params_string] unless match
113
+
114
+ [(match[1] || match[2]).strip, params_string.sub(LABEL_REGEX, ' ')]
115
+ end
116
+
117
+ def parse_steps(body)
118
+ steps = []
119
+ body.to_s.each_line do |line|
120
+ line = line.chomp
121
+ if (match = STEP_LINE_REGEX.match(line))
122
+ steps << parse_step(match[1])
123
+ elsif (match = CONTINUATION_REGEX.match(line)) && steps.any?
124
+ steps.last[:description_lines] << match[1].strip
125
+ end
126
+ end
127
+ steps.each { |step| step[:description] = step.delete(:description_lines).join(' ') }
128
+ end
129
+
130
+ def parse_step(raw)
131
+ completed = false
132
+ if (match = CHECKBOX_REGEX.match(raw.strip))
133
+ completed = match[1] != ' '
134
+ raw = match[2].to_s
135
+ end
136
+
137
+ tokens = raw.strip.split(/\s+/)
138
+ lead = []
139
+ lead << tokens.shift while tokens.any? && leading_token?(tokens.first)
140
+ lead_string = lead.join(' ')
141
+
142
+ {
143
+ completed: completed,
144
+ flags: lead & STEP_FLAGS,
145
+ attributes: AttributeParser.parse(lead_string, STEP_ATTRIBUTES),
146
+ icons: IconSlotParser.parse(lead_string, ICON_SLOTS)[:icons],
147
+ label: tokens.join(' '),
148
+ description_lines: []
149
+ }
150
+ end
151
+
152
+ def leading_token?(token)
153
+ token.start_with?('icon:') ||
154
+ STEP_FLAGS.include?(token) ||
155
+ STEP_ATTRIBUTES.values.any? { |values| values.include?(token) }
156
+ end
157
+
158
+ # The explicitly active step (last wins), else the first incomplete one,
159
+ # else the last step; nil when there are no steps.
160
+ def active_index(steps)
161
+ return nil if steps.empty?
162
+
163
+ explicit = steps.rindex { |step| step[:flags].include?('active') }
164
+ return explicit if explicit
165
+
166
+ steps.index { |step| !step[:completed] } || (steps.length - 1)
167
+ end
168
+
169
+ def build_step(step, index)
170
+ attr_parts = ["name=\"step-#{index + 1}\""]
171
+ attr_parts << 'completed' if step[:completed]
172
+ attr_parts << 'loading' if step[:flags].include?('loading')
173
+ attr_parts << 'disabled' if step[:flags].include?('disabled')
174
+ attr_parts << "variant=\"#{step[:attributes][:variant]}\"" if step[:attributes][:variant]
175
+ attr_parts << "attention=\"#{step[:attributes][:attention]}\"" if step[:attributes][:attention]
176
+
177
+ icon_html = IconSlotParser.to_html(step[:icons], ICON_SLOTS[:slot_map])
178
+ description = render_inline(step[:description])
179
+ description_html = description.empty? ? '' : "<span slot=\"description\">#{description}</span>"
180
+
181
+ "<wa-step #{attr_parts.join(' ')}>#{icon_html}#{render_inline(step[:label])}#{description_html}</wa-step>"
182
+ end
183
+
184
+ # Inline Markdown: render, then drop the wrapping <p> (the badge idiom).
185
+ def render_inline(text)
186
+ return '' if text.empty?
187
+
188
+ markdown_to_html(text).strip.sub(%r{\A<p>(.*)</p>\z}m, '\1')
189
+ end
190
+
191
+ def escape_html(text)
192
+ text.to_s
193
+ .gsub('&', '&amp;')
194
+ .gsub('<', '&lt;')
195
+ .gsub('>', '&gt;')
196
+ .gsub('"', '&quot;')
197
+ .gsub("'", '&#39;')
198
+ end
199
+ end
200
+ end
201
+ end
@@ -15,11 +15,13 @@ require_relative 'transformers/copy_button_transformer'
15
15
  require_relative 'transformers/date_transformer'
16
16
  require_relative 'transformers/details_transformer'
17
17
  require_relative 'transformers/dialog_transformer'
18
+ require_relative 'transformers/divider_transformer'
18
19
  require_relative 'transformers/icon_transformer'
19
20
  require_relative 'transformers/image_dialog_transformer'
20
21
  require_relative 'transformers/layout_transformer'
21
22
  require_relative 'transformers/popover_transformer'
22
23
  require_relative 'transformers/random_content_transformer'
24
+ require_relative 'transformers/stepper_transformer'
23
25
  require_relative 'transformers/tabs_transformer'
24
26
  require_relative 'transformers/tag_transformer'
25
27
  require_relative 'transformers/tooltip_transformer'
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Markawesome
4
- VERSION = '0.19.0'
4
+ VERSION = '0.20.0'
5
5
  end
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.19.0
4
+ version: 0.20.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Janne Waren
@@ -96,11 +96,13 @@ files:
96
96
  - lib/markawesome/transformers/date_transformer.rb
97
97
  - lib/markawesome/transformers/details_transformer.rb
98
98
  - lib/markawesome/transformers/dialog_transformer.rb
99
+ - lib/markawesome/transformers/divider_transformer.rb
99
100
  - lib/markawesome/transformers/icon_transformer.rb
100
101
  - lib/markawesome/transformers/image_dialog_transformer.rb
101
102
  - lib/markawesome/transformers/layout_transformer.rb
102
103
  - lib/markawesome/transformers/popover_transformer.rb
103
104
  - lib/markawesome/transformers/random_content_transformer.rb
105
+ - lib/markawesome/transformers/stepper_transformer.rb
104
106
  - lib/markawesome/transformers/tabs_transformer.rb
105
107
  - lib/markawesome/transformers/tag_transformer.rb
106
108
  - lib/markawesome/transformers/tooltip_transformer.rb
@@ -130,7 +132,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
130
132
  - !ruby/object:Gem::Version
131
133
  version: '0'
132
134
  requirements: []
133
- rubygems_version: 4.0.10
135
+ rubygems_version: 4.0.20
134
136
  specification_version: 4
135
137
  summary: Framework-agnostic Markdown to Web Awesome component transformer
136
138
  test_files: []