<style media="screen">
    :root {
        --m-modal-button-primary-color: #e0bff5;
        --m-modal-button-primary-hover-color: #c27fec;
        --m-modal-button-primary-border-color: #c27fec;
        --m-modal-button-primary-text-color: #1f2a36;
        --m-modal-button-secondary-color: #ff9fb4;
        --m-modal-button-secondary-hover-color: #ff4069;
        --m-modal-button-secondary-border-color: #ff4069;
        --m-modal-button-secondary-text-color: #1f2a36;
    }
</style>
<div id="modal-container" class="m-modal m-modal--has-overlay">
    <div class="m-modal__container m-modal__container--form">
        <button type="button" class="a-button a-button--standalone-icon a-button--transparent js-toggle-modal" aria-expanded="false" data-a11y-toggle="" aria-controls="" data-modal-close>
            <span class="a-button__text u-visuallyhidden">Skapa konto</span>
            <svg class="icon a-button__icon">
                <use xlink:href="#icon-close"></use>
            </svg>
        </button>
        <div class="m-modal__content">
            <h1>Skapa konto</h1>
        </div>
        <form class="m-modal__form">
            <div class="field-group">
                <div class="m-modal__content--form-email">
                    <label for="label">E-post</label>
                    <input type="text" id="name" placeholder="hej@mail.com" autocomplete="off" class="a-input ">
                </div>
                <div class="m-modal__input-wrapper">
                    <div class="m-modal__content--form-name">
                        <label for="label">Förnamn</label>
                        <input type="text" id="name" placeholder="Anna" autocomplete="off" class="a-input ">
                    </div>
                    <div class="m-modal__content--form-lname">
                        <label for="label">Efternamn</label>
                        <input type="text" id="name" placeholder="Johansson" autocomplete="off" class="a-input ">
                    </div>
                </div>
                <div class="m-modal__content--form-username">
                    <label for="label">Användarnamn</label>
                    <input type="text" id="name" placeholder="tex kattsmurfen89" autocomplete="off" class="a-input ">
                </div>
                <div class="modal__content--form-password u-m-b-default">
                    <label for="password">Lösenord</label>
                    <input type="password" id="password" placeholder="" autocomplete="off" class="a-input has-icon ">
                    <button class="input-icon js-toggle-input-type">
                        <svg class="icon">
                            <use xlink:href="#icon-read"></use>
                        </svg>
                        <span class="u-visuallyhidden">Visa lösenordet</span>
                    </button>
                </div>

                <fieldset>
                    <legend class="label-legend">Prenumerera på våra lokala nyhetsbrev:</legend>
                    <div class="checkbox checkbox--inline row no-gutters u-m-b-2">
                        <div class="grid-auto">
                            <input type="checkbox" id="radiobutton-0" name="Checkbox default" value="0" class="a-checkbox u-visuallyhidden">
                            <label for="radiobutton-0"><span>Stockholm</span></label>
                        </div>
                        <div class="grid-auto">
                            <input type="checkbox" id="radiobutton-1" name="Checkbox default" value="0" class="a-checkbox u-visuallyhidden">
                            <label for="radiobutton-1"><span>Malmö</span></label>
                        </div>
                    </div>
                </fieldset>

                <div class="checkbox">
                    <input type="checkbox" id="radiobutton-2" name="Checkbox default" value="0" class="a-checkbox u-visuallyhidden">
                    <label for="radiobutton-2"><span>Jag godkänner Goto 10:s <a href="#" class="u-link">medlemsvillkor</a> och <a href="https://internetstiftelsen.se/om-webbplatsen/integritetspolicy-for-besokare-pa-internetstiftelsens-webbplatser/" class="u-link">integritetspolicy</a>.</span></label>
                </div>
            </div>
        </form>
        <div class="m-modal__buttons u-m-t-2">
            <button type="button" class="a-button m-modal__button-primary u-z-index-foreground js-toggle-modal" aria-expanded="false" data-a11y-toggle="" aria-controls="" data-modal-close>
                <span class="a-button__text">Skapa konto</span>
            </button>
        </div>
        <div class="m-modal__content--form-text u-m-t-2">Har du redan ett konto? <a href="#" class="u-link">Logga in</a></div>
    </div>
</div>
<style media="screen">
:root {
	--m-modal-button-primary-color: {{button_primary_color}};
	--m-modal-button-primary-hover-color: {{button_primary_hover_color}};
	--m-modal-button-primary-border-color: {{button_primary_border_color}};
	--m-modal-button-primary-text-color: {{button_primary_text_color}};
	--m-modal-button-secondary-color: {{button_secondary_color}};
	--m-modal-button-secondary-hover-color: {{button_secondary_hover_color}};
	--m-modal-button-secondary-border-color: {{button_secondary_border_color}};
	--m-modal-button-secondary-text-color: {{button_secondary_text_color}};
}
</style>
<div id="modal-container" class="m-modal m-modal--has-overlay" {{#if is_hidden}}aria-hidden="true"{{/if}}>
	<div class="m-modal__container {{#if is_form}}m-modal__container--form{{/if}}">
		<button type="button" class="a-button a-button--standalone-icon a-button--transparent js-toggle-modal" aria-expanded="false" data-a11y-toggle="{{aria_controls}}" aria-controls="{{aria_controls}}" data-modal-close>
			<span class="a-button__text u-visuallyhidden">{{button_text}}</span>
			<svg class="icon a-button__icon">
				<use xlink:href="#icon-close"></use>
			</svg>
		</button>
		<div class="m-modal__content">
			{{#unless is_form}}
				<h4>{{title}}</h4>
				<p>{{{text}}}</p>
			{{/unless}}
			{{#if is_form}}
			 	<h1>{{title}}</h1>
			{{/if}}
		</div>
		{{#if is_form}}
		<form class="m-modal__form">
			<div class="field-group">
			<div class="m-modal__content--form-email">
				<label for="label">E-post</label>
					<input type="text" id="name" placeholder="hej@mail.com" autocomplete="off" class="a-input ">
			</div>
			<div class="m-modal__input-wrapper">
				<div class="m-modal__content--form-name">
					<label for="label">Förnamn</label>
					<input type="text" id="name" placeholder="Anna" autocomplete="off" class="a-input ">
				</div>
				<div class="m-modal__content--form-lname">
					<label for="label">Efternamn</label>
					<input type="text" id="name" placeholder="Johansson" autocomplete="off" class="a-input ">
				</div>
			</div>
			<div class="m-modal__content--form-username">
				<label for="label">Användarnamn</label>
				<input type="text" id="name" placeholder="tex kattsmurfen89" autocomplete="off" class="a-input ">
			</div>
			<div class="modal__content--form-password u-m-b-default">
			 <label for="password">Lösenord</label>
				<input type="password" id="password" placeholder="" autocomplete="off" class="a-input has-icon ">
				<button class="input-icon js-toggle-input-type">
					<svg class="icon">
						<use xlink:href="#icon-read"></use>
					</svg>
					<span class="u-visuallyhidden">Visa lösenordet</span>
				</button>
				</div>

				<fieldset>
					<legend class="label-legend">{{check_text}}</legend>
					<div class="checkbox checkbox--inline row no-gutters u-m-b-2">
						<div class="grid-auto">
							<input type="checkbox" id="radiobutton-0" name="Checkbox default" value="0" class="a-checkbox u-visuallyhidden">
							<label for="radiobutton-0"><span>Stockholm</span></label>
						</div>
						<div class="grid-auto">
							<input type="checkbox" id="radiobutton-1" name="Checkbox default" value="0" class="a-checkbox u-visuallyhidden">
							<label for="radiobutton-1"><span>Malmö</span></label>
						</div>
					</div>
				</fieldset>

				<div class="checkbox">
					<input type="checkbox" id="radiobutton-2" name="Checkbox default" value="0" class="a-checkbox u-visuallyhidden">
					<label for="radiobutton-2"><span>{{{terms_text}}}</span></label>
				</div>
			</div>
			</form>
		{{/if}}
		<div class="m-modal__buttons u-m-t-2">
			<button type="button" class="a-button m-modal__button-primary u-z-index-foreground js-toggle-modal" aria-expanded="false" data-a11y-toggle="{{aria_controls}}" aria-controls="{{aria_controls}}" data-modal-close>
				<span class="a-button__text">{{button_text}}</span>
			</button>
		</div>
		{{#if is_form}}
		<div class="m-modal__content--form-text u-m-t-2">{{{bottom_text}}}</div>
		{{/if}}
	</div>
</div>
{{#if is_hidden}}
	<button type="button" class="a-button a-button--lemon" data-open-demo-modal>
		<span class="a-button__text">{{btn_text}}</span>
	</button>

	<button type="button" class="a-button a-button--lemon" data-modal-open="modal-container">
		<span class="a-button__text">Open predefined modal</span>
	</button>
{{/if}}
{
  "title": "Skapa konto",
  "text": "En påminnelse kommer skickas till din adress <a href=\"https://internetstiftelsen.se/om-webbplatsen/integritetspolicy-for-besokare-pa-internetstiftelsens-webbplatser/\" class=\"u-link\">15 minuter</a> innan streamen startar.",
  "button_text": "Skapa konto",
  "aria_controls": "",
  "is_hidden": false,
  "button_primary_color": "#e0bff5",
  "button_primary_hover_color": "#c27fec",
  "button_primary_border_color": "#c27fec",
  "button_primary_text_color": "#1f2a36",
  "button_secondary_color": "#ff9fb4",
  "button_secondary_hover_color": "#ff4069",
  "button_secondary_border_color": "#ff4069",
  "button_secondary_text_color": "#1f2a36",
  "is_form": true,
  "check_text": "Prenumerera på våra lokala nyhetsbrev:",
  "terms_text": "Jag godkänner Goto 10:s <a href=\"#\" class=\"u-link\">medlemsvillkor</a> och <a href=\"https://internetstiftelsen.se/om-webbplatsen/integritetspolicy-for-besokare-pa-internetstiftelsens-webbplatser/\" class=\"u-link\">integritetspolicy</a>.",
  "bottom_text": "Har du redan ett konto? <a href=\"#\" class=\"u-link\">Logga in</a>"
}
  • Content:
    @charset "UTF-8";
    @use '../../configurations/mixins' as mixin;
    @use '../../configurations/extends';
    @use '../../configurations/bem' as bem;
    @use '../../configurations/config' as config;
    @use '../../configurations/variables' as var;
    @use '../../configurations/functions' as func;
    @use '../../configurations/colors/colors' as colors;
    @use '../../configurations/colors/colors-functions' as colorFunc;
    @use '../../vendor/grid/breakpoints' as breakpoint;
    @use '../../vendor/grid/grid' as grid;
    
    @include mixin.molecule(modal) {
    	display: flex;
    	position: fixed;
    	z-index: func.z_index(foreground);
    	top: 0;
    	right: 0;
    	bottom: 0;
    	left: 0;
    	align-items: center;
    	justify-content: center;
    
    	&[aria-hidden='true'] {
    		display: none;
    	}
    
    	// Adjust close button position
    	@include bem.m(has-overlay) {
    		&::after {
    			content: '';
    			position: absolute;
    			z-index: func.z_index(foregroundMinus);
    			top: 0;
    			right: 0;
    			bottom: 0;
    			left: 0;
    			background: rgba(0, 0, 0, 0.5);
    		}
    	}
    
    	@include bem.e(container) {
    		display: flex;
    		position: relative;
    		z-index: func.z_index(foreground);
    		flex-direction: column;
    		width: 100%;
    		max-height: calc(100vh - #{func.rhythm(2)});
    		margin: func.rhythm(1);
    		padding: func.rhythm(4) func.rhythm(2) func.rhythm(4) func.rhythm(2);
    		overflow-y: auto;
    		border-radius: var.$border-radius;
    		background: var(--snow-color);
    
    		> button {
    			position: absolute;
    			z-index: func.z_index(background);
    			top: func.rhythm(1);
    			right: func.rhythm(1);
    		}
    
    		@include breakpoint.bp-up(sm) {
    			padding: func.rhythm(4) func.rhythm(4) func.rhythm(6) func.rhythm(4);
    			width: auto;
    			min-width: func.to_rem(576px);
    		}
    
    		@include breakpoint.bp-up(md) {
    			padding: func.rhythm(8) func.rhythm(8) func.rhythm(6) func.rhythm(8);
    		}
    
    		@include breakpoint.bp-up(lg) {
    			max-width: func.to_rem(961px);
    		}
    
    		@include bem.m(no-max-width) {
    			max-width: none;
    		}
    
    		@include bem.m(dynamic-width) {
    			width: 100%;
    			max-width: calc(100vw);
    			min-width: 0;
    			max-height: calc(100% - #{func.rhythm(2)});
    			padding: 0;
    			overflow: auto;
    
    			svg {
    				pointer-events: none;
    			}
    		}
    	}
    
    	@include breakpoint.bp-up(md) {
    		@include bem.e(input-wrapper) {
    			display: flex;
    			justify-content: space-between;
    			margin-bottom: func.rhythm(2);
    		}
    	}
    
    	@include bem.e(content) {
    		position: relative;
    		margin-right: func.rhythm(2);
    
    		@include breakpoint.bp-up(sm) {
    			margin-right: 0;
    		}
    
    		@include bem.m(form-name) {
    			flex: 0 0 45%;
    		}
    
    		@include bem.m(form-lname) {
    			flex: 0 0 45%;
    		}
    
    		@include bem.e(input-wrapper) {
    			display: flex;
    			justify-content: space-between;
    			margin-bottom: func.rhythm(2);
    		}
    
    		@include breakpoint.bp-up(md) {
    
    			@include bem.m(form-email) {
    				margin-bottom: func.rhythm(2);
    			}
    
    			@include bem.m(form-username) {
    				margin-bottom: func.rhythm(2);
    			}
    		}
    		@include bem.m(form-check) {
    			display: flex;
    		}
    
    		@include bem.m(form-text) {
    			display: flex;
    			justify-content: center;
    			margin-top: func.rhythm(2);
    		}
    	}
    
    	@include bem.e(buttons) {
    		display: flex;
    		flex-shrink: 0;
    		justify-content: flex-end;
    	}
    
    	@include bem.e(button-primary) {
    		color: var(--m-modal-button-primary-color) !important;
    		box-shadow: 0 0 0 1px inset var(--m-modal-button-primary-border-color) !important;
    
    		> [class*='text'] {
    			color: var(--m-modal-button-primary-text-color) !important;
    		}
    
    		&:hover,
    		&:focus {
    			color: var(--m-modal-button-primary-hover-color) !important;
    		}
    	}
    
    	@include bem.e(button-secondary) {
    		color: var(--m-modal-button-secondary-color) !important;
    		box-shadow: 0 0 0 1px inset var(--m-modal-button-secondary-border-color) !important;
    
    		> [class*='text'] {
    			color: var(--m-modal-button-secondary-text-color) !important;
    		}
    
    		&:hover,
    		&:focus {
    			color: var(--m-modal-button-secondary-hover-color) !important;
    		}
    	}
    
    	@include bem.e(graph-button) {
    		padding: 0;
    		position: relative;
    
    		&:hover,
    		&:focus {
    			@extend %input-focus;
    		}
    
    		&::after {
    			content: attr(data-zoom);
    			color: colors.$color-snow;
    			padding: func.rhythm(1) func.rhythm(2) func.rhythm(1) func.rhythm(4);
    			display: block;
    			position: absolute;
    			top: 0;
    			left: 0;
    			border-top-left-radius: var.$border-radius;
    			border-bottom-right-radius: var.$border-radius;
    			width: auto;
    			line-height: 1;
    			height: var.$icon-size-large * 1.4;
    			background-color: rgba(colors.$color-cyberspace, 0.7);
    			background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' id='icon-search' viewbox='0 0 32 32' width='32' height='32' fill='%23ffffff'%3E%3Cpath d='M24,21.8l8,8L29.9,32l-8-8c-5.9,4.6-14.3,3.6-19-2.2S-0.7,7.6,5.1,2.9S19.3-0.7,24,5.1C27.9,10,27.9,16.9,24,21.8L24,21.8z M13.4,23.9c5.8,0,10.5-4.7,10.5-10.5S19.2,3,13.4,3S3,7.7,3,13.4S7.7,23.9,13.4,23.9z'/%3E%3C/svg%3E");
    			background-position: func.rhythm(1) center;
    			background-size: var.$icon-size-medium var.$icon-size-medium;
    			background-repeat: no-repeat;
    
    		}
    	}
    
    	@include bem.e(button-fixed) {
    		position: fixed !important;
    		top: func.rhythm(2) !important;
    		right: func.rhythm(3) !important;
    		z-index: func.z_index(foreground) !important;
    	}
    
    	@include bem.e(overlay-button) {
    		position: fixed !important;
    		color: colors.$color-snow;
    		display: flex;
    		align-items: center;
    		text-align: center;
    		justify-content: center;
    		padding: 0;
    		z-index: func.z_index(foregroundMinus) !important;
    		top: 0 !important;
    		right: 0 !important;
    		bottom: 0 !important;
    		left: 0 !important;
    		background: rgba(0, 0, 0, 0.5);
    		text-shadow: 0 0 func.rhythm(0.5) colors.$color-cyberspace;
    		font-family: var.$font-family-headings;
    		border: 0;
    		width: 100vw;
    
    		&.is-hidden {
    			display: none;
    		}
    
    		@include breakpoint.bp-up(xxl) {
    			display: none;
    		}
    	}
    
    	@include bem.b(field-group) {
    		margin-bottom: func.rhythm(1);
    	}
    }
    
  • URL: /components/raw/modal/_modal.scss
  • Filesystem Path: src/molecules/modal/_modal.scss
  • Size: 5.8 KB
  • Content:
    import focusTrap from '../../focusTrap';
    import className from '../../assets/js/className';
    
    /**
     * Modal action
     * @typedef {Object} ModalAction
     * @property {string} icon - icon name
     * @property {string} color - styleguide color
     * @property {string} modifier - styleguide modifier
     * @property {string} text - action content
     * @property {string} url - action link url
     * @property {string} target - action link target
     * @property {string} key - action click handler key shortcut
     * @property {function} onClick - action click handler
     * @property {object} attrs – action element attributes
     */
    
    /**
     * Modal content
     * @typedef {Object} ModalContent
     * @property {string} title - Modal title
     * @property {string} content - Modal content
     * @property {ModalAction[]} actions - Modal actions
     */
    
    /**
     * Modal settings
     * @typedef {Object} ModalSettings
     * @property {boolean} replaceCurrent - Replace currently displayed modal
     * @property {boolean} skipIfCurrent - Skip if currently displaying modal
     * @property {function} onClose - onClose callback
     * @property {function} onOpen - onOpen callback
     */
    
    const queue = [];
    const globalOnCloseCallbacks = [];
    const globalOnOpenCallbacks = [];
    let active = null;
    let incrementId = 0;
    let modal = null;
    let modalContent = null;
    let modalActions = null;
    let modalClose = null;
    let keyHandlers = {};
    
    /**
     * Increase increment ID and return the latest
     *
     * @returns {number}
     */
    function getId() {
    	incrementId += 1;
    
    	return incrementId;
    }
    
    function objectToAttributes(obj) {
    	return Object.entries(obj)
    		.filter(([, value]) => value !== undefined)
    		.map(([key, value]) => ((value !== null) ? `${key}=${value}` : key))
    		.join(' ');
    }
    
    /**
     * Create an action DOM node and append to modal actions container.
     *
     * @param {ModalAction} action
     */
    function addAction(action) {
    	const icon = (action.icon) ? `
    		<svg class="icon ${className('a-button__icon')}">
    			<use xlink:href="#icon-${action.icon}"></use>
    		</svg>
    	` : '';
    
    	let cls = `${className('a-button')} u-m-l-2`;
    
    	if (action.color) {
    		cls += ` ${className(`a-button--${action.color}`)}`;
    	}
    
    	if (action.modifier) {
    		cls += ` ${className(`m-modal__button-${action.modifier}`)}`;
    	}
    
    	if (action.icon) {
    		cls += ` ${className('a-button--icon')}`;
    	}
    
    	const tag = (action.url) ? 'a' : 'button';
    	const button = `
    		<${tag} ${objectToAttributes({ ...action.attrs, href: action.url, target: action.target })} class="${cls}">
    			<span class="${className('a-button__text')}">${action.text}</span>
    			${icon}
    		</${tag}>
    	`;
    
    	const dummy = document.createElement('div');
    
    	dummy.innerHTML = button;
    
    	const el = dummy.firstElementChild;
    	modalActions.appendChild(el);
    
    	if (action.onClick) {
    		el.addEventListener('click', (e) => {
    			 
    			action.onClick(e, modal, close);
    		});
    	}
    }
    
    function handleKeyUp(e) {
    	Object.entries(keyHandlers).forEach(([key, handler]) => {
    		if (e.key.toLowerCase() === key) {
    			 
    			handler(e, modal, close);
    		}
    	});
    }
    
    /**
     * Global onOpen handler
     *
     * @param {Function} cb
     * @returns {number}
     */
    export function onOpen(cb) {
    	const index = globalOnOpenCallbacks.push(cb) - 1;
    
    	return () => {
    		globalOnOpenCallbacks.splice(index, 1);
    	};
    }
    
    function dispatchOnOpenHandlers(el, id) {
    	globalOnOpenCallbacks.forEach((cb) => cb(el, id));
    }
    
    /**
     * Display the active modal.
     */
    function display() {
    	if (active.content.nodeName) {
    		// Content is a custom modal
    		active.el = active.content;
    	} else {
    		active.el = modal;
    		modalContent.innerHTML = `
    			<h1>${active.content.title}</h1>
    			${active.content.content}
    		`;
    
    		if (active.content.actions) {
    			modalActions.innerHTML = '';
    			active.content.actions.forEach(addAction);
    
    			modalActions.classList.remove('u-hide');
    		} else {
    			modalActions.classList.add('u-hide');
    		}
    	}
    
    	focusTrap(active.el);
    
    	active.el.setAttribute('aria-hidden', 'false');
    	active.el.setAttribute('data-a11y-toggle-open', 'true');
    
    	if (active.settings.onOpen) {
    		active.settings.onOpen(active.id, active.el);
    	}
    
    	dispatchOnOpenHandlers(active.el, active.id);
    
    	setTimeout(() => {
    		if (active.el.focusTrap) {
    			active.el.focusTrap.activate();
    		}
    	}, 1);
    
    	// Just to make sure
    	keyHandlers = {};
    
    	if (active.content.actions) {
    		active.content.actions.forEach((action) => {
    			if (action.key && action.onClick) {
    				keyHandlers[action.key] = action.onClick;
    			}
    		});
    	}
    
    	document.addEventListener('keyup', handleKeyUp);
    }
    
    /**
     * Dispatch the next modal in queue.
     */
    function dispatch() {
    	if (!modal || active || !queue.length) {
    		return;
    	}
    
    	active = queue.shift();
    
    	display();
    }
    
    /**
     * Global onClose handler
     *
     * @param {Function} cb
     * @returns {number}
     */
    export function onClose(cb) {
    	const index = globalOnCloseCallbacks.push(cb) - 1;
    
    	return () => {
    		globalOnCloseCallbacks.splice(index, 1);
    	};
    }
    
    function dispatchOnCloseHandlers(el, id) {
    	globalOnCloseCallbacks.forEach((cb) => cb(el, id));
    }
    
    /**
     * Close currently active modal
     * and dispatch next in queue.
     */
    function close() {
    	if (active) {
    		active.el.setAttribute('aria-hidden', 'true');
    		active.el.removeAttribute('data-a11y-toggle-open');
    
    		if (active.settings.onClose) {
    			active.settings.onClose(active.id);
    		}
    
    		dispatchOnCloseHandlers(active.el, active.id);
    
    		document.removeEventListener('keyup', handleKeyUp);
    
    		if (active.el.focusTrap) {
    			active.el.focusTrap.deactivate();
    		}
    
    		keyHandlers = {};
    		active = null;
    	}
    
    	setTimeout(() => {
    		dispatch();
    	}, 1);
    }
    
    /**
     * Create the modal skeleton and add it to the DOM.
     * Done once and cached.
     */
    function createModal() {
    	if (modal) {
    		return;
    	}
    
    	const id = 'iisModal';
    	const dummy = document.createElement('div');
    
    	dummy.innerHTML = `
    		<div id="${id}" class="${className('m-modal m-modal--has-overlay')}" data-container="true" aria-hidden="true" aria-labelledby="${id}-close">
    			<div class="${className('m-modal__container')}">
    				<button type="button" class="${className('a-button a-button--standalone-icon a-button--transparent')}" data-modal-close aria-expanded="false" data-a11y-toggle="${id}" aria-controls="${id}" id="${id}-close">
    					<span class="${className('a-button__text')} u-visuallyhidden">Stäng</span>
    					<svg class="icon ${className('a-button__icon')}">
    						<use xlink:href="#icon-close"></use>
    					</svg>
    				</button>
    				<div class="${className('m-modal__content')}" data-modal-content></div>
    				<div class="${className('m-modal__buttons')} u-m-t-2 u-hide" data-modal-actions></div>
    			</div>
    		</div>
    	`;
    
    	modal = dummy.firstElementChild;
    	modalContent = modal.querySelector('[data-modal-content]');
    	modalActions = modal.querySelector('[data-modal-actions]');
    	modalClose = modal.querySelector('[data-modal-close]');
    
    	document.body.appendChild(modal);
    
    	modalClose.addEventListener('click', close);
    
    	setTimeout(() => {
    		dispatch();
    	}, 1);
    }
    
    /**
     * Clear the current modal queue
     */
    function clearQueue() {
    	queue.length = 0;
    }
    
    /**
     * Open a modal.
     *
     * @param {ModalContent|HTMLElement} content
     * @param {ModalSettings} settings
     */
    function open(content, settings = {}) {
    	if (active && settings.skipIfCurrent) {
    		return;
    	}
    
    	queue.push({
    		id: getId(),
    		content,
    		settings,
    	});
    
    	if (settings.replaceCurrent) {
    		close();
    	} else {
    		dispatch();
    	}
    }
    
    function delegate(e) {
    	const openModal = e.target.closest('[data-modal-open]');
    
    	if (openModal) {
    		e.preventDefault();
    		e.stopPropagation();
    
    		const id = openModal.getAttribute('data-modal-open');
    		const modalEl = document.getElementById(id);
    		document.querySelector('body').classList.add('prevent-scroll');
    
    		if (modalEl) {
    			open(modalEl, {
    				replaceCurrent: openModal.hasAttribute('data-modal-replace'),
    				skipIfCurrent: openModal.hasAttribute('data-modal-skip'),
    			});
    
    			[].forEach.call(document.querySelectorAll(`[aria-controls="${id}"]`), (el) => {
    				el.setAttribute('aria-expanded', 'true');
    			});
    		}
    
    		return false;
    	}
    
    	const closeModal = e.target.closest('[data-modal-close]');
    
    	if (closeModal) {
    		e.preventDefault();
    		e.stopPropagation();
    
    		const id = closeModal.getAttribute('data-modal-close') || (active && active.el.id);
    		document.querySelector('body').classList.remove('prevent-scroll');
    
    		if (active && active.el.id === id) {
    			close();
    
    			[].forEach.call(document.querySelectorAll(`[aria-controls="${id}"]`), (el) => {
    				el.setAttribute('aria-expanded', 'false');
    			});
    		}
    
    		return false;
    	}
    
    	return true;
    }
    
    /**
     * Attach global listeners
     */
    function attach() {
    	document.body.addEventListener('click', delegate);
    }
    
    createModal();
    attach();
    
    export {
    	clearQueue,
    	open,
    	close,
    };
    
  • URL: /components/raw/modal/modal.js
  • Filesystem Path: src/molecules/modal/modal.js
  • Size: 8.6 KB

No notes defined.