Zum Hauptinhalt springen

An welchen Stellen kann der K3 erweitert werden?

Die K3Main Komponente

Die K3Main Komponente kann bis zu drei Properties übergeben bekommen:

extensions

Mit diesem Objekt können durch uns definierte React-Komponenten überschrieben werden. Die vollständige Liste der Erweiterungsmöglichkeiten kann dem Typ K3Extensions entnommen werden. Alle Elemente folgen dem gleichen Schema:

(Wrapped) => (props) => {
// Your Component implementation here
}

Wrapped ist die originale Komponente, falls man diese wiederverwenden möchte. props sind die übergebenen Properties (typisiert). Die eigene Implementierung kann entweder komplett eigenständig sein oder sich auf Wrapped und/oder props stützen. Beispiele für mögliche Komponentenerweiterungen finden sich im Beispielprojekt.

Die verschiedenen Extension-Points sind im Typ K3Extensions dokumentiert.

contexts

Benutzt man eigene React-Contexts bzw. Kontexte von einem State Management System wie Redux, sollten diese hier als Array hereingegeben werden. Das ermöglicht es auf diese auch innerhalb von Erweiterungen, insbesondere in der 3D-Szene, zuzugreifen.

additionalDynamicSettings

Der K3 erlaubt die Definition von Einstellungen (wie Texte, Zahlen, Vektoren, Bilder etc.) für eine Erweiterung. Damit kann die Erweiterung selbst parametrisiert und durch den Admin eingestellt werde!

Genauere Informationen und Beispiele sind hier zu finden.

Callbacks

Callbacks sind eine Möglichkeit JS Funktionen als Event-Listener und/oder -Modifier zu registrieren. Das passiert mithilfe der addCallbacks Funktion an jeder beliebigen Stelle im Code. (Aus Performance Gründen nach Möglichkeit nicht bei jedem rerender).

Die komplette Liste der Callbacks kann dem Typ K3Callbacks entnommen werden. Callbacks sind additiv, das bedeutet:

addCallbacks({
setPrice: (originalPrice) => originalPrice * 1.19,
saveConfiguration: (cfg) => {
console.log('Saving configuration', cfg);
return {
...cfg,
label: 'Diese Konfiguration wurde von einem Callback umbenannt',
};
},
});

ist äquivalent zu

addCallbacks({
saveConfiguration: (cfg) => {
console.log('Saving configuration', cfg);
return {
...cfg,
label: 'Diese Konfiguration wurde von einem Callback umbenannt',
};
}
});

// Some other code
addCallbacks({
setPrice: (originalPrice) => originalPrice * 1.19
});

Beispiel

tip

Du musst das Beispiel natürlich noch nicht im Detail verstehen, alles wird später noch genauer erklärt.

Wichtig ist es ein Gefühl dafür zu bekommen, weshalb es verschiedene Arten gibt den K3 zu erweitern und wie diese zusammenspielen.

Hier findet ihr ein kleines Beispiel, was alle Konzepte, die hier vorgestellt wurden vereint.

Es erweitert Radio Buttons, sodass:

  • Alle Änderungen in einem radioChangelog mitgeschrieben werden (Extension-Point),
  • Dieser changelog in einem Context gespeichert wird (contexts)
  • Dieser changelog bei der Bestellung mit abgespeichert wird (callback)
  • Ein zusätzlicher Text pro Konfigurator pflegbar ist, der über dem Radio Button steht (Extension-Point und additionalDynamicSetting)
  • Bei bestimmten keys ein weiterer Text angezeigt wird (Extension-Point und keys)
import type { K3Extensions, Value, WithChildren } from "@k3/core";
import {
addCallbacks,
DynamicSettingValueType,
EditDynamicSettings,
K3Main,
useDynamicTranslation,
} from "@k3/core";
import { Box, Typography } from "@mui/material";
import {
createContext,
useCallback,
useContext,
useEffect,
useState,
} from "react";

type ExtensionsContextType = {
radioChangelog: Value["id"][];
addToRadioChangelog: (nextValueId: Value["id"]) => void;
};

const ExtensionContext = createContext<ExtensionsContextType>({
radioChangelog: [],
addToRadioChangelog: () =>
console.warn("Cant add to changelog, probably missing the provider?"),
});

const ExtensionContextProvider = (props: WithChildren) => {
const [radioChangelog, setRadioChangelog] = useState<Value["id"][]>([]);
const addToRadioChangelog = useCallback(
(nextValueId: Value["id"]) => {
const newChangelog = [...radioChangelog, nextValueId];
setRadioChangelog(newChangelog);
},
[radioChangelog]
);

useEffect(() => {
addCallbacks({
saveConfiguration: (cfg) => {
return {
...cfg,
json: {
...cfg.json,
radioChangelog,
},
};
},
});
}, [radioChangelog]);

return (
<ExtensionContext.Provider value={{ radioChangelog, addToRadioChangelog }}>
{props.children}
</ExtensionContext.Provider>
);
};

const radioTitle = "radioTitle";

const extensions: K3Extensions = {
components: {
radio: (Wrapped) => (props) => {
const ctx = useContext(ExtensionContext);
const translate = useDynamicTranslation();
return (
<Box component="div">
{/* This only appears in the admin panel, it is automatically hidden for users.
It allows us to change the text by configurator. */}
<EditDynamicSettings keys={[radioTitle]} />
<Typography>{translate(radioTitle)}</Typography>
<Wrapped
{...props}
onChange={(newValue) => {
ctx.addToRadioChangelog(newValue as Value["id"]);
props.onChange(newValue);
}}
/>
{props.variable.key === "tischform" && (
<Typography>
Vielen Dank, dass Sie sich für{" "}
{typeof props.value === "object"
? props.value.label
: props.value}{" "}
entschieden haben.
</Typography>
)}
</Box>
);
},
},
};

export function App() {
return (
<ExtensionContextProvider>
<K3Main
extensions={extensions}
contexts={[ExtensionContext]}
additionalDynamicSettings={[
{
key: radioTitle,
defaultValue: "Ihre Auswahl",
valueType: DynamicSettingValueType.TRANSLATION,
label: "Zusätzlicher Radio-Text",
},
]}
/>
</ExtensionContextProvider>
);
}