Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

navbar compatibility #4

Merged
merged 15 commits into from
Nov 22, 2019
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
1 change: 1 addition & 0 deletions .Rbuildignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
^\.Rproj\.user$
inst/node_modules/.yarn-integrity
inst/node_modules/bootswatch/.github
^test-apps$
12 changes: 10 additions & 2 deletions R/themes.R
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ bs4_themes_join <- function(theme1 = bs4_theme(), theme2 = bs4_theme()) {
bs4_theme(
pre = as_sass(paste0(theme1$pre, theme2$pre)),
post = as_sass(paste0(theme2$post, theme1$post)),
deps = c(theme1$deps, theme1$deps)
deps = c(theme1$deps, theme2$deps)
)
}

Expand Down Expand Up @@ -69,7 +69,15 @@ bs4_theme_bootswatch <- function(theme = "") {
bs4_theme_bs3compat <- function() {
bs4_theme(
pre = sass_file(system.file("bs3compat", "_pre_variables.scss", package = "bootscss")),
post = sass_file(system.file("bs3compat", "_post_variables.scss", package = "bootscss"))
post = sass_file(system.file("bs3compat", "_post_variables.scss", package = "bootscss")),
deps = list(
htmltools::htmlDependency(
"bs3compat", packageVersion("bootscss"),
package = "bootscss",
src = "bs3compat/js",
script = c("tabs.js", "bs3compat.js")
)
)
)
}

Expand Down
7 changes: 7 additions & 0 deletions inst/bs3compat/_components_compat.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.well {
@extend .bg-light; @extend .card; @extend .p-3;
}

.help-text, .help-block {
@extend .form-text; @extend .text-muted;
}
23 changes: 23 additions & 0 deletions inst/bs3compat/_dropdown_compat.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// # DROPDOWNS
//
// In bs3, dropdown menus are .dropdown-menu>li.active>a
// In bs4, dropdown menus are .dropdown-menu>.dropdown-item.active
//
// Also, bs3 dropdowns within tabs/pills are interfered with in bs4 by
// selectors like `.bs-tabs li>a`, making menu items look like tabs.

.dropdown-menu>li>a {
@extend .dropdown-item;
}
.dropdown-menu>li.active>a {
// This @extend works, but it litters `.dropdown-menu>li.active>a` all over
// the bootstrap.css output because it's such a common class. Instead, we
// copy these few properties from from _dropdown.scss.
// @extend .active;
color: $dropdown-link-active-color;
text-decoration: none;
@include gradient-bg($dropdown-link-active-bg);
}
.dropdown-menu>li.divider {
@extend .dropdown-divider;
}
32 changes: 32 additions & 0 deletions inst/bs3compat/_nav_compat.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Fix tab selector borders in bs3.
.nav-tabs>li,
.nav-pills>li {
@extend .nav-item;
}
.nav-tabs>li>a,
.nav-pills>li>a {
@extend .nav-link;
}

// Active tab/pill.
//
// bs3 uses .nav>li.active>a, bs4 uses .nav>li>a.active or .nav>li.show>a.
//
// My original approach to this was making .nav>li.active @extend .show, but
// after a lot of trial and error I could not get it to fully work.
.nav-tabs>li.active>a {
color: $nav-tabs-link-active-color;
background-color: $nav-tabs-link-active-bg;
border-color: $nav-tabs-link-active-border-color;
}
.nav-pills>li.active>a {
color: $nav-pills-link-active-color;
background-color: $nav-pills-link-active-bg;
}

// Support vertical pills
.nav-stacked {
// Don't extend the .flex-column utility, it uses !important
// @extend .flex-column;
flex-direction: column;
}
53 changes: 53 additions & 0 deletions inst/bs3compat/_navbar_compat.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// bs4 navbars require .navbar-expand[-sm|-md|-lg|-xl], but bs3 navbars
// don't have them. This selector matches .navbar without .navbar-expand
// and defaults it to .navbar-expand-sm.
.navbar:not(.navbar-expand):not(.navbar-expand-sm):not(.navbar-expand-md):not(.navbar-expand-lg):not(.navbar-expand-xl) {
@extend .navbar-expand-sm;
}

// Map BS3 navbar positioning to general utilities
.navbar-fixed-top {
@extend .fixed-top;
}
.navbar-fixed-bottom {
@extend .fixed-bottom;
}
.navbar-sticky-top {
@extend .sticky-top;
}

ul.nav.navbar-nav {
flex: 1;
min-width: map-get($container-max-widths, sm) - 30px;
&.navbar-right {
justify-content: end;
}
}

ul.nav.navbar-nav>li:not(.dropdown) {
@extend .nav-item;
}
ul.nav.navbar-nav>li>a {
@extend .nav-link;
}
.navbar.navbar-default {
@extend .navbar-light;
@extend .bg-light;
}
.navbar.navbar-inverse {
color: $navbar-dark-color;
@extend .navbar-dark;
@extend .bg-dark;
}

// Implement bs3 navbar toggler; used in Rmd websites, i.e.
// https://github.com/rstudio/rmarkdown-website/blob/453e1802b32b5baf1c8a67f80947adcc53e49b7f/_navbar.html
.navbar-toggle {
@extend .navbar-toggler;
}
.navbar-toggle>.icon-bar+.icon-bar {
display: none;
}
.navbar-toggle>.icon-bar:first-child {
@extend .navbar-toggler-icon;
}
84 changes: 6 additions & 78 deletions inst/bs3compat/_post_variables.scss
Original file line number Diff line number Diff line change
@@ -1,79 +1,7 @@
.well {
@extend .bg-light; @extend .card; @extend .p-3;
}
@import "components_compat";
@import "dropdown_compat";
@import "navbar_compat";
@import "nav_compat";

// For verbatimTextOutput()
pre.shiny-text-output {
@extend .bg-light; @extend .card; @extend .p-2;
}

// For code inside of showcase mode
pre.shiny-code {
padding: 0.5rem;
}

.help-text, .help-block {
@extend .form-text; @extend .text-muted;
}

/*
/ Shim for navbarMenu() inside tabsetPanel() (or navlistPanel())
/ Note that the additional CSS intentionally makes it virtually impossible
/ to click the <li> tag, so we have "one source of truth" when we clean up
/ active tags in shiny's tab showing logic
/ https://github.com/rstudio/shiny/blob/2d979d0/srcjs/input_binding_tabinput.js#L41-L63
*/
.nav .dropdown-menu li:not(.divider) {
@extend .nav-pills, .dropdown-item;
padding: 0;
a.nav-link {
border: none;
border-radius: 0;
}
a.nav-link:not(.active):hover {
background-color: $light !important;
}
}

.shiny-input-checkboxgroup, .shiny-input-radiogroup {
.checkbox, .radio {
@extend .form-check;
label {
@extend .form-check-label;
}
label > input {
@extend .form-check-input;
}
}

// Since these inline classes don't have a proper div container
// (they're labels), we borrow just the styling we need from
// .form-check-inline
// https://github.com/rstudio/bs4/blob/7aadd19/inst/node_modules/bootstrap/scss/_forms.scss#L227-L240
.checkbox-inline, .radio-inline {
padding-left: 0;
margin-right: $form-check-inline-margin-x;

label > input {
margin-top: 0;
margin-right: $form-check-inline-input-margin-x;
margin-bottom: 0;
}
}
}

.input-daterange .input-group-addon.input-group-prepend.input-group-append {
padding: inherit;
line-height: inherit;
text-shadow: inherit;
border-width: 0;
}

.selectize-input.focus {
@extend .form-control:focus;
}

.selectize-control.multi .selectize-input > div.active {
background: $component-active-bg;
color: $component-active-color;
}
@import "shiny_input";
@import "shiny_misc";
42 changes: 42 additions & 0 deletions inst/bs3compat/_shiny_input.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
.shiny-input-checkboxgroup, .shiny-input-radiogroup {
.checkbox, .radio {
@extend .form-check;
label {
@extend .form-check-label;
}
label > input {
@extend .form-check-input;
}
}

// Since these inline classes don't have a proper div container
// (they're labels), we borrow just the styling we need from
// .form-check-inline
// https://github.com/rstudio/bs4/blob/7aadd19/inst/node_modules/bootstrap/scss/_forms.scss#L227-L240
.checkbox-inline, .radio-inline {
padding-left: 0;
margin-right: $form-check-inline-margin-x;

label > input {
margin-top: 0;
margin-right: $form-check-inline-input-margin-x;
margin-bottom: 0;
}
}
}

.input-daterange .input-group-addon.input-group-prepend.input-group-append {
padding: inherit;
line-height: inherit;
text-shadow: inherit;
border-width: 0;
}

.selectize-input.focus {
@extend .form-control:focus;
}

.selectize-control.multi .selectize-input > div.active {
background: $component-active-bg;
color: $component-active-color;
}
9 changes: 9 additions & 0 deletions inst/bs3compat/_shiny_misc.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// For verbatimTextOutput()
pre.shiny-text-output {
@extend .bg-light; @extend .card; @extend .p-2;
}

// For code inside of showcase mode
pre.shiny-code {
padding: 0.5rem;
}
72 changes: 72 additions & 0 deletions inst/bs3compat/js/bs3compat.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
(function($) {
if (!$.fn.tab.Constructor.VERSION.match(/^3\./)) {
(console.warn || console.error || console.log)("bs3compat.js couldn't find bs3 tab impl; bs3 tabs will not be properly supported");
return;
}
var bs3TabPlugin = $.fn.tab.noConflict();

if (!$.fn.tab.Constructor.VERSION.match(/^4\./)) {
(console.warn || console.error || console.log)("bs3compat.js couldn't find bs4 tab impl; bs3 tabs will not be properly supported");
return;
}
var bs4TabPlugin = $.fn.tab.noConflict();

var EVENT_KEY = "click.bs.tab.data-api";
var SELECTOR = '[data-toggle="tab"], [data-toggle="pill"]';

$(document).off(EVENT_KEY);
$(document).on(EVENT_KEY, SELECTOR, function(event) {
event.preventDefault();
$(this).tab("show");
});

function TabPlugin(config) {
if ($(this).closest(".nav").find(".nav-item, .nav-link").length === 0) {
// Bootstrap 3 tabs detected
bs3TabPlugin.call($(this), config);
} else {
// Bootstrap 4 tabs detected
bs4TabPlugin.call($(this), config);
}
}

var noconflict = $.fn.tab;
$.fn.tab = TabPlugin;
$.fn.tab.Constructor = bs4TabPlugin.Constructor;
$.fn.tab.noConflict = function() {
$.fn.tab = noconflict;
return TabPlugin;
};

})(jQuery);

// bs3 navbar: li.active > a
// bs4 navbar: li > a.active
// bs3 tabset: li.active > a
// bs4 tabset: li > a.active


(function($) {
/*
* Bootstrap 4 uses poppler.js to choose what direction to show dropdown
* menus, except in the case of navbars; they assume that navbars are always
* at the top of the page, so this isn't necessary. However, Bootstrap 3
* explicitly supported bottom-positioned navbars via .navbar-fixed-bottom,
* and .fixed-bottom works on Bootstrap 4 as well.
*
* We monkeypatch the dropdown plugin's _detectNavbar method to return false
* if we're in a bottom-positioned navbar.
*/
if (!$.fn.dropdown.Constructor.prototype._detectNavbar) {
// If we get here, the dropdown plugin's implementation must've changed.
// Someone will need to go into Bootstrap's dropdown.js.
(console.warn || console.error || console.log)("bs3compat.js couldn't detect the dropdown plugin's _detectNavbar method");
return;
}

var oldDetectNavbar = $.fn.dropdown.Constructor.prototype._detectNavbar;
$.fn.dropdown.Constructor.prototype._detectNavbar = function() {
return oldDetectNavbar.apply(this, this.arguments) &&
!($(this._element).closest('.navbar').filter('.navbar-fixed-bottom, .fixed-bottom').length > 0);
};
})(jQuery);
Loading