first commit

This commit is contained in:
2024-07-15 12:33:27 +02:00
commit ce50ae282b
22084 changed files with 2623791 additions and 0 deletions

View File

@@ -0,0 +1,40 @@
/**
* @file
* Maintains and deprecates Dialog jQuery events.
*/
(function ($, Drupal, once) {
if (once('drupal-dialog-deprecation-listener', 'html').length) {
const eventSpecial = {
handle($event) {
const $element = $($event.target);
const event = $event.originalEvent;
const dialog = event.dialog;
const dialogArguments = [$event, dialog, $element, event?.settings];
$event.handleObj.handler.apply(this, dialogArguments);
},
};
$.event.special['dialog:beforecreate'] = eventSpecial;
$.event.special['dialog:aftercreate'] = eventSpecial;
$.event.special['dialog:beforeclose'] = eventSpecial;
$.event.special['dialog:afterclose'] = eventSpecial;
const listenDialogEvent = (event) => {
const windowEvents = $._data(window, 'events');
const isWindowHasDialogListener = windowEvents[event.type];
if (isWindowHasDialogListener) {
Drupal.deprecationError({
message: `jQuery event ${event.type} is deprecated in 10.3.0 and is removed from Drupal:12.0.0. See https://www.drupal.org/node/3422670`,
});
}
};
[
'dialog:beforecreate',
'dialog:aftercreate',
'dialog:beforeclose',
'dialog:afterclose',
].forEach((e) => window.addEventListener(e, listenDialogEvent));
}
})(jQuery, Drupal, once);

320
core/misc/dialog/dialog.ajax.js Executable file
View File

@@ -0,0 +1,320 @@
/**
* @file
* Extends the Drupal AJAX functionality to integrate the dialog API.
*/
(function ($, Drupal, { focusable }) {
/**
* Initialize dialogs for Ajax purposes.
*
* @type {Drupal~behavior}
*
* @prop {Drupal~behaviorAttach} attach
* Attaches the behaviors for dialog ajax functionality.
*/
Drupal.behaviors.dialog = {
attach(context, settings) {
const $context = $(context);
// Provide a known 'drupal-modal' DOM element for Drupal-based modal
// dialogs. Non-modal dialogs are responsible for creating their own
// elements, since there can be multiple non-modal dialogs at a time.
if (!$('#drupal-modal').length) {
// Add 'ui-front' jQuery UI class so jQuery UI widgets like autocomplete
// sit on top of dialogs. For more information see
// http://api.jqueryui.com/theming/stacking-elements/.
$('<div id="drupal-modal" class="ui-front"></div>')
.hide()
.appendTo('body');
}
// Special behaviors specific when attaching content within a dialog.
// These behaviors usually fire after a validation error inside a dialog.
const $dialog = $context.closest('.ui-dialog-content');
if ($dialog.length) {
// Remove and replace the dialog buttons with those from the new form.
if ($dialog.dialog('option', 'drupalAutoButtons')) {
// Trigger an event to detect/sync changes to buttons.
$dialog.trigger('dialogButtonsChange');
}
setTimeout(function () {
// Account for pre-existing focus handling that may have already moved
// the focus inside the dialog.
if (!$dialog[0].contains(document.activeElement)) {
// Move focus to the first focusable element in the next event loop
// to allow dialog buttons to be changed first.
$dialog.dialog('instance')._focusedElement = null;
$dialog.dialog('instance')._focusTabbable();
}
}, 0);
}
const originalClose = settings.dialog.close;
// Overwrite the close method to remove the dialog on closing.
settings.dialog.close = function (event, ...args) {
originalClose.apply(settings.dialog, [event, ...args]);
// Check if the opener element is inside an AJAX container.
const $element = $(event.target);
const ajaxContainer = $element.data('uiDialog')
? $element
.data('uiDialog')
.opener.closest('[data-drupal-ajax-container]')
: [];
// If the opener element was in an ajax container, and focus is on the
// body element, we can assume focus was lost. To recover, focus is
// moved to the first focusable element in the container.
if (
ajaxContainer.length &&
(document.activeElement === document.body ||
$(document.activeElement).not(':visible'))
) {
const focusableChildren = focusable(ajaxContainer[0]);
if (focusableChildren.length > 0) {
setTimeout(() => {
focusableChildren[0].focus();
}, 0);
}
}
$(event.target).remove();
};
},
/**
* Scan a dialog for any primary buttons and move them to the button area.
*
* @param {jQuery} $dialog
* A jQuery object containing the element that is the dialog target.
*
* @return {Array}
* An array of buttons that need to be added to the button area.
*/
prepareDialogButtons($dialog) {
const buttons = [];
const $buttons = $dialog.find(
'.form-actions input[type=submit], .form-actions a.button, .form-actions a.action-link',
);
$buttons.each(function () {
const $originalButton = $(this);
this.style.display = 'none';
buttons.push({
text: $originalButton.html() || $originalButton.attr('value'),
class: $originalButton.attr('class'),
'data-once': $originalButton.data('once'),
click(e) {
// If the original button is an anchor tag, triggering the "click"
// event will not simulate a click. Use the click method instead.
if ($originalButton[0].tagName === 'A') {
$originalButton[0].click();
} else {
$originalButton
.trigger('mousedown')
.trigger('mouseup')
.trigger('click');
}
e.preventDefault();
},
});
});
return buttons;
},
};
/**
* Command to open a dialog.
*
* @param {Drupal.Ajax} ajax
* The Drupal Ajax object.
* @param {object} response
* Object holding the server response.
* @param {number} [status]
* The HTTP status code.
*
* @return {boolean|undefined}
* Returns false if there was no selector property in the response object.
*/
Drupal.AjaxCommands.prototype.openDialog = function (ajax, response, status) {
if (!response.selector) {
return false;
}
let $dialog = $(response.selector);
if (!$dialog.length) {
// Create the element if needed.
$dialog = $(
`<div id="${response.selector.replace(
/^#/,
'',
)}" class="ui-front"></div>`,
).appendTo('body');
}
// Set up the wrapper, if there isn't one.
if (!ajax.wrapper) {
ajax.wrapper = $dialog.attr('id');
}
// Use the ajax.js insert command to populate the dialog contents.
response.command = 'insert';
response.method = 'html';
ajax.commands.insert(ajax, response, status);
// Move the buttons to the jQuery UI dialog buttons area.
response.dialogOptions = response.dialogOptions || {};
if (typeof response.dialogOptions.drupalAutoButtons === 'undefined') {
response.dialogOptions.drupalAutoButtons = true;
} else if (response.dialogOptions.drupalAutoButtons === 'false') {
response.dialogOptions.drupalAutoButtons = false;
} else {
response.dialogOptions.drupalAutoButtons =
!!response.dialogOptions.drupalAutoButtons;
}
if (
!response.dialogOptions.buttons &&
response.dialogOptions.drupalAutoButtons
) {
response.dialogOptions.buttons =
Drupal.behaviors.dialog.prepareDialogButtons($dialog);
}
// Bind dialogButtonsChange.
$dialog.on('dialogButtonsChange', () => {
const buttons = Drupal.behaviors.dialog.prepareDialogButtons($dialog);
$dialog.dialog('option', 'buttons', buttons);
});
// Open the dialog itself.
response.dialogOptions = response.dialogOptions || {};
const dialog = Drupal.dialog($dialog.get(0), response.dialogOptions);
if (response.dialogOptions.modal) {
dialog.showModal();
} else {
dialog.show();
}
// Add the standard Drupal class for buttons for style consistency.
$dialog.parent().find('.ui-dialog-buttonset').addClass('form-actions');
};
/**
* Command to close a dialog.
*
* If no selector is given, it defaults to trying to close the modal.
*
* @param {Drupal.Ajax} [ajax]
* The ajax object.
* @param {object} response
* Object holding the server response.
* @param {string} response.selector
* The selector of the dialog.
* @param {boolean} response.persist
* Whether to persist the dialog element or not.
* @param {number} [status]
* The HTTP status code.
*/
Drupal.AjaxCommands.prototype.closeDialog = function (
ajax,
response,
status,
) {
const $dialog = $(response.selector);
if ($dialog.length) {
Drupal.dialog($dialog.get(0)).close();
if (!response.persist) {
$dialog.remove();
}
}
// Unbind dialogButtonsChange.
$dialog.off('dialogButtonsChange');
};
/**
* Command to set a dialog property.
*
* JQuery UI specific way of setting dialog options.
*
* @param {Drupal.Ajax} [ajax]
* The Drupal Ajax object.
* @param {object} response
* Object holding the server response.
* @param {string} response.selector
* Selector for the dialog element.
* @param {string} response.optionsName
* Name of a key to set.
* @param {string} response.optionValue
* Value to set.
* @param {number} [status]
* The HTTP status code.
*/
Drupal.AjaxCommands.prototype.setDialogOption = function (
ajax,
response,
status,
) {
const $dialog = $(response.selector);
if ($dialog.length) {
$dialog.dialog('option', response.optionName, response.optionValue);
}
};
/**
* Binds a listener on dialog creation to handle the cancel link.
*
* @param {jQuery.Event} e
* The event triggered.
* @param {Drupal.dialog~dialogDefinition} dialog
* The dialog instance.
* @param {jQuery} $element
* The jQuery collection of the dialog element.
* @param {object} [settings]
* Dialog settings.
*/
window.addEventListener('dialog:aftercreate', (event) => {
const $element = $(event.target);
const dialog = event.dialog;
$element.on('click.dialog', '.dialog-cancel', (e) => {
dialog.close('cancel');
e.preventDefault();
e.stopPropagation();
});
});
/**
* Removes all 'dialog' listeners.
*
* @param {jQuery.Event} e
* The event triggered.
* @param {Drupal.dialog~dialogDefinition} dialog
* The dialog instance.
* @param {jQuery} $element
* jQuery collection of the dialog element.
*/
window.addEventListener('dialog:beforeclose', (e) => {
const $element = $(e.target);
$element.off('.dialog');
});
/**
* Ajax command to open URL in a modal dialog.
*
* @param {Drupal.Ajax} [ajax]
* An Ajax object.
* @param {object} response
* The Ajax response.
*/
Drupal.AjaxCommands.prototype.openModalDialogWithUrl = function (
ajax,
response,
) {
const dialogOptions = response.dialogOptions || {};
const elementSettings = {
progress: { type: 'throbber' },
dialogType: 'modal',
dialog: dialogOptions,
url: response.url,
httpMethod: 'GET',
};
Drupal.ajax(elementSettings).execute();
};
})(jQuery, Drupal, window.tabbable);

View File

@@ -0,0 +1,75 @@
/**
* @file
* Adds default classes to buttons for styling purposes.
*/
(function ($, { tabbable, isTabbable }) {
$.widget('ui.dialog', $.ui.dialog, {
options: {
buttonClass: 'button',
buttonPrimaryClass: 'button--primary',
},
_createButtons() {
const opts = this.options;
let primaryIndex;
let index;
const il = opts.buttons.length;
for (index = 0; index < il; index++) {
if (
opts.buttons[index].primary &&
opts.buttons[index].primary === true
) {
primaryIndex = index;
delete opts.buttons[index].primary;
break;
}
}
this._super();
const $buttons = this.uiButtonSet.children().addClass(opts.buttonClass);
if (typeof primaryIndex !== 'undefined') {
$buttons.eq(index).addClass(opts.buttonPrimaryClass);
}
},
// Override jQuery UI's `_focusTabbable()` so finding tabbable elements uses
// the core/tabbable library instead of jQuery UI's `:tabbable` selector.
_focusTabbable() {
// Set focus to the first match:
// 1. An element that was focused previously.
let hasFocus = this._focusedElement ? this._focusedElement.get(0) : null;
// 2. First element inside the dialog matching [autofocus].
if (!hasFocus) {
hasFocus = this.element.find('[autofocus]').get(0);
}
// 3. Tabbable element inside the content element.
// 4. Tabbable element inside the buttonpane.
if (!hasFocus) {
const $elements = [this.element, this.uiDialogButtonPane];
for (let i = 0; i < $elements.length; i++) {
const element = $elements[i].get(0);
if (element) {
const elementTabbable = tabbable(element);
hasFocus = elementTabbable.length ? elementTabbable[0] : null;
}
if (hasFocus) {
break;
}
}
}
// 5. The close button.
if (!hasFocus) {
const closeBtn = this.uiDialogTitlebarClose.get(0);
hasFocus = closeBtn && isTabbable(closeBtn) ? closeBtn : null;
}
// 6. The dialog itself.
if (!hasFocus) {
hasFocus = this.uiDialog.get(0);
}
$(hasFocus).eq(0).trigger('focus');
},
});
})(jQuery, window.tabbable);

123
core/misc/dialog/dialog.js Executable file
View File

@@ -0,0 +1,123 @@
/**
* @file
* Dialog API inspired by HTML5 dialog element.
*
* @see http://www.whatwg.org/specs/web-apps/current-work/multipage/commands.html#the-dialog-element
*/
class DrupalDialogEvent extends Event {
constructor(type, dialog, settings = null) {
super(`dialog:${type}`, { bubbles: true });
this.dialog = dialog;
this.settings = settings;
}
}
(function ($, Drupal, drupalSettings, bodyScrollLock) {
/**
* Default dialog options.
*
* @type {object}
*
* @prop {boolean} [autoOpen=true]
* @prop {string} [dialogClass='']
* @prop {string} [buttonClass='button']
* @prop {string} [buttonPrimaryClass='button--primary']
* @prop {function} close
*/
drupalSettings.dialog = {
autoOpen: true,
dialogClass: '',
// Drupal-specific extensions: see dialog.jquery-ui.js.
buttonClass: 'button',
buttonPrimaryClass: 'button--primary',
// When using this API directly (when generating dialogs on the client
// side), you may want to override this method and do
// `jQuery(event.target).remove()` as well, to remove the dialog on
// closing.
close(event) {
Drupal.dialog(event.target).close();
Drupal.detachBehaviors(event.target, null, 'unload');
},
};
/**
* @typedef {object} Drupal.dialog~dialogDefinition
*
* @prop {boolean} open
* Is the dialog open or not.
* @prop {*} returnValue
* Return value of the dialog.
* @prop {function} show
* Method to display the dialog on the page.
* @prop {function} showModal
* Method to display the dialog as a modal on the page.
* @prop {function} close
* Method to hide the dialog from the page.
*/
/**
* Polyfill HTML5 dialog element with jQueryUI.
*
* @param {HTMLElement} element
* The element that holds the dialog.
* @param {object} options
* jQuery UI options to be passed to the dialog.
*
* @return {Drupal.dialog~dialogDefinition}
* The dialog instance.
*/
Drupal.dialog = function (element, options) {
let undef;
const $element = $(element);
const domElement = $element.get(0);
const dialog = {
open: false,
returnValue: undef,
};
function openDialog(settings) {
settings = $.extend({}, drupalSettings.dialog, options, settings);
// Trigger a global event to allow scripts to bind events to the dialog.
const event = new DrupalDialogEvent('beforecreate', dialog, settings);
domElement.dispatchEvent(event);
$element.dialog(event.settings);
dialog.open = true;
// Locks the body scroll only when it opens in modal.
if (settings.modal) {
// Locks the body when the dialog opens.
bodyScrollLock.lock(domElement);
}
domElement.dispatchEvent(
new DrupalDialogEvent('aftercreate', dialog, settings),
);
}
function closeDialog(value) {
domElement.dispatchEvent(new DrupalDialogEvent('beforeclose', dialog));
// Unlocks the body when the dialog closes.
bodyScrollLock.clearBodyLocks();
$element.dialog('close');
dialog.returnValue = value;
dialog.open = false;
domElement.dispatchEvent(new DrupalDialogEvent('afterclose', dialog));
}
dialog.show = () => {
openDialog({ modal: false });
};
dialog.showModal = () => {
openDialog({ modal: true });
};
dialog.close = closeDialog;
return dialog;
};
})(jQuery, Drupal, drupalSettings, bodyScrollLock);

View File

@@ -0,0 +1,146 @@
/**
* @file
* Positioning extensions for dialogs.
*/
/**
* Triggers when content inside a dialog changes.
*
* @event dialogContentResize
*/
(function ($, Drupal, drupalSettings, debounce, displace) {
// autoResize option will turn off resizable and draggable.
drupalSettings.dialog = $.extend(
{ autoResize: true, maxHeight: '95%' },
drupalSettings.dialog,
);
/**
* Position the dialog's center at the center of displace.offsets boundaries.
*
* @function Drupal.dialog~resetPosition
*
* @param {object} options
* Options object.
*
* @return {object}
* Altered options object.
*/
function resetPosition(options) {
const offsets = displace.offsets;
const left = offsets.left - offsets.right;
const top = offsets.top - offsets.bottom;
const leftString = `${
(left > 0 ? '+' : '-') + Math.abs(Math.round(left / 2))
}px`;
const topString = `${
(top > 0 ? '+' : '-') + Math.abs(Math.round(top / 2))
}px`;
options.position = {
my: `center${left !== 0 ? leftString : ''} center${
top !== 0 ? topString : ''
}`,
of: window,
};
return options;
}
/**
* Resets the current options for positioning.
*
* This is used as a window resize and scroll callback to reposition the
* jQuery UI dialog. Although not a built-in jQuery UI option, this can
* be disabled by setting autoResize: false in the options array when creating
* a new {@link Drupal.dialog}.
*
* @function Drupal.dialog~resetSize
*
* @param {jQuery.Event} event
* The event triggered.
*
* @fires event:dialogContentResize
*/
function resetSize(event) {
const positionOptions = [
'width',
'height',
'minWidth',
'minHeight',
'maxHeight',
'maxWidth',
'position',
];
let adjustedOptions = {};
let windowHeight = $(window).height();
let option;
let optionValue;
let adjustedValue;
for (let n = 0; n < positionOptions.length; n++) {
option = positionOptions[n];
optionValue = event.data.settings[option];
if (optionValue) {
// jQuery UI does not support percentages on heights, convert to pixels.
if (
typeof optionValue === 'string' &&
optionValue.endsWith('%') &&
/height/i.test(option)
) {
// Take offsets in account.
windowHeight -= displace.offsets.top + displace.offsets.bottom;
adjustedValue = parseInt(
0.01 * parseInt(optionValue, 10) * windowHeight,
10,
);
// Don't force the dialog to be bigger vertically than needed.
if (
option === 'height' &&
event.data.$element.parent().outerHeight() < adjustedValue
) {
adjustedValue = 'auto';
}
adjustedOptions[option] = adjustedValue;
}
}
}
// Offset the dialog center to be at the center of Drupal.displace.offsets.
if (!event.data.settings.modal) {
adjustedOptions = resetPosition(adjustedOptions);
}
event.data.$element.dialog('option', adjustedOptions);
event.data.$element
?.get(0)
?.dispatchEvent(
new CustomEvent('dialogContentResize', { bubbles: true }),
);
}
window.addEventListener('dialog:aftercreate', (e) => {
const autoResize = debounce(resetSize, 20);
const $element = $(e.target);
const { settings } = e;
const eventData = { settings, $element };
if (settings.autoResize === true || settings.autoResize === 'true') {
const uiDialog = $element
.dialog('option', { resizable: false, draggable: false })
.dialog('widget');
uiDialog[0].style.position = 'fixed';
$(window)
.on('resize.dialogResize scroll.dialogResize', eventData, autoResize)
.trigger('resize.dialogResize');
$(document).on(
'drupalViewportOffsetChange.dialogResize',
eventData,
autoResize,
);
}
});
window.addEventListener('dialog:beforeclose', () => {
$(window).off('.dialogResize');
$(document).off('.dialogResize');
});
})(jQuery, Drupal, drupalSettings, Drupal.debounce, Drupal.displace);

View File

@@ -0,0 +1,101 @@
/*
* DO NOT EDIT THIS FILE.
* See the following change record for more information,
* https://www.drupal.org/node/3084859
* @preserve
*/
/**
* @file
* Set base styles for the off-canvas dialog.
*
* @internal
*/
#drupal-off-canvas-wrapper {
--off-canvas-background-color-light: #666;
--off-canvas-background-color-medium: #444;
--off-canvas-background-color-dark: #333;
--off-canvas-background-color: var(--off-canvas-background-color-medium);
--off-canvas-padding: 1.25rem;
--off-canvas-text-color: #e5e5e5;
--off-canvas-link-color: #85bef4;
--off-canvas-border-color: #666;
--off-canvas-font-family: "Lucida Grande", "Lucida Sans Unicode", "liberation sans", sans-serif;
--off-canvas-vertical-spacing-unit: 0.5rem;
--off-canvas-focus-outline-width: 2px;
--off-canvas-focus-outline-color: #fff;
padding: 0 var(--off-canvas-padding) var(--off-canvas-padding);
color: var(--off-canvas-text-color);
background-color: var(--off-canvas-background-color);
font-family: var(--off-canvas-font-family);
}
#drupal-off-canvas-wrapper *:focus {
outline: solid var(--off-canvas-focus-outline-width) var(--off-canvas-focus-outline-color);
outline-offset: 2px;
}
#drupal-off-canvas-wrapper a,
#drupal-off-canvas-wrapper .link {
-webkit-text-decoration: none;
text-decoration: none;
color: var(--off-canvas-link-color);
}
#drupal-off-canvas-wrapper hr {
height: 1px;
background: var(--off-canvas-border-color);
}
#drupal-off-canvas-wrapper h1,
#drupal-off-canvas-wrapper .heading-a {
font-size: 1.4375rem;
line-height: 1.2;
}
#drupal-off-canvas-wrapper h2,
#drupal-off-canvas-wrapper .heading-b {
margin: var(--off-canvas-vertical-spacing-unit) 0;
font-size: 1.1875rem;
}
#drupal-off-canvas-wrapper h3,
#drupal-off-canvas-wrapper .heading-c {
margin: var(--off-canvas-vertical-spacing-unit) 0;
font-size: 1.0625rem;
}
#drupal-off-canvas-wrapper h4,
#drupal-off-canvas-wrapper .heading-d {
margin: var(--off-canvas-vertical-spacing-unit) 0;
font-size: 1rem;
}
#drupal-off-canvas-wrapper h5,
#drupal-off-canvas-wrapper .heading-e,
#drupal-off-canvas-wrapper h6,
#drupal-off-canvas-wrapper .heading-f {
margin: var(--off-canvas-vertical-spacing-unit) 0;
font-size: 0.9375rem;
}
#drupal-off-canvas-wrapper p {
margin: var(--off-canvas-vertical-spacing-unit) 0;
}
#drupal-off-canvas-wrapper img {
max-width: 100%;
height: auto;
}
#drupal-off-canvas-wrapper .links {
margin: 0;
padding: 0;
list-style: none;
}
#drupal-off-canvas-wrapper .links li {
margin: calc(var(--off-canvas-vertical-spacing-unit) / 2) 0;
}

View File

@@ -0,0 +1,93 @@
/**
* @file
* Set base styles for the off-canvas dialog.
*
* @internal
*/
#drupal-off-canvas-wrapper {
--off-canvas-background-color-light: #666;
--off-canvas-background-color-medium: #444;
--off-canvas-background-color-dark: #333;
--off-canvas-background-color: var(--off-canvas-background-color-medium);
--off-canvas-padding: 20px;
--off-canvas-text-color: #e5e5e5;
--off-canvas-link-color: #85bef4;
--off-canvas-border-color: #666;
--off-canvas-font-family: "Lucida Grande", "Lucida Sans Unicode", "liberation sans", sans-serif;
--off-canvas-vertical-spacing-unit: 8px;
--off-canvas-focus-outline-width: 2px;
--off-canvas-focus-outline-color: #fff;
padding: 0 var(--off-canvas-padding) var(--off-canvas-padding);
color: var(--off-canvas-text-color);
background-color: var(--off-canvas-background-color);
font-family: var(--off-canvas-font-family);
& *:focus {
outline: solid var(--off-canvas-focus-outline-width) var(--off-canvas-focus-outline-color);
outline-offset: 2px;
}
& a,
& .link {
text-decoration: none;
color: var(--off-canvas-link-color);
}
& hr {
height: 1px;
background: var(--off-canvas-border-color);
}
& h1,
& .heading-a {
font-size: 23px;
line-height: 1.2;
}
& h2,
& .heading-b {
margin: var(--off-canvas-vertical-spacing-unit) 0;
font-size: 19px;
}
& h3,
& .heading-c {
margin: var(--off-canvas-vertical-spacing-unit) 0;
font-size: 17px;
}
& h4,
& .heading-d {
margin: var(--off-canvas-vertical-spacing-unit) 0;
font-size: 16px;
}
& h5,
& .heading-e,
& h6,
& .heading-f {
margin: var(--off-canvas-vertical-spacing-unit) 0;
font-size: 15px;
}
& p {
margin: var(--off-canvas-vertical-spacing-unit) 0;
}
& img {
max-width: 100%;
height: auto;
}
& .links {
margin: 0;
padding: 0;
list-style: none;
& li {
margin: calc(var(--off-canvas-vertical-spacing-unit) / 2) 0;
}
}
}

View File

@@ -0,0 +1,111 @@
/*
* DO NOT EDIT THIS FILE.
* See the following change record for more information,
* https://www.drupal.org/node/3084859
* @preserve
*/
/**
* @file
* Visual styling for buttons in the off-canvas dialog.
*
* @internal
*/
#drupal-off-canvas-wrapper {
--off-canvas-button-background-color: #777;
--off-canvas-button-background-color-hover: #999;
--off-canvas-button-text-color: #f5f5f5;
--off-canvas-button-text-color-hover: #fff;
--off-canvas-button-font-size: 0.875rem;
--off-canvas-button-padding: calc(var(--off-canvas-vertical-spacing-unit) / 2) 1.25rem;
--off-canvas-button-border-color: transparent;
--off-canvas-button-border-radius: 20em;
--off-canvas-button-font-weight: 600;
--off-canvas-primary-button-background-color: #277abd;
--off-canvas-primary-button-background-color-hover: #236aaf;
--off-canvas-primary-button-text-color: #fff;
--off-canvas-primary-button-text-color-hover: #fff;
}
#drupal-off-canvas-wrapper .button {
display: inline-block;
width: 100%;
height: auto;
margin: 0 0 0.625rem;
padding: var(--off-canvas-button-padding);
cursor: pointer;
transition: background 0.5s ease;
text-align: center;
color: var(--off-canvas-button-text-color);
border: solid 1px var(--off-canvas-button-border-color);
border-radius: var(--off-canvas-button-border-radius);
background: var(--off-canvas-button-background-color);
font-family: inherit;
font-size: var(--off-canvas-button-font-size);
font-weight: var(--off-canvas-button-font-weight);
line-height: normal;
appearance: none;
}
#drupal-off-canvas-wrapper .button:hover,
#drupal-off-canvas-wrapper .button:active {
z-index: 10;
-webkit-text-decoration: none;
text-decoration: none;
color: var(--off-canvas-button-text-color-hover);
background-color: var(--off-canvas-button-background-color-hover);
}
#drupal-off-canvas-wrapper .button:disabled,
#drupal-off-canvas-wrapper .button:disabled:active,
#drupal-off-canvas-wrapper .button.is-disabled,
#drupal-off-canvas-wrapper .button.is-disabled:active {
cursor: default;
color: #5c5c5c;
background: #555;
font-weight: normal;
}
#drupal-off-canvas-wrapper .button--primary {
margin-top: 0.9375rem;
color: var(--off-canvas-primary-button-text-color);
background: var(--off-canvas-primary-button-background-color);
}
#drupal-off-canvas-wrapper .button--primary:hover,
#drupal-off-canvas-wrapper .button--primary:active {
color: var(--off-canvas-primary-button-text-color-hover);
background: var(--off-canvas-primary-button-background-color-hover);
}
#drupal-off-canvas-wrapper button.link {
display: inline;
transition: color 0.5s ease;
color: var(--off-canvas-link-color);
border: 0;
background: transparent;
font-size: var(--off-canvas-button-font-size);
}
#drupal-off-canvas-wrapper button.link:hover,
#drupal-off-canvas-wrapper button.link:focus {
-webkit-text-decoration: none;
text-decoration: none;
color: var(--off-canvas-link-color);
}
#drupal-off-canvas-wrapper .button--danger {
-webkit-text-decoration: none;
text-decoration: none;
color: #c72100;
border-radius: 0;
font-weight: 400;
}
#drupal-off-canvas-wrapper .button--danger:hover,
#drupal-off-canvas-wrapper .button--danger:focus,
#drupal-off-canvas-wrapper .button--danger:active {
-webkit-text-decoration: none;
text-decoration: none;
color: #ff2a00;
text-shadow: none;
}
#drupal-off-canvas-wrapper .button--danger:disabled,
#drupal-off-canvas-wrapper .button--danger.is-disabled {
cursor: default;
color: #737373;
}
.no-touchevents #drupal-off-canvas-wrapper .button--small {
padding: 2px 1em;
font-size: 0.8125rem;
}

View File

@@ -0,0 +1,112 @@
/**
* @file
* Visual styling for buttons in the off-canvas dialog.
*
* @internal
*/
#drupal-off-canvas-wrapper {
--off-canvas-button-background-color: #777;
--off-canvas-button-background-color-hover: #999;
--off-canvas-button-text-color: #f5f5f5;
--off-canvas-button-text-color-hover: #fff;
--off-canvas-button-font-size: 14px;
--off-canvas-button-padding: calc(var(--off-canvas-vertical-spacing-unit) / 2) 20px;
--off-canvas-button-border-color: transparent;
--off-canvas-button-border-radius: 20em;
--off-canvas-button-font-weight: 600;
--off-canvas-primary-button-background-color: #277abd;
--off-canvas-primary-button-background-color-hover: #236aaf;
--off-canvas-primary-button-text-color: #fff;
--off-canvas-primary-button-text-color-hover: #fff;
& .button {
display: inline-block;
width: 100%;
height: auto;
margin: 0 0 10px;
padding: var(--off-canvas-button-padding);
cursor: pointer;
transition: background 0.5s ease;
text-align: center;
color: var(--off-canvas-button-text-color);
border: solid 1px var(--off-canvas-button-border-color);
border-radius: var(--off-canvas-button-border-radius);
background: var(--off-canvas-button-background-color);
font-family: inherit;
font-size: var(--off-canvas-button-font-size);
font-weight: var(--off-canvas-button-font-weight);
line-height: normal;
appearance: none;
&:hover,
&:active {
z-index: 10;
text-decoration: none;
color: var(--off-canvas-button-text-color-hover);
background-color: var(--off-canvas-button-background-color-hover);
}
&:disabled,
&:disabled:active,
&.is-disabled,
&.is-disabled:active {
cursor: default;
color: #5c5c5c;
background: #555;
font-weight: normal;
}
}
& .button--primary {
margin-top: 15px;
color: var(--off-canvas-primary-button-text-color);
background: var(--off-canvas-primary-button-background-color);
&:hover,
&:active {
color: var(--off-canvas-primary-button-text-color-hover);
background: var(--off-canvas-primary-button-background-color-hover);
}
}
& button.link {
display: inline;
transition: color 0.5s ease;
color: var(--off-canvas-link-color);
border: 0;
background: transparent;
font-size: var(--off-canvas-button-font-size);
&:hover,
&:focus {
text-decoration: none;
color: var(--off-canvas-link-color);
}
}
& .button--danger {
text-decoration: none;
color: #c72100;
border-radius: 0;
font-weight: 400;
&:hover,
&:focus,
&:active {
text-decoration: none;
color: #ff2a00;
text-shadow: none;
}
&:disabled,
&.is-disabled {
cursor: default;
color: #737373;
}
}
@nest .no-touchevents & .button--small {
padding: 2px 1em;
font-size: 13px;
}
}

View File

@@ -0,0 +1,69 @@
/*
* DO NOT EDIT THIS FILE.
* See the following change record for more information,
* https://www.drupal.org/node/3084859
* @preserve
*/
/**
* @file
* Visual styling for summary and details in the off-canvas dialog.
*
* @internal
*/
#drupal-off-canvas-wrapper {
--off-canvas-details-border-width: 0;
--off-canvas-details-border-color: none;
--off-canvas-details-background-color: #474747;
--off-canvas-details-text-color: #ddd;
--off-canvas-details-summary-border: none;
--off-canvas-details-summary-padding: 0.625rem 1.25rem;
--off-canvas-details-summary-font-size: 0.875rem;
--off-canvas-details-summary-background-color: #333;
--off-canvas-details-summary-background-color-hover: #222;
--off-canvas-details-summary-text-color: #eee;
--off-canvas-details-summary-text-color-hover: #fff;
}
#drupal-off-canvas-wrapper details {
margin: var(--off-canvas-vertical-spacing-unit) calc(-1 * var(--off-canvas-padding)); /* Cancel out the padding of the parent. */
padding: 0 var(--off-canvas-padding);
color: var(--off-canvas-details-text-color);
border: solid var(--off-canvas-details-border-color) var(--off-canvas-details-border-width);
background: var(--off-canvas-details-background-color);
}
:is(#drupal-off-canvas-wrapper details) + details {
margin-top: calc(-1 * var(--off-canvas-details-border-width));
}
#drupal-off-canvas-wrapper summary {
margin: 0 calc(-1 * var(--off-canvas-padding));
padding: var(--off-canvas-details-summary-padding);
color: var(--off-canvas-details-summary-text-color);
border: var(--off-canvas-details-summary-border);
background-color: var(--off-canvas-details-summary-background-color);
font-size: var(--off-canvas-details-summary-font-size);
}
#drupal-off-canvas-wrapper summary:hover {
color: var(--off-canvas-details-summary-text-color-hover);
background-color: var(--off-canvas-details-summary-background-color-hover);
}
#drupal-off-canvas-wrapper summary:focus {
outline-offset: -4px; /* Ensure focus doesn't get cut off. */
}
#drupal-off-canvas-wrapper summary a {
color: var(--off-canvas-details-text-color);
}
#drupal-off-canvas-wrapper summary a:hover {
color: var(--off-canvas-details-summary-text-color-hover);
}
#drupal-off-canvas-wrapper .details-wrapper {
padding: var(--off-canvas-vertical-spacing-unit) 0;
}

View File

@@ -0,0 +1,62 @@
/**
* @file
* Visual styling for summary and details in the off-canvas dialog.
*
* @internal
*/
#drupal-off-canvas-wrapper {
--off-canvas-details-border-width: 0;
--off-canvas-details-border-color: none;
--off-canvas-details-background-color: #474747;
--off-canvas-details-text-color: #ddd;
--off-canvas-details-summary-border: none;
--off-canvas-details-summary-padding: 10px 20px;
--off-canvas-details-summary-font-size: 14px;
--off-canvas-details-summary-background-color: #333;
--off-canvas-details-summary-background-color-hover: #222;
--off-canvas-details-summary-text-color: #eee;
--off-canvas-details-summary-text-color-hover: #fff;
& details {
margin: var(--off-canvas-vertical-spacing-unit) calc(-1 * var(--off-canvas-padding)); /* Cancel out the padding of the parent. */
padding: 0 var(--off-canvas-padding);
color: var(--off-canvas-details-text-color);
border: solid var(--off-canvas-details-border-color) var(--off-canvas-details-border-width);
background: var(--off-canvas-details-background-color);
& + details {
margin-top: calc(-1 * var(--off-canvas-details-border-width));
}
}
& summary {
margin: 0 calc(-1 * var(--off-canvas-padding));
padding: var(--off-canvas-details-summary-padding);
color: var(--off-canvas-details-summary-text-color);
border: var(--off-canvas-details-summary-border);
background-color: var(--off-canvas-details-summary-background-color);
font-size: var(--off-canvas-details-summary-font-size);
&:hover {
color: var(--off-canvas-details-summary-text-color-hover);
background-color: var(--off-canvas-details-summary-background-color-hover);
}
&:focus {
outline-offset: -4px; /* Ensure focus doesn't get cut off. */
}
& a {
color: var(--off-canvas-details-text-color);
&:hover {
color: var(--off-canvas-details-summary-text-color-hover);
}
}
}
& .details-wrapper {
padding: var(--off-canvas-vertical-spacing-unit) 0;
}
}

View File

@@ -0,0 +1,157 @@
/*
* DO NOT EDIT THIS FILE.
* See the following change record for more information,
* https://www.drupal.org/node/3084859
* @preserve
*/
/**
* @file
* Styles for dropbuttons in the off-canvas dialog.
*
* @internal
*/
#drupal-off-canvas-wrapper {
--off-canvas-dropbutton-height: 1.5rem;
--off-canvas-dropbutton-primary-background-color: var(--off-canvas-button-background-color);
--off-canvas-dropbutton-secondary-background-color: var(--off-canvas-button-hover-background-color);
--off-canvas-dropbutton-border-color: transparent;
--off-canvas-dropbutton-border-width: 1px;
--off-canvas-dropbutton-border-radius: 2px;
--off-canvas-dropbutton-focus-outline-color: var(--off-canvas-focus-outline-color);
--off-canvas-dropbutton-font-size: 0.75rem;
--off-canvas-dropbutton-text-color: var(--off-canvas-button-text-color); /* Minimum 4.5:1 contrast ratio against --off-canvas-dropbutton-primary-background-color and --off-canvas-dropbutton-secondary-background-color. */
--off-canvas-dropbutton-text-color-hover: var(--off-canvas-button-text-color-hover); /* Minimum 4.5:1 contrast ratio against --off-canvas-dropbutton-primary-background-color and --off-canvas-dropbutton-secondary-background-color. */
}
#drupal-off-canvas-wrapper .dropbutton-wrapper {
margin-block: var(--off-canvas-vertical-spacing-unit);
/*
* Styles for when the dropbutton is expanded.
*/
}
#drupal-off-canvas-wrapper .dropbutton-wrapper.open {
position: relative;
z-index: 100;
}
#drupal-off-canvas-wrapper .dropbutton-wrapper.open .secondary-action {
visibility: visible;
}
#drupal-off-canvas-wrapper .dropbutton-wrapper.open .dropbutton-widget {
border-radius: var(--off-canvas-dropbutton-border-radius) var(--off-canvas-dropbutton-border-radius) 0 0;
}
#drupal-off-canvas-wrapper .dropbutton-wrapper.open .dropbutton-toggle button::before {
transform: translateY(25%) rotate(225deg);
}
/*
* Styles for single link variant of dropbutton.
*/
#drupal-off-canvas-wrapper .dropbutton-wrapper.dropbutton-single .dropbutton-widget {
padding-inline-end: 0;
}
#drupal-off-canvas-wrapper .dropbutton-wrapper.dropbutton-single .dropbutton-action:first-child {
border-right: solid 1px var(--off-canvas-dropbutton-border-color); /* LTR */
border-radius: var(--off-canvas-dropbutton-border-radius);
}
[dir="rtl"] #drupal-off-canvas-wrapper .dropbutton-wrapper.dropbutton-single .dropbutton-action:first-child {
border: solid 1px var(--off-canvas-dropbutton-border-color);
}
#drupal-off-canvas-wrapper .dropbutton-wrapper.dropbutton-single .dropbutton-action a {
justify-content: center;
}
#drupal-off-canvas-wrapper .dropbutton-widget {
position: relative;
width: max-content;
max-width: 100%;
height: var(--off-canvas-dropbutton-height);
padding-inline-end: var(--off-canvas-dropbutton-height);
border-radius: var(--off-canvas-dropbutton-border-radius);
}
#drupal-off-canvas-wrapper .dropbutton {
height: var(--off-canvas-dropbutton-height);
margin-block: 0;
margin-inline-start: 0;
padding-inline-start: 0;
list-style: none;
font-size: var(--off-canvas-dropbutton-font-size);
}
/* This is the button that expands/collapses the secondary options. */
#drupal-off-canvas-wrapper .dropbutton-toggle {
padding: 0;
border: 0;
}
#drupal-off-canvas-wrapper .dropbutton-toggle button {
position: absolute;
top: 0;
display: flex;
align-items: center;
justify-content: center;
width: var(--off-canvas-dropbutton-height);
height: var(--off-canvas-dropbutton-height);
padding: 0;
cursor: pointer;
border-color: var(--off-canvas-dropbutton-border-color);
border-radius: 0 var(--border-radius) var(--border-radius) 0; /* LTR */
background: var(--off-canvas-dropbutton-primary-background-color);
inset-inline-end: 0;
}
#drupal-off-canvas-wrapper .dropbutton-toggle button:focus {
outline: solid 2px var(--off-canvas-dropbutton-focus-outline-color);
outline-offset: -2px;
}
#drupal-off-canvas-wrapper .dropbutton-toggle button::before {
display: block;
width: 0.375rem;
height: 0.375rem;
content: "";
transform: translateY(-25%) rotate(45deg);
border-right: solid 2px var(--off-canvas-dropbutton-text-color);
border-bottom: solid 2px var(--off-canvas-dropbutton-text-color);
}
[dir="rtl"] #drupal-off-canvas-wrapper .dropbutton-toggle button {
border-radius: var(--off-canvas-dropbutton-border-radius) 0 0 var(--off-canvas-dropbutton-border-radius);
}
/* This is the first <li> element in the list of actions. */
#drupal-off-canvas-wrapper .dropbutton-action:first-child {
margin-inline-end: 2px;
border: solid var(--off-canvas-dropbutton-border-width) var(--off-canvas-dropbutton-border-color);
border-radius: var(--off-canvas-dropbutton-border-radius) 0 0 var(--off-canvas-dropbutton-border-radius); /* LTR */
background: var(--off-canvas-dropbutton-primary-background-color);
}
[dir="rtl"] #drupal-off-canvas-wrapper .dropbutton-action:first-child {
border: solid var(--off-canvas-dropbutton-border-width) var(--off-canvas-dropbutton-border-color);
border-radius: 0 var(--off-canvas-dropbutton-border-radius) var(--off-canvas-dropbutton-border-radius) 0;
}
#drupal-off-canvas-wrapper .dropbutton-action a {
display: flex;
align-items: center;
min-height: var(--off-canvas-dropbutton-height);
margin-bottom: -2px;
padding: 0 0.5625rem;
-webkit-text-decoration: none;
text-decoration: none;
color: var(--off-canvas-dropbutton-text-color);
font-weight: 600;
}
#drupal-off-canvas-wrapper .dropbutton-action a:hover {
color: var(--off-canvas-dropbutton-text-color);
}
#drupal-off-canvas-wrapper .dropbutton-action a:focus {
outline: solid 2px var(--off-canvas-dropbutton-focus-outline-color);
outline-offset: -1px; /* Overlap parent container by 1px. */
}
/* These are the <li> elements other than the first. */
#drupal-off-canvas-wrapper .secondary-action {
visibility: hidden;
width: calc(100% + var(--off-canvas-dropbutton-height));
margin-top: var(--off-canvas-dropbutton-border-width);
border-right: var(--off-canvas-dropbutton-border-width) solid var(--off-canvas-dropbutton-border-color);
border-left: var(--off-canvas-dropbutton-border-width) solid var(--off-canvas-dropbutton-border-color);
background-color: var(--off-canvas-dropbutton-primary-background-color);
}
#drupal-off-canvas-wrapper .secondary-action:last-child {
border-bottom: var(--off-canvas-dropbutton-border-width) solid var(--off-canvas-dropbutton-border-color);
}
#drupal-off-canvas-wrapper .secondary-action a:hover {
color: var(--off-canvas-dropbutton-text-color-hover);
background-color: var(--off-canvas-dropbutton-secondary-background-color);
}

View File

@@ -0,0 +1,179 @@
/**
* @file
* Styles for dropbuttons in the off-canvas dialog.
*
* @internal
*/
#drupal-off-canvas-wrapper {
--off-canvas-dropbutton-height: 24px;
--off-canvas-dropbutton-primary-background-color: var(--off-canvas-button-background-color);
--off-canvas-dropbutton-secondary-background-color: var(--off-canvas-button-hover-background-color);
--off-canvas-dropbutton-border-color: transparent;
--off-canvas-dropbutton-border-width: 1px;
--off-canvas-dropbutton-border-radius: 2px;
--off-canvas-dropbutton-focus-outline-color: var(--off-canvas-focus-outline-color);
--off-canvas-dropbutton-font-size: 12px;
--off-canvas-dropbutton-text-color: var(--off-canvas-button-text-color); /* Minimum 4.5:1 contrast ratio against --off-canvas-dropbutton-primary-background-color and --off-canvas-dropbutton-secondary-background-color. */
--off-canvas-dropbutton-text-color-hover: var(--off-canvas-button-text-color-hover); /* Minimum 4.5:1 contrast ratio against --off-canvas-dropbutton-primary-background-color and --off-canvas-dropbutton-secondary-background-color. */
& .dropbutton-wrapper {
margin-block: var(--off-canvas-vertical-spacing-unit);
/*
* Styles for when the dropbutton is expanded.
*/
&.open {
position: relative;
z-index: 100;
& .secondary-action {
visibility: visible;
}
& .dropbutton-widget {
border-radius: var(--off-canvas-dropbutton-border-radius) var(--off-canvas-dropbutton-border-radius) 0 0;
}
& .dropbutton-toggle button::before {
transform: translateY(25%) rotate(225deg);
}
}
/*
* Styles for single link variant of dropbutton.
*/
&.dropbutton-single {
& .dropbutton-widget {
padding-inline-end: 0;
}
& .dropbutton-action {
&:first-child {
border-right: solid 1px var(--off-canvas-dropbutton-border-color); /* LTR */
border-radius: var(--off-canvas-dropbutton-border-radius);
&:dir(rtl) {
border: solid 1px var(--off-canvas-dropbutton-border-color);
}
}
& a {
justify-content: center;
}
}
}
}
& .dropbutton-widget {
position: relative;
width: max-content;
max-width: 100%;
height: var(--off-canvas-dropbutton-height);
padding-inline-end: var(--off-canvas-dropbutton-height);
border-radius: var(--off-canvas-dropbutton-border-radius);
}
& .dropbutton {
height: var(--off-canvas-dropbutton-height);
margin-block: 0;
margin-inline-start: 0;
padding-inline-start: 0;
list-style: none;
font-size: var(--off-canvas-dropbutton-font-size);
}
/* This is the button that expands/collapses the secondary options. */
& .dropbutton-toggle {
padding: 0;
border: 0;
& button {
position: absolute;
top: 0;
display: flex;
align-items: center;
justify-content: center;
width: var(--off-canvas-dropbutton-height);
height: var(--off-canvas-dropbutton-height);
padding: 0;
cursor: pointer;
border-color: var(--off-canvas-dropbutton-border-color);
border-radius: 0 var(--border-radius) var(--border-radius) 0; /* LTR */
background: var(--off-canvas-dropbutton-primary-background-color);
inset-inline-end: 0;
&:focus {
outline: solid 2px var(--off-canvas-dropbutton-focus-outline-color);
outline-offset: -2px;
}
&::before {
display: block;
width: 6px;
height: 6px;
content: "";
transform: translateY(-25%) rotate(45deg);
border-right: solid 2px var(--off-canvas-dropbutton-text-color);
border-bottom: solid 2px var(--off-canvas-dropbutton-text-color);
}
&:dir(rtl) {
border-radius: var(--off-canvas-dropbutton-border-radius) 0 0 var(--off-canvas-dropbutton-border-radius);
}
}
}
/* This is the first <li> element in the list of actions. */
& .dropbutton-action {
&:first-child {
margin-inline-end: 2px;
border: solid var(--off-canvas-dropbutton-border-width) var(--off-canvas-dropbutton-border-color);
border-radius: var(--off-canvas-dropbutton-border-radius) 0 0 var(--off-canvas-dropbutton-border-radius); /* LTR */
background: var(--off-canvas-dropbutton-primary-background-color);
&:dir(rtl) {
border: solid var(--off-canvas-dropbutton-border-width) var(--off-canvas-dropbutton-border-color);
border-radius: 0 var(--off-canvas-dropbutton-border-radius) var(--off-canvas-dropbutton-border-radius) 0;
}
}
& a {
display: flex;
align-items: center;
min-height: var(--off-canvas-dropbutton-height);
margin-bottom: -2px;
padding: 0 9px;
text-decoration: none;
color: var(--off-canvas-dropbutton-text-color);
font-weight: 600;
&:hover {
color: var(--off-canvas-dropbutton-text-color);
}
&:focus {
outline: solid 2px var(--off-canvas-dropbutton-focus-outline-color);
outline-offset: -1px; /* Overlap parent container by 1px. */
}
}
}
/* These are the <li> elements other than the first. */
& .secondary-action {
visibility: hidden;
width: calc(100% + var(--off-canvas-dropbutton-height));
margin-top: var(--off-canvas-dropbutton-border-width);
border-right: var(--off-canvas-dropbutton-border-width) solid var(--off-canvas-dropbutton-border-color);
border-left: var(--off-canvas-dropbutton-border-width) solid var(--off-canvas-dropbutton-border-color);
background-color: var(--off-canvas-dropbutton-primary-background-color);
&:last-child {
border-bottom: var(--off-canvas-dropbutton-border-width) solid var(--off-canvas-dropbutton-border-color);
}
& a:hover {
color: var(--off-canvas-dropbutton-text-color-hover);
background-color: var(--off-canvas-dropbutton-secondary-background-color);
}
}
}

View File

@@ -0,0 +1,35 @@
/*
* DO NOT EDIT THIS FILE.
* See the following change record for more information,
* https://www.drupal.org/node/3084859
* @preserve
*/
/**
* @file
* Recreate Drupal admin styling that was removed with reset.
* @see system.admin.css
*
* @internal
*/
#drupal-off-canvas-wrapper .panel {
padding: 0.3125rem 0.3125rem 0.9375rem;
}
#drupal-off-canvas-wrapper .panel__description {
margin: 0 0 0.1875rem;
padding: 2px 0 0.1875rem 0;
}
#drupal-off-canvas-wrapper .compact-link {
margin: 0 0 0.625rem 0;
}
#drupal-off-canvas-wrapper small .admin-link::before {
content: " [";
}
#drupal-off-canvas-wrapper small .admin-link::after {
content: "]";
}

View File

@@ -0,0 +1,30 @@
/**
* @file
* Recreate Drupal admin styling that was removed with reset.
* @see system.admin.css
*
* @internal
*/
#drupal-off-canvas-wrapper {
& .panel {
padding: 5px 5px 15px;
}
& .panel__description {
margin: 0 0 3px;
padding: 2px 0 3px 0;
}
& .compact-link {
margin: 0 0 10px 0;
}
& small .admin-link::before {
content: " [";
}
& small .admin-link::after {
content: "]";
}
}

View File

@@ -0,0 +1,192 @@
/*
* DO NOT EDIT THIS FILE.
* See the following change record for more information,
* https://www.drupal.org/node/3084859
* @preserve
*/
/**
* @file
* Visual styling for forms in the off-canvas dialog.
*
* @internal
*/
#drupal-off-canvas-wrapper {
--drupal-off-canvas-input-padding: var(--off-canvas-vertical-spacing-unit);
--drupal-off-canvas-input-background-color: #fff;
--drupal-off-canvas-input-border: solid 1px transparent;
--drupal-off-canvas-input-border-radius: 2px;
--drupal-off-canvas-input-font-size: 0.875rem;
--drupal-off-canvas-input-text-color: #333;
--drupal-off-canvas-fieldset-background-color: transparent;
--drupal-off-canvas-fieldset-border-width: 1px;
--drupal-off-canvas-fieldset-border-color: var(--off-canvas-border-color);
}
#drupal-off-canvas-wrapper form {
padding-block: var(--off-canvas-padding);
}
#drupal-off-canvas-wrapper form > *:first-child {
margin-top: 0;
padding-top: 0;
}
#drupal-off-canvas-wrapper .ck-content {
color: var(--drupal-off-canvas-input-text-color);
}
#drupal-off-canvas-wrapper .form-item:where(:not(fieldset)) {
padding: var(--off-canvas-vertical-spacing-unit) 0;
}
#drupal-off-canvas-wrapper .form-items-inline > * {
display: inline-block;
}
#drupal-off-canvas-wrapper label {
display: block;
}
#drupal-off-canvas-wrapper .form-type-boolean {
padding: calc(0.5 * var(--off-canvas-vertical-spacing-unit)) 0;
}
#drupal-off-canvas-wrapper .description,
#drupal-off-canvas-wrapper .form-item__description {
margin: calc(0.5 * var(--off-canvas-vertical-spacing-unit)) 0;
font-size: 0.75rem;
}
#drupal-off-canvas-wrapper .form-required::after {
content: "*";
}
#drupal-off-canvas-wrapper .fieldset,
#drupal-off-canvas-wrapper fieldset {
margin: calc(2 * var(--off-canvas-vertical-spacing-unit)) 0;
padding: var(--off-canvas-vertical-spacing-unit);
border: solid var(--drupal-off-canvas-fieldset-border-width) var(--drupal-off-canvas-fieldset-border-color);
background-color: var(--drupal-off-canvas-fieldset-background-color);
}
#drupal-off-canvas-wrapper legend,
#drupal-off-canvas-wrapper .fieldset__legend {
display: contents;
font-weight: bold;
}
#drupal-off-canvas-wrapper :is(.fieldset, fieldset, .draggable-table) input:where(:not([type="submit"], [type="checkbox"], [type="radio"])) {
width: 100%; /* Prevent text fields from breaking out of tables and fieldsets at narrow widths. */
}
#drupal-off-canvas-wrapper input,
#drupal-off-canvas-wrapper textarea {
font-family: inherit;
}
#drupal-off-canvas-wrapper input:where(:not([type="submit"], [type="checkbox"], [type="radio"], [type="file"])),
#drupal-off-canvas-wrapper select,
#drupal-off-canvas-wrapper textarea {
max-width: 100%;
padding: var(--drupal-off-canvas-input-padding);
color: var(--drupal-off-canvas-input-text-color);
border: var(--drupal-off-canvas-input-border);
border-radius: var(--drupal-off-canvas-input-border-radius);
background-color: var(--drupal-off-canvas-input-background-color);
font-size: var(--drupal-off-canvas-input-font-size);
}
:is(#drupal-off-canvas-wrapper input[type="checkbox"]) + label,
:is(#drupal-off-canvas-wrapper input[type="radio"]) + label {
display: inline;
}
#drupal-off-canvas-wrapper input[type="file"] {
margin-bottom: var(--off-canvas-vertical-spacing-unit);
}
#drupal-off-canvas-wrapper input[type="search"] {
appearance: none; /* Necessary for Safari. */
}
#drupal-off-canvas-wrapper select {
appearance: none;
padding-inline-end: 1.25rem;
border: var(--drupal-off-canvas-input-border);
border-radius: var(--drupal-off-canvas-input-border-radius);
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 9'%3e%3cpath fill='none' stroke-width='1.5' d='M1 1l6 6 6-6' stroke='%23545560'/%3e%3c/svg%3e");
background-repeat: no-repeat;
background-position: center right 5px; /* LTR */
background-size: 0.75rem;
}
[dir="rtl"] #drupal-off-canvas-wrapper select {
background-position: center left 5px;
}
@media (forced-colors: active) {
#drupal-off-canvas-wrapper select {
appearance: revert;
padding-inline-end: 0;
background: revert;
}
}
/*
* Autocomplete.
*/
#drupal-off-canvas-wrapper .form-autocomplete {
padding-inline-end: 2.5rem; /* Room for icon. */
background-image: url("data:image/svg+xml,%3csvg width='40' height='20' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M8 1C3.46.827-.188 5.787 1.313 10.068c1.176 4.384 6.993 6.417 10.637 3.7.326-.39.565.276.846.442l3.74 3.739 1.413-1.414-4.35-4.35c2.811-3.468 1.15-9.247-3.062-10.71A7.003 7.003 0 008 1zm0 2c3.242-.123 5.849 3.42 4.777 6.477-.842 3.132-4.994 4.58-7.6 2.65-2.745-1.73-2.9-6.125-.285-8.044A5.006 5.006 0 018 3z' fill='%23868686'/%3e%3c/svg%3e");
background-repeat: no-repeat;
background-position: center right 1px; /* LTR */
}
#drupal-off-canvas-wrapper .form-autocomplete.ui-autocomplete-loading {
background-image: url(../../../icons/spinner.gif);
}
[dir="rtl"] #drupal-off-canvas-wrapper .form-autocomplete {
background-position: center left 1px;
}
/* This is the background <ul> for the autocomplete dropdown. */
#drupal-off-canvas-wrapper .ui-autocomplete {
margin: 0;
padding: 0;
list-style: none;
border: var(--drupal-off-canvas-input-border);
background-color: var(--drupal-off-canvas-input-background-color);
box-shadow: 0 1px 1px 0 var(--off-canvas-background-color); /* Ensure edge is visible if appearing over another form element. */
}
#drupal-off-canvas-wrapper .ui-autocomplete a {
display: block;
padding: var(--drupal-off-canvas-input-padding);
cursor: pointer;
color: var(--drupal-off-canvas-input-text-color);
font-size: var(--drupal-off-canvas-input-font-size);
}
#drupal-off-canvas-wrapper .ui-autocomplete a:hover {
background-color: #eee;
}
#drupal-off-canvas-wrapper .ui-autocomplete a:focus,
#drupal-off-canvas-wrapper .ui-autocomplete a.ui-state-active {
outline: solid 2px currentColor;
outline-offset: -2px;
}
/*
* Claro injects a "Loading" autocomplete message that affects the positioning
* of the ui-autocomplete dropdown. We remove this to normalize the markup.
*/
#drupal-off-canvas-wrapper .claro-autocomplete__message {
display: none;
}

View File

@@ -0,0 +1,182 @@
/**
* @file
* Visual styling for forms in the off-canvas dialog.
*
* @internal
*/
#drupal-off-canvas-wrapper {
--drupal-off-canvas-input-padding: var(--off-canvas-vertical-spacing-unit);
--drupal-off-canvas-input-background-color: #fff;
--drupal-off-canvas-input-border: solid 1px transparent;
--drupal-off-canvas-input-border-radius: 2px;
--drupal-off-canvas-input-font-size: 14px;
--drupal-off-canvas-input-text-color: #333;
--drupal-off-canvas-fieldset-background-color: transparent;
--drupal-off-canvas-fieldset-border-width: 1px;
--drupal-off-canvas-fieldset-border-color: var(--off-canvas-border-color);
& form {
padding-block: var(--off-canvas-padding);
& > *:first-child {
margin-top: 0;
padding-top: 0;
}
}
& .ck-content {
color: var(--drupal-off-canvas-input-text-color);
}
& .form-item:where(:not(fieldset)) {
padding: var(--off-canvas-vertical-spacing-unit) 0;
}
& .form-items-inline > * {
display: inline-block;
}
& label {
display: block;
}
& .form-type-boolean {
padding: calc(0.5 * var(--off-canvas-vertical-spacing-unit)) 0;
}
& .description,
& .form-item__description {
margin: calc(0.5 * var(--off-canvas-vertical-spacing-unit)) 0;
font-size: 12px;
}
& .form-required::after {
content: "*";
}
& .fieldset,
& fieldset {
margin: calc(2 * var(--off-canvas-vertical-spacing-unit)) 0;
padding: var(--off-canvas-vertical-spacing-unit);
border: solid var(--drupal-off-canvas-fieldset-border-width) var(--drupal-off-canvas-fieldset-border-color);
background-color: var(--drupal-off-canvas-fieldset-background-color);
}
& legend, /* Bartik doesn't apply BEM classes, so we use the element. */
& .fieldset__legend {
display: contents;
font-weight: bold;
}
& :is(.fieldset, fieldset, .draggable-table) input:where(:not([type="submit"], [type="checkbox"], [type="radio"])) {
width: 100%; /* Prevent text fields from breaking out of tables and fieldsets at narrow widths. */
}
& input,
& textarea {
font-family: inherit;
}
& input:where(:not([type="submit"], [type="checkbox"], [type="radio"], [type="file"])),
& select,
& textarea {
max-width: 100%;
padding: var(--drupal-off-canvas-input-padding);
color: var(--drupal-off-canvas-input-text-color);
border: var(--drupal-off-canvas-input-border);
border-radius: var(--drupal-off-canvas-input-border-radius);
background-color: var(--drupal-off-canvas-input-background-color);
font-size: var(--drupal-off-canvas-input-font-size);
}
& input[type="checkbox"],
& input[type="radio"] {
& + label {
display: inline;
}
}
& input[type="file"] {
margin-bottom: var(--off-canvas-vertical-spacing-unit);
}
& input[type="search"] {
appearance: none; /* Necessary for Safari. */
}
& select {
appearance: none;
padding-inline-end: 20px;
border: var(--drupal-off-canvas-input-border);
border-radius: var(--drupal-off-canvas-input-border-radius);
background-image: url(../../../icons/545560/chevron-down.svg);
background-repeat: no-repeat;
background-position: center right 5px; /* LTR */
background-size: 12px;
&:dir(rtl) {
background-position: center left 5px;
}
@media (forced-colors: active) {
appearance: revert;
padding-inline-end: 0;
background: revert;
}
}
/*
* Autocomplete.
*/
& .form-autocomplete {
padding-inline-end: 40px; /* Room for icon. */
background-image: url(../../../icons/868686/magnifier.svg);
background-repeat: no-repeat;
background-position: center right 1px; /* LTR */
&.ui-autocomplete-loading {
background-image: url(../../../icons/spinner.gif);
}
&:dir(rtl) {
background-position: center left 1px;
}
}
/* This is the background <ul> for the autocomplete dropdown. */
& .ui-autocomplete {
margin: 0;
padding: 0;
list-style: none;
border: var(--drupal-off-canvas-input-border);
background-color: var(--drupal-off-canvas-input-background-color);
box-shadow: 0 1px 1px 0 var(--off-canvas-background-color); /* Ensure edge is visible if appearing over another form element. */
& a {
display: block;
padding: var(--drupal-off-canvas-input-padding);
cursor: pointer;
color: var(--drupal-off-canvas-input-text-color);
font-size: var(--drupal-off-canvas-input-font-size);
&:hover {
background-color: #eee;
}
&:focus,
&.ui-state-active {
outline: solid 2px currentColor;
outline-offset: -2px;
}
}
}
/*
* Claro injects a "Loading" autocomplete message that affects the positioning
* of the ui-autocomplete dropdown. We remove this to normalize the markup.
*/
& .claro-autocomplete__message {
display: none;
}
}

View File

@@ -0,0 +1,130 @@
/*
* DO NOT EDIT THIS FILE.
* See the following change record for more information,
* https://www.drupal.org/node/3084859
* @preserve
*/
/**
* @file
* Styling for messages in the off-canvas dialog.
*
* @internal
*/
#drupal-off-canvas-wrapper {
--off-canvas-messages-icon-size: 1.25rem;
--off-canvas-messages-background-color: #f3faef;
--off-canvas-messages-text-color-status: #325e1c;
--off-canvas-messages-text-color-warning: #734c00;
--off-canvas-messages-text-color-error: #a51b00;
--off-canvas-messages-icon-status: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='%2373b355'%3e%3cpath d='M6.464 13.676c-.194.194-.513.194-.707 0l-4.96-4.955c-.194-.193-.194-.513 0-.707l1.405-1.407c.194-.195.512-.195.707 0l2.849 2.848c.194.193.513.193.707 0l6.629-6.626c.195-.194.514-.194.707 0l1.404 1.404c.193.194.193.513 0 .707l-8.741 8.736z'/%3e%3c/svg%3e");
--off-canvas-messages-icon-warning: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='%23e29700'%3e%3cpath d='M14.66 12.316l-5.316-10.633c-.738-1.476-1.946-1.476-2.685 0l-5.317 10.633c-.738 1.477.008 2.684 1.658 2.684h10.002c1.65 0 2.396-1.207 1.658-2.684zm-7.66-8.316h2.002v5h-2.002v-5zm2.252 8.615c0 .344-.281.625-.625.625h-1.25c-.345 0-.626-.281-.626-.625v-1.239c0-.344.281-.625.626-.625h1.25c.344 0 .625.281.625.625v1.239z'/%3e%3c/svg%3e");
--off-canvas-messages-icon-error: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='%23e32700'%3e%3cpath d='M8.002 1c-3.868 0-7.002 3.134-7.002 7s3.134 7 7.002 7c3.865 0 7-3.134 7-7s-3.135-7-7-7zm4.025 9.284c.062.063.1.149.1.239 0 .091-.037.177-.1.24l-1.262 1.262c-.064.062-.15.1-.24.1s-.176-.036-.24-.1l-2.283-2.283-2.286 2.283c-.064.062-.15.1-.24.1s-.176-.036-.24-.1l-1.261-1.262c-.063-.062-.1-.148-.1-.24 0-.088.036-.176.1-.238l2.283-2.285-2.283-2.284c-.063-.064-.1-.15-.1-.24s.036-.176.1-.24l1.262-1.262c.063-.063.149-.1.24-.1.089 0 .176.036.24.1l2.285 2.284 2.283-2.284c.064-.063.15-.1.24-.1s.176.036.24.1l1.262 1.262c.062.063.1.149.1.24 0 .089-.037.176-.1.24l-2.283 2.284 2.283 2.284z'/%3e%3c/svg%3e");
}
#drupal-off-canvas-wrapper .messages {
position: relative; /* Anchor ::before pseudo-element. */
margin-top: calc(2 * var(--off-canvas-vertical-spacing-unit));
padding: calc(2 * var(--off-canvas-vertical-spacing-unit));
padding-inline-start: calc(2 * var(--off-canvas-messages-icon-size)); /* Room for icon. */
border: solid 1px transparent;
background-color: var(--off-canvas-messages-background-color);
/* Icon. */
}
#drupal-off-canvas-wrapper .messages::before {
position: absolute;
top: 50%;
display: block;
width: var(--off-canvas-messages-icon-size);
height: var(--off-canvas-messages-icon-size);
content: "";
transform: translateY(-50%);
background-repeat: no-repeat;
background-size: contain;
inset-inline-start: 0.625rem;
}
@media (forced-colors: active) {
#drupal-off-canvas-wrapper .messages::before {
background: canvastext;
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
-webkit-mask-size: contain;
mask-size: contain;
}
}
#drupal-off-canvas-wrapper h2 {
margin-top: 0;
}
/*
* Some themes (Olivero) insert SVG icon. We use a background icon, so we
* need to remove this.
*/
#drupal-off-canvas-wrapper .messages__icon,
#drupal-off-canvas-wrapper .messages__close {
display: none;
}
#drupal-off-canvas-wrapper .messages__list {
margin: 0;
padding-inline-start: 1.25rem;
}
#drupal-off-canvas-wrapper .messages abbr {
-webkit-text-decoration: none;
text-decoration: none;
}
#drupal-off-canvas-wrapper .messages--status {
color: var(--off-canvas-messages-text-color-status);
}
#drupal-off-canvas-wrapper .messages--status::before {
background-image: var(--off-canvas-messages-icon-status);
}
@media (forced-colors: active) {
#drupal-off-canvas-wrapper .messages--status::before {
background: canvastext;
-webkit-mask-image: var(--off-canvas-messages-icon-status);
mask-image: var(--off-canvas-messages-icon-status);
}
}
#drupal-off-canvas-wrapper .messages--warning {
color: var(--off-canvas-messages-text-color-warning);
}
#drupal-off-canvas-wrapper .messages--warning::before {
background-image: var(--off-canvas-messages-icon-warning);
}
@media (forced-colors: active) {
#drupal-off-canvas-wrapper .messages--warning::before {
background: canvastext;
-webkit-mask-image: var(--off-canvas-messages-icon-warning);
mask-image: var(--off-canvas-messages-icon-warning);
}
}
#drupal-off-canvas-wrapper .messages--error {
color: var(--off-canvas-messages-text-color-error);
}
#drupal-off-canvas-wrapper .messages--error::before {
background-image: var(--off-canvas-messages-icon-error);
}
@media (forced-colors: active) {
#drupal-off-canvas-wrapper .messages--error::before {
background: canvastext;
-webkit-mask-image: var(--off-canvas-messages-icon-error);
mask-image: var(--off-canvas-messages-icon-error);
}
}

View File

@@ -0,0 +1,107 @@
/**
* @file
* Styling for messages in the off-canvas dialog.
*
* @internal
*/
#drupal-off-canvas-wrapper {
--off-canvas-messages-icon-size: 20px;
--off-canvas-messages-background-color: #f3faef;
--off-canvas-messages-text-color-status: #325e1c;
--off-canvas-messages-text-color-warning: #734c00;
--off-canvas-messages-text-color-error: #a51b00;
--off-canvas-messages-icon-status: url(../../../icons/73b355/check.svg);
--off-canvas-messages-icon-warning: url(../../../icons/e29700/warning.svg);
--off-canvas-messages-icon-error: url(../../../icons/e32700/error.svg);
& .messages {
position: relative; /* Anchor ::before pseudo-element. */
margin-top: calc(2 * var(--off-canvas-vertical-spacing-unit));
padding: calc(2 * var(--off-canvas-vertical-spacing-unit));
padding-inline-start: calc(2 * var(--off-canvas-messages-icon-size)); /* Room for icon. */
border: solid 1px transparent;
background-color: var(--off-canvas-messages-background-color);
/* Icon. */
&::before {
position: absolute;
top: 50%;
display: block;
width: var(--off-canvas-messages-icon-size);
height: var(--off-canvas-messages-icon-size);
content: "";
transform: translateY(-50%);
background-repeat: no-repeat;
background-size: contain;
inset-inline-start: 10px;
@media (forced-colors: active) {
background: canvastext;
mask-repeat: no-repeat;
mask-size: contain;
}
}
}
& h2 {
margin-top: 0;
}
/*
* Some themes (Olivero) insert SVG icon. We use a background icon, so we
* need to remove this.
*/
& .messages__icon,
& .messages__close {
display: none;
}
& .messages__list {
margin: 0;
padding-inline-start: 20px;
}
& .messages abbr {
text-decoration: none;
}
& .messages--status {
color: var(--off-canvas-messages-text-color-status);
&::before {
background-image: var(--off-canvas-messages-icon-status);
@media (forced-colors: active) {
background: canvastext;
mask-image: var(--off-canvas-messages-icon-status);
}
}
}
& .messages--warning {
color: var(--off-canvas-messages-text-color-warning);
&::before {
background-image: var(--off-canvas-messages-icon-warning);
@media (forced-colors: active) {
background: canvastext;
mask-image: var(--off-canvas-messages-icon-warning);
}
}
}
& .messages--error {
color: var(--off-canvas-messages-text-color-error);
&::before {
background-image: var(--off-canvas-messages-icon-error);
@media (forced-colors: active) {
background: canvastext;
mask-image: var(--off-canvas-messages-icon-error);
}
}
}
}

View File

@@ -0,0 +1,27 @@
/*
* DO NOT EDIT THIS FILE.
* See the following change record for more information,
* https://www.drupal.org/node/3084859
* @preserve
*/
/**
* @file
* Reset HTML elements styles for the off-canvas dialog.
*
* @internal
*/
#drupal-off-canvas-wrapper *:where(:not(svg, svg *, .ck-reset *, [data-drupal-ck-style-fence] *, .ui-resizable-handle)) {
all: revert;
box-sizing: border-box;
-webkit-font-smoothing: antialiased;
line-height: 1.4;
}
#drupal-off-canvas-wrapper *:where(:not(svg, svg *, .ck-reset *, [data-drupal-ck-style-fence] *, .ui-resizable-handle))::after,
#drupal-off-canvas-wrapper *:where(:not(svg, svg *, .ck-reset *, [data-drupal-ck-style-fence] *, .ui-resizable-handle))::before {
all: revert;
box-sizing: border-box;
-webkit-font-smoothing: antialiased;
}

View File

@@ -0,0 +1,20 @@
/**
* @file
* Reset HTML elements styles for the off-canvas dialog.
*
* @internal
*/
#drupal-off-canvas-wrapper *:where(:not(svg, svg *, .ck-reset *, [data-drupal-ck-style-fence] *, .ui-resizable-handle)) {
all: revert;
box-sizing: border-box;
-webkit-font-smoothing: antialiased;
line-height: 1.4;
&::after,
&::before {
all: revert;
box-sizing: border-box;
-webkit-font-smoothing: antialiased;
}
}

View File

@@ -0,0 +1,44 @@
/*
* DO NOT EDIT THIS FILE.
* See the following change record for more information,
* https://www.drupal.org/node/3084859
* @preserve
*/
/**
* @file
* Styling for tables in the off-canvas dialog.
*
* @internal
*/
#drupal-off-canvas-wrapper {
--off-canvas-table-cell-padding: 2px;
--off-canvas-first-cell-padding-start: calc(var(--off-canvas-padding) / 2);
}
#drupal-off-canvas-wrapper table {
width: calc(100% + 2 * var(--off-canvas-padding));
margin: var(--off-canvas-vertical-spacing-unit) calc(-1 * var(--off-canvas-padding));
}
#drupal-off-canvas-wrapper tr {
border-bottom: 1px solid var(--off-canvas-border-color);
}
#drupal-off-canvas-wrapper td,
#drupal-off-canvas-wrapper th {
padding: var(--off-canvas-table-cell-padding);
text-align: start;
vertical-align: middle;
}
#drupal-off-canvas-wrapper td:first-child,
#drupal-off-canvas-wrapper th:first-child {
padding-inline-start: var(--off-canvas-first-cell-padding-start);
}
#drupal-off-canvas-wrapper td:not(:last-child) td,
#drupal-off-canvas-wrapper th:not(:last-child) td {
border-bottom: solid 1px var(--off-canvas-border-color);
}

View File

@@ -0,0 +1,35 @@
/**
* @file
* Styling for tables in the off-canvas dialog.
*
* @internal
*/
#drupal-off-canvas-wrapper {
--off-canvas-table-cell-padding: 2px;
--off-canvas-first-cell-padding-start: calc(var(--off-canvas-padding) / 2);
& table {
width: calc(100% + 2 * var(--off-canvas-padding));
margin: var(--off-canvas-vertical-spacing-unit) calc(-1 * var(--off-canvas-padding));
}
& tr {
border-bottom: 1px solid var(--off-canvas-border-color);
}
& td,
& th {
padding: var(--off-canvas-table-cell-padding);
text-align: start;
vertical-align: middle;
&:first-child {
padding-inline-start: var(--off-canvas-first-cell-padding-start);
}
&:not(:last-child) td {
border-bottom: solid 1px var(--off-canvas-border-color);
}
}
}

View File

@@ -0,0 +1,115 @@
/*
* DO NOT EDIT THIS FILE.
* See the following change record for more information,
* https://www.drupal.org/node/3084859
* @preserve
*/
/**
* @file
* Table drag styling for off-canvas dialog.
*
* @see tabledrag.js
*
* @internal
*/
/* The draggable <tr> element. */
#drupal-off-canvas-wrapper .draggable:hover,
#drupal-off-canvas-wrapper .draggable:focus-within {
background-color: var(--off-canvas-background-color-light);
}
/* Appears when the row is being dragged. */
#drupal-off-canvas-wrapper .draggable.drag {
cursor: move;
background-color: var(--off-canvas-background-color-dark);
}
#drupal-off-canvas-wrapper td {
transition: background-color 0.3s ease;
/* We have to horizontally align all descendent nodes including text nodes
* that do not have wrapper elements. Since we use flex to do this, we need
* try to keep it vertically centered, so we have to give it a minimum height
* to match the rest of the table cells. */
}
#drupal-off-canvas-wrapper td:first-child {
display: flex;
align-items: center;
min-height: 3.125rem;
gap: var(--off-canvas-table-cell-padding);
}
#drupal-off-canvas-wrapper td abbr {
margin-inline: 0 0.3125rem;
-webkit-text-decoration: none;
text-decoration: none;
}
#drupal-off-canvas-wrapper .tabledrag-handle {
flex-shrink: 0;
}
#drupal-off-canvas-wrapper .tabledrag-handle::after {
display: block;
width: 1.25rem;
height: 1.25rem;
margin: 0;
padding: 0;
content: "";
cursor: move;
background-color: transparent;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16'%3e%3cpath fill='%23bebebe' d='M14.904 7.753l-2.373-2.372c-.291-.292-.529-.193-.529.22v1.399h-3v-3h1.398c.414 0 .512-.239.221-.53l-2.371-2.372c-.137-.136-.36-.136-.497 0l-2.372 2.372c-.292.292-.193.53.22.53h1.399v3h-3v-1.369c0-.413-.239-.511-.53-.22l-2.372 2.372c-.136.136-.136.359 0 .494l2.372 2.372c.291.292.53.192.53-.219v-1.43h3v3h-1.4c-.413 0-.511.238-.22.529l2.374 2.373c.137.137.36.137.495 0l2.373-2.373c.29-.291.19-.529-.222-.529h-1.398v-3h3v1.4c0 .412.238.511.529.219l2.373-2.371c.137-.137.137-.359 0-.495z'/%3e%3c/svg%3e");
background-repeat: no-repeat;
background-position: center;
}
@media (forced-colors: active) {
#drupal-off-canvas-wrapper .tabledrag-handle::after {
background: linktext;
-webkit-mask-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16'%3e%3cpath fill='%23bebebe' d='M14.904 7.753l-2.373-2.372c-.291-.292-.529-.193-.529.22v1.399h-3v-3h1.398c.414 0 .512-.239.221-.53l-2.371-2.372c-.137-.136-.36-.136-.497 0l-2.372 2.372c-.292.292-.193.53.22.53h1.399v3h-3v-1.369c0-.413-.239-.511-.53-.22l-2.372 2.372c-.136.136-.136.359 0 .494l2.372 2.372c.291.292.53.192.53-.219v-1.43h3v3h-1.4c-.413 0-.511.238-.22.529l2.374 2.373c.137.137.36.137.495 0l2.373-2.373c.29-.291.19-.529-.222-.529h-1.398v-3h3v1.4c0 .412.238.511.529.219l2.373-2.371c.137-.137.137-.359 0-.495z'/%3e%3c/svg%3e");
mask-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16'%3e%3cpath fill='%23bebebe' d='M14.904 7.753l-2.373-2.372c-.291-.292-.529-.193-.529.22v1.399h-3v-3h1.398c.414 0 .512-.239.221-.53l-2.371-2.372c-.137-.136-.36-.136-.497 0l-2.372 2.372c-.292.292-.193.53.22.53h1.399v3h-3v-1.369c0-.413-.239-.511-.53-.22l-2.372 2.372c-.136.136-.136.359 0 .494l2.372 2.372c.291.292.53.192.53-.219v-1.43h3v3h-1.4c-.413 0-.511.238-.22.529l2.374 2.373c.137.137.36.137.495 0l2.373-2.373c.29-.291.19-.529-.222-.529h-1.398v-3h3v1.4c0 .412.238.511.529.219l2.373-2.371c.137-.137.137-.359 0-.495z'/%3e%3c/svg%3e");
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
-webkit-mask-position: center;
mask-position: center;
}
}
/* Make the "row weight" <select> as small as possible. */
#drupal-off-canvas-wrapper .tabledrag-hide select {
all: revert;
}
#drupal-off-canvas-wrapper .tabledrag-changed-warning {
margin-bottom: var(--off-canvas-vertical-spacing-unit);
font-size: 0.875rem;
}
#drupal-off-canvas-wrapper .tabledrag-toggle-weight-wrapper {
padding-top: 0.625rem;
text-align: end;
}
#drupal-off-canvas-wrapper .indentation {
width: 0.3125rem;
}
.touchevents #drupal-off-canvas-wrapper .draggable td {
padding: 0 0.625rem;
}
.touchevents #drupal-off-canvas-wrapper .draggable .menu-item__link {
display: inline-block;
padding: 0.625rem 0;
}
.touchevents #drupal-off-canvas-wrapper a.tabledrag-handle {
width: 2.5rem;
height: 2.75rem;
}

View File

@@ -0,0 +1,102 @@
/**
* @file
* Table drag styling for off-canvas dialog.
*
* @see tabledrag.js
*
* @internal
*/
#drupal-off-canvas-wrapper {
/* The draggable <tr> element. */
& .draggable {
&:hover,
&:focus-within {
background-color: var(--off-canvas-background-color-light);
}
/* Appears when the row is being dragged. */
&.drag {
cursor: move;
background-color: var(--off-canvas-background-color-dark);
}
}
& td {
transition: background-color 0.3s ease;
/* We have to horizontally align all descendent nodes including text nodes
* that do not have wrapper elements. Since we use flex to do this, we need
* try to keep it vertically centered, so we have to give it a minimum height
* to match the rest of the table cells. */
&:first-child {
display: flex;
align-items: center;
min-height: 50px;
gap: var(--off-canvas-table-cell-padding);
}
& abbr {
margin-inline: 0 5px;
text-decoration: none;
}
}
& .tabledrag-handle {
flex-shrink: 0;
&::after {
display: block;
width: 20px;
height: 20px;
margin: 0;
padding: 0;
content: "";
cursor: move;
background-color: transparent;
background-image: url(../../../icons/bebebe/move.svg);
background-repeat: no-repeat;
background-position: center;
@media (forced-colors: active) {
background: linktext;
mask-image: url(../../../icons/bebebe/move.svg);
mask-repeat: no-repeat;
mask-position: center;
}
}
}
/* Make the "row weight" <select> as small as possible. */
& .tabledrag-hide select {
all: revert;
}
& .tabledrag-changed-warning {
margin-bottom: var(--off-canvas-vertical-spacing-unit);
font-size: 14px;
}
& .tabledrag-toggle-weight-wrapper {
padding-top: 10px;
text-align: end;
}
& .indentation {
width: 5px;
}
@nest .touchevents & .draggable td {
padding: 0 10px;
}
@nest .touchevents & .draggable .menu-item__link {
display: inline-block;
padding: 10px 0;
}
@nest .touchevents & a.tabledrag-handle {
width: 40px;
height: 44px;
}
}

View File

@@ -0,0 +1,51 @@
/*
* DO NOT EDIT THIS FILE.
* See the following change record for more information,
* https://www.drupal.org/node/3084859
* @preserve
*/
/**
* @file
* Styling of AJAX actions throbber in off-canvas dialog.
*
* @internal
*/
#drupal-off-canvas-wrapper .ajax-progress,
#drupal-off-canvas-wrapper .ajax-progress-throbber {
display: inline-block;
overflow: hidden;
width: 0.9375rem;
height: 0.9375rem;
margin: 0 0.625rem;
animation: off-canvas-throbber-spin 1s linear infinite;
vertical-align: middle;
border: 2px solid var(--off-canvas-text-color);
border-top-color: transparent;
border-radius: 50%;
}
@media (forced-colors: active) {
#drupal-off-canvas-wrapper .ajax-progress,
#drupal-off-canvas-wrapper .ajax-progress-throbber {
border-top-color: transparent;
}
}
#drupal-off-canvas-wrapper .layout-selection .ajax-progress,
#drupal-off-canvas-wrapper .inline-block-list .ajax-progress,
#drupal-off-canvas-wrapper .layout-selection .ajax-progress-throbber,
#drupal-off-canvas-wrapper .inline-block-list .ajax-progress-throbber {
position: absolute;
inset-block-start: 0;
inset-block-end: 0;
inset-inline-end: 0;
margin-block: auto;
}
@keyframes off-canvas-throbber-spin {
to {
transform: rotate(360deg);
}
}

View File

@@ -0,0 +1,44 @@
/**
* @file
* Styling of AJAX actions throbber in off-canvas dialog.
*
* @internal
*/
#drupal-off-canvas-wrapper {
& .ajax-progress, /* This is the CSS class used in Claro. */
& .ajax-progress-throbber {
display: inline-block;
overflow: hidden;
width: 15px;
height: 15px;
margin: 0 10px;
animation: off-canvas-throbber-spin 1s linear infinite;
vertical-align: middle;
border: 2px solid var(--off-canvas-text-color);
border-top-color: transparent;
border-radius: 50%;
@media (forced-colors: active) {
border-top-color: transparent;
}
}
& .layout-selection,
& .inline-block-list {
& .ajax-progress,
& .ajax-progress-throbber {
position: absolute;
inset-block-start: 0;
inset-block-end: 0;
inset-inline-end: 0;
margin-block: auto;
}
}
}
@keyframes off-canvas-throbber-spin {
to {
transform: rotate(360deg);
}
}

View File

@@ -0,0 +1,108 @@
/*
* DO NOT EDIT THIS FILE.
* See the following change record for more information,
* https://www.drupal.org/node/3084859
* @preserve
*/
/**
* @file
* Styling for the titlebar within the off-canvas dialog.
*
* @internal
*/
#drupal-off-canvas-wrapper {
--off-canvas-title-padding: calc(3 * var(--off-canvas-vertical-spacing-unit));
--off-canvas-title-background-color: #2d2d2d;
--off-canvas-title-text-color: #fff;
--off-canvas-title-font-size: 1rem;
}
#drupal-off-canvas-wrapper .ui-dialog-titlebar {
position: relative;
margin: 0 calc(-1 * var(--off-canvas-padding));
padding: var(--off-canvas-title-padding) 3.125rem;
color: var(--off-canvas-title-text-color);
background-color: var(--off-canvas-title-background-color);
font-family: var(--off-canvas-title-font-family);
font-size: var(--off-canvas-title-font-size);
font-weight: bold;
/* The pencil icon. */
}
#drupal-off-canvas-wrapper .ui-dialog-titlebar::before {
position: absolute;
top: 0;
inset-inline-start: 1em;
display: block;
width: 1.25rem;
height: 100%;
content: "";
background-color: currentColor;
-webkit-mask-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16'%3e%3cg%3e%3cpath fill='%23ffffff' d='M14.545 3.042l-1.586-1.585c-.389-.389-1.025-.389-1.414 0l-1.293 1.293 3 3 1.293-1.293c.389-.389.389-1.026 0-1.415z'/%3e%3crect fill='%23ffffff' x='5.129' y='3.8' transform='matrix(-.707 -.707 .707 -.707 6.189 20.064)' width='4.243' height='9.899'/%3e%3cpath fill='%23ffffff' d='M.908 14.775c-.087.262.055.397.316.312l2.001-.667-1.65-1.646-.667 2.001z'/%3e%3c/g%3e%3c/svg%3e");
mask-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16'%3e%3cg%3e%3cpath fill='%23ffffff' d='M14.545 3.042l-1.586-1.585c-.389-.389-1.025-.389-1.414 0l-1.293 1.293 3 3 1.293-1.293c.389-.389.389-1.026 0-1.415z'/%3e%3crect fill='%23ffffff' x='5.129' y='3.8' transform='matrix(-.707 -.707 .707 -.707 6.189 20.064)' width='4.243' height='9.899'/%3e%3cpath fill='%23ffffff' d='M.908 14.775c-.087.262.055.397.316.312l2.001-.667-1.65-1.646-.667 2.001z'/%3e%3c/g%3e%3c/svg%3e");
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
-webkit-mask-size: contain;
mask-size: contain;
-webkit-mask-position: center;
mask-position: center;
}
@media (forced-colors: active) {
#drupal-off-canvas-wrapper .ui-dialog-titlebar::before {
background-color: canvastext;
}
}
/* Close button. */
#drupal-off-canvas-wrapper .ui-dialog-titlebar-close {
position: absolute;
top: 50%;
inset-inline: auto 0.625rem;
overflow: hidden;
width: 1.875rem;
height: 1.875rem;
cursor: pointer;
transform: translateY(-50%);
text-indent: -624.9375rem;
color: inherit;
border: 1px solid transparent;
background-color: transparent;
appearance: none;
}
#drupal-off-canvas-wrapper .ui-dialog-titlebar-close:focus {
outline: solid 2px currentColor;
outline-offset: 2px;
}
/* The plus icon. */
#drupal-off-canvas-wrapper .ui-dialog-titlebar-close::before,
#drupal-off-canvas-wrapper .ui-dialog-titlebar-close::after {
position: absolute;
top: calc(50% - 1px);
left: 50%;
width: 50%;
height: 0;
content: "";
border-top: solid 2px currentColor;
}
#drupal-off-canvas-wrapper .ui-dialog-titlebar-close::before {
transform: translate(-50%, 50%) rotate(-45deg);
}
#drupal-off-canvas-wrapper .ui-dialog-titlebar-close::after {
transform: translate(-50%, 50%) rotate(45deg);
}
/* Hide the default jQuery UI dialog close button. */
#drupal-off-canvas-wrapper .ui-dialog-titlebar-close .ui-icon {
display: none;
}

View File

@@ -0,0 +1,91 @@
/**
* @file
* Styling for the titlebar within the off-canvas dialog.
*
* @internal
*/
#drupal-off-canvas-wrapper {
--off-canvas-title-padding: calc(3 * var(--off-canvas-vertical-spacing-unit));
--off-canvas-title-background-color: #2d2d2d;
--off-canvas-title-text-color: #fff;
--off-canvas-title-font-size: 16px;
& .ui-dialog-titlebar {
position: relative;
margin: 0 calc(-1 * var(--off-canvas-padding));
padding: var(--off-canvas-title-padding) 50px;
color: var(--off-canvas-title-text-color);
background-color: var(--off-canvas-title-background-color);
font-family: var(--off-canvas-title-font-family);
font-size: var(--off-canvas-title-font-size);
font-weight: bold;
/* The pencil icon. */
&::before {
position: absolute;
top: 0;
inset-inline-start: 1em;
display: block;
width: 20px;
height: 100%;
content: "";
background-color: currentColor;
mask-image: url(../../../icons/ffffff/pencil.svg);
mask-repeat: no-repeat;
mask-size: contain;
mask-position: center;
@media (forced-colors: active) {
background-color: canvastext;
}
}
}
/* Close button. */
& .ui-dialog-titlebar-close {
position: absolute;
top: 50%;
inset-inline: auto 10px;
overflow: hidden;
width: 30px;
height: 30px;
cursor: pointer;
transform: translateY(-50%);
text-indent: -9999px;
color: inherit;
border: 1px solid transparent;
background-color: transparent;
appearance: none;
&:focus {
outline: solid 2px currentColor;
outline-offset: 2px;
}
/* The plus icon. */
&::before,
&::after {
position: absolute;
top: calc(50% - 1px);
left: 50%;
width: 50%;
height: 0;
content: "";
border-top: solid 2px currentColor;
}
&::before {
transform: translate(-50%, 50%) rotate(-45deg);
}
&::after {
transform: translate(-50%, 50%) rotate(45deg);
}
/* Hide the default jQuery UI dialog close button. */
& .ui-icon {
display: none;
}
}
}

View File

@@ -0,0 +1,38 @@
/*
* DO NOT EDIT THIS FILE.
* See the following change record for more information,
* https://www.drupal.org/node/3084859
* @preserve
*/
/**
* @file
* Re-create utility styles for off-canvas dialog that are removed in the reset.
*
* @internal
*/
#drupal-off-canvas-wrapper .hidden {
display: none;
}
#drupal-off-canvas-wrapper .visually-hidden {
position: absolute !important;
overflow: hidden;
clip: rect(1px, 1px, 1px, 1px);
width: 1px !important;
height: 1px !important;
word-wrap: normal;
}
#drupal-off-canvas-wrapper .visually-hidden.focusable:is(:active, :focus) {
position: static !important;
overflow: visible;
clip: auto;
width: auto !important;
height: auto !important;
}
#drupal-off-canvas-wrapper .invisible {
visibility: hidden;
}

View File

@@ -0,0 +1,33 @@
/**
* @file
* Re-create utility styles for off-canvas dialog that are removed in the reset.
*
* @internal
*/
#drupal-off-canvas-wrapper {
& .hidden {
display: none;
}
& .visually-hidden {
position: absolute !important;
overflow: hidden;
clip: rect(1px, 1px, 1px, 1px);
width: 1px !important;
height: 1px !important;
word-wrap: normal;
&.focusable:is(:active, :focus) {
position: static !important;
overflow: visible;
clip: auto;
width: auto !important;
height: auto !important;
}
}
& .invisible {
visibility: hidden;
}
}

View File

@@ -0,0 +1,52 @@
/*
* DO NOT EDIT THIS FILE.
* See the following change record for more information,
* https://www.drupal.org/node/3084859
* @preserve
*/
/**
* @file
* CSS for off-canvas dialog wrapper.
*
* @internal
*/
#drupal-off-canvas-wrapper {
--off-canvas-wrapper-box-shadow: 0 0 0.25rem 2px rgba(0, 0, 0, 0.3);
--off-canvas-wrapper-border-color: #2d2d2d;
--off-canvas-wrapper-border-width: 1px;
z-index: 501; /* Layer the dialog just under the toolbar. */
overflow: auto;
box-sizing: border-box;
height: 100%;
border-inline-start: solid var(--off-canvas-wrapper-border-width) var(--off-canvas-wrapper-border-color);
box-shadow: var(--off-canvas-wrapper-box-shadow);
/*
* Force the off-canvas dialog to be 100% width at the same breakpoint the
* dialog system uses to expand dialog widths.
*/
}
@media (max-width: 48rem) {
#drupal-off-canvas-wrapper {
width: 100% !important;
}
}
/* When off-canvas dialog is at 100% width stop the body from scrolling */
@media (max-width: 48rem) {
body.js-off-canvas-dialog-open {
position: fixed;
}
}
/* This is a page level content wrapper that shrinks when off-canvas is open. */
.dialog-off-canvas-main-canvas {
transition:
padding-right 0.7s ease,
padding-left 0.7s ease,
padding-top 0.3s ease;
}
@media (prefers-reduced-motion: reduce) {
.dialog-off-canvas-main-canvas {
transition: none;
}
}

View File

@@ -0,0 +1,45 @@
/**
* @file
* CSS for off-canvas dialog wrapper.
*
* @internal
*/
#drupal-off-canvas-wrapper {
--off-canvas-wrapper-box-shadow: 0 0 4px 2px rgba(0, 0, 0, 0.3);
--off-canvas-wrapper-border-color: #2d2d2d;
--off-canvas-wrapper-border-width: 1px;
z-index: 501; /* Layer the dialog just under the toolbar. */
overflow: auto;
box-sizing: border-box;
height: 100%;
border-inline-start: solid var(--off-canvas-wrapper-border-width) var(--off-canvas-wrapper-border-color);
box-shadow: var(--off-canvas-wrapper-box-shadow);
/*
* Force the off-canvas dialog to be 100% width at the same breakpoint the
* dialog system uses to expand dialog widths.
*/
@media (max-width: 768px) {
width: 100% !important;
}
}
/* When off-canvas dialog is at 100% width stop the body from scrolling */
body.js-off-canvas-dialog-open {
@media (max-width: 768px) {
position: fixed;
}
}
/* This is a page level content wrapper that shrinks when off-canvas is open. */
.dialog-off-canvas-main-canvas {
transition:
padding-right 0.7s ease,
padding-left 0.7s ease,
padding-top 0.3s ease;
@media (prefers-reduced-motion: reduce) {
transition: none;
}
}

View File

@@ -0,0 +1,384 @@
/**
* @file
* Drupal's off-canvas library.
*/
(($, Drupal, debounce, displace) => {
/**
* Off-canvas dialog implementation using jQuery Dialog.
*
* Transforms the regular dialogs created using Drupal.dialog when the dialog
* element equals '#drupal-off-canvas' into a side-loading dialog.
*
* @namespace
*/
Drupal.offCanvas = {
/**
* Storage for position information about the tray.
*
* @type {?String}
*/
position: null,
/**
* The minimum height of the tray when opened at the top of the page.
*
* @type {Number}
*/
minimumHeight: 30,
/**
* The minimum width to use body displace needs to match the width at which
* the tray will be 100% width. @see core/misc/dialog/off-canvas.css
*
* @type {Number}
*/
minDisplaceWidth: 768,
/**
* Wrapper used to position off-canvas dialog.
*
* @type {jQuery}
*/
$mainCanvasWrapper: $('[data-off-canvas-main-canvas]'),
/**
* Determines if an element is an off-canvas dialog.
*
* @param {jQuery} $element
* The dialog element.
*
* @return {boolean}
* True this is currently an off-canvas dialog.
*/
isOffCanvas($element) {
return $element[0].id === 'drupal-off-canvas';
},
/**
* Remove off-canvas dialog events.
*
* @param {jQuery} $element
* The target element.
*/
removeOffCanvasEvents($element) {
$element.off('.off-canvas');
$(document).off('.off-canvas');
$(window).off('.off-canvas');
},
/**
* Handler fired before an off-canvas dialog has been opened.
*
* @param {Object} settings
* Settings related to the composition of the dialog.
*
* @return {undefined}
*/
beforeCreate({ settings, $element }) {
// Clean up previous dialog event handlers.
Drupal.offCanvas.removeOffCanvasEvents($element);
$('body').addClass('js-off-canvas-dialog-open');
// @see http://api.jqueryui.com/position/
settings.position = {
my: 'left top',
at: `${Drupal.offCanvas.getEdge()} top`,
of: window,
};
/**
* Applies initial height and with to dialog based depending on position.
* @see http://api.jqueryui.com/dialog for all dialog options.
*/
const position = settings.drupalOffCanvasPosition;
const height = position === 'side' ? $(window).height() : settings.height;
const width = position === 'side' ? settings.width : '100%';
settings.height = height;
settings.width = width;
},
/**
* Handler fired after an off-canvas dialog has been closed.
*
* @return {undefined}
*/
beforeClose({ $element }) {
$('body').removeClass('js-off-canvas-dialog-open');
// Remove all *.off-canvas events
Drupal.offCanvas.removeOffCanvasEvents($element);
Drupal.offCanvas.resetPadding();
},
/**
* Handler fired when an off-canvas dialog has been opened.
*
* @param {jQuery} $element
* The off-canvas dialog element.
* @param {Object} settings
* Settings related to the composition of the dialog.
*
* @return {undefined}
*/
afterCreate({ $element, settings }) {
const eventData = { settings, $element, offCanvasDialog: this };
$element
.on(
'dialogContentResize.off-canvas',
eventData,
Drupal.offCanvas.handleDialogResize,
)
.on(
'dialogContentResize.off-canvas',
eventData,
Drupal.offCanvas.bodyPadding,
);
Drupal.offCanvas
.getContainer($element)
.attr(`data-offset-${Drupal.offCanvas.getEdge()}`, '');
$(window)
.on(
'resize.off-canvas',
eventData,
debounce(Drupal.offCanvas.resetSize, 100, true),
)
.trigger('resize.off-canvas');
},
/**
* Toggle classes based on title existence.
* Called with Drupal.offCanvas.afterCreate.
*
* @param {Object} settings
* Settings related to the composition of the dialog.
*
* @return {undefined}
*/
render({ settings }) {
$(
'.ui-dialog-off-canvas, .ui-dialog-off-canvas .ui-dialog-titlebar',
).toggleClass('ui-dialog-empty-title', !settings.title);
$('.ui-dialog-off-canvas').attr('id', 'drupal-off-canvas-wrapper');
},
/**
* Adjusts the dialog on resize.
*
* @param {jQuery.Event} event
* The event triggered.
* @param {object} event.data
* Data attached to the event.
*/
handleDialogResize(event) {
const $element = event.data.$element;
const $container = Drupal.offCanvas.getContainer($element);
const $offsets = $container.find(
'> :not(#drupal-off-canvas, .ui-resizable-handle)',
);
let offset = 0;
// Let scroll element take all the height available.
$element[0].style.height = 'auto';
const modalHeight = $container.height();
$offsets.each((i, e) => {
offset += $(e).outerHeight();
});
// Take internal padding into account.
const scrollOffset = $element.outerHeight() - $element.height();
$element.height(modalHeight - offset - scrollOffset);
},
/**
* Resets the size of the dialog.
*
* @param {jQuery.Event} event
* The event triggered.
* @param {object} event.data
* Data attached to the event.
*/
resetSize(event) {
const $element = event.data.$element;
const container = Drupal.offCanvas.getContainer($element);
const position = event.data.settings.drupalOffCanvasPosition;
// Only remove the `data-offset-*` attribute if the value previously
// exists and the orientation is changing.
if (Drupal.offCanvas.position && Drupal.offCanvas.position !== position) {
container.removeAttr(`data-offset-${Drupal.offCanvas.position}`);
}
// Set a minimum height on $element
if (position === 'top') {
$element[0].style.minHeight = `${Drupal.offCanvas.minimumHeight}px`;
}
displace();
const offsets = displace.offsets;
const topPosition =
position === 'side' && offsets.top !== 0 ? `+${offsets.top}` : '';
const adjustedOptions = {
// @see http://api.jqueryui.com/position/
position: {
my: `${Drupal.offCanvas.getEdge()} top`,
at: `${Drupal.offCanvas.getEdge()} top${topPosition}`,
of: window,
},
};
const height =
position === 'side'
? `${$(window).height() - (offsets.top + offsets.bottom)}px`
: event.data.settings.height;
Object.assign(container[0].style, {
position: 'fixed',
height: Number.isNaN(parseFloat(height))
? height
: `${parseFloat(height)}px`,
});
$element.dialog('option', adjustedOptions);
$element
?.get(0)
?.dispatchEvent(
new CustomEvent('dialogContentResize', { bubbles: true }),
);
Drupal.offCanvas.position = position;
},
/**
* Adjusts the body padding when the dialog is resized.
*
* @param {jQuery.Event} event
* The event triggered.
* @param {object} event.data
* Data attached to the event.
*/
bodyPadding(event) {
const position = event.data.settings.drupalOffCanvasPosition;
if (
position === 'side' &&
$('body').outerWidth() < Drupal.offCanvas.minDisplaceWidth
) {
return;
}
Drupal.offCanvas.resetPadding();
const $element = event.data.$element;
const $container = Drupal.offCanvas.getContainer($element);
const mainCanvasWrapper = Drupal.offCanvas.$mainCanvasWrapper[0];
const width = $container.outerWidth();
const mainCanvasPadding =
window.getComputedStyle(mainCanvasWrapper)[
`padding-${Drupal.offCanvas.getEdge()}`
];
if (position === 'side' && width !== mainCanvasPadding) {
mainCanvasWrapper.style[`padding-${Drupal.offCanvas.getEdge()}`] =
`${width}px`;
$container.attr(`data-offset-${Drupal.offCanvas.getEdge()}`, width);
displace();
}
const height = $container.outerHeight();
if (position === 'top') {
mainCanvasWrapper.style.paddingTop = `${height}px`;
$container.attr('data-offset-top', height);
displace();
}
},
/**
* The HTML element that surrounds the dialog.
* @param {HTMLElement} $element
* The dialog element.
*
* @return {HTMLElement}
* The containing element.
*/
getContainer($element) {
return $element.dialog('widget');
},
/**
* The edge of the screen that the dialog should appear on.
*
* @return {string}
* The edge the tray will be shown on, left or right.
*/
getEdge() {
return document.documentElement.dir === 'rtl' ? 'left' : 'right';
},
/**
* Resets main canvas wrapper and toolbar padding / margin.
*/
resetPadding() {
Drupal.offCanvas.$mainCanvasWrapper[0].style[
`padding-${Drupal.offCanvas.getEdge()}`
] = 0;
Drupal.offCanvas.$mainCanvasWrapper[0].style.paddingTop = 0;
displace();
},
};
/**
* Attaches off-canvas dialog behaviors.
*
* @type {Drupal~behavior}
*
* @prop {Drupal~behaviorAttach} attach
* Attaches event listeners for off-canvas dialogs.
*/
Drupal.behaviors.offCanvasEvents = {
attach: () => {
if (!once('off-canvas', 'html').length) {
return;
}
window.addEventListener('dialog:beforecreate', (e) => {
const $element = $(e.target);
if (Drupal.offCanvas.isOffCanvas($element)) {
Drupal.offCanvas.beforeCreate({
$element,
settings: e.settings,
});
}
});
window.addEventListener('dialog:aftercreate', (e) => {
const $element = $(e.target);
if (Drupal.offCanvas.isOffCanvas($element)) {
Drupal.offCanvas.render({
$element,
dialog: e.dialog,
settings: e.settings,
});
Drupal.offCanvas.afterCreate({
$element,
settings: e.settings,
});
}
});
window.addEventListener('dialog:beforeclose', (e) => {
const $element = $(e.target);
if (Drupal.offCanvas.isOffCanvas($element)) {
Drupal.offCanvas.beforeClose({
$element,
});
}
});
},
};
})(jQuery, Drupal, Drupal.debounce, Drupal.displace);