Dialogs
A dialog is an application window that is designed to interrupt the current processing of an application in order to prompt the user to enter information or require a response.
Normal dialog (default)
Default implementation of the dialog. Will display an horizontally and vertically centered container with the text. When pressed, a top-right dismiss button will remove the container and its transparent overlay. The small container goes fullscreen for screens smaller than 480px.
Wide dialog
Contrary to the normal dialog, when shown this variant of the dialog will always fill the entire screen no matter the user’s screen size
Resources
{#
Usage:
- theme: (string)
Possible variation of the component. `dark` is supported at the moment.
- dialog_id: (string)
Overrideable `id` of the dialog: defaults to 'ecl-dialog'
- dialog_aria_labelledby: (string)
Overrideable `aria-labelledby` of the dialog: defaults to 'dialog-title'
- dialog_aria_describedby: (string)
Overrideable `aria-describedby` of the dialog: defaults to 'dialog-description'
- dialog_aria_hidden: (string)
Overrideable `aria-hidden` of the dialog: defaults to `true`
- extra_attributes: (iterable)
Conventional map of possible extra attributes for the dialog.
Pass any attribute, except: id, aria-hidden, aria-labelledby, aria-describedby, role.
Most of these attributes are managed by their corresponding variables described above.
- extra_classes: (string)
Possible additional classes to add to the dialog.
- dialog_title: {
value: the title of the dialog (default: '')
id: the id to match an `aria-labelledby` attribute (default: '')
classes: classes to apply to dialog title field (default: 'ecl-u-sr-only')
}
- dialog_description: {
value: the description of the dialog (default: '')
id: the id to match an `aria-describedby` attribute (default: '')
classes: classes to apply to dialog description field (default: 'ecl-u-sr-only')
}
- dialog_body (mixed): content of the dialog (default: lorem ipsum text)
- dismiss: {
hide: hide the default dismiss button in case you want to include a custom one in the "dialog_body" block (default: false)
label: the value for the button label to close the dialog window (default: 'Dismiss this dialog window')
}
#}
{# Internal properties #}
{% set variant = variant|default('default') %}
{% set _dialog_id = dialog_id|default('ecl-dialog') %}
{% set _dialog_aria_labelledby = dialog_aria_labelledby|default('ecl-dialog-title') %}
{% set _dialog_aria_describedby = dialog_aria_describedby|default('ecl-dialog-description') %}
{% set _dialog_aria_hidden = dialog_aria_hidden|default(true) %}
{% set _dialog_title = {
value: 'Dialog',
id: 'ecl-dialog-title',
classes: 'ecl-u-sr-only'
}|merge(dialog_title|default({})) %}
{% set _dialog_description = {
value: '',
id: 'ecl-dialog-description',
classes: 'ecl-u-sr-only',
}|merge(dialog_description|default({})) %}
{% set dismiss = {
hide: dismiss.hide|default(false),
label: dimiss.label|default('Dismiss this dialog window'),
} %}
{% set _css_class = 'ecl-dialog' %}
{% set _extra_attributes = '' %}
{# Internal logic - Process properties #}
{% if theme is defined %}
{% set _css_class = _css_class ~ ' ecl-dialog--' ~ theme %}
{% endif %}
{% if extra_classes is defined %}
{% set _css_class = _css_class ~ ' ' ~ extra_classes %}
{% endif %}
{% if extra_attributes is defined %}
{% for attr in extra_attributes %}
{% if attr != 'id' and attr != 'aria-labelledby' and attr != 'aria-describedby' and attr != 'aria-hidden' %}
{% set _extra_attributes = _extra_attributes ~ ' ' ~ attr.name ~ '="' ~ attr.value ~ '"' %}
{% endif %}
{% endfor %}
{% endif %}
{# Attach the additional attributes on the dialog #}
{% set _extra_attributes = _extra_attributes ~ ' ' ~ 'id="' ~ _dialog_id ~ '"' %}
{% set _extra_attributes = _extra_attributes ~ ' ' ~ 'aria-labelledby="' ~ _dialog_aria_labelledby ~ '"' %}
{% set _extra_attributes = _extra_attributes ~ ' ' ~ 'aria-describedby="' ~ _dialog_aria_describedby ~ '"' %}
{% set _extra_attributes = _extra_attributes ~ ' ' ~ 'aria-hidden="' ~ _dialog_aria_hidden ~ '"' %}
{# Print result #}
<div class="{{ _css_class }}" {{ _extra_attributes|raw }} role="dialog">
<h3 id="{{ _dialog_title.id }}" class="ecl-heading ecl-heading--h3 {{ _dialog_title.classes }}">{{ _dialog_title.value }}</h3>
{% if dialog_description is defined %}
<p id="{{ _dialog_description.id }}" class="{{ _dialog_description.classes }}">{{ _dialog_description.value }}</p>
{% endif %}
<div class="ecl-dialog__body">
{% block dialog_body %}
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce et augue quis est dignissim lacinia. Curabitur interdum iaculis sagittis. Maecenas sodales elit est, et suscipit nisl vulputate eget. Mauris vel pulvinar odio. Sed diam turpis, cursus vel congue vel, lobortis a ipsum. Donec vel quam nec enim tristique efficitur at eget nisl.
{% endblock %}
</div>
{% if not dismiss.hide %}
<button type="button" class="ecl-message__dismiss" aria-label="{{ dismiss.label }}">×</button>
{% endif %}
</div>
{
"_demo": {
"scripts": "\n document.addEventListener('DOMContentLoaded', function () {\n // This is only for demo purposes to facilitate end-users.\n\n // Create a link.\n var link = document.createElement('a');\n var text = document.createTextNode('Open dialog');\n\n // Include textual content.\n link.appendChild(text);\n link.title = \"Click to test the modal\";\n\n // Add necessary demo attributes.\n link.setAttribute('href', '#dialog');\n link.setAttribute('class', 'ecl-link');\n link.setAttribute('data-ecl-dialog', 'ecl-dialog');\n\n // Show the link\n document.body.appendChild(link);\n\n ECL.dialogs();\n });\n "
},
"dialog_description": {
"value": "Example description"
},
"dismiss": {
"label": "Dismiss this dialog window"
},
"variant": "wide",
"theme": "wide"
}
<div class="ecl-dialog ecl-dialog--wide" id="ecl-dialog" aria-labelledby="ecl-dialog-title" aria-describedby="ecl-dialog-description" aria-hidden="true" role="dialog">
<h3 id="ecl-dialog-title" class="ecl-heading ecl-heading--h3 ecl-u-sr-only">Dialog</h3>
<p id="ecl-dialog-description" class="ecl-u-sr-only">Example description</p>
<div class="ecl-dialog__body">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce et augue quis est dignissim lacinia. Curabitur interdum iaculis sagittis. Maecenas sodales elit est, et suscipit nisl vulputate eget. Mauris vel pulvinar odio. Sed diam turpis, cursus vel
congue vel, lobortis a ipsum. Donec vel quam nec enim tristique efficitur at eget nisl.
</div>
<button type="button" class="ecl-message__dismiss" aria-label="Dismiss this dialog window">×</button>
</div>
-
Content:
import { queryAll } from '@ec-europa/ecl-base/helpers/dom'; /** * @param {object} options Object containing configuration overrides * * Available options: * - options.triggerElementsSelector - any selector to which event listeners * are attached. When clicked on any element with such a selector, a dialog opens. * * - options.dialogWindowId - id of target dialog window. Defaults to `ecl-dialog`. * * - options.dialogOverlayId - id of target dialog window. Defaults to `ecl-overlay`. * Overlay element is created in the document if not provided by the user. */ export const dialogs = ({ triggerElementsSelector: triggerElementsSelector = '[data-ecl-dialog]', dialogWindowId: dialogWindowId = 'ecl-dialog', dialogOverlayId: dialogOverlayId = 'ecl-overlay', } = {}) => { // SUPPORTS if (!('querySelector' in document) || !('addEventListener' in window)) { return null; } // SETUP const triggerElements = queryAll(triggerElementsSelector); const dialogWindow = document.getElementById(dialogWindowId); let dialogOverlay = document.getElementById(dialogOverlayId); // Create an overlay element if the user does not supply one. if (!dialogOverlay) { const element = document.createElement('div'); element.setAttribute('id', 'ecl-overlay'); element.setAttribute('class', 'ecl-dialog__overlay'); element.setAttribute('aria-hidden', 'true'); document.body.appendChild(element); dialogOverlay = element; } // What we can focus on in the modal. const focusableElements = [].slice.call( queryAll( ` a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), [tabindex="0"] `, dialogWindow ) ); // Use this variable to return focus on element after dialog being closed. let focusedElBeforeOpen = null; // Specific elements to take care when openning and closing the dialog. const firstFocusableElement = focusableElements[0]; const lastFocusableElement = focusableElements[focusableElements.length - 1]; // EVENTS // Hide dialog and overlay elements. function close(event) { event.preventDefault(); dialogWindow.setAttribute('aria-hidden', true); dialogOverlay.setAttribute('aria-hidden', true); if (focusedElBeforeOpen) { focusedElBeforeOpen.focus(); } document.querySelector('body').classList.remove('ecl-u-disablescroll'); } // Keyboard behaviors. function handleKeyDown(e) { const KEY_TAB = 9; const KEY_ESC = 27; function handleBackwardTab() { if (document.activeElement === firstFocusableElement) { e.preventDefault(); lastFocusableElement.focus(); } } function handleForwardTab() { if (document.activeElement === lastFocusableElement) { e.preventDefault(); firstFocusableElement.focus(); } } switch (e.keyCode) { // Keep tabbing in the scope of the dialog. case KEY_TAB: if (focusableElements.length === 1) { e.preventDefault(); break; } if (e.shiftKey) { handleBackwardTab(); } else { handleForwardTab(); } break; case KEY_ESC: close(); break; default: break; } } // Show dialog and overlay elements. function open(event) { event.preventDefault(); dialogWindow.setAttribute('aria-hidden', false); dialogOverlay.setAttribute('aria-hidden', false); // This is the element to have the focus after closing the dialog. // Usually the element which triggered the dialog. focusedElBeforeOpen = document.activeElement; // Focus on the first element in the dialog. firstFocusableElement.focus(); // Close dialog when clicked out of the dialog window. dialogOverlay.addEventListener('click', close); // Handle tabbing, esc and keyboard in the dialog window. dialogWindow.addEventListener('keydown', handleKeyDown); document.querySelector('body').classList.add('ecl-u-disablescroll'); } // BIND EVENTS function bindDialogEvents(elements) { elements.forEach(element => element.addEventListener('click', open)); // const closeButtons = document.querySelectorAll('.ecl-message__dismiss'); queryAll('.ecl-message__dismiss').forEach(button => { button.addEventListener('click', close); }); } // UNBIND EVENTS function unbindDialogEvents(elements) { elements.forEach(element => element.removeEventListener('click', open)); // const closeButtons = document.querySelectorAll('.ecl-message__dismiss'); queryAll('.ecl-message__dismiss').forEach(button => { button.removeEventListener('click', close); }); } // DESTROY function destroy() { unbindDialogEvents(triggerElements); } // INIT function init() { if (triggerElements.length) { bindDialogEvents(triggerElements); } } init(); // REVEAL API return { init, destroy, }; }; // module exports export default dialogs;
- URL: /components/raw/ecl-dialogs/dialogs.js
- Filesystem Path: framework/components/ecl-dialogs/dialogs.js
- Size: 5.1 KB
-
Content:
/** * Dialog * @define dialog */ .ecl-dialog { background-color: #fff; display: flex; height: 100%; left: 0; margin: 0; padding: map-get($ecl-spacing, 'l'); position: fixed; top: 0%; width: 100%; z-index: map-get($ecl-z-index, 'modal'); } .ecl-dialog--transparent { background-color: transparent; } .ecl-dialog[aria-hidden='true'] { display: none; } .ecl-dialog__body { max-height: 100%; overflow: auto; } .ecl-dialog__overlay { background-color: rgba(0, 0, 0, 0.7); height: 100%; left: 0; position: fixed; top: 0; width: 100%; z-index: map-get($ecl-z-index, 'highlight'); } .ecl-dialog__overlay--blue { background-color: rgba($ecl-color-primary, 0.95); } .ecl-dialog--wide .ecl-dialog__body { overflow: visible; width: 100%; } .ecl-dialog__title { clear: both; color: #fff; font-size: map-get($ecl-font-size, 'l'); margin: 0; padding: map-get($ecl-spacing, 'l') 0; } @include ecl-media-breakpoint-up('sm') { .ecl-dialog { height: auto; left: 50%; max-height: 100%; max-width: 100%; top: 50%; transform: translate(-50%, -50%); width: auto; } .ecl-dialog--wide { height: 100%; left: 0; overflow: auto; right: 0; top: 0; transform: none; } }
- URL: /components/raw/ecl-dialogs/ecl-dialogs.scss
- Filesystem Path: framework/components/ecl-dialogs/ecl-dialogs.scss
- Size: 1.3 KB