Skip to content
Draft
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
788003f
Create focus-handler.js
BurningTreeC Dec 28, 2025
0655630
add functionality
BurningTreeC Dec 28, 2025
ad97de8
remove flex.tid
BurningTreeC Dec 28, 2025
7cedc8c
make sidebar slide out
BurningTreeC Dec 28, 2025
04f6a32
make it work for fixed-fluid
BurningTreeC Dec 28, 2025
f4c3496
no changed order in rtl
BurningTreeC Dec 28, 2025
0449b7d
reduce padding-top of story-river
BurningTreeC Dec 28, 2025
f052b2d
also scroll-margin-left
BurningTreeC Dec 28, 2025
9c32080
Refactor focus-handler.js for consistency
BurningTreeC Dec 29, 2025
bc2106e
Refactor focus-handler.js for consistent spacing
BurningTreeC Dec 29, 2025
fb00b69
Fix string quotes in getBounds function
BurningTreeC Dec 29, 2025
d5513ba
Add change note for sidebar movement enhancement
BurningTreeC Dec 29, 2025
b43d26c
Update flexbox-story-sidebar.tid in release notes
BurningTreeC Dec 29, 2025
ec14a79
Refactor focus handling and prevent spacebar scrolling
BurningTreeC Dec 29, 2025
ddf6062
Update focus handler for sidebar and secondary containers
BurningTreeC Dec 29, 2025
0852590
Update sidebar class for secondary container
BurningTreeC Dec 29, 2025
9c188d8
Change menubar class to secondary container
BurningTreeC Dec 29, 2025
d39a142
Remove outline from secondary container
BurningTreeC Dec 29, 2025
f558c5f
Refactor focus-handler for iframe and selector updates
BurningTreeC Dec 29, 2025
75427e6
Refactor PageTemplate by removing div wrapper
BurningTreeC Dec 29, 2025
62c2b3e
Enhance focus handling with text selection check
BurningTreeC Dec 29, 2025
ce7df68
Update menubar class for improved styling
BurningTreeC Dec 29, 2025
7ee54ae
Define order for secondary container positions
BurningTreeC Dec 29, 2025
32b06fd
Refactor focus-handler module for sidebar layout
BurningTreeC Dec 29, 2025
a6a527a
Fix sidebar HTML structure
BurningTreeC Dec 29, 2025
e21ec97
Implement focusWithSelection to preserve text selection
BurningTreeC Dec 29, 2025
284c481
Prevent focus stealing from sidebar-search
BurningTreeC Dec 29, 2025
766ef2d
Prevent focus stealing from sidebar-search
BurningTreeC Dec 29, 2025
5ba4c9f
Refactor focus handling for interactive elements
BurningTreeC Dec 29, 2025
94b3e13
Modify section class in PageTemplate story
BurningTreeC Dec 29, 2025
e912813
Enhance isInteractiveElement function for accuracy
BurningTreeC Dec 29, 2025
96b2dd7
Adjust padding in base.tid file
BurningTreeC Dec 29, 2025
bb66a37
Refactor page container styles in base.tid
BurningTreeC Dec 29, 2025
f0c453e
Implement responsive styles for dropzone
BurningTreeC Dec 29, 2025
68063ee
Update styles.tid
BurningTreeC Dec 29, 2025
e2779b2
Update base.tid
BurningTreeC Dec 29, 2025
4712ea9
Update base.tid
BurningTreeC Dec 29, 2025
4cb84e2
Update styles.tid
BurningTreeC Dec 29, 2025
ac1462e
Update styles.tid
BurningTreeC Dec 29, 2025
4c5b669
Update story.tid
BurningTreeC Dec 29, 2025
daf6f72
Update story.tid
BurningTreeC Dec 29, 2025
ab8037f
Update PageTemplate.tid
BurningTreeC Dec 29, 2025
469b93c
Update menu.tid
BurningTreeC Dec 29, 2025
1e8f31b
Update dropzone.js to add tabindex attribute to domNode
BurningTreeC Dec 29, 2025
fa2fc08
Update base.tid
BurningTreeC Dec 29, 2025
5b45b1f
Update base.tid
BurningTreeC Dec 29, 2025
6227bfa
Update base.tid
BurningTreeC Dec 29, 2025
2b9f838
Update base.tid
BurningTreeC Dec 29, 2025
d1e74d5
Update toprightbar.tid
BurningTreeC Dec 29, 2025
1122153
Update topleftbar.tid
BurningTreeC Dec 29, 2025
e5e3f68
Update base.tid
BurningTreeC Dec 29, 2025
33f0a14
Update styles.tid
BurningTreeC Dec 29, 2025
759d915
Update base.tid with logical css properties
BurningTreeC Dec 29, 2025
6220203
Update base.tid with logical css
BurningTreeC Dec 29, 2025
85124e3
more logical css properties
BurningTreeC Dec 29, 2025
2695629
update menubar styles with logical css properties
BurningTreeC Dec 29, 2025
81a2c04
fix 2 missing semicolons in snowwhite stylesheet and animate "color" …
BurningTreeC Dec 29, 2025
bcff1b7
add scroll-margins to tc-tiddler-frame
BurningTreeC Dec 29, 2025
cf34eaf
add some popup clamps
BurningTreeC Dec 29, 2025
fe435b7
fix padding-block-start of tc-sidebar-scrollable
BurningTreeC Dec 29, 2025
f8bccd9
fix dropzone not catching imports
BurningTreeC Dec 29, 2025
1177d7c
update dropzone widget
BurningTreeC Dec 29, 2025
6bb9068
Update startup.js
BurningTreeC Dec 30, 2025
b617ea9
Update load-modules.js
BurningTreeC Dec 30, 2025
ba06506
Update platform.js
BurningTreeC Dec 30, 2025
ff30566
Create mediaquerytracker.js
BurningTreeC Dec 30, 2025
ae2fb0b
Create filter-tracker.js
BurningTreeC Dec 30, 2025
bc0966a
Create background-actions.js
BurningTreeC Dec 30, 2025
dec2a90
Rename core/modules/mediaquerytracker.js to core/modules/info/mediaqu…
BurningTreeC Dec 30, 2025
5f5b9aa
Create MinWidth.tid
BurningTreeC Dec 30, 2025
a3ba6e6
Update PageTemplate.tid
BurningTreeC Dec 30, 2025
72d7960
Update story.tid
BurningTreeC Dec 30, 2025
fb56dc2
Update mediaquerytracker.js
BurningTreeC Dec 30, 2025
7a16901
Update filter-tracker.js
BurningTreeC Dec 30, 2025
7bf6d54
Merge branch 'TiddlyWiki:master' into flexbox-story-sidebar
BurningTreeC Dec 30, 2025
cd20b61
Create BottomToolbar.multids
BurningTreeC Dec 30, 2025
8e527e5
Create bottom-toolbar.tid
BurningTreeC Dec 30, 2025
873cb2c
Create bottom-toolbar.tid
BurningTreeC Dec 30, 2025
11e65fb
Update bottom-toolbar.tid
BurningTreeC Dec 30, 2025
bf6331e
Update bottom-toolbar.tid
BurningTreeC Dec 30, 2025
ec0ea1a
Update bottom-toolbar.tid
BurningTreeC Dec 30, 2025
493dfe1
Update bottom-toolbar.tid
BurningTreeC Dec 30, 2025
a517c9a
Update focus-handler.js
BurningTreeC Dec 30, 2025
816fd5b
Update base.tid
BurningTreeC Dec 30, 2025
98d100d
Update dropzone.js
BurningTreeC Dec 30, 2025
c1b706d
Update PageTemplate.tid
BurningTreeC Dec 30, 2025
0ecddfc
Update bottom-toolbar.tid
BurningTreeC Dec 30, 2025
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
123 changes: 123 additions & 0 deletions core/modules/startup/focus-handler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/*\
title: $:/plugins/custom/sidebar-focus/startup.js
type: application/javascript
module-type: startup
Handles focus management and spacebar scrolling for sidebar layout
\*/
"use strict";

exports.name = "sidebar-focus";
exports.platforms = ["browser"];
exports.after = ["story"];
exports.synchronous = true;

exports.startup = function() {
var mainSelector = ".tc-story-river";
var secondarySelector = ".tc-secondary-container";

// Helper: Check if element is in any secondary container
function isInSecondary(element) {
var containers = document.querySelectorAll(secondarySelector);
return Array.from(containers).some(function(container) {
return container === element || container.contains(element);
});
}

// Wait for DOM to be fully ready
function initialize() {
var main = document.querySelector(mainSelector);

if(!main) {
setTimeout(initialize, 100);
return;
}

// Make main focusable
if(!main.hasAttribute("tabindex")) {
main.setAttribute("tabindex", "-1");
}
main.focus();

// Make secondary containers unfocusable
var secondaryContainers = document.querySelectorAll(secondarySelector);
secondaryContainers.forEach(function(element) {
element.removeAttribute("tabindex");
});
}

// Handle spacebar scrolling in secondary containers
document.addEventListener("keydown", function(e) {
if(e.key !== " ") return;

if(isInSecondary(e.target)) {
// Allow spacebar in input fields
if(e.target.tagName === "INPUT" ||
e.target.tagName === "TEXTAREA" ||
e.target.isContentEditable) {
return;
}
e.preventDefault();
}
}, true);

// Tab-Trapping: Keep tab navigation within main content
document.addEventListener("keydown", function(e) {
if(e.key !== "Tab") return;

var main = document.querySelector(mainSelector);
if(!main) return;

var focusableElements = main.querySelectorAll(
'a[href], button, input, textarea, select, details, [tabindex]:not([tabindex="-1"])'
);

if(focusableElements.length === 0) {
e.preventDefault();
main.focus();
return;
}

var firstElement = focusableElements[0];
var lastElement = focusableElements[focusableElements.length - 1];
var activeElement = document.activeElement;

// Only trap if we're in main
var inMain = activeElement === main || main.contains(activeElement);
if(!inMain) {
e.preventDefault();
main.focus();
return;
}

// Trap tab at boundaries
if(e.shiftKey && activeElement === firstElement) {
e.preventDefault();
lastElement.focus();
} else if(!e.shiftKey && activeElement === lastElement) {
e.preventDefault();
firstElement.focus();
} else if(activeElement === main) {
e.preventDefault();
firstElement.focus();
}
});

// Click-Handler: Always refocus main after clicks (except in input fields)
document.addEventListener("click", function(e) {
var main = document.querySelector(mainSelector);
if(!main) return;

// Don't refocus if clicking in input fields
if(e.target.tagName === "INPUT" ||
e.target.tagName === "TEXTAREA" ||
e.target.isContentEditable) {
return;
}

setTimeout(function() {
main.focus();
}, 10);
}, true);

initialize();
};
88 changes: 74 additions & 14 deletions core/modules/utils/dom/scroller.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,32 @@ PageScroller.prototype.cancelScroll = function(srcWindow) {
}
};

/*
Find the scrollable ancestor of an element
Returns the first ancestor with overflow-y: auto|scroll, or null if none found
*/
PageScroller.prototype.getScrollContainer = function(element,srcWindow) {
var node = element.parentElement;
while(node) {
var style = srcWindow.getComputedStyle(node);
var overflowY = style.getPropertyValue("overflow-y");
if(overflowY === "auto" || overflowY === "scroll") {
return node;
}
node = node.parentElement;
}
return null;
};

/*
Get scroll-margin value from element's computed style
*/
PageScroller.prototype.getScrollMargin = function(element,srcWindow,propertyValue) {
var style = srcWindow.getComputedStyle(element);
var scrollMargin = style.getPropertyValue(propertyValue);
return parseFloat(scrollMargin) || 0;
};

/*
Handle an event
*/
Expand All @@ -66,7 +92,10 @@ Handle a scroll event hitting the page document
PageScroller.prototype.scrollIntoView = function(element,callback,options) {
var self = this,
duration = $tw.utils.hop(options,"animationDuration") ? parseInt(options.animationDuration) : $tw.utils.getAnimationDuration(),
srcWindow = element ? element.ownerDocument.defaultView : window;
srcWindow = element ? element.ownerDocument.defaultView : window,
scrollContainer = this.getScrollContainer(element,srcWindow),
scrollMarginTop = this.getScrollMargin(element,srcWindow,"scroll-margin-top"),
scrollMarginLeft = this.getScrollMargin(element,srcWindow,"scroll-margin-left");
// Now get ready to scroll the body
this.cancelScroll(srcWindow);
this.startTime = Date.now();
Expand All @@ -78,14 +107,26 @@ PageScroller.prototype.scrollIntoView = function(element,callback,options) {
}
// Get the client bounds of the element and adjust by the scroll position
var getBounds = function() {
var clientBounds = typeof callback === 'function' ? callback() : element.getBoundingClientRect(),
scrollPosition = $tw.utils.getScrollPosition(srcWindow);
return {
left: clientBounds.left + scrollPosition.x,
top: clientBounds.top + scrollPosition.y - offset,
width: clientBounds.width,
height: clientBounds.height
};
var clientBounds = typeof callback === "function" ? callback() : element.getBoundingClientRect();
if(scrollContainer) {
// Position relative to scroll container
var containerBounds = scrollContainer.getBoundingClientRect();
return {
left: clientBounds.left - containerBounds.left + scrollContainer.scrollLeft - scrollMarginLeft,
top: clientBounds.top - containerBounds.top + scrollContainer.scrollTop - offset - scrollMarginTop,
width: clientBounds.width,
height: clientBounds.height
};
} else {
// Position relative to window
var scrollPosition = $tw.utils.getScrollPosition(srcWindow);
return {
left: clientBounds.left + scrollPosition.x,
top: clientBounds.top + scrollPosition.y - offset - scrollMarginTop,
width: clientBounds.width,
height: clientBounds.height
};
}
},
// We'll consider the horizontal and vertical scroll directions separately via this function
// targetPos/targetSize - position and size of the target element
Expand All @@ -111,11 +152,30 @@ PageScroller.prototype.scrollIntoView = function(element,callback,options) {
t = 1;
}
t = $tw.utils.slowInSlowOut(t);
var scrollPosition = $tw.utils.getScrollPosition(srcWindow),
bounds = getBounds(),
endX = getEndPos(bounds.left,bounds.width,scrollPosition.x,srcWindow.innerWidth),
endY = getEndPos(bounds.top,bounds.height,scrollPosition.y,srcWindow.innerHeight);
srcWindow.scrollTo(scrollPosition.x + (endX - scrollPosition.x) * t,scrollPosition.y + (endY - scrollPosition.y) * t);
var bounds = getBounds(),
scrollX,scrollY,viewportWidth,viewportHeight,endX,endY;
if(scrollContainer) {
scrollX = scrollContainer.scrollLeft;
scrollY = scrollContainer.scrollTop;
viewportWidth = scrollContainer.clientWidth;
viewportHeight = scrollContainer.clientHeight;
} else {
var scrollPosition = $tw.utils.getScrollPosition(srcWindow);
scrollX = scrollPosition.x;
scrollY = scrollPosition.y;
viewportWidth = srcWindow.innerWidth;
viewportHeight = srcWindow.innerHeight;
}
endX = getEndPos(bounds.left,bounds.width,scrollX,viewportWidth);
endY = getEndPos(bounds.top,bounds.height,scrollY,viewportHeight);
var newX = scrollX + (endX - scrollX) * t,
newY = scrollY + (endY - scrollY) * t;
if(scrollContainer) {
scrollContainer.scrollLeft = newX;
scrollContainer.scrollTop = newY;
} else {
srcWindow.scrollTo(newX,newY);
}
if(t < 1) {
self.idRequestFrame = self.requestAnimationFrame.call(srcWindow,drawFrame);
}
Expand Down
14 changes: 3 additions & 11 deletions core/ui/PageTemplate.tid
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ code-body: yes

\whitespace trim
\import [subfilter{$:/core/config/GlobalImportFilter}]

<$vars
tv-config-toolbar-icons={{$:/config/Toolbar/Icons}}
tv-config-toolbar-text={{$:/config/Toolbar/Text}}
Expand All @@ -15,23 +14,16 @@ code-body: yes
tv-show-missing-links={{$:/config/MissingLinks}}
storyviewTitle={{$:/view}}
languageTitle={{{ [{$:/language}get[name]] }}}>

<div class={{{ [all[shadows+tiddlers]tag[$:/tags/ClassFilters/PageTemplate]!is[draft]] :map:flat[subfilter{!!text}] tc-page-container [[tc-page-view-]addsuffix<storyviewTitle>] [[tc-language-]addsuffix<languageTitle>] :and[unique[]join[ ]] }}} >

<$navigator story="$:/StoryList" history="$:/HistoryList" openLinkFromInsideRiver={{$:/config/Navigation/openLinkFromInsideRiver}} openLinkFromOutsideRiver={{$:/config/Navigation/openLinkFromOutsideRiver}} relinkOnRename={{$:/config/RelinkOnRename}}>

<$list filter="[all[shadows+tiddlers]tag[$:/tags/PageTemplate/Outside]!has[draft.of]]" variable="listItem">
<$transclude tiddler=<<listItem>>/>
</$list>
<$dropzone enable=<<tv-enable-drag-and-drop>> class="tc-dropzone tc-page-container-inner">

<$list filter="[all[shadows+tiddlers]tag[$:/tags/PageTemplate]!has[draft.of]]" variable="listItem">

<$transclude tiddler=<<listItem>>/>

</$list>

</$dropzone>

</$navigator>

</div>

</$vars>
4 changes: 4 additions & 0 deletions core/ui/PageTemplate/sidebar.tid
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ tags: $:/tags/PageTemplate
$:/config/SideBarSegments/Visibility/$(listItem)$
\end

<aside class="tc-sidebar tc-secondary-container" tabindex="-1">

<$scrollable fallthrough="no" class="tc-sidebar-scrollable">

<div class="tc-sidebar-header">
Expand All @@ -27,3 +29,5 @@ $:/config/SideBarSegments/Visibility/$(listItem)$
</div>

</$scrollable>

</aside>
6 changes: 5 additions & 1 deletion core/ui/PageTemplate/story.tid
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ title: $:/core/ui/PageTemplate/story
tags: $:/tags/PageTemplate

\whitespace trim
<section class="tc-story-river" role="main">
<section class="tc-story-river" role="main" tabindex="-1">

<div class="tc-main-content">

<section class="story-backdrop">

Expand All @@ -26,4 +28,6 @@ tags: $:/tags/PageTemplate

</section>

</div>

</section>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
title: $:/changenotes/5.4.0/#9532
created: 20251229082625621
modified: 20251229082625621
tags: $:/tags/ChangeNote
change-type: enhancement
change-category: usability
description: The sidebar moves out of view and into view
release: 5.4.0
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9532
github-contributors: BurningTreeC
type: text/vnd.tiddlywiki

This pull request makes the sidebar move when hiding and showing, rather than jumping.
7 changes: 4 additions & 3 deletions plugins/tiddlywiki/menubar/menu.tid
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
title: $:/plugins/tiddlywiki/menubar/menu
tags: $:/tags/PageTemplate
tags: $:/tags/PageTemplate/Outside

\define menubar-inner(size)
\whitespace trim
<ul class="tc-menubar-list">
<$list filter="[all[shadows+tiddlers]tag[$:/tags/MenuBar]!has[draft.of]] -[all[tiddlers+shadows]tag[$:/tags/TopLeftBar]limit[1]then[]else[$:/plugins/tiddlywiki/menubar/items/topleftbar]] -[all[tiddlers+shadows]tag[$:/tags/TopRightBar]limit[1]then[]else[$:/plugins/tiddlywiki/menubar/items/toprightbar]]">
<$list filter="[<currentTiddler>addprefix[$:/config/plugins/menubar/MenuItems/Visibility/]get[text]] ~show +[match[show]]" variable="ignore">
Expand Down Expand Up @@ -41,10 +42,10 @@ tags: $:/tags/PageTemplate
</$list>
</ul>
\end

\whitespace trim
<$list filter="[<tv-config-static>!match[yes]]" variable="ignore">
<$list filter="[all[shadows+tiddlers]tag[$:/tags/MenuBar]!has[draft.of]] -[all[tiddlers+shadows]tag[$:/tags/TopLeftBar]limit[1]then[]else[$:/plugins/tiddlywiki/menubar/items/topleftbar]] -[all[tiddlers+shadows]tag[$:/tags/TopRightBar]limit[1]then[]else[$:/plugins/tiddlywiki/menubar/items/toprightbar]] +[limit[1]]" variable="listItem">
<nav class="tc-menubar tc-adjust-top-of-scroll">
<nav class="tc-menubar tc-secondary-container tc-adjust-top-of-scroll">
<div class="tc-menubar-narrow">
<<menubar-inner narrow>>
</div>
Expand Down
9 changes: 5 additions & 4 deletions plugins/tiddlywiki/menubar/styles.tid
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,13 @@ tags: [[$:/tags/Stylesheet]]
\rules only filteredtranscludeinline transcludeinline macrodef macrocallinline

nav.tc-menubar {
position: fixed;
position: relative;
flex-shrink: 0;
z-index: 850;
display: inline-block;
top: 0;
right: 0;
left: 0;
top: auto;
right: auto;
left: auto;
}

nav.tc-menubar ul.tc-menubar-list {
Expand Down
Loading