asciidoctor-tabs 1.0.0.alpha.10 → 1.0.0.alpha.11

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 07f0dd2b889d4de8d8c69e590e6f491ba46921cd666cfa035a4d96aee505626b
4
- data.tar.gz: bee696a1b3f4e0cafa3ddf758cb43cec40c826f56c142a5fdb648346a13db8c2
3
+ metadata.gz: 7fabd40d3903b96a2982c4bb90a3a6d783fe55369bea21e06f98e4ec97a306bd
4
+ data.tar.gz: b6259434eb0eafd0c3c8a5a51bc1f786a111120fe68786ad21b4ad52b737412b
5
5
  SHA512:
6
- metadata.gz: 32166ea582c1644e3cc2d4da17158f1d9e21fafa5353d455bb116fb9601e0df1001dc308cfe2d75dec16bd612e92d7755c465c9f031927ce237578a890c9eae6
7
- data.tar.gz: dfca342f289480ae0c56ba93d00b9f36be79f175981b5ac9e827b81e25cd64be245ba527853c0e4562326df3be4ec11cc41617668214702f3aafe5b9d159c3ea
6
+ metadata.gz: 8990b67f318bbe16cb3441dadc8f8af8cbb78b4e8f31f53da1c4e8ef855e51eb458a024e1ed2886ceb66bc58bc38ab860c244e2a500bf13c43f87bf2b4212155
7
+ data.tar.gz: baca94e8a45013ef881a2a2bc689225225892d145a877a6ec51d7bb4cf697fb98ae7bdd57f516fa831170b9e8e7b6c1c60e0310a5f850ddefcb046225ba7077b
data/CHANGELOG.adoc CHANGED
@@ -4,6 +4,30 @@
4
4
  This document provides a curated view of the changes to Asciidoctor Tabs per release.
5
5
  For a detailed view of what has changed, refer to the {url-repo}/commits/main[commit history] on GitHub.
6
6
 
7
+ == 1.0.0-alpha.11 (2022-12-08) - @mojavelinux
8
+
9
+ === Changed
10
+
11
+ * *BREAKING CHANGE:* Align terminology with ARIA / Open UI recommendations for a tabs component; requires change to custom CSS (#38)
12
+ ** `.tabset` becomes `.tabs`
13
+ ** `.tabs` becomes `.tablist`
14
+ ** `.tab-panel` becomes `.tabpanel`
15
+ ** `.is-active` for selected tab becomes `.is-selected`
16
+ ** `.is-active` for visible panel becomes `:not(.is-hidden)`
17
+ * Assign ARIA attributes in JavaScript (i.e., role, aria-controls, aria-selected, hidden) where recommended (#38)
18
+ * *BREAKING CHANGE:* Convert tabs block to openblock instead of passthrough block (#15)
19
+ ** `openblock` class added to `.tabs`
20
+ ** `.tablist` becomes child of `.content`
21
+ ** `.tabpanel` elements become siblings of `.tablist`
22
+
23
+ === Fixed
24
+
25
+ * Clear margin on .tablist.ulist and child ul
26
+
27
+ === Details
28
+
29
+ {url-repo}/releases/tag/v1.0.0-alpha.11[git tag] | {url-repo}/compare/v1.0.0-alpha.10\...v1.0.0-alpha.11[full diff]
30
+
7
31
  == 1.0.0-alpha.10 (2022-12-08) - @mojavelinux
8
32
 
9
33
  === Fixed
data/README.adoc CHANGED
@@ -1,6 +1,6 @@
1
1
  = Asciidoctor Tabs
2
2
  Dan Allen <https://github.com/mojavelinux[@mojavelinux]>
3
- v1.0.0-alpha.10, 2022-12-08
3
+ v1.0.0-alpha.11, 2022-12-08
4
4
  :idprefix:
5
5
  :idseparator: -
6
6
  ifndef::env-github[:icons: font]
@@ -14,7 +14,8 @@ An Asciidoctor extension that adds a tabs block to the AsciiDoc syntax.
14
14
  NOTE: This extension is intended to be used with HTML backends (e.g., `html5`).
15
15
  For all other backends (i.e., the filetype is not html), the custom block enclosure is taken away and its contents (a dlist) is converted normally.
16
16
 
17
- TIP: This extension is also published as an npm package named `@asciidoctor/tabs` for use with Asciidoctor.js (and thus Antora).
17
+ TIP: This extension is also published as an npm package named `@asciidoctor/tabs` for use with Asciidoctor.js.
18
+ See the xref:js/README.adoc[README in the js folder] for details.
18
19
 
19
20
  == Overview
20
21
 
@@ -35,5 +35,5 @@ Gem::Specification.new do |s|
35
35
  s.add_runtime_dependency 'asciidoctor', ['>= 2.0.0', '< 3.0.0']
36
36
 
37
37
  s.add_development_dependency 'rake', '~> 13.0.0'
38
- s.add_development_dependency 'rspec', '~> 3.11.0'
38
+ s.add_development_dependency 'rspec', '~> 3.12.0'
39
39
  end
data/data/css/tabs.css CHANGED
@@ -1,17 +1,17 @@
1
1
  /*! Asciidoctor Tabs | Copyright (c) 2018-present Dan Allen | MIT License */
2
- .tabset {
2
+ .tabs {
3
3
  margin-bottom: 1.25em;
4
4
  }
5
5
 
6
- .tabs > ul {
6
+ .tablist > ul {
7
7
  display: flex;
8
8
  flex-wrap: wrap;
9
9
  list-style: none;
10
- margin: 0 -0.25em 0 0;
10
+ margin: 0;
11
11
  padding: 0;
12
12
  }
13
13
 
14
- .tabs > ul li {
14
+ .tablist > ul li {
15
15
  align-items: center;
16
16
  background-color: #fff;
17
17
  cursor: pointer;
@@ -22,26 +22,22 @@
22
22
  position: relative;
23
23
  }
24
24
 
25
- .tabs.ulist > ul li {
26
- margin: 0;
27
- }
28
-
29
- .tabs > ul p {
30
- line-height: inherit;
25
+ .tablist.ulist,
26
+ .tablist.ulist > ul li {
31
27
  margin: 0;
32
28
  }
33
29
 
34
- .tabs.ulist > ul li + li {
30
+ .tablist.ulist > ul li + li {
35
31
  margin-left: 0.25em;
36
32
  }
37
33
 
38
- .tabset.is-loading .tabs li:not(:first-child),
39
- .tabset:not(.is-loading) .tabs li:not(.is-active) {
34
+ .tabs.is-loading .tablist li:not(:first-child),
35
+ .tabs:not(.is-loading) .tablist li:not(.is-selected) {
40
36
  background-color: #f5f5f5;
41
37
  }
42
38
 
43
- .tabset.is-loading .tabs li:first-child::after,
44
- .tabset:not(.is-loading) .tabs li.is-active::after {
39
+ .tabs.is-loading .tablist li:first-child::after,
40
+ .tabs:not(.is-loading) .tablist li.is-selected::after {
45
41
  background-color: inherit;
46
42
  content: "";
47
43
  display: block;
@@ -52,37 +48,42 @@
52
48
  right: 0;
53
49
  }
54
50
 
55
- .tab-pane {
51
+ .tablist > ul p {
52
+ line-height: inherit;
53
+ margin: 0;
54
+ }
55
+
56
+ .tabpanel {
56
57
  background-color: #fff;
57
58
  padding: 1.25em;
58
59
  }
59
60
 
60
- .tab-pane > table.tableblock {
61
+ .tabpanel > table.tableblock {
61
62
  border-width: 0;
62
63
  display: block;
63
64
  overflow-x: auto;
64
65
  }
65
66
 
66
- .tabs > ul li,
67
- .tab-pane {
67
+ .tablist > ul li,
68
+ .tabpanel {
68
69
  border: 1px solid #dcdcdc;
69
70
  }
70
71
 
71
- .tabs > ul li {
72
+ .tablist > ul li {
72
73
  border-bottom: 0;
73
74
  }
74
75
 
75
- .tabset.is-loading .tab-pane:not(:first-child),
76
- .tabset:not(.is-loading) .tab-pane:not(.is-active) {
76
+ .tabs.is-loading .tabpanel:not(:first-child),
77
+ .tabs:not(.is-loading) .tabpanel.is-hidden {
77
78
  display: none;
78
79
  }
79
80
 
80
- .tab-pane > :first-child {
81
+ .tabpanel > :first-child {
81
82
  margin-top: 0;
82
83
  }
83
84
 
84
- #content .tab-pane > :last-child,
85
- #content .tab-pane > :last-child > :last-child,
86
- #content .tab-pane > :last-child > :last-child > li:last-child > :last-child {
85
+ #content .tabpanel > :last-child,
86
+ #content .tabpanel > :last-child > :last-child,
87
+ #content .tabpanel > :last-child > :last-child > li:last-child > :last-child {
87
88
  margin-bottom: 0;
88
89
  }
data/data/js/tabs.js CHANGED
@@ -3,26 +3,29 @@
3
3
 
4
4
  var forEach = Array.prototype.forEach
5
5
 
6
- init(document.querySelectorAll('.tabset'))
6
+ init(document.querySelectorAll('.tabs'))
7
7
 
8
- function init (tabsets) {
9
- if (!tabsets.length) return
10
- forEach.call(tabsets, function (tabset) {
11
- var tabs = tabset.querySelectorAll('.tabs li')
12
- var syncIds = tabset.classList.contains('is-sync') ? {} : undefined
13
- forEach.call(tabs, function (tab, idx) {
14
- var id = tab.id
15
- if (!id) {
16
- var anchor = tab.querySelector('a[id]')
17
- if (!anchor) return // invalid state
8
+ function init (tabsBlocks) {
9
+ if (!tabsBlocks.length) return
10
+ forEach.call(tabsBlocks, function (tabs) {
11
+ var syncIds = tabs.classList.contains('is-sync') ? {} : undefined
12
+ var tablist = tabs.querySelector('.tablist ul')
13
+ tablist.setAttribute('role', 'tablist')
14
+ forEach.call(tablist.querySelectorAll('li'), function (tab, idx) {
15
+ tab.setAttribute('role', (tab.className = 'tab')) // NOTE converter may not have set class on li
16
+ var id, anchor
17
+ if (!(id = tab.id)) {
18
+ if (!(anchor = tab.querySelector('a[id]'))) return // invalid state
18
19
  tab.id = id = anchor.parentNode.removeChild(anchor).id
19
20
  }
20
- tab.className = idx ? 'tab' : 'tab is-active'
21
- var pane = tabset.querySelector('.tab-pane[aria-labelledby~="' + id + '"]')
22
- if (!pane) return // invalid state
23
- if (!idx) pane.classList.add('is-active')
21
+ var panel = tabs.querySelector('.tabpanel[aria-labelledby~="' + id + '"]')
22
+ if (!panel) return // invalid state
23
+ tab.tabIndex = -1
24
+ tab.setAttribute('aria-controls', panel.id)
25
+ panel.setAttribute('role', 'tabpanel')
26
+ idx ? toggleHidden(panel, true) : toggleSelected(tab, true)
24
27
  var onClick = activateTab
25
- var instance = { tabset: tabset, tab: tab, pane: pane }
28
+ var instance = { tabs: tabs, tab: tab, panel: panel }
26
29
  var syncId
27
30
  if (syncIds && !((syncId = tab.textContent.trim()) in syncIds)) {
28
31
  syncIds[(tab.dataset.syncId = syncId)] = true
@@ -32,18 +35,21 @@
32
35
  })
33
36
  })
34
37
  onHashChange()
35
- forEach.call(tabsets, function (tabset) {
36
- tabset.classList.remove('is-loading')
38
+ forEach.call(tabsBlocks, function (tabs) {
39
+ tabs.classList.remove('is-loading')
37
40
  })
38
41
  window.addEventListener('hashchange', onHashChange)
39
42
  }
40
43
 
41
44
  function activateTab (e) {
42
45
  var tab = this.tab
43
- var tabset = this.tabset || (this.tabset = tab.closest('.tabset'))
44
- var pane = this.pane || tabset.querySelector('.tab-pane[aria-labelledby~="' + tab.id + '"]')
45
- forEach.call(tabset.querySelectorAll('.tabs li, .tab-pane'), function (el) {
46
- el === tab || el === pane ? el.classList.add('is-active') : el.classList.remove('is-active')
46
+ var tabs = this.tabs || (this.tabs = tab.closest('.tabs'))
47
+ var panel = this.panel || (this.panel = document.getElementById(tab.getAttribute('aria-controls')))
48
+ forEach.call(tabs.querySelectorAll('.tablist .tab'), function (el) {
49
+ toggleSelected(el, el === tab)
50
+ })
51
+ forEach.call(tabs.querySelectorAll('.tabpanel'), function (el) {
52
+ toggleHidden(el, el !== panel)
47
53
  })
48
54
  if (!e) return
49
55
  var loc = window.location
@@ -54,16 +60,26 @@
54
60
 
55
61
  function activateTabSync (e) {
56
62
  activateTab.call(this, e)
57
- var tabset = this.tabset
63
+ var tabs = this.tabs
58
64
  var thisTab = this.tab
59
- var initialY = tabset.getBoundingClientRect().y
60
- forEach.call(document.querySelectorAll('.tabs li'), function (tab) {
65
+ var initialY = tabs.getBoundingClientRect().y
66
+ forEach.call(document.querySelectorAll('.tabs .tablist .tab'), function (tab) {
61
67
  if (tab !== thisTab && tab.dataset.syncId === thisTab.dataset.syncId) activateTab.call({ tab: tab })
62
68
  })
63
- var shiftedBy = tabset.getBoundingClientRect().y - initialY
69
+ var shiftedBy = tabs.getBoundingClientRect().y - initialY
64
70
  if (shiftedBy && (shiftedBy = Math.round(shiftedBy))) window.scrollBy({ top: shiftedBy, behavior: 'instant' })
65
71
  }
66
72
 
73
+ function toggleHidden (el, state) {
74
+ el.classList.toggle('is-hidden', (el.hidden = state))
75
+ }
76
+
77
+ function toggleSelected (el, state) {
78
+ el.setAttribute('aria-selected', state)
79
+ el.classList.toggle('is-selected', state)
80
+ el.tabIndex = state ? 0 : -1
81
+ }
82
+
67
83
  function onHashChange () {
68
84
  var id = window.location.hash.slice(1)
69
85
  if (!id) return
@@ -9,38 +9,34 @@ module Asciidoctor
9
9
  def process parent, reader, attrs
10
10
  block = create_block parent, attrs['cloaked-context'], nil, attrs, content_model: :compound
11
11
  children = (parse_content block, reader).blocks
12
- return block unless children.size == 1 && (source_tabs = children[0]).context == :dlist && source_tabs.items?
12
+ return block unless children.size == 1 && (seed_tabs = children[0]).context == :dlist && seed_tabs.items?
13
13
  unless (doc = parent.document).attr? 'filetype', 'html'
14
- (id = attrs['id']) && (doc.register :refs, [(source_tabs.id = id), source_tabs]) unless source_tabs.id
15
- (reftext = attrs['reftext']) && (source_tabs.set_attr 'reftext', reftext) unless source_tabs.reftext?
16
- parent << source_tabs
14
+ (id = attrs['id']) && (doc.register :refs, [(seed_tabs.id = id), seed_tabs]) unless seed_tabs.id
15
+ (reftext = attrs['reftext']) && (seed_tabs.set_attr 'reftext', reftext) unless seed_tabs.reftext?
16
+ parent << seed_tabs
17
17
  return
18
18
  end
19
- tabset_number = doc.counter 'tabset-number'
20
- tabs_id = attrs['id'] || (generate_id %(tabset #{tabset_number}), doc)
19
+ tabs_number = doc.counter 'tabs-number'
20
+ tabs_id = attrs['id'] || (generate_id %(tabs #{tabs_number}), doc)
21
21
  sync = !(block.option? 'nosync') && ((block.option? 'sync') || (doc.option? 'tabs-sync')) ? ' is-sync' : nil
22
- parent << (create_html_fragment parent, %(<div id="#{tabs_id}" class="tabset#{sync || ''} is-loading">))
23
- if (title = attrs['title'])
24
- parent << (create_html_fragment parent, %(<div class="title">#{parent.apply_subs title}</div>))
25
- end
26
- tabs = create_list parent, :ulist
27
- tabs.add_role 'tabs'
22
+ tabs = create_open_block parent, nil, { 'id' => tabs_id, 'role' => %(tabs#{sync || ''} is-loading) }
23
+ tabs.title = attrs['title']
24
+ tablist = create_list parent, :ulist, { 'role' => 'tablist' }
28
25
  panes = {}
29
26
  set_id_on_tab = (doc.backend == 'html5') || (list_item_supports_id? doc)
30
- source_tabs.items.each do |labels, content|
27
+ seed_tabs.items.each do |labels, content|
31
28
  tab_ids = labels.map do |tab|
32
- tabs << tab
29
+ tablist << tab
33
30
  tab_id = generate_id tab.text, doc, tabs_id
34
- tab_source_text = tab.instance_variable_get :@text
35
- set_id_on_tab ? (tab.id = tab_id) : (tab.text = %([[#{tab_id}]]#{tab_source_text}))
36
- tab.add_role 'tab'
37
- (doc.register :refs, [tab_id, tab]).set_attr 'reftext', tab_source_text
31
+ tab_text_source = tab.instance_variable_get :@text
32
+ set_id_on_tab ? (tab.id = tab_id) : (tab.text = %([[#{tab_id}]]#{tab_text_source}))
33
+ tab.role = 'tab'
34
+ (doc.register :refs, [tab_id, tab]).set_attr 'reftext', tab_text_source
38
35
  tab_id
39
36
  end
40
37
  if content
41
38
  tab_blocks = content.text? ?
42
- [(create_paragraph parent, (content.instance_variable_get :@text), nil, subs: :normal)]
43
- : []
39
+ [(create_paragraph parent, (content.instance_variable_get :@text), nil, subs: :normal)] : []
44
40
  if content.blocks?
45
41
  if (block0 = (blocks = content.blocks)[0]).context == :open && blocks.size == 1 && block0.blocks?
46
42
  blocks = block0.blocks
@@ -50,15 +46,14 @@ module Asciidoctor
50
46
  end
51
47
  panes[tab_ids] = tab_blocks || []
52
48
  end
53
- parent << tabs
54
- parent << (create_html_fragment parent, '<div class="content">')
49
+ tabs << tablist
55
50
  panes.each do |tab_ids, blocks|
56
- parent << (create_html_fragment parent, %(<div class="tab-pane" aria-labelledby="#{tab_ids.join ' '}">))
57
- blocks.each {|it| parent << it }
58
- parent << (create_html_fragment parent, '</div>')
51
+ attrs = %( id="#{tab_ids[0]}--panel" class="tabpanel" aria-labelledby="#{tab_ids.join ' '}")
52
+ tabs << (create_html_fragment parent, %(<div#{attrs}>))
53
+ blocks.each {|it| tabs << it }
54
+ tabs << (create_html_fragment parent, '</div>')
59
55
  end
60
- parent << (create_html_fragment parent, '</div>')
61
- create_html_fragment parent, '</div>', 'id' => tabs_id
56
+ tabs
62
57
  end
63
58
 
64
59
  private
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Asciidoctor
4
4
  module Tabs
5
- VERSION = '1.0.0.alpha.10'
5
+ VERSION = '1.0.0.alpha.11'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: asciidoctor-tabs
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.alpha.10
4
+ version: 1.0.0.alpha.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Allen
@@ -50,14 +50,14 @@ dependencies:
50
50
  requirements:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
- version: 3.11.0
53
+ version: 3.12.0
54
54
  type: :development
55
55
  prerelease: false
56
56
  version_requirements: !ruby/object:Gem::Requirement
57
57
  requirements:
58
58
  - - "~>"
59
59
  - !ruby/object:Gem::Version
60
- version: 3.11.0
60
+ version: 3.12.0
61
61
  description: An Asciidoctor extension that adds a tabs block to the AsciiDoc syntax.
62
62
  The tabset is constructed from a dlist enclosed in an example block marked with
63
63
  the tabs style.