Skip to content

Commit

Permalink
Merge branch 'main' into main-lmp-side-navigation
Browse files Browse the repository at this point in the history
  • Loading branch information
julien-deramond authored Jul 15, 2022
2 parents 3119c65 + bc91bbe commit 2b0c2a3
Show file tree
Hide file tree
Showing 53 changed files with 465 additions and 399 deletions.
2 changes: 1 addition & 1 deletion .bundlewatch.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
},
{
"path": "./dist/js/boosted.esm.js",
"maxSize": "32.75 kB"
"maxSize": "33 kB"
},
{
"path": "./dist/js/boosted.esm.min.js",
Expand Down
89 changes: 42 additions & 47 deletions js/src/dom/event-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,12 @@ const nativeEvents = new Set([
* Private methods
*/

function getUidEvent(element, uid) {
function makeEventUid(element, uid) {
return (uid && `${uid}::${uidEvent++}`) || element.uidEvent || uidEvent++
}

function getEvent(element) {
const uid = getUidEvent(element)
function getElementEvents(element) {
const uid = makeEventUid(element)

element.uidEvent = uid
eventRegistry[uid] = eventRegistry[uid] || {}
Expand Down Expand Up @@ -121,32 +121,30 @@ function bootstrapDelegationHandler(element, selector, fn) {
}
}

function findHandler(events, handler, delegationSelector = null) {
function findHandler(events, callable, delegationSelector = null) {
return Object.values(events)
.find(event => event.originalHandler === handler && event.delegationSelector === delegationSelector)
.find(event => event.callable === callable && event.delegationSelector === delegationSelector)
}

function normalizeParameters(originalTypeEvent, handler, delegationFunction) {
const delegation = typeof handler === 'string'
const originalHandler = delegation ? delegationFunction : handler
const isDelegated = typeof handler === 'string'
// todo: tooltip passes `false` instead of selector, so we need to check
const callable = isDelegated ? delegationFunction : (handler || delegationFunction)
let typeEvent = getTypeEvent(originalTypeEvent)

if (!nativeEvents.has(typeEvent)) {
typeEvent = originalTypeEvent
}

return [delegation, originalHandler, typeEvent]
return [isDelegated, callable, typeEvent]
}

function addHandler(element, originalTypeEvent, handler, delegationFunction, oneOff) {
if (typeof originalTypeEvent !== 'string' || !element) {
return
}

if (!handler) {
handler = delegationFunction
delegationFunction = null
}
let [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)

// in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position
// this prevents the handler from being dispatched the same way as mouseover or mouseout does
Expand All @@ -159,36 +157,31 @@ function addHandler(element, originalTypeEvent, handler, delegationFunction, one
}
}

if (delegationFunction) {
delegationFunction = wrapFunction(delegationFunction)
} else {
handler = wrapFunction(handler)
}
callable = wrapFunction(callable)
}

const [delegation, originalHandler, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)
const events = getEvent(element)
const events = getElementEvents(element)
const handlers = events[typeEvent] || (events[typeEvent] = {})
const previousFunction = findHandler(handlers, originalHandler, delegation ? handler : null)
const previousFunction = findHandler(handlers, callable, isDelegated ? handler : null)

if (previousFunction) {
previousFunction.oneOff = previousFunction.oneOff && oneOff

return
}

const uid = getUidEvent(originalHandler, originalTypeEvent.replace(namespaceRegex, ''))
const fn = delegation ?
bootstrapDelegationHandler(element, handler, delegationFunction) :
bootstrapHandler(element, handler)
const uid = makeEventUid(callable, originalTypeEvent.replace(namespaceRegex, ''))
const fn = isDelegated ?
bootstrapDelegationHandler(element, handler, callable) :
bootstrapHandler(element, callable)

fn.delegationSelector = delegation ? handler : null
fn.originalHandler = originalHandler
fn.delegationSelector = isDelegated ? handler : null
fn.callable = callable
fn.oneOff = oneOff
fn.uidEvent = uid
handlers[uid] = fn

element.addEventListener(typeEvent, fn, delegation)
element.addEventListener(typeEvent, fn, isDelegated)
}

function removeHandler(element, events, typeEvent, handler, delegationSelector) {
Expand All @@ -208,7 +201,7 @@ function removeNamespacedHandlers(element, events, typeEvent, namespace) {
for (const handlerKey of Object.keys(storeElementEvent)) {
if (handlerKey.includes(namespace)) {
const event = storeElementEvent[handlerKey]
removeHandler(element, events, typeEvent, event.originalHandler, event.delegationSelector)
removeHandler(element, events, typeEvent, event.callable, event.delegationSelector)
}
}
}
Expand All @@ -233,18 +226,19 @@ const EventHandler = {
return
}

const [delegation, originalHandler, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)
const [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)
const inNamespace = typeEvent !== originalTypeEvent
const events = getEvent(element)
const events = getElementEvents(element)
const storeElementEvent = events[typeEvent] || {}
const isNamespace = originalTypeEvent.startsWith('.')

if (typeof originalHandler !== 'undefined') {
if (typeof callable !== 'undefined') {
// Simplest case: handler is passed, remove that listener ONLY.
if (!events || !events[typeEvent]) {
if (!storeElementEvent) {
return
}

removeHandler(element, events, typeEvent, originalHandler, delegation ? handler : null)
removeHandler(element, events, typeEvent, callable, isDelegated ? handler : null)
return
}

Expand All @@ -254,13 +248,12 @@ const EventHandler = {
}
}

const storeElementEvent = events[typeEvent] || {}
for (const keyHandlers of Object.keys(storeElementEvent)) {
const handlerKey = keyHandlers.replace(stripUidRegex, '')

if (!inNamespace || originalTypeEvent.includes(handlerKey)) {
const event = storeElementEvent[keyHandlers]
removeHandler(element, events, typeEvent, event.originalHandler, event.delegationSelector)
removeHandler(element, events, typeEvent, event.callable, event.delegationSelector)
}
}
},
Expand Down Expand Up @@ -288,18 +281,8 @@ const EventHandler = {
defaultPrevented = jQueryEvent.isDefaultPrevented()
}

const evt = new Event(event, { bubbles, cancelable: true })

// merge custom information in our event
if (typeof args !== 'undefined') {
for (const key of Object.keys(args)) {
Object.defineProperty(evt, key, {
get() {
return args[key]
}
})
}
}
let evt = new Event(event, { bubbles, cancelable: true })
evt = hydrateObj(evt, args)

if (defaultPrevented) {
evt.preventDefault()
Expand All @@ -317,4 +300,16 @@ const EventHandler = {
}
}

function hydrateObj(obj, meta) {
for (const [key, value] of Object.entries(meta || {})) {
Object.defineProperty(obj, key, {
get() {
return value
}
})
}

return obj
}

export default EventHandler
2 changes: 1 addition & 1 deletion js/tests/visual/modal.html
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ <h4 class="modal-title" id="slowModalLabel">Lorem slowly</h4>

<br><br>

<div class="bg-dark text-white p-2" id="tall" style="display: none;">
<div class="text-bg-dark p-2" id="tall" style="display: none;">
Tall body content to force the page to have a scrollbar.
</div>

Expand Down
1 change: 1 addition & 0 deletions scss/_back-to-top.scss
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
right: var(--#{$prefix}back-to-top-right);
bottom: var(--#{$prefix}back-to-top-bottom);
z-index: var(--#{$prefix}back-to-top-zindex);
pointer-events: none;
}

.back-to-top-link {
Expand Down
2 changes: 1 addition & 1 deletion scss/_buttons.scss
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@
--#{$prefix}btn-border-color: transparent;
--#{$prefix}btn-hover-color: #{$btn-link-hover-color};
--#{$prefix}btn-hover-border-color: transparent;
--#{$prefix}btn-active-color: #{$primary}; // Boosted mod
--#{$prefix}btn-active-color: var(--#{$prefix}btn-hover-color); // Boosted mod
--#{$prefix}btn-active-border-color: transparent;
--#{$prefix}btn-disabled-color: #{$btn-link-disabled-color};
--#{$prefix}btn-disabled-border-color: transparent;
Expand Down
22 changes: 11 additions & 11 deletions scss/_offcanvas.scss
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,6 @@
@include box-shadow(var(--#{$prefix}offcanvas-box-shadow));
@include transition(transform $offcanvas-transition-duration ease-in-out);

&.showing,
&.show:not(.hiding) {
transform: none;
}

&.showing,
&.hiding,
&.show {
visibility: visible;
}

&.offcanvas-start {
top: 0;
left: 0;
Expand Down Expand Up @@ -88,6 +77,17 @@
border-top: var(--#{$prefix}offcanvas-border-width) solid var(--#{$prefix}offcanvas-border-color);
transform: translateY(100%);
}

&.showing,
&.show:not(.hiding) {
transform: none;
}

&.showing,
&.hiding,
&.show {
visibility: visible;
}
}

@if not ($infix == "") {
Expand Down
8 changes: 4 additions & 4 deletions scss/_variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -1001,8 +1001,8 @@ $input-placeholder-color: $gray-700 !default;
$input-plaintext-color: var(--#{$prefix}body-color) !default;

$input-height-inner: add($input-line-height * 1em, $input-padding-y * 2) !default;
// Boosted mod: no $input-height-inner-half
// Boosted mod: no $input-height-inner-quarter
$input-height-inner-half: $spacer !default; // Boosted mod
$input-height-inner-quarter: map-get($spacers, 2) !default; // Boosted mod

$input-height: 2.5rem !default;
// Boosted mod: no $input-height-sm
Expand Down Expand Up @@ -1041,8 +1041,8 @@ $form-check-input-checked-bg-image: var(--#{$boosted-prefix}check-icon) !d
$form-check-input-disabled-color: $gray-900 !default; // Boosted mod
$form-check-radio-checked-bg-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'><circle r='2' fill='#{$form-check-input-checked-color}'/></svg>") !default;

$form-check-input-indeterminate-color: color-contrast($component-active-color) !default;
$form-check-input-indeterminate-bg-color: $component-active-color !default;
$form-check-input-indeterminate-color: $form-check-input-checked-color !default;
$form-check-input-indeterminate-bg-color: $form-check-input-checked-bg-color !default;
$form-check-input-indeterminate-border-color: $form-check-input-indeterminate-bg-color !default;
$form-check-input-indeterminate-bg-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 3'><path fill='#{$form-check-input-indeterminate-color}' d='M0 0h10v3H0z'/></svg>") !default;

Expand Down
15 changes: 9 additions & 6 deletions scss/forms/_form-check.scss
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,18 @@
border-radius: $form-check-radio-border-radius;
}

&:focus {
border-color: $form-check-input-focus-border;
box-shadow: $form-check-input-focus-box-shadow;
}

&:active {
background-color: $form-check-input-active-bg-color; // Boosted mod
filter: $form-check-input-active-filter;
border-color: $form-check-input-active-bg-color; // Boosted mod
}

&:focus {
border-color: $form-check-input-focus-border;
// Boosted mod: default outline
box-shadow: $form-check-input-focus-box-shadow;
}

&:checked {
background-color: $form-check-input-checked-bg-color;
border-color: $form-check-input-checked-border-color;
Expand Down Expand Up @@ -103,7 +104,8 @@
opacity: $form-check-input-disabled-opacity;

// Boosted mod
&:checked {
&:checked,
&:indeterminate {
background-color: $form-check-input-disabled-color;
filter: $invert-filter;
border-color: $form-check-input-disabled-color;
Expand All @@ -117,6 +119,7 @@
&:disabled {
~ .form-check-label {
color: $form-label-disabled-color; // Boosted mod
pointer-events: none;
cursor: default;
opacity: $form-check-label-disabled-opacity;
}
Expand Down
5 changes: 4 additions & 1 deletion scss/mixins/_forms.scss
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@
@if $enable-validation-icons {
.form-control {
@include form-validation-state-selector($state) {
background: $icon no-repeat right map-get($spacers, 2) center / $spacer;
background-image: escape-svg($icon);
background-repeat: no-repeat;
background-position: right $input-height-inner-quarter center;
background-size: $input-height-inner-half $input-height-inner-half;
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions site/assets/js/snippets.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,9 @@
}

// Indeterminate checkbox example
document.querySelectorAll('.bd-example-indeterminate [type="checkbox"]')
.forEach(checkbox => {
checkbox.indeterminate = true
document.querySelectorAll('.bd-example-indeterminate')
.forEach(example => {
example.querySelector('[type="checkbox"]').indeterminate = true
})

// Disable empty links in docs examples
Expand Down
3 changes: 1 addition & 2 deletions site/assets/scss/_boosted.scss
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ body {
height: 25em;
font-size: 36%; // 1
box-shadow: -2em 2em $gray-600, -4em 4em $gray-300;
transform: rotateX(50deg) rotateY(0deg) rotateZ(-45deg);
scale: .7;
transform: rotateX(50deg) rotateY(0deg) rotateZ(-45deg) scale(.7);

@include media-breakpoint-up(sm) {
font-size: xx-small;
Expand Down
16 changes: 1 addition & 15 deletions site/assets/scss/_footer.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,4 @@
// Footer
//

.bd-footer {
@include font-size(.875rem);
position: sticky;
top: 100vh;
font-weight: 700;

a {
color: var(--#{$prefix}link-color); // Boosted mod: use CSS var instead of $link-color

&:hover,
&:focus {
color: var(--#{$prefix}link-hover-color); // Boosted mod: use CSS var instead of $link-hover-color
}
}
}
// Boosted mod: no .bd-footer
Loading

0 comments on commit 2b0c2a3

Please sign in to comment.