k3-plugin-api 1.2.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +75 -10
- package/index.ts +131 -1
- package/package.json +6 -5
package/README.md
CHANGED
|
@@ -62,6 +62,69 @@ export default plugin;
|
|
|
62
62
|
|
|
63
63
|
K3 plugins can extend three layers of the configurator.
|
|
64
64
|
|
|
65
|
+
### Runtime Hooks
|
|
66
|
+
|
|
67
|
+
Plugins can access K3 configurator state at runtime using React hooks. These hooks are automatically injected when the plugin is loaded.
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
import { useSettings, useBOM, usePrice } from "k3-plugin-api";
|
|
71
|
+
|
|
72
|
+
const MyComponent = () => {
|
|
73
|
+
// Access plugin-specific settings
|
|
74
|
+
const settings = useSettings("acme.my-plugin");
|
|
75
|
+
|
|
76
|
+
// Access current Bill-of-Materials
|
|
77
|
+
const bom = useBOM();
|
|
78
|
+
|
|
79
|
+
// Access current total price
|
|
80
|
+
const price = usePrice();
|
|
81
|
+
|
|
82
|
+
return (
|
|
83
|
+
<div>
|
|
84
|
+
<p>API Key: {settings.apiKey}</p>
|
|
85
|
+
<p>Total items: {bom.length}</p>
|
|
86
|
+
<p>Price: €{price}</p>
|
|
87
|
+
</div>
|
|
88
|
+
);
|
|
89
|
+
};
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Available hooks:
|
|
93
|
+
- `useSettings(pluginId: string)` — Access settings for a specific plugin
|
|
94
|
+
- `useBOM()` — Get current Bill-of-Materials entries
|
|
95
|
+
- `usePrice()` — Get current total price (MOV-adjusted or overall)
|
|
96
|
+
|
|
97
|
+
### `settings` — Plugin Settings Component
|
|
98
|
+
|
|
99
|
+
Plugins can provide a settings UI component that will be rendered in the K3 admin panel. This allows administrators to configure plugin-specific options that are persisted per plugin instance.
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
import type { K3PluginDescriptor } from "k3-plugin-api";
|
|
103
|
+
|
|
104
|
+
const SettingsComponent = ({ settings, onSave }) => {
|
|
105
|
+
return (
|
|
106
|
+
<div>
|
|
107
|
+
<input
|
|
108
|
+
value={settings.apiKey || ""}
|
|
109
|
+
onChange={(e) => onSave({ ...settings, apiKey: e.target.value })}
|
|
110
|
+
/>
|
|
111
|
+
</div>
|
|
112
|
+
);
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const plugin: K3PluginDescriptor = {
|
|
116
|
+
id: "acme.my-plugin",
|
|
117
|
+
version: "1.0.0",
|
|
118
|
+
settings: SettingsComponent,
|
|
119
|
+
};
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
The `settings` component receives:
|
|
123
|
+
- `settings: unknown` — The current settings object (initially `{}`)
|
|
124
|
+
- `onSave: (settings: unknown) => void` — Callback to persist updated settings
|
|
125
|
+
|
|
126
|
+
Settings are stored per plugin instance and can be accessed at runtime via the plugin's configuration.
|
|
127
|
+
|
|
65
128
|
### `ui` — UI Extensions
|
|
66
129
|
|
|
67
130
|
| Property | Description |
|
|
@@ -124,16 +187,18 @@ const plugin: K3PluginDescriptor = {
|
|
|
124
187
|
|
|
125
188
|
## Key Types
|
|
126
189
|
|
|
127
|
-
| Type | Description
|
|
128
|
-
| --------------------------- |
|
|
129
|
-
| `K3PluginDescriptor` | Root descriptor object exported by a plugin
|
|
130
|
-
| `
|
|
131
|
-
| `
|
|
132
|
-
| `
|
|
133
|
-
| `
|
|
134
|
-
| `
|
|
135
|
-
| `
|
|
136
|
-
| `
|
|
190
|
+
| Type | Description |
|
|
191
|
+
| --------------------------- | --------------------------------------------------------------- |
|
|
192
|
+
| `K3PluginDescriptor` | Root descriptor object exported by a plugin |
|
|
193
|
+
| `K3Hooks` | Runtime hooks interface (useSettings, useBOM, usePrice) |
|
|
194
|
+
| `HOC<P>` | Higher-Order Component: `(Default: FC<P>) => FC<P>` |
|
|
195
|
+
| `VariableVisualisation` | Descriptor for a custom input visualisation |
|
|
196
|
+
| `K3VariableComponentProps` | Props injected into a custom variable renderer |
|
|
197
|
+
| `DynamicModel` | 3D model type definition for the viewer |
|
|
198
|
+
| `K3Configuration` | A persisted configuration with code, price, and selection JSON |
|
|
199
|
+
| `K3ConfigurationSavedEvent` | Event payload dispatched on completed save |
|
|
200
|
+
| `K3BomEntry` | Single Bill-of-Materials entry |
|
|
201
|
+
| `VariableType` | Const enum of all variable types |
|
|
137
202
|
|
|
138
203
|
---
|
|
139
204
|
|
package/index.ts
CHANGED
|
@@ -1,5 +1,62 @@
|
|
|
1
1
|
import type React from "react";
|
|
2
2
|
|
|
3
|
+
// ─── Plugin Runtime Hooks ───────────────────────────────────────────────────
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* K3 runtime hooks available to plugins after initialization.
|
|
7
|
+
* Set via `init()` when the plugin is loaded.
|
|
8
|
+
*/
|
|
9
|
+
export interface K3Hooks {
|
|
10
|
+
/**
|
|
11
|
+
* React hook to access plugin-specific settings.
|
|
12
|
+
* @param pluginId - The unique plugin ID (e.g. "acme.my-plugin")
|
|
13
|
+
* @returns The settings object for this plugin, or `{}` if none are configured
|
|
14
|
+
*/
|
|
15
|
+
useSettings: (pluginId: string) => unknown;
|
|
16
|
+
/**
|
|
17
|
+
* React hook to access the current Bill-of-Materials.
|
|
18
|
+
* @returns Array of BOM entries derived from the current selection
|
|
19
|
+
*/
|
|
20
|
+
useBOM: () => K3BomEntry[];
|
|
21
|
+
/**
|
|
22
|
+
* React hook to access the current total price.
|
|
23
|
+
* @returns The effective total price (MOV-adjusted or overall price)
|
|
24
|
+
*/
|
|
25
|
+
usePrice: () => number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Hook functions injected by K3 at runtime.
|
|
30
|
+
* Use these in your plugin components to access configurator state.
|
|
31
|
+
*/
|
|
32
|
+
export let useSettings: K3Hooks["useSettings"] = () => {
|
|
33
|
+
throw new Error(
|
|
34
|
+
"k3-plugin-api not initialized. Make sure K3 calls init() before using hooks.",
|
|
35
|
+
);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export let useBOM: K3Hooks["useBOM"] = () => {
|
|
39
|
+
throw new Error(
|
|
40
|
+
"k3-plugin-api not initialized. Make sure K3 calls init() before using hooks.",
|
|
41
|
+
);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export let usePrice: K3Hooks["usePrice"] = () => {
|
|
45
|
+
throw new Error(
|
|
46
|
+
"k3-plugin-api not initialized. Make sure K3 calls init() before using hooks.",
|
|
47
|
+
);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Called by K3 when the plugin is loaded to inject runtime hooks.
|
|
52
|
+
* @internal This function is called by K3 automatically - plugins should not call it directly.
|
|
53
|
+
*/
|
|
54
|
+
export function init(hooks: K3Hooks): void {
|
|
55
|
+
useSettings = hooks.useSettings;
|
|
56
|
+
useBOM = hooks.useBOM;
|
|
57
|
+
usePrice = hooks.usePrice;
|
|
58
|
+
}
|
|
59
|
+
|
|
3
60
|
// ─── HOC type (mirrors K3 internal, no K3 imports) ──────────────────────────
|
|
4
61
|
|
|
5
62
|
/** A Higher-Order Component: takes the default component, returns a new one. */
|
|
@@ -43,6 +100,10 @@ export interface K3PluginDescriptor {
|
|
|
43
100
|
viewer?: K3ViewerExtensions;
|
|
44
101
|
/** Logic/callback hooks: config, camera, core. */
|
|
45
102
|
logic?: K3LogicExtensions;
|
|
103
|
+
settings?: React.ComponentType<{
|
|
104
|
+
settings: unknown;
|
|
105
|
+
onSave: (settings: unknown) => void;
|
|
106
|
+
}>;
|
|
46
107
|
|
|
47
108
|
/** @deprecated Use viewer.models instead. */
|
|
48
109
|
dynamicModels?: DynamicModel[];
|
|
@@ -627,6 +688,65 @@ export interface K3LogicExtensions {
|
|
|
627
688
|
};
|
|
628
689
|
}
|
|
629
690
|
|
|
691
|
+
// ─── Model Slot Types ────────────────────────────────────────────────────────
|
|
692
|
+
|
|
693
|
+
/**
|
|
694
|
+
* Declares a named slot where child models can be placed inside a parent dynamic model.
|
|
695
|
+
* Attach an array of these to `DynamicModel.slotDefinitions`.
|
|
696
|
+
*/
|
|
697
|
+
export interface SlotDefinition {
|
|
698
|
+
/** Unique identifier (UUID) — primary key used in rule columns to reference this slot. */
|
|
699
|
+
id: string;
|
|
700
|
+
/** Human-readable name shown in the admin slot picker. */
|
|
701
|
+
name: string;
|
|
702
|
+
/** Optional fallback model ID rendered when no rule assigns a model to this slot. */
|
|
703
|
+
defaultModelId?: string | number;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
/**
|
|
707
|
+
* A resolved model instance placed into a slot at runtime.
|
|
708
|
+
* Received via `DynamicModelComponentProps.slots[slotId]`.
|
|
709
|
+
*/
|
|
710
|
+
export interface SlotModelInstance {
|
|
711
|
+
/** The model data object for this slot instance. */
|
|
712
|
+
model: { id: string | number; [key: string]: unknown };
|
|
713
|
+
/** URL of the model's 3D file, or `undefined` if this is a dynamic model with a component. */
|
|
714
|
+
fileURL: string | undefined;
|
|
715
|
+
/** The React component used to render this model if it is a dynamic model otherwise `undefined`. */
|
|
716
|
+
component: React.ComponentType<any> | undefined;
|
|
717
|
+
/** Evaluated props passed to the model component. */
|
|
718
|
+
props: Record<string, unknown>;
|
|
719
|
+
/** The rule-engine action that placed this model into the scene. */
|
|
720
|
+
modelAction: {
|
|
721
|
+
/** Unique ID of the model action record. */
|
|
722
|
+
id: string;
|
|
723
|
+
/** ID of the model referenced by this action. */
|
|
724
|
+
modelId: string | number;
|
|
725
|
+
/** Props overrides defined on the action. */
|
|
726
|
+
props?: Record<string, unknown>;
|
|
727
|
+
/** ID of the slot this action targets. */
|
|
728
|
+
slotId?: string;
|
|
729
|
+
[key: string]: unknown;
|
|
730
|
+
};
|
|
731
|
+
/** The slot definition this instance was placed into. */
|
|
732
|
+
slotDefinition: SlotDefinition;
|
|
733
|
+
/** Recursively nested slot instances when the slotted model itself has slots. */
|
|
734
|
+
slots?: Record<string, SlotModelInstance[]>;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
/**
|
|
738
|
+
* Props automatically injected into every `DynamicModel.component` at runtime.
|
|
739
|
+
* Extend this with your custom prop types: `DynamicModelComponentProps & { myProp: string }`.
|
|
740
|
+
*/
|
|
741
|
+
export interface DynamicModelComponentProps {
|
|
742
|
+
/**
|
|
743
|
+
* Resolved child model instances keyed by slot ID.
|
|
744
|
+
* Only present when the model has `slotDefinitions` and at least one slot is filled.
|
|
745
|
+
*/
|
|
746
|
+
slots?: Record<string, SlotModelInstance[]>;
|
|
747
|
+
[key: string]: unknown;
|
|
748
|
+
}
|
|
749
|
+
|
|
630
750
|
// ─── Legacy types (unchanged) ────────────────────────────────────────────────
|
|
631
751
|
|
|
632
752
|
export interface DynamicModel {
|
|
@@ -652,8 +772,18 @@ export interface DynamicModel {
|
|
|
652
772
|
/**
|
|
653
773
|
* Default prop values used when a new model action is created.
|
|
654
774
|
* Each key matches a `propsDialog` key; values may be plain data or `{ expression: string }`.
|
|
775
|
+
* Include `slotDefinitions` here to declare named slots for child models.
|
|
655
776
|
*/
|
|
656
|
-
defaultProps:
|
|
777
|
+
defaultProps: {
|
|
778
|
+
slotDefinitions?: SlotDefinition[];
|
|
779
|
+
[key: string]:
|
|
780
|
+
| string
|
|
781
|
+
| number
|
|
782
|
+
| boolean
|
|
783
|
+
| ModelPropDefault
|
|
784
|
+
| undefined
|
|
785
|
+
| SlotDefinition[];
|
|
786
|
+
};
|
|
657
787
|
/** Optional tag used to group or filter models in the admin UI. */
|
|
658
788
|
tag?: string;
|
|
659
789
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "k3-plugin-api",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Official TypeScript types and plugin API for the K3 product configurator",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.ts",
|
|
@@ -25,14 +25,15 @@
|
|
|
25
25
|
],
|
|
26
26
|
"author": "ObjectCode GmbH <info@objectcode.de> (https://k3-konfigurator.de/)",
|
|
27
27
|
"license": "MIT",
|
|
28
|
+
"scripts": {
|
|
29
|
+
"prepublishOnly": "tsc --emitDeclarationOnly",
|
|
30
|
+
"yalc": "pnpm prepublishOnly && yalc publish"
|
|
31
|
+
},
|
|
28
32
|
"peerDependencies": {
|
|
29
33
|
"react": ">=19"
|
|
30
34
|
},
|
|
31
35
|
"devDependencies": {
|
|
32
36
|
"typescript": "^5.8.3",
|
|
33
37
|
"@types/react": "^19.0.0"
|
|
34
|
-
},
|
|
35
|
-
"scripts": {
|
|
36
|
-
"yalc": "pnpm prepublishOnly && yalc publish"
|
|
37
38
|
}
|
|
38
|
-
}
|
|
39
|
+
}
|