Layout-Komponenten
Layout-Komponenten ermöglichen es, das visuelle Erscheinungsbild und die Struktur des K3-Konfigurators anzupassen. Über Higher-Order Components (HOCs) können Sie bestehende Komponenten erweitern oder komplett ersetzen.
Higher-Order Components (HOCs)
Ein HOC ist eine Funktion, die eine React-Komponente nimmt und eine neue, erweiterte Komponente zurückgibt:
import type { HOC } from "k3-plugin-api";
const myHOC: HOC = (OriginalComponent) => {
return (props) => {
// Eigene Logik vor dem Rendering
console.log("Rendering component with props:", props);
// Original-Komponente mit modifizierten oder zusätzlichen Props rendern
return (
<div className="my-wrapper">
<OriginalComponent {...props} customProp="value" />
</div>
);
};
};
Grundstruktur
Layout-Erweiterungen werden im ui.layout Objekt registriert:
// In Plugin.tsx
export default {
// ...
ui: {
layout: {
header: {
hoc: myHeaderHOC,
description: "Erweitert die Kopfzeile mit einem Custom Badge"
},
sidebar: {
hoc: mySidebarHOC,
description: "Fügt zusätzliche Navigation hinzu"
}
}
}
}
Jeder Layout-Slot benötigt:
- hoc: Die HOC-Funktion
- description: Beschreibung des Extension Points (String oder LocalizedString)
Verfügbare Layout-Slots
root
Überschreibt die oberste Wrapper-Komponente der gesamten Applikation. Umhüllt alles — Header, Sidebar, Content und Footer.
Anwendungsbeispiele:
- Globale Theme-Provider
- Fehler-Boundaries
- App-weite Kontexte
root: {
hoc: (Original) => (props) => (
<MyThemeProvider>
<Original {...props} />
</MyThemeProvider>
),
description: "Fügt einen globalen Theme-Provider hinzu"
}
header
Überschreibt die Kopfzeile des Konfigurators (Header Bar).
Enthält typischerweise:
- Logo/Branding
- Navigationsbuttons
- Szenenbuttons
- Preisanzeige
header: {
hoc: (Original) => (props) => (
<>
<div className="custom-banner">Sonderaktion!</div>
<Original {...props} />
</>
),
description: "Fügt einen Banner über dem Header hinzu"
}
sidebar
Überschreibt die gesamte Seitenleiste (Sidebar), die die Gruppen und Variablen enthält.
sidebar: {
hoc: (Original) => (props) => (
<div className="custom-sidebar-wrapper">
<Original {...props} />
<div className="sidebar-footer">Zusätzliche Infos</div>
</div>
),
description: "Erweitert die Sidebar mit Footer"
}
sidebarHeader
Überschreibt den Kopfbereich der Seitenleiste (oberhalb der Gruppenliste).
sidebarFooter
Überschreibt den Fußbereich der Seitenleiste (unterhalb der Gruppenliste).
footer
Überschreibt die Fußzeile des Konfigurators.
contentView
Überschreibt den Hauptinhaltsbereich (3D-Viewer, Gallery etc.).
gallery
Überschreibt die Galerieansicht für Bildkonfiguratoren.
branding
Überschreibt die Branding-Komponente (Logo + Markenname).
branding: {
hoc: (Original) => (props) => (
<div style={{ display: "flex", alignItems: "center", gap: "10px" }}>
<Original {...props} />
<span className="beta-badge">BETA</span>
</div>
),
description: "Fügt ein Beta-Badge neben dem Logo hinzu"
}
logo
Überschreibt nur das Logo-Element innerhalb des Brandings.
navigationButtons
Überschreibt die Navigationsschaltflächen (Zurück/Weiter zwischen Gruppen).
exitButtons
Überschreibt die Beenden-Schaltflächen.
sceneButtons
Überschreibt die Szenen-Schaltflächen (AR, Screenshot, Fullscreen etc.).
price
Überschreibt die Preisanzeige.
price: {
hoc: (Original) => (props) => (
<div className="custom-price-wrapper">
<span className="price-label">Ihr Preis:</span>
<Original {...props} />
<span className="price-vat">inkl. MwSt.</span>
</div>
),
description: "Erweitert Preisanzeige mit Label und MwSt-Hinweis"
}
labelActionDisplay
Überschreibt die Label/Hotspot-Anzeige auf dem Desktop 3D-Canvas.
mobileLabelActionDisplay
Überschreibt die Label/Hotspot-Anzeige auf mobilen Geräten.
invalidRuleModal
Überschreibt das Modal, das bei ungültigen Regelkonstellationen angezeigt wird.
mountedWhenLoaded
Eine Komponente, die erst nach vollständigem Laden des Konfigurators eingehängt wird.
Anwendungsbeispiele:
- Analytics-Tracking
- Custom Loading-Completion-Handler
mountedWhenLoaded: {
hoc: (Original) => (props) => {
useEffect(() => {
console.log("Configurator fully loaded!");
// Analytics Event senden
}, []);
return <Original {...props} />;
},
description: "Führt Code nach vollständigem Laden aus"
}
configurator
Überschreibt die Konfigurator-Hauptkomponente (Gruppennavigation + Variablenbereich).
groupLabel
Überschreibt die Gruppenbezeichnung in der Sidebar-Navigation.
groupLabel: {
hoc: (Original) => (props) => (
<div className="custom-group-label">
<span className="group-icon">📁</span>
<Original {...props} />
</div>
),
description: "Fügt Icons vor Gruppennamen hinzu"
}
groupPanel
Überschreibt das ausklappbare Gruppenfeld, das die Variablen enthält.
additionalGroups
Ermöglicht das Hinzufügen zusätzlicher Gruppen am Ende der Gruppenliste.
additionalGroups: {
hoc: (Original) => (props) => (
<>
<Original {...props} />
<div className="custom-group">
<h3>Zusätzliche Optionen</h3>
{/* Custom Content */}
</div>
</>
),
description: "Fügt eine zusätzliche Gruppe hinzu"
}
additionalVars
Ermöglicht das Hinzufügen zusätzlicher Variablen am Ende der Variablenliste einer Gruppe.
variableLabel
Überschreibt die Bezeichnung jeder einzelnen Variable in der Sidebar.
Anwendungsbeispiele:
- Eigene Tooltip-Icons
- Pflichtfeld-Markierungen (*)
- Barrierefreiheits-Ergänzungen
variableLabel: {
hoc: (Original) => (props) => (
<div style={{ display: "flex", alignItems: "center" }}>
<Original {...props} />
{props.required && <span className="required">*</span>}
</div>
),
description: "Fügt Pflichtfeld-Markierung hinzu"
}
Lokalisierte Beschreibungen
Beschreibungen können mehrsprachig sein:
import type { LocalizedString } from "k3-plugin-api";
header: {
hoc: myHeaderHOC,
description: {
de: "Überschreibt die Kopfzeile",
en: "Overrides the header bar",
fr: "Remplace la barre d'en-tête",
nl: "Overschrijft de headerbalk"
} as LocalizedString
}
Best Practices
1. Original-Komponente immer rendern
Wenn Sie nicht die komplette Komponente ersetzen wollen, rendern Sie immer die Original-Komponente:
hoc: (Original) => (props) => (
<>
{/* Ihr Custom Content */}
<Original {...props} />
</>
)
2. Props nicht mutieren
Erstellen Sie bei Bedarf neue Props-Objekte statt die bestehenden zu ändern:
hoc: (Original) => (props) => {
const enhancedProps = { ...props, customValue: "added" };
return <Original {...enhancedProps} />;
}
3. Performance beachten
HOCs werden bei jedem Render aufgerufen. Vermeiden Sie teure Berechnungen:
hoc: (Original) => {
// ❌ Schlecht: Berechnung bei jedem Render
return (props) => {
const expensiveValue = computeExpensive();
return <Original {...props} extra={expensiveValue} />;
};
// ✅ Gut: Memoization verwenden
return (props) => {
const expensiveValue = useMemo(() => computeExpensive(), []);
return <Original {...props} extra={expensiveValue} />;
};
}
4. TypeScript-Typen nutzen
Nutzen Sie die bereitgestellten TypeScript-Typen für bessere IDE-Unterstützung:
import type { HOC, K3LayoutExtensions } from "k3-plugin-api";
const myHOC: HOC = (Original) => (props) => <Original {...props} />;
const layoutExtensions: K3LayoutExtensions = {
header: {
hoc: myHOC,
description: "My header extension"
}
};
Vollständiges Beispiel
import type { HOC } from "k3-plugin-api";
// Root Theme Wrapper
const rootHOC: HOC = (Original) => (props) => (
<div className="custom-theme">
<Original {...props} />
</div>
);
// Logo mit Badge
const logoHOC: HOC = (Original) => (props) => (
<div style={{ position: "relative" }}>
<Original {...props} />
<span className="badge">NEU</span>
</div>
);
// Erweiterte Preisanzeige
const priceHOC: HOC = (Original) => (props) => (
<div className="enhanced-price">
<div className="price-main">
<Original {...props} />
</div>
<div className="price-disclaimer">
* Alle Preise inkl. MwSt.
</div>
</div>
);
// Im Plugin registrieren:
export default {
// ...
ui: {
layout: {
root: {
hoc: rootHOC,
description: "Fügt Custom Theme Wrapper hinzu"
},
logo: {
hoc: logoHOC,
description: {
de: "Fügt Badge neben dem Logo hinzu",
en: "Adds badge next to logo"
}
},
price: {
hoc: priceHOC,
description: "Erweiterte Preisanzeige mit Disclaimer"
}
}
}
};