Add add-to-list overlay pattern

This commit is contained in:
2026-06-15 10:39:30 +02:00
parent e35643c270
commit 87425b693d
+153 -89
View File
@@ -13,7 +13,7 @@
<section id="pattern-overlay-card" class="sg-delete-confirmation-pattern"> <section id="pattern-overlay-card" class="sg-delete-confirmation-pattern">
<p class="sg-preview-label">Pattern: Overlay Card</p> <p class="sg-preview-label">Pattern: Overlay Card</p>
<div class="sg-delete-confirmation-pattern__stage sg-delete-confirmation-pattern__host sg-object-card" data-pattern="overlay-card" data-dialog-open="false"> <div class="sg-delete-confirmation-pattern__stage sg-delete-confirmation-pattern__host sg-object-card" data-pattern="overlay-card" data-dialog-open="false" data-overlay-confirmation-value="DELETE">
<article class="sg-card sg-object-card sg-delete-confirmation-pattern__target" aria-label="Zu löschendes Objekt"> <article class="sg-card sg-object-card sg-delete-confirmation-pattern__target" aria-label="Zu löschendes Objekt">
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header"> <header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header">
<div class="sg-strong">Alcon Inc.</div> <div class="sg-strong">Alcon Inc.</div>
@@ -53,7 +53,7 @@
type="text" type="text"
placeholder="DELETE" placeholder="DELETE"
aria-label="Löschbestätigung durch DELETE" aria-label="Löschbestätigung durch DELETE"
data-delete-confirmation-input data-overlay-confirmation-input
> >
</label> </label>
@@ -64,7 +64,7 @@
type="button" type="button"
disabled disabled
aria-disabled="true" aria-disabled="true"
data-delete-confirmation-submit data-overlay-confirmation-submit
data-overlay-dialog-close data-overlay-dialog-close
> >
Löschen Löschen
@@ -75,109 +75,173 @@
</div> </div>
</section> </section>
<section id="pattern-add-to-list-overlay" class="sg-delete-confirmation-pattern">
<p class="sg-preview-label">Pattern: Add to List Overlay</p>
<div class="sg-delete-confirmation-pattern__stage sg-delete-confirmation-pattern__host sg-object-card" data-pattern="add-to-list-overlay" data-dialog-open="false" data-overlay-confirmation-value="ADD">
<article class="sg-card sg-object-card sg-delete-confirmation-pattern__target" aria-label="Zu einer Liste hinzuzufügendes Objekt">
<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-object-card__header">
<div class="sg-strong">Alcon Inc.</div>
<div class="sg-sandwich-menu-wrap" data-open="false" data-align="right" data-component="sandwich-menu" data-component-size="small">
<button class="sg-interaction-element sg-sandwich-button sg-sandwich-button--small" type="button" aria-expanded="false" aria-label="Menü öffnen" data-component-part="sandwich-trigger">
<span class="sg-sandwich-button__icon" aria-hidden="true">
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
<span class="sg-sandwich-button__line"></span>
</span>
</button>
<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">
<a class="sg-sandwich-menu-link" href="#!" data-overlay-open-dialog="add-to-list">Zur Liste hinzufügen</a>
</div>
</div>
</header>
<div class="sg-card-segment sg-card-segment--body sg-object-card__content">
<p class="sg-body">Objekt-Inhalt der Card. Während das Overlay sichtbar ist, wird dieses Objekt um 50% ausgegraut.</p>
</div>
<footer class="sg-card-segment sg-card-segment--body sg-object-card__actions-segment">
<div class="sg-object-card__actions">
<button class="sg-interaction-element sg-button sg-button--active sg-object-card__action" type="button">Peer-Group</button>
<button class="sg-interaction-element sg-button sg-button--active sg-object-card__action" type="button">Fundamentalanalyse</button>
</div>
</footer>
</article>
<article class="sg-card sg-card--overlay-host sg-delete-confirmation-pattern__floating-card" aria-label="Zur Liste hinzufügen" role="dialog" aria-modal="true" aria-labelledby="add-to-list-title" data-overlay-dialog="add-to-list" hidden>
<div class="sg-card-segment sg-card-segment--body sg-delete-confirmation-pattern__body">
<p class="sg-body sg-delete-confirmation-pattern__text" id="add-to-list-title"><strong>Möchtest du Alcon Inc. zu einer Liste hinzufügen?</strong></p>
<p class="sg-body sg-delete-confirmation-pattern__text">Bestätige durch Eingabe von <span class="sg-delete-confirmation-pattern__code">ADD</span>.</p>
<label class="sg-labeled-input-row sg-delete-confirmation-pattern__input-row">
<span class="sg-label">Bestätigung</span>
<input
class="sg-interaction-element sg-input-single-line sg-input-single-line--inactive-selectable sg-form-inactive-selectable"
type="text"
placeholder="ADD"
aria-label="Bestätigung durch ADD"
data-overlay-confirmation-input
>
</label>
<div class="sg-delete-confirmation-pattern__actions">
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-overlay-dialog-close>Abbrechen</button>
<button
class="sg-interaction-element sg-button sg-button--process sg-button--process-inactive"
type="button"
disabled
aria-disabled="true"
data-overlay-confirmation-submit
data-overlay-dialog-close
>
Hinzufügen
</button>
</div>
</div>
</article>
</div>
</section>
<script> <script>
const confirmationInput = document.querySelector('[data-delete-confirmation-input]'); const setupOverlayStage = (stage) => {
const confirmationSubmitButton = document.querySelector('[data-delete-confirmation-submit]'); const confirmationInput = stage.querySelector('[data-overlay-confirmation-input]');
const confirmationSubmitButton = stage.querySelector('[data-overlay-confirmation-submit]');
const expectedConfirmationValue = stage.dataset.overlayConfirmationValue ?? '';
if (confirmationInput && confirmationSubmitButton) { const closeStageDialogs = () => {
const updateDeleteConfirmationState = () => { stage.querySelectorAll('[data-overlay-dialog]').forEach((dialog) => {
const isValid = confirmationInput.value === 'DELETE'; dialog.hidden = true;
});
confirmationSubmitButton.disabled = !isValid; stage.dataset.dialogOpen = 'false';
confirmationSubmitButton.setAttribute('aria-disabled', String(!isValid));
confirmationSubmitButton.classList.toggle('sg-button--process-inactive', !isValid);
}; };
confirmationInput.addEventListener('input', updateDeleteConfirmationState); if (confirmationInput && confirmationSubmitButton) {
updateDeleteConfirmationState(); const updateConfirmationState = () => {
} const isValid = confirmationInput.value === expectedConfirmationValue;
const closeStageDialogs = (stage) => { confirmationSubmitButton.disabled = !isValid;
stage.querySelectorAll('[data-overlay-dialog]').forEach((dialog) => { confirmationSubmitButton.setAttribute('aria-disabled', String(!isValid));
dialog.hidden = true; confirmationSubmitButton.classList.toggle('sg-button--process-inactive', !isValid);
}); };
stage.dataset.dialogOpen = 'false';
};
document.querySelectorAll('.sg-delete-confirmation-pattern__stage').forEach((stage) => { confirmationInput.addEventListener('input', updateConfirmationState);
closeStageDialogs(stage); updateConfirmationState();
});
document.querySelectorAll('[data-overlay-open-dialog]').forEach((link) => {
link.addEventListener('click', (event) => {
event.preventDefault();
event.stopPropagation();
const stage = link.closest('.sg-delete-confirmation-pattern__stage');
if (!stage) {
return;
}
const target = link.getAttribute('data-overlay-open-dialog');
const dialog = stage.querySelector(`[data-overlay-dialog="${target}"]`);
if (!dialog) {
return;
}
closeStageDialogs(stage);
dialog.hidden = false;
stage.dataset.dialogOpen = 'true';
const menuWrap = link.closest('.sg-sandwich-menu-wrap');
const menuButton = menuWrap?.querySelector('.sg-sandwich-button');
if (menuWrap) {
menuWrap.dataset.open = 'false';
}
if (menuButton) {
menuButton.setAttribute('aria-expanded', 'false');
}
});
});
document.querySelectorAll('[data-overlay-dialog-close]').forEach((button) => {
button.addEventListener('click', (event) => {
event.preventDefault();
const stage = button.closest('.sg-delete-confirmation-pattern__stage');
if (!stage) {
return;
}
closeStageDialogs(stage);
});
});
document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((wrap) => {
const button = wrap.querySelector('.sg-sandwich-button');
const panel = wrap.querySelector('.sg-sandwich-menu-panel');
if (!button) {
return;
} }
button.addEventListener('click', (event) => { closeStageDialogs();
event.stopPropagation();
const nextState = wrap.dataset.open !== 'true';
document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((otherWrap) => { stage.querySelectorAll('[data-overlay-open-dialog]').forEach((link) => {
const otherButton = otherWrap.querySelector('.sg-sandwich-button'); link.addEventListener('click', (event) => {
otherWrap.dataset.open = 'false'; event.preventDefault();
if (otherButton) { event.stopPropagation();
otherButton.setAttribute('aria-expanded', 'false');
const target = link.getAttribute('data-overlay-open-dialog');
const dialog = stage.querySelector(`[data-overlay-dialog="${target}"]`);
if (!dialog) {
return;
}
closeStageDialogs();
dialog.hidden = false;
stage.dataset.dialogOpen = 'true';
const menuWrap = link.closest('.sg-sandwich-menu-wrap');
const menuButton = menuWrap?.querySelector('.sg-sandwich-button');
if (menuWrap) {
menuWrap.dataset.open = 'false';
}
if (menuButton) {
menuButton.setAttribute('aria-expanded', 'false');
} }
}); });
});
wrap.dataset.open = String(nextState); stage.querySelectorAll('[data-overlay-dialog-close]').forEach((button) => {
button.setAttribute('aria-expanded', String(nextState)); button.addEventListener('click', (event) => {
event.preventDefault();
closeStageDialogs();
});
});
if (!nextState || !panel) { stage.querySelectorAll('.sg-sandwich-menu-wrap').forEach((wrap) => {
const button = wrap.querySelector('.sg-sandwich-button');
const panel = wrap.querySelector('.sg-sandwich-menu-panel');
if (!button) {
return; return;
} }
wrap.dataset.align = 'right'; button.addEventListener('click', (event) => {
const panelRect = panel.getBoundingClientRect(); event.stopPropagation();
if (panelRect.left < 0) { const nextState = wrap.dataset.open !== 'true';
wrap.dataset.align = 'left';
} document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((otherWrap) => {
const otherButton = otherWrap.querySelector('.sg-sandwich-button');
otherWrap.dataset.open = 'false';
if (otherButton) {
otherButton.setAttribute('aria-expanded', 'false');
}
});
wrap.dataset.open = String(nextState);
button.setAttribute('aria-expanded', String(nextState));
if (!nextState || !panel) {
return;
}
wrap.dataset.align = 'right';
const panelRect = panel.getBoundingClientRect();
if (panelRect.left < 0) {
wrap.dataset.align = 'left';
}
});
}); });
return closeStageDialogs;
};
const overlayStages = Array.from(document.querySelectorAll('.sg-delete-confirmation-pattern__stage'));
overlayStages.forEach((stage) => {
setupOverlayStage(stage);
}); });
document.addEventListener('click', (event) => { document.addEventListener('click', (event) => {