Zum Hauptinhalt springen

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"
}

Ü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"
}

Ü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).

Überschreibt die Fußzeile des Konfigurators.

contentView​

Überschreibt den Hauptinhaltsbereich (3D-Viewer, Gallery etc.).

Ü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"
}

Überschreibt nur das Logo-Element innerhalb des Brandings.

Ü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"
}
}
}
};