@process.co/ui 0.0.22 → 0.0.23
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/css/ui.css +48 -0
- package/dist/components/dev/index.cjs +213 -7
- package/dist/components/dev/index.cjs.map +1 -1
- package/dist/components/dev/index.d.cts +64 -3
- package/dist/components/dev/index.d.ts +64 -3
- package/dist/components/dev/index.js +214 -9
- package/dist/components/dev/index.js.map +1 -1
- package/dist/components/fields/index.cjs.map +1 -1
- package/dist/components/fields/index.js.map +1 -1
- package/dist/components/slots/index.cjs +73 -59
- package/dist/components/slots/index.cjs.map +1 -1
- package/dist/components/slots/index.d.cts +1 -1
- package/dist/components/slots/index.d.ts +1 -1
- package/dist/components/slots/index.js +73 -60
- package/dist/components/slots/index.js.map +1 -1
- package/dist/{index-NpNmoYuX.d.cts → index-D4Fc9AJv.d.cts} +15 -2
- package/dist/{index-NpNmoYuX.d.ts → index-D4Fc9AJv.d.ts} +15 -2
- package/dist/index.cjs +14 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +15 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
import React__default, { PropsWithChildren } from 'react';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Optional config for slot/case awareness in dev.
|
|
5
|
+
* Each control type can have unique data shape; getSlots interprets the field value and returns slot options.
|
|
6
|
+
*/
|
|
7
|
+
interface DevSlotConfig {
|
|
8
|
+
/** Property key (field) whose value holds the slot data (e.g. 'switchValue' or 'cases'). When set, getSlots and activeIdPath are applied to data[field]. */
|
|
9
|
+
field?: string;
|
|
10
|
+
/** Path (relative to the field value when field is set) where we store the active slot id in dev. This is mocked in dev only; we do not use the element definition's slots.activeSlotId (e.g. $.results.pathId). */
|
|
11
|
+
activeIdPath: string;
|
|
12
|
+
/**
|
|
13
|
+
* Given the field value (or full data when field is unset), return the list of slots for the Active path/case selector.
|
|
14
|
+
* Enables any control-specific shape (e.g. value.cases.cases, value.branches, etc.).
|
|
15
|
+
*/
|
|
16
|
+
getSlots: (fieldValueOrData: Record<string, any>) => {
|
|
17
|
+
id: string;
|
|
18
|
+
label: string;
|
|
19
|
+
}[];
|
|
20
|
+
}
|
|
21
|
+
/** Preset for slot/case awareness (legacy); prefer deriving from elementDefinition.slots. */
|
|
22
|
+
type SlotPreset = 'switch' | 'cases' | 'branches';
|
|
23
|
+
/**
|
|
24
|
+
* Action/signal definition shape (defineAction): optional slots, initValue, props.
|
|
25
|
+
* Used to derive slotConfig and optionally initialData.
|
|
26
|
+
*/
|
|
27
|
+
interface ElementDefinition {
|
|
28
|
+
slots?: {
|
|
29
|
+
slots?: any[];
|
|
30
|
+
activeSlotId?: string;
|
|
31
|
+
[k: string]: any;
|
|
32
|
+
};
|
|
33
|
+
initValue?: Record<string, any>;
|
|
34
|
+
props?: Record<string, any>;
|
|
35
|
+
[k: string]: any;
|
|
36
|
+
}
|
|
3
37
|
/**
|
|
4
38
|
* Configuration for the DevProvider
|
|
5
39
|
*/
|
|
@@ -12,6 +46,17 @@ interface DevProviderConfig {
|
|
|
12
46
|
persist?: boolean;
|
|
13
47
|
/** Mock node ID (default: 'dev-node-1') */
|
|
14
48
|
nodeId?: string;
|
|
49
|
+
/** Key in dev data that holds the control value (e.g. devField). In the definition, the control is the prop with the UI (e.g. cases with ui.switch); in dev that value lives at data[propertyKey], so devField = $.data.cases. Default: 'devField' */
|
|
50
|
+
propertyKey?: string;
|
|
51
|
+
/** When set, provider builds slotConfig internally; loader does not need to pass slotConfig. */
|
|
52
|
+
slotPreset?: SlotPreset;
|
|
53
|
+
/** Optional. Full slot config; overrides slotPreset and elementDefinition when provided. */
|
|
54
|
+
slotConfig?: DevSlotConfig;
|
|
55
|
+
/**
|
|
56
|
+
* Action or signal definition (defineAction result). Provider derives slotConfig from slots + initValue
|
|
57
|
+
* and uses initValue as initialData when initialData is not provided.
|
|
58
|
+
*/
|
|
59
|
+
elementDefinition?: ElementDefinition | null;
|
|
15
60
|
}
|
|
16
61
|
/**
|
|
17
62
|
* Context value for development/testing
|
|
@@ -28,6 +73,14 @@ interface DevContextValue {
|
|
|
28
73
|
/** Remove all inferred types */
|
|
29
74
|
clearAllInferredTypes: () => void;
|
|
30
75
|
nodeId: string;
|
|
76
|
+
/** Current active slot/case id (for elements with slots, e.g. Switch). Null when none selected. Provider state only; not stored in data. */
|
|
77
|
+
activeSlotId: string | null;
|
|
78
|
+
/** Set the active slot/case id. Stored in provider state only; not written to data. */
|
|
79
|
+
setActiveSlotId: (id: string | null) => void;
|
|
80
|
+
/** Slot config when provided to DevProvider (so toolbar can call getSlots(data)). */
|
|
81
|
+
slotConfig: DevSlotConfig | undefined;
|
|
82
|
+
/** Action/signal definition passed to DevProvider (for debugging). */
|
|
83
|
+
elementDefinition: ElementDefinition | null | undefined;
|
|
31
84
|
clearAll: () => void;
|
|
32
85
|
exportData: () => string;
|
|
33
86
|
importData: (json: string) => void;
|
|
@@ -74,15 +127,23 @@ declare function useInferredTypes(): {
|
|
|
74
127
|
* }
|
|
75
128
|
* ```
|
|
76
129
|
*/
|
|
77
|
-
declare function DevProvider({ children, storageKey, initialData, persist, nodeId, }: PropsWithChildren<DevProviderConfig>): React__default.JSX.Element;
|
|
130
|
+
declare function DevProvider({ children, storageKey, initialData, persist, nodeId, propertyKey, slotPreset, slotConfig: slotConfigProp, elementDefinition, }: PropsWithChildren<DevProviderConfig>): React__default.JSX.Element;
|
|
78
131
|
|
|
132
|
+
/**
|
|
133
|
+
* Helper: get slots from data when the shape is { cases: { cases: [...] } } or similar.
|
|
134
|
+
* Use this inside slotConfig.getSlots for Switch-style data, or implement your own for other shapes.
|
|
135
|
+
*/
|
|
136
|
+
declare function getSlotsFromCasesData(data: Record<string, any>): {
|
|
137
|
+
id: string;
|
|
138
|
+
label: string;
|
|
139
|
+
}[];
|
|
79
140
|
/**
|
|
80
141
|
* DevToolbar - Optional toolbar for development
|
|
81
142
|
* Shows current data state and provides controls for import/export/clear
|
|
82
|
-
* Also allows spoofing inferred types
|
|
143
|
+
* Also allows spoofing inferred types and selecting active path/case when slotConfig.getSlots is provided
|
|
83
144
|
*/
|
|
84
145
|
declare function DevToolbar({ className }: {
|
|
85
146
|
className?: string;
|
|
86
147
|
}): React__default.JSX.Element;
|
|
87
148
|
|
|
88
|
-
export { DevContext, type DevContextValue, DevProvider, type DevProviderConfig, DevToolbar, useDevContext, useInferredTypes, useNodeProperty };
|
|
149
|
+
export { DevContext, type DevContextValue, DevProvider, type DevProviderConfig, type DevSlotConfig, DevToolbar, type ElementDefinition, type SlotPreset, getSlotsFromCasesData, useDevContext, useInferredTypes, useNodeProperty };
|
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
import React__default, { PropsWithChildren } from 'react';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Optional config for slot/case awareness in dev.
|
|
5
|
+
* Each control type can have unique data shape; getSlots interprets the field value and returns slot options.
|
|
6
|
+
*/
|
|
7
|
+
interface DevSlotConfig {
|
|
8
|
+
/** Property key (field) whose value holds the slot data (e.g. 'switchValue' or 'cases'). When set, getSlots and activeIdPath are applied to data[field]. */
|
|
9
|
+
field?: string;
|
|
10
|
+
/** Path (relative to the field value when field is set) where we store the active slot id in dev. This is mocked in dev only; we do not use the element definition's slots.activeSlotId (e.g. $.results.pathId). */
|
|
11
|
+
activeIdPath: string;
|
|
12
|
+
/**
|
|
13
|
+
* Given the field value (or full data when field is unset), return the list of slots for the Active path/case selector.
|
|
14
|
+
* Enables any control-specific shape (e.g. value.cases.cases, value.branches, etc.).
|
|
15
|
+
*/
|
|
16
|
+
getSlots: (fieldValueOrData: Record<string, any>) => {
|
|
17
|
+
id: string;
|
|
18
|
+
label: string;
|
|
19
|
+
}[];
|
|
20
|
+
}
|
|
21
|
+
/** Preset for slot/case awareness (legacy); prefer deriving from elementDefinition.slots. */
|
|
22
|
+
type SlotPreset = 'switch' | 'cases' | 'branches';
|
|
23
|
+
/**
|
|
24
|
+
* Action/signal definition shape (defineAction): optional slots, initValue, props.
|
|
25
|
+
* Used to derive slotConfig and optionally initialData.
|
|
26
|
+
*/
|
|
27
|
+
interface ElementDefinition {
|
|
28
|
+
slots?: {
|
|
29
|
+
slots?: any[];
|
|
30
|
+
activeSlotId?: string;
|
|
31
|
+
[k: string]: any;
|
|
32
|
+
};
|
|
33
|
+
initValue?: Record<string, any>;
|
|
34
|
+
props?: Record<string, any>;
|
|
35
|
+
[k: string]: any;
|
|
36
|
+
}
|
|
3
37
|
/**
|
|
4
38
|
* Configuration for the DevProvider
|
|
5
39
|
*/
|
|
@@ -12,6 +46,17 @@ interface DevProviderConfig {
|
|
|
12
46
|
persist?: boolean;
|
|
13
47
|
/** Mock node ID (default: 'dev-node-1') */
|
|
14
48
|
nodeId?: string;
|
|
49
|
+
/** Key in dev data that holds the control value (e.g. devField). In the definition, the control is the prop with the UI (e.g. cases with ui.switch); in dev that value lives at data[propertyKey], so devField = $.data.cases. Default: 'devField' */
|
|
50
|
+
propertyKey?: string;
|
|
51
|
+
/** When set, provider builds slotConfig internally; loader does not need to pass slotConfig. */
|
|
52
|
+
slotPreset?: SlotPreset;
|
|
53
|
+
/** Optional. Full slot config; overrides slotPreset and elementDefinition when provided. */
|
|
54
|
+
slotConfig?: DevSlotConfig;
|
|
55
|
+
/**
|
|
56
|
+
* Action or signal definition (defineAction result). Provider derives slotConfig from slots + initValue
|
|
57
|
+
* and uses initValue as initialData when initialData is not provided.
|
|
58
|
+
*/
|
|
59
|
+
elementDefinition?: ElementDefinition | null;
|
|
15
60
|
}
|
|
16
61
|
/**
|
|
17
62
|
* Context value for development/testing
|
|
@@ -28,6 +73,14 @@ interface DevContextValue {
|
|
|
28
73
|
/** Remove all inferred types */
|
|
29
74
|
clearAllInferredTypes: () => void;
|
|
30
75
|
nodeId: string;
|
|
76
|
+
/** Current active slot/case id (for elements with slots, e.g. Switch). Null when none selected. Provider state only; not stored in data. */
|
|
77
|
+
activeSlotId: string | null;
|
|
78
|
+
/** Set the active slot/case id. Stored in provider state only; not written to data. */
|
|
79
|
+
setActiveSlotId: (id: string | null) => void;
|
|
80
|
+
/** Slot config when provided to DevProvider (so toolbar can call getSlots(data)). */
|
|
81
|
+
slotConfig: DevSlotConfig | undefined;
|
|
82
|
+
/** Action/signal definition passed to DevProvider (for debugging). */
|
|
83
|
+
elementDefinition: ElementDefinition | null | undefined;
|
|
31
84
|
clearAll: () => void;
|
|
32
85
|
exportData: () => string;
|
|
33
86
|
importData: (json: string) => void;
|
|
@@ -74,15 +127,23 @@ declare function useInferredTypes(): {
|
|
|
74
127
|
* }
|
|
75
128
|
* ```
|
|
76
129
|
*/
|
|
77
|
-
declare function DevProvider({ children, storageKey, initialData, persist, nodeId, }: PropsWithChildren<DevProviderConfig>): React__default.JSX.Element;
|
|
130
|
+
declare function DevProvider({ children, storageKey, initialData, persist, nodeId, propertyKey, slotPreset, slotConfig: slotConfigProp, elementDefinition, }: PropsWithChildren<DevProviderConfig>): React__default.JSX.Element;
|
|
78
131
|
|
|
132
|
+
/**
|
|
133
|
+
* Helper: get slots from data when the shape is { cases: { cases: [...] } } or similar.
|
|
134
|
+
* Use this inside slotConfig.getSlots for Switch-style data, or implement your own for other shapes.
|
|
135
|
+
*/
|
|
136
|
+
declare function getSlotsFromCasesData(data: Record<string, any>): {
|
|
137
|
+
id: string;
|
|
138
|
+
label: string;
|
|
139
|
+
}[];
|
|
79
140
|
/**
|
|
80
141
|
* DevToolbar - Optional toolbar for development
|
|
81
142
|
* Shows current data state and provides controls for import/export/clear
|
|
82
|
-
* Also allows spoofing inferred types
|
|
143
|
+
* Also allows spoofing inferred types and selecting active path/case when slotConfig.getSlots is provided
|
|
83
144
|
*/
|
|
84
145
|
declare function DevToolbar({ className }: {
|
|
85
146
|
className?: string;
|
|
86
147
|
}): React__default.JSX.Element;
|
|
87
148
|
|
|
88
|
-
export { DevContext, type DevContextValue, DevProvider, type DevProviderConfig, DevToolbar, useDevContext, useInferredTypes, useNodeProperty };
|
|
149
|
+
export { DevContext, type DevContextValue, DevProvider, type DevProviderConfig, type DevSlotConfig, DevToolbar, type ElementDefinition, type SlotPreset, getSlotsFromCasesData, useDevContext, useInferredTypes, useNodeProperty };
|
|
@@ -1,6 +1,148 @@
|
|
|
1
|
-
import React2, { createContext, useContext, useCallback, useState,
|
|
1
|
+
import React2, { createContext, useContext, useCallback, useState, useMemo, useEffect } from 'react';
|
|
2
2
|
|
|
3
3
|
// src/components/dev/DevProvider.tsx
|
|
4
|
+
function evaluateSimplePath(obj, path) {
|
|
5
|
+
if (!path || !obj) return void 0;
|
|
6
|
+
const cleanPath = path.startsWith("$.") ? path.slice(2) : path.startsWith("$") ? path.slice(1) : path;
|
|
7
|
+
const parts = cleanPath.split(".");
|
|
8
|
+
let current = obj.data ?? obj;
|
|
9
|
+
for (const part of parts) {
|
|
10
|
+
if (current == null) return void 0;
|
|
11
|
+
const cleanPart = part.replace(/\[\*\]$/, "");
|
|
12
|
+
if (cleanPart) current = current[cleanPart];
|
|
13
|
+
}
|
|
14
|
+
return current;
|
|
15
|
+
}
|
|
16
|
+
function evaluateCollectionPath(obj, path) {
|
|
17
|
+
if (!path || !obj) return [];
|
|
18
|
+
let cleanPath = path.startsWith("$.") ? path.slice(2) : path.startsWith("$") ? path.slice(1) : path;
|
|
19
|
+
cleanPath = cleanPath.replace(/\[\*\]$/, "");
|
|
20
|
+
const parts = cleanPath.split(".");
|
|
21
|
+
let current = obj.data ?? obj;
|
|
22
|
+
for (const part of parts) {
|
|
23
|
+
if (current == null) return [];
|
|
24
|
+
if (part) current = current[part];
|
|
25
|
+
}
|
|
26
|
+
if (Array.isArray(current)) return current;
|
|
27
|
+
if (parts.length >= 2) {
|
|
28
|
+
const parentPath = parts.slice(0, -1).join(".");
|
|
29
|
+
let parent = obj;
|
|
30
|
+
for (const part of parentPath.split(".")) {
|
|
31
|
+
if (parent == null) return [];
|
|
32
|
+
if (part) parent = parent[part];
|
|
33
|
+
}
|
|
34
|
+
if (Array.isArray(parent)) return parent;
|
|
35
|
+
}
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
function evaluateItemPath(item, fullPath, _index) {
|
|
39
|
+
if (!fullPath || item == null) return void 0;
|
|
40
|
+
const wildcardIndex = fullPath.indexOf("[*]");
|
|
41
|
+
if (wildcardIndex === -1) return evaluateSimplePath(item, fullPath);
|
|
42
|
+
const afterWildcard = fullPath.slice(wildcardIndex + 3);
|
|
43
|
+
if (!afterWildcard || afterWildcard === "") return item;
|
|
44
|
+
const propertyPath = afterWildcard.startsWith(".") ? afterWildcard.slice(1) : afterWildcard;
|
|
45
|
+
const parts = propertyPath.split(".");
|
|
46
|
+
let current = item;
|
|
47
|
+
for (const part of parts) {
|
|
48
|
+
if (current == null) return void 0;
|
|
49
|
+
current = current[part];
|
|
50
|
+
}
|
|
51
|
+
return current;
|
|
52
|
+
}
|
|
53
|
+
function deriveFieldFromSlotsDefinition(slotsConfig) {
|
|
54
|
+
for (const slot of slotsConfig) {
|
|
55
|
+
const path = slot.path ?? slot.idPath ?? slot.labelPath;
|
|
56
|
+
if (typeof path !== "string") continue;
|
|
57
|
+
const afterData = path.replace(/^\$\.data\./, "").replace(/^\$\./, "");
|
|
58
|
+
const firstSegment = afterData.split(".")[0];
|
|
59
|
+
if (firstSegment) return firstSegment;
|
|
60
|
+
}
|
|
61
|
+
return void 0;
|
|
62
|
+
}
|
|
63
|
+
function deriveControlPropertyKey(def, slotsField) {
|
|
64
|
+
const props = def?.props;
|
|
65
|
+
if (!props) return slotsField;
|
|
66
|
+
const arr = Array.isArray(props) ? props : Object.keys(props).map((k) => ({ key: k, ...props[k] }));
|
|
67
|
+
const withUi = arr.find((p) => p?.ui != null);
|
|
68
|
+
const matchKey = slotsField ? arr.find((p) => p?.key === slotsField) : withUi;
|
|
69
|
+
return matchKey?.key ?? withUi?.key ?? slotsField;
|
|
70
|
+
}
|
|
71
|
+
function isDynamicSlot(slot) {
|
|
72
|
+
if (slot.type === "dynamic") return true;
|
|
73
|
+
const path = slot.path ?? slot.idPath ?? slot.labelPath ?? "";
|
|
74
|
+
return typeof path === "string" && path.includes("[*]");
|
|
75
|
+
}
|
|
76
|
+
function getSlotDefinitions(slotsConfig) {
|
|
77
|
+
return slotsConfig.map((slot) => ({
|
|
78
|
+
...slot,
|
|
79
|
+
type: isDynamicSlot(slot) ? "dynamic" : "static"
|
|
80
|
+
}));
|
|
81
|
+
}
|
|
82
|
+
function rewritePathForControlBase(path, definitionPropertyKey) {
|
|
83
|
+
if (!path || !definitionPropertyKey) return path;
|
|
84
|
+
const afterData = path.replace(/^\$\.data\./, "");
|
|
85
|
+
if (!afterData.startsWith(definitionPropertyKey + ".")) return path;
|
|
86
|
+
const rest = afterData.slice(definitionPropertyKey.length + 1);
|
|
87
|
+
return rest ? "$." + rest : path;
|
|
88
|
+
}
|
|
89
|
+
function resolveSlotDefinitions(slotDefinitions, node, nodeIdForStatic, definitionPropertyKey) {
|
|
90
|
+
const result = [];
|
|
91
|
+
for (const slot of slotDefinitions) {
|
|
92
|
+
if (slot.type === "static") {
|
|
93
|
+
const idPath = slot.idPath != null ? rewritePathForControlBase(slot.idPath, definitionPropertyKey) : void 0;
|
|
94
|
+
const id = idPath != null ? evaluateSimplePath(node, idPath) : slot.id != null ? String(slot.id).replace(/\{\{ID_GUID\}\}/g, nodeIdForStatic) : void 0;
|
|
95
|
+
const labelPath = slot.labelPath != null ? rewritePathForControlBase(slot.labelPath, definitionPropertyKey) : void 0;
|
|
96
|
+
const label = labelPath != null ? evaluateSimplePath(node, labelPath) : slot.labelPlaceholderValue ?? slot.label ?? (id ?? "");
|
|
97
|
+
result.push({ id: id ?? "", label: label ?? id ?? "" });
|
|
98
|
+
} else {
|
|
99
|
+
const path = slot.path ?? slot.idPath;
|
|
100
|
+
if (!path) continue;
|
|
101
|
+
const pathRewritten = rewritePathForControlBase(path, definitionPropertyKey);
|
|
102
|
+
const collection = evaluateCollectionPath(node, pathRewritten);
|
|
103
|
+
if (!Array.isArray(collection)) continue;
|
|
104
|
+
const idPath = rewritePathForControlBase(slot.idPath ?? path, definitionPropertyKey);
|
|
105
|
+
const labelPath = rewritePathForControlBase(slot.labelPath ?? path, definitionPropertyKey);
|
|
106
|
+
collection.forEach((item, index) => {
|
|
107
|
+
const id = evaluateItemPath(item, idPath) ?? item?.id ?? String(index);
|
|
108
|
+
const label = evaluateItemPath(item, labelPath) ?? item?.label ?? id ?? String(index);
|
|
109
|
+
result.push({ id: String(id), label: String(label) });
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
115
|
+
function buildGetSlotsFromDefinition(slotDefinitions, nodeIdForStatic, options) {
|
|
116
|
+
const { devPropertyKey, definitionPropertyKey } = options;
|
|
117
|
+
return (fullData) => {
|
|
118
|
+
const controlValue = devPropertyKey != null && fullData != null ? fullData[devPropertyKey] : fullData;
|
|
119
|
+
const node = { data: controlValue ?? {} };
|
|
120
|
+
return resolveSlotDefinitions(
|
|
121
|
+
slotDefinitions,
|
|
122
|
+
node,
|
|
123
|
+
nodeIdForStatic,
|
|
124
|
+
definitionPropertyKey
|
|
125
|
+
);
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
function deriveSlotConfigFromDefinition(def, nodeId, propertyKeyFromLoader) {
|
|
129
|
+
const slotsRoot = def?.slots;
|
|
130
|
+
const slotsConfig = Array.isArray(slotsRoot) ? slotsRoot : slotsRoot?.slots;
|
|
131
|
+
if (!Array.isArray(slotsConfig) || slotsConfig.length === 0) return void 0;
|
|
132
|
+
const field = deriveFieldFromSlotsDefinition(slotsConfig);
|
|
133
|
+
const definitionPropertyKey = deriveControlPropertyKey(def, field);
|
|
134
|
+
const devPropertyKey = propertyKeyFromLoader ?? definitionPropertyKey;
|
|
135
|
+
const slotDefinitions = getSlotDefinitions(slotsConfig);
|
|
136
|
+
const getSlots = buildGetSlotsFromDefinition(slotDefinitions, nodeId ?? "dev-node", {
|
|
137
|
+
devPropertyKey,
|
|
138
|
+
definitionPropertyKey
|
|
139
|
+
});
|
|
140
|
+
return {
|
|
141
|
+
field: devPropertyKey ?? field ?? void 0,
|
|
142
|
+
activeIdPath: "activeSlotId",
|
|
143
|
+
getSlots
|
|
144
|
+
};
|
|
145
|
+
}
|
|
4
146
|
var DevContext = createContext(null);
|
|
5
147
|
function useDevContext() {
|
|
6
148
|
return useContext(DevContext);
|
|
@@ -34,20 +176,33 @@ function DevProvider({
|
|
|
34
176
|
storageKey = "process-dev",
|
|
35
177
|
initialData = {},
|
|
36
178
|
persist = true,
|
|
37
|
-
nodeId = "dev-node-1"
|
|
179
|
+
nodeId = "dev-node-1",
|
|
180
|
+
propertyKey = "devField",
|
|
181
|
+
slotPreset,
|
|
182
|
+
slotConfig: slotConfigProp,
|
|
183
|
+
elementDefinition
|
|
38
184
|
}) {
|
|
185
|
+
const slotConfig = useMemo(
|
|
186
|
+
() => slotConfigProp ?? deriveSlotConfigFromDefinition(elementDefinition, nodeId, propertyKey),
|
|
187
|
+
[slotConfigProp, elementDefinition, nodeId, propertyKey]
|
|
188
|
+
);
|
|
189
|
+
const effectiveInitialData = useMemo(
|
|
190
|
+
() => Object.keys(initialData).length > 0 ? initialData : elementDefinition?.initValue ?? {},
|
|
191
|
+
[initialData, elementDefinition?.initValue]
|
|
192
|
+
);
|
|
193
|
+
const [activeSlotId, setActiveSlotIdState] = useState(null);
|
|
39
194
|
const [data, setData] = useState(() => {
|
|
40
195
|
if (persist && typeof window !== "undefined") {
|
|
41
196
|
try {
|
|
42
197
|
const stored = localStorage.getItem(`${storageKey}:data`);
|
|
43
198
|
if (stored) {
|
|
44
|
-
return { ...
|
|
199
|
+
return { ...effectiveInitialData, ...JSON.parse(stored) };
|
|
45
200
|
}
|
|
46
201
|
} catch (e) {
|
|
47
202
|
console.warn("DevProvider: Failed to load from localStorage", e);
|
|
48
203
|
}
|
|
49
204
|
}
|
|
50
|
-
return
|
|
205
|
+
return effectiveInitialData;
|
|
51
206
|
});
|
|
52
207
|
const [inferredTypes, setInferredTypesState] = useState(() => {
|
|
53
208
|
if (persist && typeof window !== "undefined") {
|
|
@@ -62,6 +217,10 @@ function DevProvider({
|
|
|
62
217
|
}
|
|
63
218
|
return {};
|
|
64
219
|
});
|
|
220
|
+
useEffect(() => {
|
|
221
|
+
if (!elementDefinition?.initValue || typeof elementDefinition.initValue !== "object") return;
|
|
222
|
+
setData((prev) => Object.keys(prev).length === 0 ? { ...elementDefinition.initValue } : prev);
|
|
223
|
+
}, [elementDefinition?.initValue]);
|
|
65
224
|
useEffect(() => {
|
|
66
225
|
if (persist && typeof window !== "undefined") {
|
|
67
226
|
try {
|
|
@@ -83,6 +242,9 @@ function DevProvider({
|
|
|
83
242
|
const setProperty = useCallback((key, value2) => {
|
|
84
243
|
setData((prev) => ({ ...prev, [key]: value2 }));
|
|
85
244
|
}, []);
|
|
245
|
+
const setActiveSlotId = useCallback((id) => {
|
|
246
|
+
setActiveSlotIdState(id);
|
|
247
|
+
}, []);
|
|
86
248
|
const getProperty = useCallback((key) => {
|
|
87
249
|
return data[key];
|
|
88
250
|
}, [data]);
|
|
@@ -131,18 +293,36 @@ function DevProvider({
|
|
|
131
293
|
clearInferredType,
|
|
132
294
|
clearAllInferredTypes,
|
|
133
295
|
nodeId,
|
|
296
|
+
activeSlotId,
|
|
297
|
+
setActiveSlotId,
|
|
298
|
+
slotConfig,
|
|
299
|
+
elementDefinition,
|
|
134
300
|
clearAll,
|
|
135
301
|
exportData,
|
|
136
302
|
importData
|
|
137
|
-
}), [data, setProperty, getProperty, inferredTypes, setInferredType, getInferredType, clearInferredType, clearAllInferredTypes, nodeId, clearAll, exportData, importData]);
|
|
303
|
+
}), [data, setProperty, getProperty, inferredTypes, setInferredType, getInferredType, clearInferredType, clearAllInferredTypes, nodeId, activeSlotId, setActiveSlotId, slotConfig, elementDefinition, clearAll, exportData, importData]);
|
|
138
304
|
return /* @__PURE__ */ React2.createElement(DevContext.Provider, { value }, children);
|
|
139
305
|
}
|
|
306
|
+
function getSlotsFromCasesData(data) {
|
|
307
|
+
const list = data?.cases?.cases ?? data?.cases ?? data?.branches;
|
|
308
|
+
if (!Array.isArray(list)) return [];
|
|
309
|
+
return list.map((item) => ({
|
|
310
|
+
id: item.id ?? String(item),
|
|
311
|
+
label: item.label ?? item.id ?? String(item)
|
|
312
|
+
}));
|
|
313
|
+
}
|
|
140
314
|
function DevToolbar({ className }) {
|
|
141
315
|
const devCtx = useDevContext();
|
|
142
316
|
const [showData, setShowData] = useState(false);
|
|
317
|
+
const [showDefinition, setShowDefinition] = useState(false);
|
|
143
318
|
const [showTypeEditor, setShowTypeEditor] = useState(false);
|
|
144
319
|
const [newTypeKey, setNewTypeKey] = useState("");
|
|
145
320
|
const [newTypeValue, setNewTypeValue] = useState("");
|
|
321
|
+
const slots = useMemo(() => {
|
|
322
|
+
if (!devCtx?.slotConfig?.getSlots) return [];
|
|
323
|
+
const data = devCtx.data ?? {};
|
|
324
|
+
return devCtx.slotConfig.getSlots(data);
|
|
325
|
+
}, [devCtx?.slotConfig, devCtx?.data]);
|
|
146
326
|
if (!devCtx) {
|
|
147
327
|
return /* @__PURE__ */ React2.createElement("div", { className }, "DevToolbar: Not inside DevProvider");
|
|
148
328
|
}
|
|
@@ -161,7 +341,7 @@ function DevToolbar({ className }) {
|
|
|
161
341
|
devCtx.clearAllInferredTypes();
|
|
162
342
|
}
|
|
163
343
|
};
|
|
164
|
-
return /* @__PURE__ */ React2.createElement("div", { className: `${className || ""} uii:border uii:rounded-lg uii:p-4 uii:bg-gray-50 dark:uii:bg-gray-900` }, /* @__PURE__ */ React2.createElement("div", { className: "uii:flex uii:items-center uii:gap-4 uii:mb-2 uii:flex-wrap" }, /* @__PURE__ */ React2.createElement("span", { className: "uii:font-semibold uii:text-sm" }, "\u{1F6E0}\uFE0F Dev Mode"), /* @__PURE__ */ React2.createElement("span", { className: "uii:text-xs uii:text-gray-500" }, "Node: ", devCtx.nodeId), /* @__PURE__ */ React2.createElement(
|
|
344
|
+
return /* @__PURE__ */ React2.createElement("div", { className: `${className || ""} uii:border uii:rounded-lg uii:p-4 uii:bg-gray-50 dark:uii:bg-gray-900` }, /* @__PURE__ */ React2.createElement("div", { className: "uii:flex uii:items-center uii:gap-4 uii:mb-2 uii:flex-wrap" }, /* @__PURE__ */ React2.createElement("span", { className: "uii:font-semibold uii:text-sm " }, "\u{1F6E0}\uFE0F Dev Mode"), /* @__PURE__ */ React2.createElement("span", { className: "uii:text-xs uii:text-gray-500" }, "Node: ", devCtx.nodeId), /* @__PURE__ */ React2.createElement(
|
|
165
345
|
"button",
|
|
166
346
|
{
|
|
167
347
|
onClick: () => setShowData(!showData),
|
|
@@ -169,6 +349,14 @@ function DevToolbar({ className }) {
|
|
|
169
349
|
},
|
|
170
350
|
showData ? "Hide" : "Show",
|
|
171
351
|
" Data"
|
|
352
|
+
), /* @__PURE__ */ React2.createElement(
|
|
353
|
+
"button",
|
|
354
|
+
{
|
|
355
|
+
onClick: () => setShowDefinition(!showDefinition),
|
|
356
|
+
className: "uii:text-xs uii:px-2 uii:py-1 uii:bg-amber-100 dark:uii:bg-amber-900 uii:rounded hover:uii:bg-amber-200"
|
|
357
|
+
},
|
|
358
|
+
showDefinition ? "Hide" : "Show",
|
|
359
|
+
" Definition"
|
|
172
360
|
), /* @__PURE__ */ React2.createElement(
|
|
173
361
|
"button",
|
|
174
362
|
{
|
|
@@ -207,7 +395,24 @@ function DevToolbar({ className }) {
|
|
|
207
395
|
className: "uii:text-xs uii:px-2 uii:py-1 uii:bg-red-100 dark:uii:bg-red-900 uii:rounded hover:uii:bg-red-200"
|
|
208
396
|
},
|
|
209
397
|
"Clear"
|
|
210
|
-
)),
|
|
398
|
+
)), slots.length > 0 && /* @__PURE__ */ React2.createElement("div", { className: "uii:mt-2 uii:p-2 uii:bg-slate-50 dark:uii:bg-slate-900 uii:rounded-lg uii:border uii:border-slate-200 dark:uii:border-slate-700" }, /* @__PURE__ */ React2.createElement("div", { className: "uii:text-xs uii:font-medium uii:mb-1.5 uii:text-slate-600 dark:uii:text-slate-400" }, "Active path / case"), /* @__PURE__ */ React2.createElement("div", { className: "uii:flex uii:flex-wrap uii:gap-1" }, /* @__PURE__ */ React2.createElement(
|
|
399
|
+
"button",
|
|
400
|
+
{
|
|
401
|
+
type: "button",
|
|
402
|
+
onClick: () => devCtx.setActiveSlotId(null),
|
|
403
|
+
className: `uii:text-xs uii:px-2 uii:py-1 uii:rounded uii:border ${devCtx.activeSlotId === null ? "uii:bg-slate-300 dark:uii:bg-slate-600 uii:border-slate-500" : "uii:bg-slate-100 dark:uii:bg-slate-800 uii:border-slate-300 dark:uii:border-slate-600 hover:uii:bg-slate-200"}`
|
|
404
|
+
},
|
|
405
|
+
"(none)"
|
|
406
|
+
), slots.map((slot) => /* @__PURE__ */ React2.createElement(
|
|
407
|
+
"button",
|
|
408
|
+
{
|
|
409
|
+
key: slot.id,
|
|
410
|
+
type: "button",
|
|
411
|
+
onClick: () => devCtx.setActiveSlotId(slot.id),
|
|
412
|
+
className: `uii:text-xs uii:px-2 uii:py-1 uii:rounded uii:border ${devCtx.activeSlotId === slot.id ? "uii:bg-blue-200 dark:uii:bg-blue-800 uii:border-blue-500" : "uii:bg-white dark:uii:bg-slate-800 uii:border-slate-300 dark:uii:border-slate-600 hover:uii:bg-slate-100 dark:uii:hover:bg-slate-700"}`
|
|
413
|
+
},
|
|
414
|
+
slot.label || slot.id
|
|
415
|
+
)))), showTypeEditor && /* @__PURE__ */ React2.createElement("div", { className: "uii:mt-3 uii:p-3 uii:bg-purple-50 dark:uii:bg-purple-950 uii:rounded-lg uii:border uii:border-purple-200 dark:uii:border-purple-800" }, /* @__PURE__ */ React2.createElement("div", { className: "uii:text-xs uii:font-medium uii:mb-2 uii:text-purple-700 dark:uii:text-purple-300" }, "Spoof Inferred Types (simulate external field types)"), /* @__PURE__ */ React2.createElement("div", { className: "uii:flex uii:gap-2 uii:mb-2 uii:flex-wrap" }, /* @__PURE__ */ React2.createElement(
|
|
211
416
|
"input",
|
|
212
417
|
{
|
|
213
418
|
type: "text",
|
|
@@ -280,9 +485,9 @@ function DevToolbar({ className }) {
|
|
|
280
485
|
},
|
|
281
486
|
"\u2715"
|
|
282
487
|
)
|
|
283
|
-
))))), showData && /* @__PURE__ */ React2.createElement("div", { className: "uii:mt-2" }, /* @__PURE__ */ React2.createElement("div", { className: "uii:text-xs uii:mb-1 uii:font-medium" }, "Data:"), /* @__PURE__ */ React2.createElement("pre", { className: "uii:text-xs uii:bg-gray-100 dark:uii:bg-gray-800 uii:p-2 uii:rounded uii:overflow-auto uii:max-h-48" }, JSON.stringify(devCtx.data, null, 2)), /* @__PURE__ */ React2.createElement("div", { className: "uii:text-xs uii:mb-1 uii:mt-2 uii:font-medium" }, "Inferred Types:"), /* @__PURE__ */ React2.createElement("pre", { className: "uii:text-xs uii:bg-gray-100 dark:uii:bg-gray-800 uii:p-2 uii:rounded uii:overflow-auto uii:max-h-24" }, JSON.stringify(devCtx.inferredTypes, null, 2))));
|
|
488
|
+
))))), showData && /* @__PURE__ */ React2.createElement("div", { className: "uii:mt-2" }, /* @__PURE__ */ React2.createElement("div", { className: "uii:text-xs uii:mb-1 uii:font-medium" }, "Data:"), /* @__PURE__ */ React2.createElement("pre", { className: "uii:text-xs uii:bg-gray-100 dark:uii:bg-gray-800 uii:p-2 uii:rounded uii:overflow-auto uii:max-h-48" }, JSON.stringify(devCtx.data, null, 2)), /* @__PURE__ */ React2.createElement("div", { className: "uii:text-xs uii:mb-1 uii:mt-2 uii:font-medium" }, "Inferred Types:"), /* @__PURE__ */ React2.createElement("pre", { className: "uii:text-xs uii:bg-gray-100 dark:uii:bg-gray-800 uii:p-2 uii:rounded uii:overflow-auto uii:max-h-24" }, JSON.stringify(devCtx.inferredTypes, null, 2))), showDefinition && /* @__PURE__ */ React2.createElement("div", { className: "uii:mt-2" }, /* @__PURE__ */ React2.createElement("div", { className: "uii:text-xs uii:mb-1 uii:font-medium" }, "Action / signal definition:"), devCtx.elementDefinition != null ? /* @__PURE__ */ React2.createElement("pre", { className: "uii:text-xs uii:bg-amber-50 dark:uii:bg-amber-950/30 uii:p-2 uii:rounded uii:overflow-auto uii:max-h-64 uii:border uii:border-amber-200 dark:uii:border-amber-800" }, JSON.stringify(devCtx.elementDefinition, null, 2)) : /* @__PURE__ */ React2.createElement("p", { className: "uii:text-xs uii:text-gray-500 uii:italic" }, "No definition passed to DevProvider.")));
|
|
284
489
|
}
|
|
285
490
|
|
|
286
|
-
export { DevContext, DevProvider, DevToolbar, useDevContext, useInferredTypes, useNodeProperty };
|
|
491
|
+
export { DevContext, DevProvider, DevToolbar, getSlotsFromCasesData, useDevContext, useInferredTypes, useNodeProperty };
|
|
287
492
|
//# sourceMappingURL=index.js.map
|
|
288
493
|
//# sourceMappingURL=index.js.map
|