Skip to content

Commit 6e79e23

Browse files
authored
fix: improve sidebar resize handle for fine and coarse pointers (#1299)
* fix: improve sidebar resize handle width and activation behavior - Set resize handle width to 8px for fine pointers (mouse) and 26px for touch users via @media (any-pointer: coarse) - Prevent resize activation when clicking the sidebar scrollbar by requiring the mouse to cross the sidebar's outer edge before the handle becomes active (adds .handle-active class) - Use a 5px trip area at the sidebar edge that expands to 24px (12px per side) once activated, with engagement-point dismissal to create perceived directional bias - Handle stays pointer-events: none for fine pointers so the native scrollbar remains fully clickable beneath it - Touch users bypass activation logic and get full handle interactivity Fixes #1294 * Resave distributed files (GitHub Action) * Resave data (GitHub Action) * feat: add `resizable` argument to `sidebar()` Add a `resizable` parameter (default TRUE) that controls whether the sidebar resize handle is enabled. When TRUE, a `data-resizable` attribute is added to the sidebar `<aside>` element; the JS and CSS only enable resize functionality when this attribute is present. Fixes #1294 * Resave distributed files (GitHub Action)
1 parent e26a8cc commit 6e79e23

File tree

12 files changed

+290
-22
lines changed

12 files changed

+290
-22
lines changed

NEWS.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## Improvements and bug fixes
44

5+
* Improved the sidebar resize handle to avoid conflicts with the sidebar's native scrollbar and to better support touch devices. (#1299)
6+
7+
* `sidebar()` gains a `resizable` argument (default `TRUE`) to control whether the sidebar can be resized by dragging its edge on desktop (wide screen sizes). (#1299)
8+
59
* Fixed `toolbar_input_button()` alignment and spacing issues. (#1290)
610

711
* The brand.yml example app (`shiny::runExample("brand.yml", package = "bslib")`) now uses `brand_pluck()` and `brand_has()` from `{brand.yml}`. (#1288)

R/sidebar.R

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@
8787
#' @param fillable Whether or not the sidebar should be considered a fillable
8888
#' container. When `TRUE`, the sidebar and its content can use `fill` to
8989
#' consume available vertical space.
90+
#' @param resizable Whether the sidebar can be resized by dragging its edge.
91+
#' When `TRUE` (the default), a resize handle is added to the sidebar that
92+
#' allows users to adjust the sidebar width on desktop (wide screen sizes).
9093
#'
9194
#' @export
9295
sidebar <- function(
@@ -102,7 +105,8 @@ sidebar <- function(
102105
max_height_mobile = NULL,
103106
gap = NULL,
104107
padding = NULL,
105-
fillable = FALSE
108+
fillable = FALSE,
109+
resizable = TRUE
106110
) {
107111
position <- rlang::arg_match(position)
108112
gap <- validateCssUnit(gap)
@@ -150,6 +154,7 @@ sidebar <- function(
150154
max_height_mobile = max_height_mobile,
151155
color = list(bg = bg, fg = fg),
152156
fillable = fillable,
157+
resizable = resizable,
153158
attributes = dots$attribs,
154159
children = dots$children
155160
)
@@ -220,6 +225,7 @@ as.tags.bslib_sidebar <- function(x, ...) {
220225
id = x$id,
221226
class = c("sidebar", x$class),
222227
hidden = if (hidden_initially) NA,
228+
`data-resizable` = if (isTRUE(x$resizable)) NA,
223229
if (isTRUE(x$fillable)) as_fillable_container(),
224230
tags$div(
225231
class = "sidebar-content bslib-gap-spacing",

R/sysdata.rda

582 Bytes
Binary file not shown.

inst/components/dist/components.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

inst/components/dist/components.js

Lines changed: 87 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

inst/components/dist/components.js.map

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

inst/components/dist/components.min.js

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

inst/components/dist/components.min.js.map

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

inst/components/scss/sidebar.scss

Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,11 @@ $bslib-sidebar-column-sidebar: Min(calc(100% - var(--_padding-icon)), var(--_sid
6262
--_toggle-collective-height: calc(calc(var(--_icon-button-size) + 0.5em) * var(--_js-toggle-count-max-side, 1));
6363

6464
// Resize handle variables
65-
--_resize-handle-width: var(--bslib-sidebar-resize-handle-width, 12px);
65+
--_resize-handle-width: var(--bslib-sidebar-resize-handle-width, 8px);
66+
67+
@media (any-pointer: coarse) {
68+
--_resize-handle-width: var(--bslib-sidebar-resize-handle-width, 26px);
69+
}
6670
--_resize-indicator-color: var(--_sidebar-fg, var(--bs-emphasis-color, black));
6771
--_resize-indicator-color-active: var(--bslib-sidebar-resize-indicator-color-active, var(--bs-primary, #0d6efd));
6872

@@ -309,20 +313,45 @@ $bslib-sidebar-column-sidebar: Min(calc(100% - var(--_padding-icon)), var(--_sid
309313
width: var(--_resize-handle-width);
310314
left: calc(calc(-1 * var(--_resize-handle-width)) - 2px);
311315
grid-column: 2;
312-
cursor: ew-resize;
316+
pointer-events: none;
313317
user-select: none;
314318
z-index: calc(#{$zindex-dropdown} + 1); // Above toggle button
315319

316-
// Make the handle easier to grab
320+
// Trip area: a narrow strip at the sidebar outer edge that detects the
321+
// mouse crossing the sidebar boundary. Positioned past the handle so
322+
// it doesn't overlap the sidebar scrollbar beneath the handle.
323+
// Expands when .handle-active is added to prevent accidental deactivation.
317324
&::before {
318325
content: "";
319326
position: absolute;
320327
top: 0;
321328
bottom: 0;
322-
// Invisible expanded hit area
323-
left: 0;
324-
right: calc(-1 * var(--_resize-handle-width) - 2px);
325-
z-index: calc(#{$zindex-dropdown} + 1); // Above toggle button
329+
left: 100%;
330+
width: 5px;
331+
pointer-events: auto;
332+
}
333+
334+
// When the mouse crosses the sidebar edge, JS adds .handle-active
335+
// to show the resize cursor and expand the trip area.
336+
&.handle-active {
337+
cursor: ew-resize;
338+
339+
&::before {
340+
left: calc(100% - 10px);
341+
width: 24px;
342+
}
343+
}
344+
345+
// Touch users get the full handle + extended hit area
346+
@media (any-pointer: coarse) {
347+
pointer-events: auto;
348+
cursor: ew-resize;
349+
350+
&::before {
351+
left: 0;
352+
width: auto;
353+
right: calc(-1 * var(--_resize-handle-width) - 2px);
354+
}
326355
}
327356

328357
.resize-indicator {
@@ -338,14 +367,15 @@ $bslib-sidebar-column-sidebar: Min(calc(100% - var(--_padding-icon)), var(--_sid
338367
transition: all 0.15s ease;
339368
}
340369

341-
&:hover, &:focus, &:active, &:focus {
370+
&:hover, &:focus, &:active, &.handle-active {
342371
.resize-indicator {
343372
opacity: 1;
344373
}
345374
}
346375

347376
&:hover .resize-indicator,
348-
&:focus .resize-indicator {
377+
&:focus .resize-indicator,
378+
&.handle-active .resize-indicator {
349379
width: 3px;
350380
height: 40px;
351381
}
@@ -370,6 +400,20 @@ $bslib-sidebar-column-sidebar: Min(calc(100% - var(--_padding-icon)), var(--_sid
370400
// Right sidebar resize handle positioning
371401
&.sidebar-right > .bslib-sidebar-resize-handle {
372402
left: 2px;
403+
404+
&::before {
405+
left: auto;
406+
right: 100%;
407+
}
408+
409+
&.handle-active::before {
410+
right: calc(100% - 10px);
411+
}
412+
}
413+
414+
// Hide resize handle when sidebar is not resizable
415+
> .sidebar:not([data-resizable]) ~ .bslib-sidebar-resize-handle {
416+
display: none;
373417
}
374418

375419
// Hide resize handle during transitions and when collapsed

man/sidebar.Rd

Lines changed: 6 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)