1268 lines
58 KiB
HTML
1268 lines
58 KiB
HTML
<!doctype html>
|
||
<html lang="de">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Styleguide – Interactive Elements</title>
|
||
<link rel="stylesheet" href="../styleguide.css">
|
||
</head>
|
||
<body>
|
||
|
||
<h1 class="sg-main-heading">Components – Interactive Elements</h1>
|
||
<p class="sg-body">
|
||
Formular-Layout-Regel: Wenn Pulldowns, Slider, Radio-Felder, Checkbox-Felder oder Eingabefelder direkt untereinander als Gruppe dargestellt werden, nutzen alle Zeilen dieselbe Label-Spaltenbreite und denselben horizontalen Abstand zwischen Label und Interaktionselement. Auf Mobile erfolgt der Umbruch komponentenspezifisch in eine einspaltige Darstellung.
|
||
</p>
|
||
|
||
|
||
<!-- Component: Link Buttons -->
|
||
<section id="component-link-buttons">
|
||
<p class="sg-preview-label">Component: Link-Buttons</p>
|
||
|
||
<div class="sg-component-row">
|
||
<button class="sg-interaction-element sg-button sg-button--inactive" type="button" data-component="button" data-component-state="inactive" disabled aria-disabled="true">
|
||
Link-Button inaktiv
|
||
</button>
|
||
|
||
<button class="sg-interaction-element sg-button sg-button--active" type="button" data-component="button" data-component-state="active">
|
||
Link-Button aktiv
|
||
</button>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Component: Prozessbutton -->
|
||
<section id="component-process-button">
|
||
<p class="sg-preview-label">Component: Prozessbutton</p>
|
||
|
||
<div class="sg-component-row">
|
||
<button class="sg-interaction-element sg-button sg-button--process sg-button--process-inactive" type="button" data-component="button" data-component-variant="process" data-component-state="inactive" disabled aria-disabled="true">
|
||
Prozess Button inaktiv
|
||
</button>
|
||
|
||
<button class="sg-interaction-element sg-button sg-button--process" type="button" data-component="button" data-component-variant="process" data-component-state="active">
|
||
Prozess Button
|
||
</button>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Component: Button Tab Navigation -->
|
||
<section id="component-button-tab-navigation">
|
||
<p class="sg-preview-label">Component: Tasten-Navigation-gross</p>
|
||
|
||
<div class="sg-tab-button-group" role="tablist" aria-label="Tasten Navigation" data-component="tab-navigation" data-component-size="large">
|
||
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" data-component-part="tab-button">Gesamtbewertung</button>
|
||
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="true" data-component-part="tab-button">Marktbewertung</button>
|
||
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" data-component-part="tab-button">Wachstum</button>
|
||
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" data-component-part="tab-button">Profitabilität</button>
|
||
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" data-component-part="tab-button">Stabilität</button>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Component: Link Menu Items -->
|
||
<section id="component-linksmenu-items">
|
||
<p class="sg-preview-label">Component: Linksmenue-Items</p>
|
||
|
||
<div class="sg-tab-button-group" role="tablist" aria-label="Linksmenue Items" data-component="tab-navigation" data-component-size="large" data-component-variant="linksmenu-items">
|
||
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" data-component-part="tab-button">Gesamtbewertung</button>
|
||
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="true" data-component-part="tab-button">Marktbewertung</button>
|
||
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" data-component-part="tab-button">Wachstum</button>
|
||
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" data-component-part="tab-button">Profitabilität</button>
|
||
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" data-component-part="tab-button">Stabilität</button>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Component: Button Tab Navigation In Content -->
|
||
<section id="component-button-tab-navigation-in-content">
|
||
<p class="sg-preview-label">Component: Tasten-Navigation-gross in content</p>
|
||
|
||
<div class="sg-tab-button-group" role="tablist" aria-label="Tasten Navigation im Content" data-component="tab-navigation" data-component-size="large" data-component-context="content">
|
||
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" data-component-part="tab-button">Gesamtbewertung</button>
|
||
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="true" data-component-part="tab-button">Marktbewertung</button>
|
||
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" data-component-part="tab-button">Wachstum</button>
|
||
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" data-component-part="tab-button">Profitabilität</button>
|
||
<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" data-component-part="tab-button">Stabilität</button>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Component: Compact Button Tab Navigation -->
|
||
<section id="component-button-tab-navigation-compact">
|
||
<p class="sg-preview-label">Component: Tasten-Navigation-schmal</p>
|
||
|
||
<div class="sg-tab-button-group" role="tablist" aria-label="Schmale Tasten Navigation" data-component="tab-navigation" data-component-size="compact">
|
||
<button class="sg-interaction-element sg-button sg-tab-button sg-tab-button--compact" type="button" role="tab" aria-selected="true" data-component-part="tab-button">PE</button>
|
||
<button class="sg-interaction-element sg-button sg-tab-button sg-tab-button--compact" type="button" role="tab" aria-selected="false" data-component-part="tab-button">PE Forward</button>
|
||
<button class="sg-interaction-element sg-button sg-tab-button sg-tab-button--compact" type="button" role="tab" aria-selected="false" data-component-part="tab-button">PEG</button>
|
||
<button class="sg-interaction-element sg-button sg-tab-button sg-tab-button--compact" type="button" role="tab" aria-selected="false" data-component-part="tab-button">FCF Yield</button>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Component: Pulldown -->
|
||
<section id="component-pulldown">
|
||
<p class="sg-preview-label">Component: Pulldown</p>
|
||
|
||
<!--
|
||
Pulldown examples are shown on the form-area preview background.
|
||
This wrapper is only the evaluation surface; it is not part of the pulldown component.
|
||
State meaning:
|
||
- form-inactive-selectable: selectable but not currently active.
|
||
- form-active / selected: currently selected and opens the option panel.
|
||
- form-disabled: technically unavailable and cannot be operated.
|
||
-->
|
||
<div class="sg-form-preview-area">
|
||
<div class="sg-state-example">
|
||
<p class="sg-state-example__label sg-table-label">Komponente normal</p>
|
||
|
||
<div class="sg-labeled-input-row">
|
||
<span class="sg-label">Label</span>
|
||
<div class="sg-pulldown-demo" data-open="false" data-align="left" data-selection-mode="single" data-component="pulldown" data-component-state="inactive-selectable">
|
||
<!--
|
||
Inactive selectable pulldowns use the same overlay behavior as active pulldowns.
|
||
The option panel opens below the trigger and may be aligned left or right to remain visible inside the viewport.
|
||
-->
|
||
<button class="sg-interaction-element sg-pulldown sg-pulldown--inactive-selectable sg-pulldown-demo__trigger" type="button" aria-expanded="false" aria-label="Pulldown ohne aktive Auswahl" data-component-part="pulldown-trigger">
|
||
Auswahl
|
||
</button>
|
||
|
||
<div class="sg-pulldown-panel" aria-label="Geöffnetes inaktives Pulldown" data-component-part="pulldown-panel">
|
||
<ul class="sg-pulldown-option-list" aria-label="Verfügbare Optionen im inaktiven Pulldown">
|
||
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option>
|
||
<span>Menüpunkt 1</span>
|
||
</li>
|
||
|
||
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option>
|
||
<span>Menüpunkt 2</span>
|
||
</li>
|
||
|
||
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option>
|
||
<span>Menüpunkt 3</span>
|
||
</li>
|
||
|
||
<li class="sg-pulldown-option" role="checkbox" aria-checked="false" data-pulldown-option>
|
||
<span>Menüpunkt 4</span>
|
||
</li>
|
||
|
||
<li class="sg-pulldown-option sg-pulldown-option--disabled">
|
||
<span>Menüpunkt 5</span>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="sg-state-example">
|
||
<p class="sg-state-example__label sg-table-label">Variante aktivierbar</p>
|
||
|
||
<div class="sg-activatable-row">
|
||
<div class="sg-pulldown-activatable-header">
|
||
<button class="sg-mode-toggle sg-mode-toggle--local sg-activation-mode-toggle" type="button" data-active="absolute" aria-label="Aktivierung: aus" data-activation-target="component-pulldown-activatable">
|
||
<span class="sg-mode-toggle__switch" aria-hidden="true" data-component-part="toggle-track">
|
||
<span class="sg-activation-mode-toggle__switch-label sg-activation-mode-toggle__switch-label--left">aus</span>
|
||
<span class="sg-activation-mode-toggle__switch-label sg-activation-mode-toggle__switch-label--right">an</span>
|
||
<span class="sg-mode-toggle__handle" data-component-part="toggle-handle"></span>
|
||
</span>
|
||
</button>
|
||
<span class="sg-label">Label</span>
|
||
</div>
|
||
|
||
<div class="sg-pulldown-demo" id="component-pulldown-activatable" data-open="false" data-align="left" data-selection-mode="multiple" data-component="pulldown" data-component-state="inactive-selectable" data-activatable="true">
|
||
<!--
|
||
The number in brackets shows the count of currently selected options inside this pulldown.
|
||
Initial state: the activation toggle is off, therefore the trigger starts as inactive selectable.
|
||
Switching the activation toggle to "an" applies the active default selection and shows the selected count.
|
||
-->
|
||
<span class="sg-activatable-control">
|
||
<button class="sg-interaction-element sg-pulldown sg-pulldown--inactive-selectable sg-pulldown-demo__trigger" type="button" aria-expanded="false" aria-label="Pulldown ohne aktive Auswahl" data-label-base="Auswahl" data-component-part="pulldown-trigger">
|
||
Auswahl
|
||
</button>
|
||
</span>
|
||
|
||
<div class="sg-pulldown-panel" aria-label="Geöffnetes Pulldown" data-component-part="pulldown-panel">
|
||
<!--
|
||
Interactive styleguide variant:
|
||
The panel opens and closes via the pulldown button above.
|
||
It closes when clicking outside, when another pulldown opens, or when a sandwich menu opens.
|
||
If the panel is wider than the trigger or would overflow the viewport, it aligns from the opposite side of the trigger.
|
||
Cross-dependencies between pulldowns are application logic and are not defined in this component.
|
||
-->
|
||
|
||
<div class="sg-checkbox-field-list sg-pulldown-panel__checkbox-list" aria-label="Checkboxen im Pulldown">
|
||
<label class="sg-checkbox-field-option sg-body" data-component="checkbox-field" data-component-state="inactive-selectable">
|
||
<button class="sg-checkbox-field sg-checkbox-field--on-grey sg-checkbox-field--inactive-selectable" type="button" role="checkbox" aria-checked="false" aria-label="Checkbox 1" data-pulldown-option>
|
||
<span class="sg-checkbox-field__mark" aria-hidden="true">✓</span>
|
||
</button>
|
||
<span>Checkbox 1</span>
|
||
</label>
|
||
|
||
<label class="sg-checkbox-field-option sg-body" data-component="checkbox-field" data-component-state="inactive-selectable">
|
||
<button class="sg-checkbox-field sg-checkbox-field--on-grey sg-checkbox-field--inactive-selectable" type="button" role="checkbox" aria-checked="false" aria-label="Checkbox 2" data-pulldown-option>
|
||
<span class="sg-checkbox-field__mark" aria-hidden="true">✓</span>
|
||
</button>
|
||
<span>Checkbox 2</span>
|
||
</label>
|
||
|
||
<label class="sg-checkbox-field-option sg-body" data-component="checkbox-field" data-component-state="inactive-selectable">
|
||
<button class="sg-checkbox-field sg-checkbox-field--on-grey sg-checkbox-field--inactive-selectable" type="button" role="checkbox" aria-checked="false" aria-label="Checkbox 3" data-pulldown-option>
|
||
<span class="sg-checkbox-field__mark" aria-hidden="true">✓</span>
|
||
</button>
|
||
<span>Checkbox 3</span>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="sg-state-example">
|
||
<p class="sg-state-example__label sg-table-label">form-disabled</p>
|
||
<label class="sg-labeled-input-row">
|
||
<span class="sg-label">Label</span>
|
||
<select class="sg-interaction-element sg-pulldown sg-pulldown--disabled" aria-label="Deaktivierter Pulldown" disabled data-component="pulldown" data-component-state="disabled">
|
||
<option>Nicht verfügbar</option>
|
||
</select>
|
||
</label>
|
||
</div>
|
||
|
||
<div class="sg-state-example">
|
||
<p class="sg-state-example__label sg-table-label">Variante ohne Label</p>
|
||
<div class="sg-labeled-input-row">
|
||
<div class="sg-pulldown-demo" data-open="false" data-align="left" data-selection-mode="single" data-component="pulldown" data-component-state="inactive-selectable">
|
||
<button class="sg-interaction-element sg-pulldown sg-pulldown--inactive-selectable sg-pulldown-demo__trigger" type="button" aria-expanded="false" aria-label="Pulldown ohne Label ohne aktive Auswahl" data-component-part="pulldown-trigger">
|
||
Auswahl
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</section>
|
||
|
||
|
||
<!-- Component: Search Field -->
|
||
<section id="component-input-single-line" class="sg-input-component">
|
||
<p class="sg-preview-label">Component: Suchfeld</p>
|
||
|
||
<!--
|
||
Input examples are shown on the form-area preview background.
|
||
This wrapper is only the evaluation surface; it is not part of the input component.
|
||
State meaning:
|
||
- form-inactive-selectable: empty, selectable input with placeholder text.
|
||
- form-active / selected: input with current value and visible remove button.
|
||
- form-disabled: unavailable input; no value can be entered and no remove button is shown.
|
||
-->
|
||
<div class="sg-form-preview-area">
|
||
<div class="sg-state-example">
|
||
<p class="sg-state-example__label sg-table-label">form-inactive-selectable</p>
|
||
<span class="sg-search-field-row">
|
||
<span class="sg-input-single-line-wrap" data-has-value="false" data-component="single-line-input" data-component-state="inactive-selectable">
|
||
<input
|
||
class="sg-interaction-element sg-input-single-line sg-search-field-input sg-input-single-line--inactive-selectable sg-form-inactive-selectable"
|
||
type="text"
|
||
placeholder="Suchfeld"
|
||
aria-label="Suchfeld ohne Eingabe"
|
||
>
|
||
<button class="sg-input-clear-button" type="button" aria-label="Eingabe löschen">×</button>
|
||
</span>
|
||
<span class="sg-search-result-count">0 Treffer</span>
|
||
</span>
|
||
</div>
|
||
|
||
<div class="sg-state-example">
|
||
<p class="sg-state-example__label sg-table-label">form-active / selected</p>
|
||
<span class="sg-search-field-row">
|
||
<span class="sg-input-single-line-wrap" data-has-value="true" data-component="single-line-input" data-component-state="active">
|
||
<input
|
||
class="sg-interaction-element sg-input-single-line sg-search-field-input sg-form-active"
|
||
type="text"
|
||
value="Produkt"
|
||
aria-label="Suchfeld mit Eingabe"
|
||
>
|
||
<button class="sg-input-clear-button" type="button" aria-label="Eingabe löschen">×</button>
|
||
</span>
|
||
<span class="sg-search-result-count">12 Treffer</span>
|
||
</span>
|
||
</div>
|
||
|
||
<div class="sg-state-example">
|
||
<p class="sg-state-example__label sg-table-label">form-disabled</p>
|
||
<span class="sg-search-field-row">
|
||
<input
|
||
class="sg-interaction-element sg-input-single-line sg-search-field-input sg-input-single-line--disabled sg-form-disabled"
|
||
type="text"
|
||
value="Nicht verfügbar"
|
||
aria-label="Deaktiviertes Suchfeld"
|
||
disabled
|
||
data-component="single-line-input"
|
||
data-component-state="disabled"
|
||
>
|
||
</span>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Component: Single Line Input -->
|
||
<section id="component-input-field-single-line" class="sg-input-component">
|
||
<p class="sg-preview-label">Component: Eingabefeld einzeilig</p>
|
||
|
||
<div class="sg-form-preview-area">
|
||
<div class="sg-state-example">
|
||
<p class="sg-state-example__label sg-table-label">form-inactive-selectable</p>
|
||
<label class="sg-labeled-input-row">
|
||
<span class="sg-label">Label</span>
|
||
<input
|
||
class="sg-interaction-element sg-input-single-line sg-input-single-line--inactive-selectable sg-form-inactive-selectable"
|
||
type="text"
|
||
placeholder="Einzeiliges Eingabefeld"
|
||
aria-label="Einzeiliges Eingabefeld ohne Eingabe"
|
||
>
|
||
</label>
|
||
</div>
|
||
|
||
<div class="sg-state-example">
|
||
<p class="sg-state-example__label sg-table-label">form-active / selected</p>
|
||
<label class="sg-labeled-input-row">
|
||
<span class="sg-label">Label</span>
|
||
<input
|
||
class="sg-interaction-element sg-input-single-line sg-form-active"
|
||
type="text"
|
||
value="Aktive Eingabe"
|
||
aria-label="Einzeiliges Eingabefeld mit aktiver Eingabe"
|
||
>
|
||
</label>
|
||
</div>
|
||
|
||
<div class="sg-state-example">
|
||
<p class="sg-state-example__label sg-table-label">form-invalid</p>
|
||
<label class="sg-labeled-input-row">
|
||
<span class="sg-label">Label</span>
|
||
<span class="sg-input-validation-stack">
|
||
<input
|
||
class="sg-interaction-element sg-input-single-line sg-form-active"
|
||
type="text"
|
||
value="Ungültige Eingabe"
|
||
aria-label="Einzeiliges Eingabefeld mit Validierung"
|
||
aria-invalid="true"
|
||
aria-describedby="single-line-invalid-feedback"
|
||
>
|
||
<span class="sg-form-validation-text" id="single-line-invalid-feedback">Bitte eine gültige Eingabe machen.</span>
|
||
</span>
|
||
</label>
|
||
</div>
|
||
|
||
<div class="sg-state-example">
|
||
<p class="sg-state-example__label sg-table-label">form-disabled</p>
|
||
<label class="sg-labeled-input-row">
|
||
<span class="sg-label">Label</span>
|
||
<input
|
||
class="sg-interaction-element sg-input-single-line sg-input-single-line--disabled sg-form-disabled"
|
||
type="text"
|
||
value="Nicht verfügbar"
|
||
aria-label="Deaktiviertes einzeiliges Eingabefeld"
|
||
disabled
|
||
>
|
||
</label>
|
||
</div>
|
||
|
||
<div class="sg-state-example">
|
||
<p class="sg-state-example__label sg-table-label">Variante ohne Label</p>
|
||
<div class="sg-labeled-input-row">
|
||
<input
|
||
class="sg-interaction-element sg-input-single-line sg-input-single-line--inactive-selectable sg-form-inactive-selectable"
|
||
type="text"
|
||
placeholder="Einzeiliges Eingabefeld"
|
||
aria-label="Einzeiliges Eingabefeld ohne Label ohne Eingabe"
|
||
>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Component: Multi Line Input -->
|
||
<section id="component-input-field-multi-line" class="sg-input-component">
|
||
<p class="sg-preview-label">Component: Eingabefeld mehrzeilig</p>
|
||
|
||
<div class="sg-form-preview-area">
|
||
<div class="sg-state-example">
|
||
<p class="sg-state-example__label sg-table-label">form-inactive-selectable</p>
|
||
<label class="sg-labeled-input-row">
|
||
<span class="sg-label">Label</span>
|
||
<textarea
|
||
class="sg-input-multi-line sg-form-inactive-selectable"
|
||
rows="3"
|
||
placeholder="Mehrzeiliges Eingabefeld"
|
||
aria-label="Mehrzeiliges Eingabefeld ohne Eingabe"
|
||
></textarea>
|
||
</label>
|
||
</div>
|
||
|
||
<div class="sg-state-example">
|
||
<p class="sg-state-example__label sg-table-label">form-active / selected</p>
|
||
<label class="sg-labeled-input-row">
|
||
<span class="sg-label">Label</span>
|
||
<textarea
|
||
class="sg-input-multi-line sg-form-active"
|
||
rows="3"
|
||
aria-label="Mehrzeiliges Eingabefeld mit aktiver Eingabe"
|
||
>Aktive Eingabe über mehrere Zeilen</textarea>
|
||
</label>
|
||
</div>
|
||
|
||
<div class="sg-state-example">
|
||
<p class="sg-state-example__label sg-table-label">form-invalid</p>
|
||
<label class="sg-labeled-input-row">
|
||
<span class="sg-label">Label</span>
|
||
<span class="sg-input-validation-stack">
|
||
<textarea
|
||
class="sg-input-multi-line sg-form-active"
|
||
rows="3"
|
||
aria-label="Mehrzeiliges Eingabefeld mit Validierung"
|
||
aria-invalid="true"
|
||
aria-describedby="multi-line-invalid-feedback"
|
||
>Ungültige Eingabe über mehrere Zeilen</textarea>
|
||
<span class="sg-form-validation-text" id="multi-line-invalid-feedback">Bitte einen längeren Text eingeben.</span>
|
||
</span>
|
||
</label>
|
||
</div>
|
||
|
||
<div class="sg-state-example">
|
||
<p class="sg-state-example__label sg-table-label">form-disabled</p>
|
||
<label class="sg-labeled-input-row">
|
||
<span class="sg-label">Label</span>
|
||
<textarea
|
||
class="sg-input-multi-line sg-form-disabled"
|
||
rows="3"
|
||
aria-label="Deaktiviertes mehrzeiliges Eingabefeld"
|
||
disabled
|
||
>Nicht verfügbar</textarea>
|
||
</label>
|
||
</div>
|
||
|
||
<div class="sg-state-example">
|
||
<p class="sg-state-example__label sg-table-label">Variante ohne Label</p>
|
||
<div class="sg-labeled-input-row">
|
||
<textarea
|
||
class="sg-input-multi-line sg-form-inactive-selectable"
|
||
rows="3"
|
||
placeholder="Mehrzeiliges Eingabefeld"
|
||
aria-label="Mehrzeiliges Eingabefeld ohne Label ohne Eingabe"
|
||
></textarea>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Component: Checkbox Field -->
|
||
<section id="component-checkbox-field">
|
||
<p class="sg-preview-label">Component: Kreuzchenfeld / Multiple Choice</p>
|
||
|
||
<!--
|
||
Checkbox examples are shown on the form-area preview background.
|
||
This wrapper is only the evaluation surface; it is not part of the checkbox component.
|
||
State meaning:
|
||
- form-inactive-selectable: not checked, but selectable.
|
||
- form-active / selected: checked and currently selected.
|
||
- form-disabled: technically unavailable and cannot be toggled.
|
||
-->
|
||
<div class="sg-form-preview-area sg-checkbox-field-list">
|
||
<label class="sg-checkbox-field-option sg-body" data-component="checkbox-field" data-component-state="default">
|
||
<span class="sg-state-example__label sg-table-label">Komponente normal</span>
|
||
<button class="sg-checkbox-field" type="button" role="checkbox" aria-checked="false" aria-label="Standard Checkbox">
|
||
<span class="sg-checkbox-field__mark" aria-hidden="true">✓</span>
|
||
</button>
|
||
<span>Standard Checkbox</span>
|
||
</label>
|
||
|
||
<div class="sg-checkbox-field-option sg-checkbox-field-option--inactive-selectable sg-body" id="component-checkbox-activatable" data-component="checkbox-field" data-component-state="inactive-selectable" data-activatable="true">
|
||
<span class="sg-state-example__label sg-table-label">Variante aktivierbar</span>
|
||
<button class="sg-mode-toggle sg-mode-toggle--local sg-activation-mode-toggle" type="button" data-active="absolute" aria-label="Aktivierung: aus" data-activation-target="component-checkbox-activatable">
|
||
<span class="sg-mode-toggle__switch" aria-hidden="true" data-component-part="toggle-track">
|
||
<span class="sg-activation-mode-toggle__switch-label sg-activation-mode-toggle__switch-label--left">aus</span>
|
||
<span class="sg-activation-mode-toggle__switch-label sg-activation-mode-toggle__switch-label--right">an</span>
|
||
<span class="sg-mode-toggle__handle" data-component-part="toggle-handle"></span>
|
||
</span>
|
||
</button>
|
||
<button class="sg-checkbox-field sg-checkbox-field--inactive-selectable" type="button" role="checkbox" aria-checked="false" aria-label="Option wählen">
|
||
<span class="sg-checkbox-field__mark" aria-hidden="true">✓</span>
|
||
</button>
|
||
<span>Option wählbar</span>
|
||
</div>
|
||
|
||
<label class="sg-checkbox-field-option sg-checkbox-field-option--disabled sg-body" data-component="checkbox-field" data-component-state="disabled">
|
||
<span class="sg-state-example__label sg-table-label">form-disabled</span>
|
||
<button class="sg-checkbox-field sg-checkbox-field--disabled" type="button" role="checkbox" aria-checked="false" aria-label="Option nicht verfügbar" disabled>
|
||
<span class="sg-checkbox-field__mark" aria-hidden="true">✓</span>
|
||
</button>
|
||
<span>Option nicht verfügbar</span>
|
||
</label>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Component: Radio Field -->
|
||
<section id="component-radio-field">
|
||
<p class="sg-preview-label">Component: Radio Button / Single Choice</p>
|
||
|
||
<!--
|
||
Radio examples are shown on the form-area preview background.
|
||
This wrapper is only the evaluation surface; it is not part of the radio component.
|
||
State meaning:
|
||
- form-inactive-selectable: not selected, but selectable.
|
||
- form-active / selected: selected radio option.
|
||
- form-disabled: technically unavailable and cannot be selected.
|
||
-->
|
||
<div class="sg-form-preview-area sg-checkbox-field-list">
|
||
<label class="sg-checkbox-field-option sg-body" data-component="radio-field" data-component-state="default">
|
||
<span class="sg-state-example__label sg-table-label">Komponente normal</span>
|
||
<span class="sg-radio-field-row">
|
||
<span class="sg-label">Label</span>
|
||
<span class="sg-radio-activatable-group__choices">
|
||
<span class="sg-radio-activatable-group__choice">
|
||
<button class="sg-radio-field" type="button" role="radio" aria-checked="false" aria-label="Radio 1 wählen">
|
||
<span class="sg-radio-field__mark" aria-hidden="true"></span>
|
||
</button>
|
||
<span>Radio 1</span>
|
||
</span>
|
||
<span class="sg-radio-activatable-group__choice">
|
||
<button class="sg-radio-field" type="button" role="radio" aria-checked="false" aria-label="Radio 2 wählen">
|
||
<span class="sg-radio-field__mark" aria-hidden="true"></span>
|
||
</button>
|
||
<span>Radio 2</span>
|
||
</span>
|
||
</span>
|
||
</span>
|
||
</label>
|
||
|
||
<div class="sg-checkbox-field-option sg-checkbox-field-option--inactive-selectable sg-body sg-radio-activatable-group" id="component-radio-activatable" data-component="radio-field" data-component-state="inactive-selectable" data-activatable="true" data-activatable-radio-group="true">
|
||
<span class="sg-state-example__label sg-table-label">Variante aktivierbar</span>
|
||
<span class="sg-radio-field-row">
|
||
<button class="sg-mode-toggle sg-mode-toggle--local sg-activation-mode-toggle" type="button" data-active="absolute" aria-label="Aktivierung: aus" data-activation-target="component-radio-activatable">
|
||
<span class="sg-mode-toggle__switch" aria-hidden="true" data-component-part="toggle-track">
|
||
<span class="sg-activation-mode-toggle__switch-label sg-activation-mode-toggle__switch-label--left">aus</span>
|
||
<span class="sg-activation-mode-toggle__switch-label sg-activation-mode-toggle__switch-label--right">an</span>
|
||
<span class="sg-mode-toggle__handle" data-component-part="toggle-handle"></span>
|
||
</span>
|
||
</button>
|
||
<span class="sg-label">Label</span>
|
||
<span class="sg-radio-activatable-group__choices">
|
||
<span class="sg-radio-activatable-group__choice">
|
||
<button class="sg-radio-field sg-radio-field--inactive-selectable" type="button" role="radio" aria-checked="false" aria-label="Option 1 wählen" disabled>
|
||
<span class="sg-radio-field__mark" aria-hidden="true"></span>
|
||
</button>
|
||
<span>Option 1</span>
|
||
</span>
|
||
<span class="sg-radio-activatable-group__choice">
|
||
<button class="sg-radio-field sg-radio-field--inactive-selectable" type="button" role="radio" aria-checked="false" aria-label="Option 2 wählen" disabled>
|
||
<span class="sg-radio-field__mark" aria-hidden="true"></span>
|
||
</button>
|
||
<span>Option 2</span>
|
||
</span>
|
||
</span>
|
||
</span>
|
||
</div>
|
||
|
||
<label class="sg-checkbox-field-option sg-checkbox-field-option--disabled sg-body" data-component="radio-field" data-component-state="disabled">
|
||
<span class="sg-state-example__label sg-table-label">form-disabled</span>
|
||
<span class="sg-radio-field-row">
|
||
<button class="sg-radio-field sg-radio-field--disabled" type="button" role="radio" aria-checked="false" aria-label="Option nicht verfügbar" disabled>
|
||
<span class="sg-radio-field__mark" aria-hidden="true"></span>
|
||
</button>
|
||
<span>Option nicht verfügbar</span>
|
||
</span>
|
||
</label>
|
||
|
||
<div class="sg-checkbox-field-option sg-body" data-component="radio-field" data-component-state="default">
|
||
<span class="sg-state-example__label sg-table-label">Variante ohne Gesamtlabel</span>
|
||
<span class="sg-radio-field-row sg-radio-field-row--without-label">
|
||
<span class="sg-radio-activatable-group__choices">
|
||
<span class="sg-radio-activatable-group__choice">
|
||
<button class="sg-radio-field" type="button" role="radio" aria-checked="false" aria-label="Radio 1 wählen">
|
||
<span class="sg-radio-field__mark" aria-hidden="true"></span>
|
||
</button>
|
||
<span>Radio 1</span>
|
||
</span>
|
||
<span class="sg-radio-activatable-group__choice">
|
||
<button class="sg-radio-field" type="button" role="radio" aria-checked="false" aria-label="Radio 2 wählen">
|
||
<span class="sg-radio-field__mark" aria-hidden="true"></span>
|
||
</button>
|
||
<span>Radio 2</span>
|
||
</span>
|
||
</span>
|
||
</span>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Component: Mode Toggle -->
|
||
<section id="component-mode-toggle">
|
||
<p class="sg-preview-label">Component: Modus Schieber global</p>
|
||
|
||
<button class="sg-mode-toggle" type="button" data-active="relative" aria-label="Modus Schieber global: relativ aktiv" data-component="mode-toggle" data-mode-label="Modus Schieber global">
|
||
<span class="sg-mode-toggle__label">absolut</span>
|
||
|
||
<span class="sg-mode-toggle__switch" aria-hidden="true" data-component-part="toggle-track">
|
||
<span class="sg-mode-toggle__handle" data-component-part="toggle-handle"></span>
|
||
</span>
|
||
|
||
<span class="sg-mode-toggle__label">relativ</span>
|
||
</button>
|
||
</section>
|
||
|
||
<!-- Component: Mode Toggle Local -->
|
||
<section id="component-mode-toggle-local">
|
||
<p class="sg-preview-label">Component: Modus Schieber lokal</p>
|
||
|
||
<button class="sg-mode-toggle sg-mode-toggle--local" type="button" data-active="relative" aria-label="Modus Schieber lokal: relativ aktiv" data-component="mode-toggle-local" data-mode-label="Modus Schieber lokal">
|
||
<span class="sg-mode-toggle__label">absolut</span>
|
||
|
||
<span class="sg-mode-toggle__switch" aria-hidden="true" data-component-part="toggle-track">
|
||
<span class="sg-mode-toggle__handle" data-component-part="toggle-handle"></span>
|
||
</span>
|
||
|
||
<span class="sg-mode-toggle__label">relativ</span>
|
||
</button>
|
||
</section>
|
||
|
||
<!-- Component: Aktivierungs-Schalter -->
|
||
<section id="component-activation-toggle">
|
||
<p class="sg-preview-label">Component: Aktivierungs-Schalter (an/aus)</p>
|
||
|
||
<div class="sg-activation-toggle-pattern">
|
||
<button class="sg-mode-toggle sg-mode-toggle--local sg-activation-mode-toggle" type="button" data-active="absolute" aria-label="Aktivierung: aus">
|
||
<span class="sg-mode-toggle__switch" aria-hidden="true" data-component-part="toggle-track">
|
||
<span class="sg-activation-mode-toggle__switch-label sg-activation-mode-toggle__switch-label--left">aus</span>
|
||
<span class="sg-activation-mode-toggle__switch-label sg-activation-mode-toggle__switch-label--right">an</span>
|
||
<span class="sg-mode-toggle__handle" data-component-part="toggle-handle"></span>
|
||
</span>
|
||
</button>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Component: Slider -->
|
||
<section id="component-slider">
|
||
<p class="sg-preview-label">Component: Slider</p>
|
||
|
||
<div class="sg-form-preview-area">
|
||
<div class="sg-state-example">
|
||
<p class="sg-state-example__label sg-table-label">Komponente normal</p>
|
||
<label class="sg-slider-row" data-component="slider" data-component-state="default">
|
||
<span class="sg-label">Wert</span>
|
||
<input
|
||
class="sg-interaction-element sg-slider"
|
||
type="range"
|
||
min="0"
|
||
max="10"
|
||
step="0.1"
|
||
value="6.5"
|
||
aria-label="Slider"
|
||
>
|
||
<output class="sg-slider-value" for="slider">6.5</output>
|
||
</label>
|
||
</div>
|
||
|
||
<div class="sg-state-example">
|
||
<p class="sg-state-example__label sg-table-label">Variante aktivierbar</p>
|
||
<div class="sg-activatable-row">
|
||
<span class="sg-slider-activatable-header">
|
||
<button class="sg-mode-toggle sg-mode-toggle--local sg-activation-mode-toggle" type="button" data-active="absolute" aria-label="Aktivierung: aus" data-activation-target="component-slider-activatable">
|
||
<span class="sg-mode-toggle__switch" aria-hidden="true" data-component-part="toggle-track">
|
||
<span class="sg-activation-mode-toggle__switch-label sg-activation-mode-toggle__switch-label--left">aus</span>
|
||
<span class="sg-activation-mode-toggle__switch-label sg-activation-mode-toggle__switch-label--right">an</span>
|
||
<span class="sg-mode-toggle__handle" data-component-part="toggle-handle"></span>
|
||
</span>
|
||
</button>
|
||
<span class="sg-label">Wert</span>
|
||
</span>
|
||
<label class="sg-slider-row sg-slider-row--inactive-selectable" id="component-slider-activatable" data-component="slider" data-component-state="inactive-selectable" data-activatable="true">
|
||
<input
|
||
class="sg-interaction-element sg-slider sg-form-inactive-selectable"
|
||
type="range"
|
||
min="0"
|
||
max="10"
|
||
step="0.1"
|
||
value="2.0"
|
||
aria-label="Slider inaktiv auswählbar"
|
||
disabled
|
||
>
|
||
<output class="sg-slider-value" for="slider">2.0</output>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Component: Sandwich Menu Button -->
|
||
<section id="component-sandwich-menu-button">
|
||
<p class="sg-preview-label">Component: Sandwich-Menü-Button Portal (groß)</p>
|
||
|
||
<div class="sg-component-row">
|
||
<div class="sg-sandwich-menu-wrap" data-open="false" data-component="sandwich-menu" data-component-size="default">
|
||
<button class="sg-interaction-element sg-sandwich-button" type="button" aria-expanded="false" aria-label="Portal-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 Portal-Menü" data-component-part="sandwich-panel">
|
||
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
|
||
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
|
||
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<p class="sg-preview-label">Component: Sandwich-Menü-Button Objekt (klein)</p>
|
||
|
||
<div class="sg-component-row">
|
||
<div class="sg-sandwich-menu-wrap" data-open="false" 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="Objekt-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 Objekt-Menü" data-component-part="sandwich-panel">
|
||
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
|
||
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
|
||
<a class="sg-sandwich-menu-link" href="#">Menüpunkt</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Component: Help Icon -->
|
||
<section id="component-help-icon">
|
||
<p class="sg-preview-label">Component: Fragezeichen-Icon</p>
|
||
|
||
<span class="sg-help-icon-wrap" data-open="false" data-align="left" data-component="help-icon">
|
||
<button class="sg-help-icon" type="button" aria-expanded="false" aria-label="Hilfetext anzeigen" data-component-part="help-trigger">?</button>
|
||
|
||
<span class="sg-help-icon-panel sg-table-label" role="tooltip" data-component-part="help-panel">
|
||
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.
|
||
</span>
|
||
</span>
|
||
</section>
|
||
|
||
|
||
<!-- Component: Hyperlink -->
|
||
<section id="component-hyperlink">
|
||
<p class="sg-preview-label">Component: Hyperlink</p>
|
||
|
||
<p class="sg-body">
|
||
Dies ist ein Text mit einem <a class="sg-hyperlink" href="#" data-component="hyperlink">Hyperlink</a>.
|
||
</p>
|
||
</section>
|
||
|
||
<script src="../scripts/help-icon-overlays.js"></script>
|
||
<script>
|
||
document.querySelectorAll('.sg-mode-toggle:not(.sg-activation-mode-toggle)').forEach((toggle) => {
|
||
toggle.addEventListener('click', () => {
|
||
const nextState = toggle.dataset.active === 'relative' ? 'absolute' : 'relative';
|
||
const modeLabel = toggle.dataset.modeLabel || 'Modus Schieber';
|
||
toggle.dataset.active = nextState;
|
||
toggle.setAttribute(
|
||
'aria-label',
|
||
`${modeLabel}: ${nextState === 'relative' ? 'relativ' : 'absolut'} aktiv`
|
||
);
|
||
});
|
||
});
|
||
|
||
const ensurePulldownDefaultSelection = (demo) => {
|
||
if (demo.dataset.defaultSelectionInitialized === 'true') {
|
||
return;
|
||
}
|
||
const options = demo.querySelectorAll('[data-pulldown-option]');
|
||
if (options.length === 0) {
|
||
return;
|
||
}
|
||
const hasSelectedOption = Array.from(options).some((option) => option.getAttribute('aria-checked') === 'true');
|
||
if (!hasSelectedOption) {
|
||
options[0].setAttribute('aria-checked', 'true');
|
||
}
|
||
demo.dataset.defaultSelectionInitialized = 'true';
|
||
};
|
||
|
||
const setActivatableComponentState = (target, isActive) => {
|
||
if (!target) {
|
||
return;
|
||
}
|
||
|
||
const componentType = target.dataset.component;
|
||
target.dataset.componentState = isActive ? 'active' : 'inactive-selectable';
|
||
|
||
if (componentType === 'pulldown') {
|
||
const trigger = target.querySelector('.sg-pulldown-demo__trigger');
|
||
const options = target.querySelectorAll('[data-pulldown-option]');
|
||
if (!trigger || options.length === 0) {
|
||
return;
|
||
}
|
||
|
||
if (isActive && target.dataset.activatable === 'true') {
|
||
ensurePulldownDefaultSelection(target);
|
||
}
|
||
target.dataset.open = 'false';
|
||
trigger.setAttribute('aria-expanded', 'false');
|
||
updatePulldownSelectionState(target);
|
||
return;
|
||
}
|
||
|
||
if (componentType === 'checkbox-field') {
|
||
const checkbox = target.querySelector('.sg-checkbox-field');
|
||
if (!checkbox) {
|
||
return;
|
||
}
|
||
|
||
if (!isActive) {
|
||
checkbox.setAttribute('aria-checked', 'false');
|
||
}
|
||
const isChecked = checkbox.getAttribute('aria-checked') === 'true';
|
||
checkbox.classList.toggle('sg-form-active', isChecked);
|
||
checkbox.classList.toggle('sg-checkbox-field--inactive-selectable', !isActive);
|
||
return;
|
||
}
|
||
|
||
if (componentType === 'radio-field') {
|
||
const radios = target.querySelectorAll('.sg-radio-field');
|
||
radios.forEach((radio) => {
|
||
radio.disabled = !isActive;
|
||
if (!isActive) {
|
||
radio.setAttribute('aria-checked', 'false');
|
||
}
|
||
const checked = radio.getAttribute('aria-checked') === 'true';
|
||
radio.setAttribute('aria-checked', String(checked));
|
||
radio.classList.toggle('sg-form-active', checked);
|
||
radio.classList.toggle('sg-radio-field--inactive-selectable', !isActive);
|
||
});
|
||
return;
|
||
}
|
||
|
||
if (componentType === 'slider') {
|
||
const slider = target.querySelector('.sg-slider');
|
||
if (!slider) {
|
||
return;
|
||
}
|
||
|
||
target.classList.toggle('sg-slider-row--inactive-selectable', !isActive);
|
||
slider.classList.toggle('sg-form-active', isActive);
|
||
slider.classList.toggle('sg-form-inactive-selectable', !isActive);
|
||
slider.disabled = !isActive;
|
||
}
|
||
};
|
||
|
||
document.querySelectorAll('.sg-activation-mode-toggle').forEach((toggle) => {
|
||
toggle.addEventListener('click', () => {
|
||
const nextState = toggle.dataset.active === 'absolute' ? 'relative' : 'absolute';
|
||
const isActive = nextState === 'relative';
|
||
toggle.dataset.active = nextState;
|
||
toggle.setAttribute('aria-label', `Aktivierung: ${isActive ? 'an' : 'aus'}`);
|
||
|
||
const targetId = toggle.dataset.activationTarget;
|
||
if (!targetId) {
|
||
return;
|
||
}
|
||
|
||
const target = document.getElementById(targetId);
|
||
setActivatableComponentState(target, isActive);
|
||
});
|
||
});
|
||
|
||
document.querySelectorAll('.sg-tab-button-group').forEach((group) => {
|
||
group.querySelectorAll('.sg-tab-button').forEach((button) => {
|
||
button.addEventListener('click', () => {
|
||
group.querySelectorAll('.sg-tab-button').forEach((otherButton) => {
|
||
otherButton.setAttribute('aria-selected', String(otherButton === button));
|
||
});
|
||
});
|
||
});
|
||
});
|
||
|
||
document.querySelectorAll('.sg-input-single-line-wrap').forEach((wrap) => {
|
||
const input = wrap.querySelector('.sg-input-single-line');
|
||
const clearButton = wrap.querySelector('.sg-input-clear-button');
|
||
|
||
const updateState = () => {
|
||
wrap.dataset.hasValue = String(input.value.length > 0);
|
||
};
|
||
|
||
input.addEventListener('input', updateState);
|
||
|
||
clearButton.addEventListener('click', () => {
|
||
if (input.disabled || clearButton.disabled) {
|
||
return;
|
||
}
|
||
|
||
input.value = '';
|
||
updateState();
|
||
input.focus();
|
||
});
|
||
|
||
updateState();
|
||
});
|
||
|
||
document.querySelectorAll('.sg-slider-row').forEach((row) => {
|
||
const slider = row.querySelector('.sg-slider');
|
||
const valueOutput = row.querySelector('.sg-slider-value');
|
||
if (!slider || !valueOutput) {
|
||
return;
|
||
}
|
||
|
||
const updateSliderState = () => {
|
||
const min = Number(slider.min || 0);
|
||
const max = Number(slider.max || 100);
|
||
const value = Number(slider.value || 0);
|
||
const denominator = max - min;
|
||
const progress = denominator > 0 ? ((value - min) / denominator) * 100 : 0;
|
||
|
||
slider.style.setProperty('--sg-slider-progress', `${progress}%`);
|
||
valueOutput.textContent = value.toFixed(1);
|
||
};
|
||
|
||
slider.addEventListener('input', () => {
|
||
if (row.dataset.activatable === 'true' && row.dataset.componentState !== 'active') {
|
||
return;
|
||
}
|
||
updateSliderState();
|
||
});
|
||
updateSliderState();
|
||
});
|
||
|
||
document.querySelectorAll('.sg-checkbox-field').forEach((checkbox) => {
|
||
checkbox.addEventListener('click', () => {
|
||
if (checkbox.disabled) {
|
||
return;
|
||
}
|
||
if (checkbox.matches('[data-pulldown-option]')) {
|
||
return;
|
||
}
|
||
|
||
const activatableOption = checkbox.closest('[data-component="checkbox-field"][data-activatable="true"]');
|
||
if (activatableOption) {
|
||
if (activatableOption.dataset.componentState !== 'active') {
|
||
return;
|
||
}
|
||
}
|
||
|
||
const nextState = checkbox.getAttribute('aria-checked') !== 'true';
|
||
checkbox.setAttribute('aria-checked', String(nextState));
|
||
|
||
const pulldownDemo = checkbox.closest('.sg-pulldown-demo');
|
||
if (pulldownDemo) {
|
||
updatePulldownSelectionState(pulldownDemo);
|
||
}
|
||
});
|
||
});
|
||
|
||
document.querySelectorAll('[data-pulldown-option]').forEach((option) => {
|
||
option.addEventListener('click', (event) => {
|
||
event.stopPropagation();
|
||
const pulldownDemo = option.closest('.sg-pulldown-demo');
|
||
if (!pulldownDemo) {
|
||
return;
|
||
}
|
||
if (pulldownDemo.dataset.activatable === 'true' && pulldownDemo.dataset.componentState !== 'active') {
|
||
return;
|
||
}
|
||
|
||
const selectionMode = pulldownDemo.dataset.selectionMode || 'single';
|
||
if (selectionMode === 'multiple') {
|
||
const nextState = option.getAttribute('aria-checked') !== 'true';
|
||
option.setAttribute('aria-checked', String(nextState));
|
||
} else {
|
||
pulldownDemo.querySelectorAll('[data-pulldown-option]').forEach((otherOption) => {
|
||
otherOption.setAttribute('aria-checked', String(otherOption === option));
|
||
});
|
||
}
|
||
if (pulldownDemo.dataset.activatable === 'true') {
|
||
pulldownDemo.dataset.defaultSelectionInitialized = 'true';
|
||
}
|
||
|
||
updatePulldownSelectionState(pulldownDemo);
|
||
|
||
if (selectionMode !== 'multiple') {
|
||
pulldownDemo.dataset.open = 'false';
|
||
const trigger = pulldownDemo.querySelector('.sg-pulldown-demo__trigger');
|
||
if (trigger) {
|
||
trigger.setAttribute('aria-expanded', 'false');
|
||
}
|
||
}
|
||
});
|
||
});
|
||
|
||
document.querySelectorAll('.sg-radio-field').forEach((radio) => {
|
||
radio.addEventListener('click', () => {
|
||
if (radio.disabled) {
|
||
return;
|
||
}
|
||
|
||
const activatableGroup = radio.closest('[data-activatable-radio-group="true"]');
|
||
if (activatableGroup) {
|
||
if (activatableGroup.dataset.componentState !== 'active') {
|
||
return;
|
||
}
|
||
|
||
const radios = activatableGroup.querySelectorAll('.sg-radio-field');
|
||
radios.forEach((otherRadio) => {
|
||
otherRadio.setAttribute('aria-checked', String(otherRadio === radio));
|
||
otherRadio.classList.remove('sg-radio-field--inactive-selectable');
|
||
otherRadio.classList.toggle('sg-form-active', otherRadio === radio);
|
||
});
|
||
return;
|
||
}
|
||
|
||
const group = radio.closest('.sg-form-preview-area');
|
||
if (!group) {
|
||
return;
|
||
}
|
||
|
||
group.querySelectorAll('.sg-radio-field').forEach((otherRadio) => {
|
||
otherRadio.setAttribute('aria-checked', String(otherRadio === radio));
|
||
});
|
||
});
|
||
});
|
||
|
||
const updatePulldownSelectionState = (demo) => {
|
||
const trigger = demo.querySelector('.sg-pulldown-demo__trigger');
|
||
const selectableOptions = demo.querySelectorAll('[data-pulldown-option]');
|
||
const selectionMode = demo.dataset.selectionMode || 'single';
|
||
const isActivatableInactive = demo.dataset.activatable === 'true' && demo.dataset.componentState !== 'active';
|
||
|
||
if (!trigger || selectableOptions.length === 0) {
|
||
return;
|
||
}
|
||
|
||
const selectedCount = Array.from(selectableOptions).filter((option) => {
|
||
return option.getAttribute('aria-checked') === 'true';
|
||
}).length;
|
||
|
||
const selectedOption = Array.from(selectableOptions).find((option) => {
|
||
return option.getAttribute('aria-checked') === 'true';
|
||
});
|
||
|
||
selectableOptions.forEach((option) => {
|
||
const isSelected = option.getAttribute('aria-checked') === 'true';
|
||
const optionRow = option.closest('.sg-pulldown-option');
|
||
if (!optionRow) {
|
||
if (option.classList.contains('sg-checkbox-field')) {
|
||
option.classList.toggle('sg-form-active', !isActivatableInactive && isSelected);
|
||
option.classList.toggle('sg-checkbox-field--inactive-selectable', isActivatableInactive || !isSelected);
|
||
}
|
||
return;
|
||
}
|
||
|
||
optionRow.classList.toggle(
|
||
'sg-pulldown-option--selected',
|
||
isSelected
|
||
);
|
||
if (option.classList.contains('sg-checkbox-field')) {
|
||
option.classList.toggle('sg-form-active', !isActivatableInactive && isSelected);
|
||
option.classList.toggle('sg-checkbox-field--inactive-selectable', isActivatableInactive || !isSelected);
|
||
}
|
||
});
|
||
|
||
const labelBase = trigger.dataset.labelBase || 'Auswahl';
|
||
if (selectionMode === 'multiple') {
|
||
trigger.textContent = selectedCount > 0 ? `${labelBase} (${selectedCount})` : labelBase;
|
||
} else if (selectedOption) {
|
||
const selectedText = selectedOption.closest('.sg-pulldown-option')?.querySelector('span')?.textContent?.trim()
|
||
|| selectedOption.closest('label')?.querySelector('span:last-child')?.textContent?.trim()
|
||
|| selectedOption.textContent?.trim();
|
||
trigger.textContent = selectedText || labelBase;
|
||
} else {
|
||
trigger.textContent = labelBase;
|
||
}
|
||
const isActivatableActive = demo.dataset.activatable === 'true' && demo.dataset.componentState === 'active';
|
||
const showActiveState = !isActivatableInactive && (selectedCount > 0 || isActivatableActive);
|
||
trigger.classList.toggle('sg-pulldown--selected', showActiveState);
|
||
trigger.classList.toggle('sg-form-active', showActiveState);
|
||
trigger.classList.toggle('sg-pulldown--inactive-selectable', !showActiveState);
|
||
trigger.setAttribute(
|
||
'aria-label',
|
||
showActiveState ? 'Pulldown mit aktiver Auswahl' : 'Pulldown ohne aktive Auswahl'
|
||
);
|
||
};
|
||
|
||
document.querySelectorAll('.sg-pulldown-demo').forEach(updatePulldownSelectionState);
|
||
// Sync activatable targets to the toggle's initial state on load.
|
||
document.querySelectorAll('.sg-activation-mode-toggle[data-activation-target]').forEach((toggle) => {
|
||
const target = document.getElementById(toggle.dataset.activationTarget);
|
||
if (!target) {
|
||
return;
|
||
}
|
||
setActivatableComponentState(target, toggle.dataset.active === 'relative');
|
||
});
|
||
|
||
// Pulldown behavior: pulldown demos open their panel below the trigger.
|
||
// Opening one closes all sandwich menus and any other open pulldown demo.
|
||
// If the panel is wider than the trigger or would overflow the viewport, it aligns from the opposite trigger edge.
|
||
document.querySelectorAll('.sg-pulldown-demo').forEach((demo) => {
|
||
const trigger = demo.querySelector('.sg-pulldown-demo__trigger');
|
||
|
||
if (!trigger) {
|
||
return;
|
||
}
|
||
|
||
trigger.addEventListener('click', (event) => {
|
||
event.stopPropagation();
|
||
if (demo.dataset.activatable === 'true' && demo.dataset.componentState !== 'active') {
|
||
return;
|
||
}
|
||
const nextState = demo.dataset.open !== 'true';
|
||
|
||
document.querySelectorAll('.sg-pulldown-demo').forEach((otherDemo) => {
|
||
const otherTrigger = otherDemo.querySelector('.sg-pulldown-demo__trigger');
|
||
otherDemo.dataset.open = 'false';
|
||
if (otherTrigger) {
|
||
otherTrigger.setAttribute('aria-expanded', 'false');
|
||
}
|
||
});
|
||
|
||
document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((wrap) => {
|
||
const button = wrap.querySelector('.sg-sandwich-button');
|
||
wrap.dataset.open = 'false';
|
||
if (button) {
|
||
button.setAttribute('aria-expanded', 'false');
|
||
}
|
||
});
|
||
|
||
demo.dataset.align = 'left';
|
||
demo.dataset.open = String(nextState);
|
||
trigger.setAttribute('aria-expanded', String(nextState));
|
||
|
||
if (!nextState) {
|
||
return;
|
||
}
|
||
|
||
const panel = demo.querySelector('.sg-pulldown-panel');
|
||
if (!panel) {
|
||
return;
|
||
}
|
||
|
||
const triggerRect = trigger.getBoundingClientRect();
|
||
const panelRect = panel.getBoundingClientRect();
|
||
if (panelRect.width > triggerRect.width || panelRect.right > window.innerWidth) {
|
||
demo.dataset.align = 'right';
|
||
}
|
||
|
||
const alignedPanelRect = panel.getBoundingClientRect();
|
||
if (alignedPanelRect.left < 0) {
|
||
demo.dataset.align = 'left';
|
||
}
|
||
});
|
||
});
|
||
|
||
// Filter rows inside the opened pulldown start as inactive preselected rows.
|
||
// They are visually dimmed but remain operable; clicking or changing them activates the row.
|
||
document.querySelectorAll('[data-pulldown-filter-row]').forEach((row) => {
|
||
const select = row.querySelector('.sg-pulldown');
|
||
const removeButton = row.querySelector('.sg-pulldown-panel__remove');
|
||
|
||
const updateFilterRowState = () => {
|
||
const isActive = row.dataset.active === 'true';
|
||
row.classList.toggle('sg-pulldown-panel__row--disabled', !isActive);
|
||
select.classList.toggle('sg-pulldown--selected', isActive);
|
||
select.classList.toggle('sg-pulldown--inactive-selectable', !isActive);
|
||
removeButton.hidden = !isActive;
|
||
};
|
||
|
||
row.addEventListener('click', (event) => {
|
||
if (event.target === removeButton) {
|
||
return;
|
||
}
|
||
|
||
if (row.dataset.active !== 'true') {
|
||
row.dataset.active = 'true';
|
||
updateFilterRowState();
|
||
}
|
||
});
|
||
|
||
select.addEventListener('change', () => {
|
||
row.dataset.active = 'true';
|
||
updateFilterRowState();
|
||
});
|
||
|
||
removeButton.addEventListener('click', () => {
|
||
row.dataset.active = 'false';
|
||
updateFilterRowState();
|
||
});
|
||
|
||
updateFilterRowState();
|
||
});
|
||
|
||
document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((wrap) => {
|
||
const button = wrap.querySelector('.sg-sandwich-button');
|
||
const panel = wrap.querySelector('.sg-sandwich-menu-panel');
|
||
|
||
button.addEventListener('click', (event) => {
|
||
event.stopPropagation();
|
||
const nextState = wrap.dataset.open !== 'true';
|
||
|
||
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');
|
||
}
|
||
});
|
||
|
||
document.querySelectorAll('.sg-pulldown-demo').forEach((demo) => {
|
||
const trigger = demo.querySelector('.sg-pulldown-demo__trigger');
|
||
demo.dataset.open = 'false';
|
||
if (trigger) {
|
||
trigger.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';
|
||
}
|
||
});
|
||
});
|
||
|
||
window.sgInitHelpIconOverlays({
|
||
closeOnOpenSelectors: ['.sg-pulldown-demo', '.sg-sandwich-menu-wrap'],
|
||
outsideClickIgnoreSelectors: ['.sg-pulldown-demo', '.sg-sandwich-menu-wrap'],
|
||
});
|
||
|
||
// Global close behavior for overlay-style controls.
|
||
// A click outside sandwich menus and pulldown demos closes both overlay types.
|
||
document.addEventListener('click', (event) => {
|
||
if (
|
||
event.target.closest('.sg-sandwich-menu-wrap')
|
||
|| event.target.closest('.sg-pulldown-demo')
|
||
) {
|
||
return;
|
||
}
|
||
|
||
document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((wrap) => {
|
||
const button = wrap.querySelector('.sg-sandwich-button');
|
||
wrap.dataset.open = 'false';
|
||
if (button) {
|
||
button.setAttribute('aria-expanded', 'false');
|
||
}
|
||
});
|
||
|
||
document.querySelectorAll('.sg-pulldown-demo').forEach((demo) => {
|
||
const trigger = demo.querySelector('.sg-pulldown-demo__trigger');
|
||
demo.dataset.open = 'false';
|
||
if (trigger) {
|
||
trigger.setAttribute('aria-expanded', 'false');
|
||
}
|
||
});
|
||
|
||
});
|
||
</script>
|
||
|
||
</body>
|
||
</html>
|