Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@

## Unreleased

- 👌 IMPROVE: Restore keyboard focus rings on tab labels, dropdown summaries,
buttons and stretched-link cards, using `:focus-visible` so they are visible
for keyboard users but not shown on mouse click, thanks to {user}`gabalafou`
in {pr}`230` (carried in {pr}`283`)
- 👌 IMPROVE: Each tab label now carries an `aria-controls` attribute
referencing its content panel's id, establishing the programmatic
relationship in the accessibility tree (note: this is not a full WAI-ARIA
tabs pattern; assistive-technology support for `aria-controls` varies)
({pr}`283`, {issue}`30`)
- 🐛 FIX: `card`/`grid-item-card` `:link:` no longer strips whitespace from reference targets (and lowercases them for `link-type: ref`, matching the `:ref:` role), completing the fix for {issue}`110` ({pr}`282`)
- 🐛 FIX: `button-ref` no longer strips whitespace from reference targets, so
multi-word labels (e.g. from `autosectionlabel`) resolve correctly
Expand Down
2 changes: 1 addition & 1 deletion sphinx_design/static/sphinx-design.min.css

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions sphinx_design/tabs.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,9 @@ def depart_tab_input(self, node):

def visit_tab_label(self, node):
attributes = {"for": node["input_id"]}
if "aria_controls" in node:
# programmatically associate the label with the content panel it toggles
attributes["aria-controls"] = node["aria_controls"]
if "sync_id" in node and "sync_group" in node:
attributes["data-sync-id"] = node["sync_id"]
attributes["data-sync-group"] = node["sync_group"]
Expand Down Expand Up @@ -319,6 +322,13 @@ def run(self, **kwargs: Any) -> None:
label_node.source, label_node.line = tab_item.source, tab_item.line
children.append(label_node)

# give the content panel a stable id and point the label at it
# via aria-controls; prepend so any existing ids (e.g. anchors
# propagated from a preceding hyperlink target) still resolve
tab_content_identity = f"{tab_item_identity}-content"
tab_content["ids"].insert(0, tab_content_identity)
label_node["aria_controls"] = tab_content_identity

# add content
children.append(tab_content)

Expand Down
7 changes: 7 additions & 0 deletions style/_button.scss
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
-moz-user-select: none;
-ms-user-select: none;
-webkit-user-select: none;
outline-offset: 0.25rem;

&:hover {
text-decoration: none;
Expand Down Expand Up @@ -77,6 +78,12 @@
border-width: 1px !important;
border-style: solid !important;
}
.sd-btn-#{$color}:focus-visible {
outline-color: var(--sd-color-#{$color}) !important;
&::after {
outline-color: var(--sd-color-#{$color}) !important;
}
}
}

// make parent clickable
Expand Down
9 changes: 9 additions & 0 deletions style/_cards.scss
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@
margin-left: 0;
margin-right: 0;
}

.sd-stretched-link:focus-visible {
outline: none;

&::after {
outline-style: auto;
outline-color: var(--sd-color-primary);
}
}
}

.sd-card-hover:hover {
Expand Down
9 changes: 9 additions & 0 deletions style/_colors.scss
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,18 @@ $semantic-colors: (
&.sd-bg-#{$color}:hover {
background-color: var(--sd-color-#{$color}-highlight) !important;
}
&.sd-bg-#{$color}:focus-visible {
outline-color: var(--sd-color-#{$color}-highlight) !important;
}
}
a {
&.sd-bg-#{$color}:focus,
&.sd-bg-#{$color}:hover {
background-color: var(--sd-color-#{$color}-highlight) !important;
}
&.sd-bg-#{$color}:focus-visible {
outline-color: var(--sd-color-#{$color}-highlight) !important;
}
}
}

Expand All @@ -90,6 +96,9 @@ $semantic-colors: (
&.sd-outline-#{$color}:hover {
border-color: var(--sd-color-#{$color}-highlight) !important;
}
&.sd-outline-#{$color}:focus-visible {
outline-color: var(--sd-color-#{$color}-highlight) !important;
}
}
}

Expand Down
7 changes: 2 additions & 5 deletions style/_dropdown.scss
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,14 @@ details.sd-dropdown {
display: none;
}

&:focus {
outline: none;
}

// The title is split into three parts:
// 1. The icon (optional), which should be on the left
// 2. The text, which should be in the middle, and take all available space
// 3. The state marker, which should be on the right

display: inline-flex;
justify-content: space-between;
outline-offset: 0.25rem;

.sd-summary-icon {
margin-right: 0.6em;
Expand All @@ -64,7 +61,7 @@ details.sd-dropdown {
pointer-events: none;
// align the icon vertically within its container
display: inline-flex;
align-items: center;
align-self: center;
}

// make the state marker a bit more prominent when hovered
Expand Down
4 changes: 4 additions & 0 deletions style/_overrides.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,7 @@
.sd-sphinx-override p {
margin-top: 0;
}

.sd-sphinx-override:focus-visible {
outline-offset: 0.25rem;
}
4 changes: 2 additions & 2 deletions style/_tabs.scss
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
}

// Disable focus indicator for pointer devices
&:not(.focus-visible) + label {
&:not(:focus-visible) + label {
outline: none;
-webkit-tap-highlight-color: transparent;
}
Expand All @@ -48,7 +48,7 @@
cursor: pointer;
font-size: var(--sd-fontsize-tabs-label);
font-weight: 700;
padding: 1em 1.25em 0.5em;
padding: 0.5em 1.25em;
transition: color 250ms;
width: auto;
z-index: 1;
Expand Down
8 changes: 4 additions & 4 deletions tests/test_misc/test_tab_set_with_invalid_children.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
Tab Test document
<container classes="sd-tab-set" design_component="tab-set" is_div="True">
<sd_tab_input checked="True" id="sd-tab-item-0" set_id="sd-tab-set-0" type="radio">
<sd_tab_label classes="sd-tab-label" input_id="sd-tab-item-0">
<sd_tab_label aria_controls="sd-tab-item-0-content" classes="sd-tab-label" input_id="sd-tab-item-0">
A
<container classes="sd-tab-content" design_component="tab-content" is_div="True">
<container classes="sd-tab-content" design_component="tab-content" ids="sd-tab-item-0-content" is_div="True">
<paragraph>
A content
<sd_tab_input checked="False" id="sd-tab-item-1" set_id="sd-tab-set-0" type="radio">
<sd_tab_label classes="sd-tab-label" input_id="sd-tab-item-1">
<sd_tab_label aria_controls="sd-tab-item-1-content" classes="sd-tab-label" input_id="sd-tab-item-1">
B
<container classes="sd-tab-content" design_component="tab-content" is_div="True">
<container classes="sd-tab-content" design_component="tab-content" ids="sd-tab-item-1-content" is_div="True">
<paragraph>
B content
8 changes: 4 additions & 4 deletions tests/test_snippets/snippet_post_tab-basic.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
Heading
<container classes="sd-tab-set" design_component="tab-set" is_div="True">
<sd_tab_input checked="True" id="sd-tab-item-0" set_id="sd-tab-set-0" type="radio">
<sd_tab_label classes="sd-tab-label" input_id="sd-tab-item-0">
<sd_tab_label aria_controls="sd-tab-item-0-content" classes="sd-tab-label" input_id="sd-tab-item-0">
Label1
<container classes="sd-tab-content" design_component="tab-content" is_div="True">
<container classes="sd-tab-content" design_component="tab-content" ids="sd-tab-item-0-content" is_div="True">
<paragraph>
Content 1
<sd_tab_input checked="False" id="sd-tab-item-1" set_id="sd-tab-set-0" type="radio">
<sd_tab_label classes="sd-tab-label" input_id="sd-tab-item-1">
<sd_tab_label aria_controls="sd-tab-item-1-content" classes="sd-tab-label" input_id="sd-tab-item-1">
Label2
<container classes="sd-tab-content" design_component="tab-content" is_div="True">
<container classes="sd-tab-content" design_component="tab-content" ids="sd-tab-item-1-content" is_div="True">
<paragraph>
Content 2
8 changes: 4 additions & 4 deletions tests/test_snippets/snippet_post_tab-code-set.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
Heading
<container classes="sd-tab-set" design_component="tab-set" is_div="True">
<sd_tab_input checked="True" id="sd-tab-item-0" set_id="sd-tab-set-0" type="radio">
<sd_tab_label classes="sd-tab-label" input_id="sd-tab-item-0" sync_group="code" sync_id="python">
<sd_tab_label aria_controls="sd-tab-item-0-content" classes="sd-tab-label" input_id="sd-tab-item-0" sync_group="code" sync_id="python">
PYTHON
<container classes="sd-tab-content" design_component="tab-content" is_div="True">
<container classes="sd-tab-content" design_component="tab-content" ids="sd-tab-item-0-content" is_div="True">
<literal_block force="False" highlight_args="{'linenostart': 1}" language="python" linenos="False" source="snippet.py" xml:space="preserve">
a = 1
<sd_tab_input checked="False" id="sd-tab-item-1" set_id="sd-tab-set-0" type="radio">
<sd_tab_label classes="sd-tab-label" input_id="sd-tab-item-1" sync_group="code" sync_id="javascript">
<sd_tab_label aria_controls="sd-tab-item-1-content" classes="sd-tab-label" input_id="sd-tab-item-1" sync_group="code" sync_id="javascript">
JAVASCRIPT
<container classes="sd-tab-content" design_component="tab-content" is_div="True">
<container classes="sd-tab-content" design_component="tab-content" ids="sd-tab-item-1-content" is_div="True">
<literal_block force="False" highlight_args="{}" language="javascript" linenos="False" xml:space="preserve">
a = 1;
4 changes: 2 additions & 2 deletions tests/test_snippets/snippet_post_tab-options.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
Heading
<container classes="sd-tab-set class-set" design_component="tab-set" is_div="True">
<sd_tab_input checked="True" id="sd-tab-item-0" set_id="sd-tab-set-0" type="radio">
<sd_tab_label classes="sd-tab-label class-label" ids="target" input_id="sd-tab-item-0">
<sd_tab_label aria_controls="sd-tab-item-0-content" classes="sd-tab-label class-label" ids="target" input_id="sd-tab-item-0">
<strong>
Label
<container classes="sd-tab-content class-content" design_component="tab-content" is_div="True">
<container classes="sd-tab-content class-content" design_component="tab-content" ids="sd-tab-item-0-content" is_div="True">
<paragraph>
Content
<paragraph>
Expand Down
16 changes: 8 additions & 8 deletions tests/test_snippets/snippet_post_tab-sync.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,27 @@
Heading
<container classes="sd-tab-set" design_component="tab-set" is_div="True">
<sd_tab_input checked="True" id="sd-tab-item-0" set_id="sd-tab-set-0" type="radio">
<sd_tab_label classes="sd-tab-label" input_id="sd-tab-item-0" sync_group="category" sync_id="key1">
<sd_tab_label aria_controls="sd-tab-item-0-content" classes="sd-tab-label" input_id="sd-tab-item-0" sync_group="category" sync_id="key1">
Label1
<container classes="sd-tab-content" design_component="tab-content" is_div="True">
<container classes="sd-tab-content" design_component="tab-content" ids="sd-tab-item-0-content" is_div="True">
<paragraph>
Content 1
<sd_tab_input checked="False" id="sd-tab-item-1" set_id="sd-tab-set-0" type="radio">
<sd_tab_label classes="sd-tab-label" input_id="sd-tab-item-1" sync_group="category" sync_id="key2">
<sd_tab_label aria_controls="sd-tab-item-1-content" classes="sd-tab-label" input_id="sd-tab-item-1" sync_group="category" sync_id="key2">
Label2
<container classes="sd-tab-content" design_component="tab-content" is_div="True">
<container classes="sd-tab-content" design_component="tab-content" ids="sd-tab-item-1-content" is_div="True">
<paragraph>
Content 2
<container classes="sd-tab-set" design_component="tab-set" is_div="True">
<sd_tab_input checked="True" id="sd-tab-item-2" set_id="sd-tab-set-1" type="radio">
<sd_tab_label classes="sd-tab-label" input_id="sd-tab-item-2" sync_group="category" sync_id="key1">
<sd_tab_label aria_controls="sd-tab-item-2-content" classes="sd-tab-label" input_id="sd-tab-item-2" sync_group="category" sync_id="key1">
Label1
<container classes="sd-tab-content" design_component="tab-content" is_div="True">
<container classes="sd-tab-content" design_component="tab-content" ids="sd-tab-item-2-content" is_div="True">
<paragraph>
Content 1
<sd_tab_input checked="False" id="sd-tab-item-3" set_id="sd-tab-set-1" type="radio">
<sd_tab_label classes="sd-tab-label" input_id="sd-tab-item-3" sync_group="category" sync_id="key2">
<sd_tab_label aria_controls="sd-tab-item-3-content" classes="sd-tab-label" input_id="sd-tab-item-3" sync_group="category" sync_id="key2">
Label2
<container classes="sd-tab-content" design_component="tab-content" is_div="True">
<container classes="sd-tab-content" design_component="tab-content" ids="sd-tab-item-3-content" is_div="True">
<paragraph>
Content 2
Loading
Loading