markdowndocs 0.10.0 → 0.11.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: 6ca89d7b3d1decf28b07cfaccfd1e2e0e0924f8ef7d56d1374e3cb600cbd4933
4
- data.tar.gz: 036b99af3190b230d1ceb327171300758b76d09392a4d28b32a9a0129b9cdaf3
3
+ metadata.gz: 4066fc2cf3c03c9f743aaaab41c62611b5206ef9d0dad6cdead66c02f39eba29
4
+ data.tar.gz: 9594a84833fca33b4ec4d4a6c81efd1cc21d28e57fddca30f1f4765073ced9bb
5
5
  SHA512:
6
- metadata.gz: 80f8fb1ad69d4e83407943a1655a7da909d3704ce950ccb3e01a01a515aa3b7a96804e3ae93ceea7ed2cace9497267d750010a2c6fd05b56db27abc89f597432
7
- data.tar.gz: 7b7a5ba65d0e5e549811734b03aed0bcc5d52b0c13b768f5e06599162b367998f7d4f7294fe7af2a37d82924ce1826e7e65fbfa39b616bf97828f6b68f83fe2a
6
+ metadata.gz: 82e59acd421e1b32d0739167035ec770049ac0d27e1e5f00e7f3a9df5a01df00a7419be05443f9ae1ac45110eba1ad23fc0ccc73daf5c56388b2d1d867676d2e
7
+ data.tar.gz: 96b3a5cefdde9a74e349111f33b7f33106e1587d3e1cbeef911a2cdafb0588d3ba43b0dd7cdb591c88256a4d151ecc44e076a0c87d009121cf200b62ee1f21da
data/CHANGELOG.md CHANGED
@@ -5,6 +5,24 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.11.0] - 2026-07-13
9
+
10
+ ### Accessibility
11
+
12
+ - **Keyboard-scrollable tables (WCAG 2.1.1).** A wide GFM table overflows and
13
+ becomes horizontally scrollable via the host's typography CSS. The renderer
14
+ now marks every `<table>` with `tabindex="0"` so keyboard-only users can
15
+ scroll it with the arrow keys (axe `scrollable-region-focusable`). The
16
+ table's implicit `role="table"` is preserved — no `role="region"` is added,
17
+ which would strip row/column semantics — and an un-captioned table gets a
18
+ minimal `aria-label="Table"` so the focus stop is announced. `tabindex` is
19
+ now in the sanitizer's base attribute allow-list.
20
+ - **44px chrome target sizes (WCAG 2.5.5 AAA).** Sidebar table-of-contents
21
+ links, related-documentation links, breadcrumb links, and the audience
22
+ mode-switcher buttons now meet the 44×44 minimum target size (they measured
23
+ ~20–28px). Purely additive utility classes; no visual change beyond the
24
+ taller hit area.
25
+
8
26
  ## [0.10.0] - 2026-06-24
9
27
 
10
28
  ### Added
@@ -48,7 +48,7 @@ module Markdowndocs
48
48
  options = markdown_render_options
49
49
  doc = Commonmarker.parse(markdown, options: options)
50
50
  html = doc.to_html(options: options)
51
- html = apply_syntax_highlighting(html)
51
+ html = post_process_html(html)
52
52
  sanitize_html(html)
53
53
  rescue => e
54
54
  # Bare rescue is intentional: third-party errors from commonmarker,
@@ -66,7 +66,7 @@ module Markdowndocs
66
66
  %(<pre class="markdowndocs-render-error">#{escaped}</pre>)
67
67
  end
68
68
 
69
- def apply_syntax_highlighting(html)
69
+ def post_process_html(html)
70
70
  # HTML5 parsing preserves case-sensitive SVG/MathML foreign-content
71
71
  # attributes (e.g. viewBox) that Nokogiri::HTML would lowercase.
72
72
  doc = Nokogiri::HTML5.fragment(html)
@@ -84,9 +84,37 @@ module Markdowndocs
84
84
  end
85
85
  end
86
86
 
87
+ mark_tables_keyboard_accessible(doc)
88
+
87
89
  doc.to_html
88
90
  end
89
91
 
92
+ # A wide GFM table overflows its column and becomes horizontally
93
+ # scrollable — via the host's typography/prose CSS, which the engine
94
+ # does not control and cannot inspect at render time. A scrollable
95
+ # region that isn't keyboard-focusable strands keyboard-only users
96
+ # (WCAG 2.1.1; axe `scrollable-region-focusable`).
97
+ #
98
+ # `tabindex="0"` directly on the <table> makes it focusable so a
99
+ # keyboard user can scroll it with the arrow keys, whether the host CSS
100
+ # scrolls the table itself or a wrapper. We deliberately do NOT add
101
+ # `role="region"`: on a <table> that would override the implicit
102
+ # `role="table"` and strip row/column semantics from screen readers.
103
+ # A <caption> already names the table for AT; when absent we add a
104
+ # minimal aria-label so the focus stop is announced. The focus ring is
105
+ # the user-agent default (no engine CSS suppresses it).
106
+ #
107
+ # Trade-off: every table becomes a tab stop, not only the ones that
108
+ # actually overflow — scroll state is unknowable without a browser, and
109
+ # a static (JS-free) engine fix is worth that small amount of extra tab
110
+ # travel.
111
+ def mark_tables_keyboard_accessible(doc)
112
+ doc.css("table").each do |table|
113
+ table["tabindex"] = "0"
114
+ table["aria-label"] = "Table" unless table.at_css("caption") || table["aria-label"]
115
+ end
116
+ end
117
+
90
118
  def lexer_exists?(language)
91
119
  Rouge::Lexer.find(language).present?
92
120
  rescue
@@ -131,6 +159,7 @@ module Markdowndocs
131
159
  href title src alt align class lang
132
160
  role aria-label aria-labelledby aria-describedby aria-hidden
133
161
  open
162
+ tabindex
134
163
  ].freeze
135
164
 
136
165
  # Curated structural SVG subset. Deliberately excludes script,
@@ -159,7 +188,7 @@ module Markdowndocs
159
188
  transform opacity text-anchor dominant-baseline
160
189
  font-size font-family font-weight
161
190
  marker-start marker-end markerWidth markerHeight refX refY orient
162
- id xmlns focusable tabindex
191
+ id xmlns focusable
163
192
  ].freeze
164
193
 
165
194
  def sanitize_html(html)
@@ -19,7 +19,8 @@
19
19
  <% if item[:current] %>
20
20
  <span class="font-medium text-gray-900 dark:text-slate-100" aria-current="page"><%= item[:name] %></span>
21
21
  <% elsif item[:path] %>
22
- <%= link_to item[:name], item[:path], class: "hover:text-indigo-700 dark:hover:text-indigo-300 transition-colors" %>
22
+ <%# inline-flex min-h-11 (44px) meets WCAG 2.5.5 AAA target size. %>
23
+ <%= link_to item[:name], item[:path], class: "hover:text-indigo-700 dark:hover:text-indigo-300 transition-colors inline-flex min-h-11 items-center" %>
23
24
  <% else %>
24
25
  <span class="text-gray-700 dark:text-slate-300"><%= item[:name] %></span>
25
26
  <% end %>
@@ -21,7 +21,9 @@
21
21
  aria-pressed="<%= current_mode == mode %>"
22
22
  data-mode="<%= mode %>"
23
23
  data-action="click->docs-mode#rememberFocus"
24
- class="px-3 py-1.5 text-sm font-medium rounded-md border transition-colors <%= (current_mode == mode) ? 'border-cyan-500 bg-cyan-50 text-cyan-900 dark:bg-cyan-900/40 dark:border-cyan-400 dark:text-cyan-100' : 'border-slate-200 text-slate-700 hover:bg-slate-50 dark:border-slate-700 dark:text-slate-300 dark:hover:bg-slate-700' %>"
24
+ <%# inline-flex min-h-11 (44px) meets WCAG 2.5.5 AAA target size the
25
+ toggle buttons measured ~28px tall. %>
26
+ class="inline-flex min-h-11 items-center justify-center px-3 py-1.5 text-sm font-medium rounded-md border transition-colors <%= (current_mode == mode) ? 'border-cyan-500 bg-cyan-50 text-cyan-900 dark:bg-cyan-900/40 dark:border-cyan-400 dark:text-cyan-100' : 'border-slate-200 text-slate-700 hover:bg-slate-50 dark:border-slate-700 dark:text-slate-300 dark:hover:bg-slate-700' %>"
25
27
  >
26
28
  <%= t("markdowndocs.modes.#{mode}", default: mode.titleize) %>
27
29
  </button>
@@ -7,7 +7,10 @@
7
7
  <ul class="space-y-2">
8
8
  <% toc_items.each do |item| %>
9
9
  <li class="<%= 'ml-4' if item[:level] == 3 %>">
10
- <a href="#<%= item[:slug] %>" class="text-sm text-gray-700 dark:text-slate-300 hover:text-indigo-700 dark:hover:text-indigo-300 transition-colors block py-1">
10
+ <%# min-h-11 (44px) meets WCAG 2.5.5 AAA target size sidebar TOC links
11
+ measured ~20px. flex + items-center keeps the label vertically
12
+ centered in the taller hit area. %>
13
+ <a href="#<%= item[:slug] %>" class="text-sm text-gray-700 dark:text-slate-300 hover:text-indigo-700 dark:hover:text-indigo-300 transition-colors flex min-h-11 items-center">
11
14
  <%= item[:text] %>
12
15
  </a>
13
16
  </li>
@@ -23,7 +26,8 @@
23
26
  <ul class="space-y-3">
24
27
  <% related_docs.each do |related_doc| %>
25
28
  <li>
26
- <%= link_to related_doc.title, markdowndocs.doc_path(related_doc.slug), class: "text-sm text-indigo-700 dark:text-indigo-300 hover:text-indigo-800 dark:hover:text-indigo-200 font-medium transition-colors" %>
29
+ <%# inline-flex min-h-11 (44px) meets WCAG 2.5.5 AAA target size. %>
30
+ <%= link_to related_doc.title, markdowndocs.doc_path(related_doc.slug), class: "text-sm text-indigo-700 dark:text-indigo-300 hover:text-indigo-800 dark:hover:text-indigo-200 font-medium transition-colors inline-flex min-h-11 items-center" %>
27
31
  <p class="text-xs text-gray-700 dark:text-slate-300 mt-1"><%= related_doc.description %></p>
28
32
  </li>
29
33
  <% end %>
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Markdowndocs
4
- VERSION = "0.10.0"
4
+ VERSION = "0.11.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: markdowndocs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dave Chmura
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2026-06-24 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: rails
@@ -115,7 +114,6 @@ metadata:
115
114
  homepage_uri: https://github.com/dschmura/markdowndocs
116
115
  source_code_uri: https://github.com/dschmura/markdowndocs
117
116
  changelog_uri: https://github.com/dschmura/markdowndocs/blob/main/CHANGELOG.md
118
- post_install_message:
119
117
  rdoc_options: []
120
118
  require_paths:
121
119
  - lib
@@ -130,8 +128,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
130
128
  - !ruby/object:Gem::Version
131
129
  version: '0'
132
130
  requirements: []
133
- rubygems_version: 3.4.19
134
- signing_key:
131
+ rubygems_version: 3.6.9
135
132
  specification_version: 4
136
133
  summary: A drop-in markdown documentation site for Rails apps
137
134
  test_files: []