@surveystudio/node-registery 1.0.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 +25 -0
- package/dist/builder.d.mts +65 -0
- package/dist/builder.mjs +122 -0
- package/dist/logic.d.mts +41 -0
- package/dist/logic.mjs +72 -0
- package/dist/runner.d.mts +21 -0
- package/dist/runner.mjs +82 -0
- package/dist/types-DJePy6HU.d.mts +140 -0
- package/package.json +71 -0
package/README.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# @survey-studio/node-registery
|
|
2
|
+
|
|
3
|
+
Typed survey question node registry with separate entrypoints for pure logic, runner UI, and builder UI.
|
|
4
|
+
|
|
5
|
+
This package is currently in early migration. It exports the first migrated node, `plainText`, while the remaining SurveyChamp question nodes are being moved into the registry.
|
|
6
|
+
|
|
7
|
+
## Entrypoints
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { logicRegistry } from "@survey-studio/node-registery/logic";
|
|
11
|
+
import { runnerRegistry } from "@survey-studio/node-registery/runner";
|
|
12
|
+
import { builderRegistry } from "@survey-studio/node-registery/builder";
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Use `/logic` for Worker, export, and server runtimes. It is intentionally React-free.
|
|
16
|
+
|
|
17
|
+
Use `/runner` and `/builder` only in React runtimes. React is a peer dependency and is not bundled.
|
|
18
|
+
|
|
19
|
+
## Current Status
|
|
20
|
+
|
|
21
|
+
Migrated nodes:
|
|
22
|
+
|
|
23
|
+
- `plainText`
|
|
24
|
+
|
|
25
|
+
The registry contract test intentionally fails until all planned question nodes are migrated.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { CSSProperties } from 'react';
|
|
3
|
+
import { i as NodeBuilderProps, P as PlainTextData, j as NodeCanvasProps, J as JsonValue } from './types-DJePy6HU.mjs';
|
|
4
|
+
export { B as BuilderRegistry, k as CompleteBuilderRegistry, l as NodeBuilder, m as NodeManifest, n as PropertyField, o as PropertyFieldType, Q as QuestionNodeDefinition, S as SelectOption, p as defineBuilderRegistry, c as defineQuestionNode } from './types-DJePy6HU.mjs';
|
|
5
|
+
|
|
6
|
+
declare function PlainTextBuilderPreview({ data }: NodeCanvasProps<PlainTextData>): react.DetailedReactHTMLElement<{
|
|
7
|
+
style: CSSProperties;
|
|
8
|
+
}, HTMLElement>;
|
|
9
|
+
declare function PlainTextSettings(_props: NodeBuilderProps<PlainTextData>): null;
|
|
10
|
+
declare const plainTextBuilder: {
|
|
11
|
+
type: "plainText";
|
|
12
|
+
label: string;
|
|
13
|
+
SettingsComponent: typeof PlainTextSettings;
|
|
14
|
+
CanvasComponent: typeof PlainTextBuilderPreview;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
declare const plainTextManifest: {
|
|
18
|
+
type: "plainText";
|
|
19
|
+
label: string;
|
|
20
|
+
description: string;
|
|
21
|
+
category: "media";
|
|
22
|
+
dataType: "none";
|
|
23
|
+
defaultData: PlainTextData;
|
|
24
|
+
properties: ({
|
|
25
|
+
name: string;
|
|
26
|
+
label: string;
|
|
27
|
+
type: "text";
|
|
28
|
+
placeholder: string;
|
|
29
|
+
defaultValue?: never;
|
|
30
|
+
} | {
|
|
31
|
+
name: string;
|
|
32
|
+
label: string;
|
|
33
|
+
type: "textarea";
|
|
34
|
+
placeholder: string;
|
|
35
|
+
defaultValue: string;
|
|
36
|
+
} | {
|
|
37
|
+
name: string;
|
|
38
|
+
label: string;
|
|
39
|
+
type: "text";
|
|
40
|
+
defaultValue: string;
|
|
41
|
+
placeholder?: never;
|
|
42
|
+
} | {
|
|
43
|
+
name: string;
|
|
44
|
+
label: string;
|
|
45
|
+
type: "condition";
|
|
46
|
+
defaultValue: {
|
|
47
|
+
id: string;
|
|
48
|
+
type: "group";
|
|
49
|
+
logicType: "AND" | "OR";
|
|
50
|
+
children: JsonValue[];
|
|
51
|
+
};
|
|
52
|
+
placeholder?: never;
|
|
53
|
+
})[];
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
declare const builderRegistry: {
|
|
57
|
+
readonly plainText: {
|
|
58
|
+
type: "plainText";
|
|
59
|
+
label: string;
|
|
60
|
+
SettingsComponent: typeof PlainTextSettings;
|
|
61
|
+
CanvasComponent: typeof PlainTextBuilderPreview;
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export { NodeBuilderProps, NodeCanvasProps, builderRegistry, plainTextBuilder, plainTextManifest };
|
package/dist/builder.mjs
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
// src/types.ts
|
|
2
|
+
function defineQuestionNode(definition) {
|
|
3
|
+
return definition;
|
|
4
|
+
}
|
|
5
|
+
function defineBuilderRegistry(registry) {
|
|
6
|
+
return registry;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// src/nodes/plainText/builder.ts
|
|
10
|
+
import { createElement } from "react";
|
|
11
|
+
var shellStyle = {
|
|
12
|
+
display: "grid",
|
|
13
|
+
gap: "12px",
|
|
14
|
+
minWidth: "220px"
|
|
15
|
+
};
|
|
16
|
+
var titleStyle = {
|
|
17
|
+
color: "#111827",
|
|
18
|
+
fontSize: "14px",
|
|
19
|
+
fontWeight: 600,
|
|
20
|
+
lineHeight: 1.3,
|
|
21
|
+
margin: 0
|
|
22
|
+
};
|
|
23
|
+
var descriptionStyle = {
|
|
24
|
+
background: "#f3f4f6",
|
|
25
|
+
borderRadius: "6px",
|
|
26
|
+
color: "#4b5563",
|
|
27
|
+
fontSize: "12px",
|
|
28
|
+
lineHeight: 1.45,
|
|
29
|
+
margin: 0,
|
|
30
|
+
maxHeight: "96px",
|
|
31
|
+
overflow: "hidden",
|
|
32
|
+
padding: "8px",
|
|
33
|
+
whiteSpace: "pre-wrap"
|
|
34
|
+
};
|
|
35
|
+
var footerStyle = {
|
|
36
|
+
display: "flex",
|
|
37
|
+
justifyContent: "flex-end"
|
|
38
|
+
};
|
|
39
|
+
var buttonStyle = {
|
|
40
|
+
background: "#111827",
|
|
41
|
+
border: 0,
|
|
42
|
+
borderRadius: "6px",
|
|
43
|
+
color: "#ffffff",
|
|
44
|
+
fontSize: "12px",
|
|
45
|
+
fontWeight: 500,
|
|
46
|
+
padding: "4px 10px"
|
|
47
|
+
};
|
|
48
|
+
function PlainTextBuilderPreview({ data }) {
|
|
49
|
+
const label = data.label || "Info Screen";
|
|
50
|
+
const description = data.description || "No content provided...";
|
|
51
|
+
const buttonLabel = data.buttonLabel || "Continue";
|
|
52
|
+
return createElement(
|
|
53
|
+
"div",
|
|
54
|
+
{ style: shellStyle },
|
|
55
|
+
createElement("p", { style: titleStyle }, label),
|
|
56
|
+
createElement("p", { style: descriptionStyle }, description),
|
|
57
|
+
createElement(
|
|
58
|
+
"div",
|
|
59
|
+
{ style: footerStyle },
|
|
60
|
+
createElement("button", { disabled: true, style: buttonStyle, type: "button" }, buttonLabel)
|
|
61
|
+
)
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
function PlainTextSettings(_props) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
var plainTextBuilder = {
|
|
68
|
+
type: "plainText",
|
|
69
|
+
label: "Info / Text",
|
|
70
|
+
SettingsComponent: PlainTextSettings,
|
|
71
|
+
CanvasComponent: PlainTextBuilderPreview
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// src/nodes/plainText/manifest.ts
|
|
75
|
+
var plainTextDefaultData = {
|
|
76
|
+
label: "Info / Text",
|
|
77
|
+
description: "",
|
|
78
|
+
buttonLabel: "Continue",
|
|
79
|
+
condition: {
|
|
80
|
+
id: "root",
|
|
81
|
+
type: "group",
|
|
82
|
+
logicType: "AND",
|
|
83
|
+
children: []
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
var plainTextManifest = {
|
|
87
|
+
type: "plainText",
|
|
88
|
+
label: "Info / Text",
|
|
89
|
+
description: "Display text with a continue button",
|
|
90
|
+
category: "media",
|
|
91
|
+
dataType: "none",
|
|
92
|
+
defaultData: plainTextDefaultData,
|
|
93
|
+
properties: [
|
|
94
|
+
{ name: "label", label: "Field Label", type: "text", placeholder: "Info Screen" },
|
|
95
|
+
{
|
|
96
|
+
name: "description",
|
|
97
|
+
label: "Content",
|
|
98
|
+
type: "textarea",
|
|
99
|
+
placeholder: "Enter your message here...",
|
|
100
|
+
defaultValue: ""
|
|
101
|
+
},
|
|
102
|
+
{ name: "buttonLabel", label: "Button Label", type: "text", defaultValue: "Continue" },
|
|
103
|
+
{
|
|
104
|
+
name: "condition",
|
|
105
|
+
label: "Logic Rule",
|
|
106
|
+
type: "condition",
|
|
107
|
+
defaultValue: plainTextDefaultData.condition
|
|
108
|
+
}
|
|
109
|
+
]
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
// src/builder/index.ts
|
|
113
|
+
var builderRegistry = defineBuilderRegistry({
|
|
114
|
+
plainText: plainTextBuilder
|
|
115
|
+
});
|
|
116
|
+
export {
|
|
117
|
+
builderRegistry,
|
|
118
|
+
defineBuilderRegistry,
|
|
119
|
+
defineQuestionNode,
|
|
120
|
+
plainTextBuilder,
|
|
121
|
+
plainTextManifest
|
|
122
|
+
};
|
package/dist/logic.d.mts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { P as PlainTextData, a as PlainTextValue } from './types-DJePy6HU.mjs';
|
|
2
|
+
export { C as CompleteLogicRegistry, D as DataType, E as ExtractedValue, b as ExtractionContext, L as LogicRegistry, N as NodeLogic, Q as QuestionNodeDefinition, V as ValidationResult, d as defineLogicRegistry, c as defineQuestionNode } from './types-DJePy6HU.mjs';
|
|
3
|
+
import 'react';
|
|
4
|
+
|
|
5
|
+
declare const plainTextLogic: {
|
|
6
|
+
type: "plainText";
|
|
7
|
+
dataType: "none";
|
|
8
|
+
defaultData: PlainTextData;
|
|
9
|
+
defaultValue: {
|
|
10
|
+
viewed: false;
|
|
11
|
+
};
|
|
12
|
+
validate: () => {
|
|
13
|
+
valid: true;
|
|
14
|
+
};
|
|
15
|
+
extractValue: (value: PlainTextValue) => {
|
|
16
|
+
columnKey: string;
|
|
17
|
+
columnLabel: string;
|
|
18
|
+
booleanValue: boolean;
|
|
19
|
+
}[];
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
declare const logicRegistry: {
|
|
23
|
+
readonly plainText: {
|
|
24
|
+
type: "plainText";
|
|
25
|
+
dataType: "none";
|
|
26
|
+
defaultData: PlainTextData;
|
|
27
|
+
defaultValue: {
|
|
28
|
+
viewed: false;
|
|
29
|
+
};
|
|
30
|
+
validate: () => {
|
|
31
|
+
valid: true;
|
|
32
|
+
};
|
|
33
|
+
extractValue: (value: PlainTextValue) => {
|
|
34
|
+
columnKey: string;
|
|
35
|
+
columnLabel: string;
|
|
36
|
+
booleanValue: boolean;
|
|
37
|
+
}[];
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export { logicRegistry, plainTextLogic };
|
package/dist/logic.mjs
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// src/types.ts
|
|
2
|
+
function defineQuestionNode(definition) {
|
|
3
|
+
return definition;
|
|
4
|
+
}
|
|
5
|
+
function defineLogicRegistry(registry) {
|
|
6
|
+
return registry;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// src/nodes/plainText/manifest.ts
|
|
10
|
+
var plainTextDefaultData = {
|
|
11
|
+
label: "Info / Text",
|
|
12
|
+
description: "",
|
|
13
|
+
buttonLabel: "Continue",
|
|
14
|
+
condition: {
|
|
15
|
+
id: "root",
|
|
16
|
+
type: "group",
|
|
17
|
+
logicType: "AND",
|
|
18
|
+
children: []
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
var plainTextManifest = {
|
|
22
|
+
type: "plainText",
|
|
23
|
+
label: "Info / Text",
|
|
24
|
+
description: "Display text with a continue button",
|
|
25
|
+
category: "media",
|
|
26
|
+
dataType: "none",
|
|
27
|
+
defaultData: plainTextDefaultData,
|
|
28
|
+
properties: [
|
|
29
|
+
{ name: "label", label: "Field Label", type: "text", placeholder: "Info Screen" },
|
|
30
|
+
{
|
|
31
|
+
name: "description",
|
|
32
|
+
label: "Content",
|
|
33
|
+
type: "textarea",
|
|
34
|
+
placeholder: "Enter your message here...",
|
|
35
|
+
defaultValue: ""
|
|
36
|
+
},
|
|
37
|
+
{ name: "buttonLabel", label: "Button Label", type: "text", defaultValue: "Continue" },
|
|
38
|
+
{
|
|
39
|
+
name: "condition",
|
|
40
|
+
label: "Logic Rule",
|
|
41
|
+
type: "condition",
|
|
42
|
+
defaultValue: plainTextDefaultData.condition
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// src/nodes/plainText/logic.ts
|
|
48
|
+
var plainTextLogic = {
|
|
49
|
+
type: "plainText",
|
|
50
|
+
dataType: "none",
|
|
51
|
+
defaultData: plainTextDefaultData,
|
|
52
|
+
defaultValue: { viewed: false },
|
|
53
|
+
validate: () => ({ valid: true }),
|
|
54
|
+
extractValue: (value) => [
|
|
55
|
+
{
|
|
56
|
+
columnKey: "viewed",
|
|
57
|
+
columnLabel: "Viewed",
|
|
58
|
+
booleanValue: Boolean(value?.viewed)
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
// src/logic/index.ts
|
|
64
|
+
var logicRegistry = defineLogicRegistry({
|
|
65
|
+
plainText: plainTextLogic
|
|
66
|
+
});
|
|
67
|
+
export {
|
|
68
|
+
defineLogicRegistry,
|
|
69
|
+
defineQuestionNode,
|
|
70
|
+
logicRegistry,
|
|
71
|
+
plainTextLogic
|
|
72
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { CSSProperties } from 'react';
|
|
3
|
+
import { e as NodeRunnerProps, P as PlainTextData, a as PlainTextValue } from './types-DJePy6HU.mjs';
|
|
4
|
+
export { f as CompleteRunnerRegistry, g as NodeRunner, Q as QuestionNodeDefinition, R as RunnerRegistry, c as defineQuestionNode, h as defineRunnerRegistry } from './types-DJePy6HU.mjs';
|
|
5
|
+
|
|
6
|
+
declare function PlainTextRunnerView({ data, onChange, onNext, isActive, }: NodeRunnerProps<PlainTextData, PlainTextValue>): react.DetailedReactHTMLElement<{
|
|
7
|
+
style: CSSProperties;
|
|
8
|
+
}, HTMLElement>;
|
|
9
|
+
declare const plainTextRunner: {
|
|
10
|
+
type: "plainText";
|
|
11
|
+
Component: typeof PlainTextRunnerView;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
declare const runnerRegistry: {
|
|
15
|
+
readonly plainText: {
|
|
16
|
+
type: "plainText";
|
|
17
|
+
Component: typeof PlainTextRunnerView;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export { NodeRunnerProps, plainTextRunner, runnerRegistry };
|
package/dist/runner.mjs
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// src/types.ts
|
|
2
|
+
function defineQuestionNode(definition) {
|
|
3
|
+
return definition;
|
|
4
|
+
}
|
|
5
|
+
function defineRunnerRegistry(registry) {
|
|
6
|
+
return registry;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// src/nodes/plainText/runner.ts
|
|
10
|
+
import { createElement } from "react";
|
|
11
|
+
var shellStyle = {
|
|
12
|
+
display: "grid",
|
|
13
|
+
gap: "24px",
|
|
14
|
+
maxWidth: "576px",
|
|
15
|
+
padding: "16px 0",
|
|
16
|
+
width: "100%"
|
|
17
|
+
};
|
|
18
|
+
var descriptionStyle = {
|
|
19
|
+
color: "#334155",
|
|
20
|
+
fontSize: "18px",
|
|
21
|
+
lineHeight: 1.65,
|
|
22
|
+
margin: 0,
|
|
23
|
+
whiteSpace: "pre-wrap"
|
|
24
|
+
};
|
|
25
|
+
var buttonStyle = {
|
|
26
|
+
alignItems: "center",
|
|
27
|
+
background: "#111827",
|
|
28
|
+
border: 0,
|
|
29
|
+
borderRadius: "999px",
|
|
30
|
+
color: "#ffffff",
|
|
31
|
+
cursor: "pointer",
|
|
32
|
+
display: "inline-flex",
|
|
33
|
+
fontSize: "15px",
|
|
34
|
+
fontWeight: 600,
|
|
35
|
+
gap: "8px",
|
|
36
|
+
justifySelf: "start",
|
|
37
|
+
padding: "12px 24px"
|
|
38
|
+
};
|
|
39
|
+
function PlainTextRunnerView({
|
|
40
|
+
data,
|
|
41
|
+
onChange,
|
|
42
|
+
onNext,
|
|
43
|
+
isActive
|
|
44
|
+
}) {
|
|
45
|
+
const description = data.description || "No description provided...";
|
|
46
|
+
const buttonLabel = data.buttonLabel || "Continue";
|
|
47
|
+
const children = [createElement("p", { key: "description", style: descriptionStyle }, description)];
|
|
48
|
+
if (isActive) {
|
|
49
|
+
children.push(
|
|
50
|
+
createElement(
|
|
51
|
+
"button",
|
|
52
|
+
{
|
|
53
|
+
key: "button",
|
|
54
|
+
onClick: () => {
|
|
55
|
+
onChange({ viewed: true });
|
|
56
|
+
onNext?.();
|
|
57
|
+
},
|
|
58
|
+
style: buttonStyle,
|
|
59
|
+
type: "button"
|
|
60
|
+
},
|
|
61
|
+
buttonLabel,
|
|
62
|
+
" ->"
|
|
63
|
+
)
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
return createElement("div", { style: shellStyle }, children);
|
|
67
|
+
}
|
|
68
|
+
var plainTextRunner = {
|
|
69
|
+
type: "plainText",
|
|
70
|
+
Component: PlainTextRunnerView
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
// src/runner/index.ts
|
|
74
|
+
var runnerRegistry = defineRunnerRegistry({
|
|
75
|
+
plainText: plainTextRunner
|
|
76
|
+
});
|
|
77
|
+
export {
|
|
78
|
+
defineQuestionNode,
|
|
79
|
+
defineRunnerRegistry,
|
|
80
|
+
plainTextRunner,
|
|
81
|
+
runnerRegistry
|
|
82
|
+
};
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { ReactNode, ComponentType } from 'react';
|
|
2
|
+
|
|
3
|
+
declare const QUESTION_NODE_TYPES: readonly ["textInput", "numberInput", "emailInput", "dateInput", "multiInput", "zipCodeInput", "singleChoice", "multipleChoice", "dropdown", "ranking", "cascadingChoice", "matrixChoice", "rating", "slider", "consent", "captcha", "image", "video", "audio", "plainText", "emojiRating"];
|
|
4
|
+
declare const FLOW_NODE_TYPES: readonly ["start", "end", "branch", "validation"];
|
|
5
|
+
type QuestionNodeType = (typeof QUESTION_NODE_TYPES)[number];
|
|
6
|
+
type FlowNodeType = (typeof FLOW_NODE_TYPES)[number];
|
|
7
|
+
type SurveyNodeType = QuestionNodeType | FlowNodeType;
|
|
8
|
+
type NodeCategory = "input" | "choice" | "logic" | "media" | "flow";
|
|
9
|
+
type PrimitiveValue = string | number | boolean | null;
|
|
10
|
+
type JsonValue = PrimitiveValue | JsonValue[] | {
|
|
11
|
+
[key: string]: JsonValue;
|
|
12
|
+
};
|
|
13
|
+
type NodeData = Record<string, JsonValue | undefined>;
|
|
14
|
+
type NodeValue = JsonValue | undefined;
|
|
15
|
+
type DataType = "text" | "number" | "boolean" | "option" | "array" | "object" | "none";
|
|
16
|
+
type PropertyFieldType = "text" | "textarea" | "number" | "switch" | "select" | "color" | "options" | "condition" | "stepBuilder" | "fileTextarea" | "file" | "files" | "emojiOptions";
|
|
17
|
+
interface SelectOption {
|
|
18
|
+
readonly label: string;
|
|
19
|
+
readonly value: string;
|
|
20
|
+
}
|
|
21
|
+
interface PropertyField<TData extends NodeData = NodeData> {
|
|
22
|
+
readonly name: keyof TData & string;
|
|
23
|
+
readonly label: string;
|
|
24
|
+
readonly type: PropertyFieldType;
|
|
25
|
+
readonly placeholder?: string;
|
|
26
|
+
readonly helperText?: string;
|
|
27
|
+
readonly defaultValue?: JsonValue;
|
|
28
|
+
readonly options?: readonly SelectOption[];
|
|
29
|
+
readonly visible?: (data: Readonly<TData>) => boolean;
|
|
30
|
+
readonly min?: number;
|
|
31
|
+
readonly max?: number;
|
|
32
|
+
}
|
|
33
|
+
interface NodeManifest<TType extends SurveyNodeType = SurveyNodeType, TData extends NodeData = NodeData> {
|
|
34
|
+
readonly type: TType;
|
|
35
|
+
readonly label: string;
|
|
36
|
+
readonly description: string;
|
|
37
|
+
readonly category: NodeCategory;
|
|
38
|
+
readonly dataType: DataType;
|
|
39
|
+
readonly defaultData: Readonly<TData>;
|
|
40
|
+
readonly properties: readonly PropertyField<TData>[];
|
|
41
|
+
}
|
|
42
|
+
interface ValidationResult {
|
|
43
|
+
readonly valid: boolean;
|
|
44
|
+
readonly error?: string;
|
|
45
|
+
}
|
|
46
|
+
interface ExtractedValue {
|
|
47
|
+
readonly questionId?: string;
|
|
48
|
+
readonly columnKey?: string;
|
|
49
|
+
readonly columnLabel?: string;
|
|
50
|
+
readonly textValue?: string;
|
|
51
|
+
readonly numberValue?: number;
|
|
52
|
+
readonly booleanValue?: boolean;
|
|
53
|
+
readonly optionUuid?: string;
|
|
54
|
+
readonly optionText?: string;
|
|
55
|
+
readonly arrayValue?: readonly JsonValue[];
|
|
56
|
+
readonly objectValue?: Readonly<Record<string, JsonValue>>;
|
|
57
|
+
readonly metadata?: Readonly<Record<string, JsonValue>>;
|
|
58
|
+
}
|
|
59
|
+
interface ExtractionContext<TType extends SurveyNodeType = SurveyNodeType> {
|
|
60
|
+
readonly nodeId: string;
|
|
61
|
+
readonly nodeType: TType;
|
|
62
|
+
readonly questionLabel?: string;
|
|
63
|
+
}
|
|
64
|
+
interface NodeLogic<TType extends SurveyNodeType = SurveyNodeType, TData extends NodeData = NodeData, TValue extends NodeValue = NodeValue> {
|
|
65
|
+
readonly type: TType;
|
|
66
|
+
readonly dataType: DataType;
|
|
67
|
+
readonly defaultData: Readonly<TData>;
|
|
68
|
+
readonly defaultValue?: TValue;
|
|
69
|
+
validate(value: TValue, nodeData: Readonly<TData>): ValidationResult;
|
|
70
|
+
extractValue(value: TValue, nodeData: Readonly<TData>, context: ExtractionContext<TType>): readonly ExtractedValue[];
|
|
71
|
+
}
|
|
72
|
+
interface NodeRunnerProps<TData extends NodeData = NodeData, TValue extends NodeValue = NodeValue> {
|
|
73
|
+
readonly data: Readonly<TData>;
|
|
74
|
+
readonly value: TValue;
|
|
75
|
+
readonly onChange: (newValue: TValue) => void;
|
|
76
|
+
readonly onNext?: () => void;
|
|
77
|
+
readonly error?: string;
|
|
78
|
+
readonly isActive?: boolean;
|
|
79
|
+
}
|
|
80
|
+
interface NodeRunner<TType extends SurveyNodeType = SurveyNodeType, TData extends NodeData = NodeData, TValue extends NodeValue = NodeValue> {
|
|
81
|
+
readonly type: TType;
|
|
82
|
+
readonly Component: ComponentType<NodeRunnerProps<TData, TValue>>;
|
|
83
|
+
}
|
|
84
|
+
interface NodeBuilderProps<TData extends NodeData = NodeData> {
|
|
85
|
+
readonly data: Readonly<TData>;
|
|
86
|
+
readonly onChange: (newData: TData) => void;
|
|
87
|
+
}
|
|
88
|
+
interface NodeCanvasProps<TData extends NodeData = NodeData> {
|
|
89
|
+
readonly id: string;
|
|
90
|
+
readonly type: SurveyNodeType;
|
|
91
|
+
readonly data: Readonly<TData>;
|
|
92
|
+
readonly selected?: boolean;
|
|
93
|
+
}
|
|
94
|
+
interface NodeBuilder<TType extends SurveyNodeType = SurveyNodeType, TData extends NodeData = NodeData> {
|
|
95
|
+
readonly type: TType;
|
|
96
|
+
readonly label: string;
|
|
97
|
+
readonly icon?: ReactNode;
|
|
98
|
+
readonly SettingsComponent?: ComponentType<NodeBuilderProps<TData>>;
|
|
99
|
+
readonly CanvasComponent?: ComponentType<NodeCanvasProps<TData>>;
|
|
100
|
+
}
|
|
101
|
+
interface QuestionNodeDefinition<TType extends QuestionNodeType = QuestionNodeType, TData extends NodeData = NodeData, TValue extends NodeValue = NodeValue> {
|
|
102
|
+
readonly manifest: NodeManifest<TType, TData>;
|
|
103
|
+
readonly logic: NodeLogic<TType, TData, TValue>;
|
|
104
|
+
readonly builder: NodeBuilder<TType, TData>;
|
|
105
|
+
readonly runner: NodeRunner<TType, TData, TValue>;
|
|
106
|
+
}
|
|
107
|
+
type CompleteLogicRegistry<TType extends QuestionNodeType = QuestionNodeType> = Readonly<Record<TType, NodeLogic<TType, NodeData, NodeValue>>>;
|
|
108
|
+
type CompleteBuilderRegistry<TType extends QuestionNodeType = QuestionNodeType> = Readonly<Record<TType, NodeBuilder<TType, NodeData>>>;
|
|
109
|
+
type CompleteRunnerRegistry<TType extends QuestionNodeType = QuestionNodeType> = Readonly<Record<TType, NodeRunner<TType, NodeData, NodeValue>>>;
|
|
110
|
+
type LogicRegistry<TType extends SurveyNodeType = SurveyNodeType> = Readonly<Partial<{
|
|
111
|
+
[K in TType]: NodeLogic<K, NodeData, NodeValue>;
|
|
112
|
+
}>>;
|
|
113
|
+
type BuilderRegistry<TType extends SurveyNodeType = SurveyNodeType> = Readonly<Partial<{
|
|
114
|
+
[K in TType]: NodeBuilder<K, NodeData>;
|
|
115
|
+
}>>;
|
|
116
|
+
type RunnerRegistry<TType extends SurveyNodeType = SurveyNodeType> = Readonly<Partial<{
|
|
117
|
+
[K in TType]: NodeRunner<K, NodeData, NodeValue>;
|
|
118
|
+
}>>;
|
|
119
|
+
declare function defineQuestionNode<const TType extends QuestionNodeType, TData extends NodeData, TValue extends NodeValue>(definition: QuestionNodeDefinition<TType, TData, TValue>): QuestionNodeDefinition<TType, TData, TValue>;
|
|
120
|
+
type RegistryKeySet = Readonly<Partial<Record<SurveyNodeType, unknown>>>;
|
|
121
|
+
declare function defineLogicRegistry<const TRegistry extends RegistryKeySet>(registry: TRegistry): TRegistry;
|
|
122
|
+
declare function defineBuilderRegistry<const TRegistry extends RegistryKeySet>(registry: TRegistry): TRegistry;
|
|
123
|
+
declare function defineRunnerRegistry<const TRegistry extends RegistryKeySet>(registry: TRegistry): TRegistry;
|
|
124
|
+
|
|
125
|
+
type PlainTextData = NodeData & {
|
|
126
|
+
label: string;
|
|
127
|
+
description: string;
|
|
128
|
+
buttonLabel: string;
|
|
129
|
+
condition: {
|
|
130
|
+
id: string;
|
|
131
|
+
type: "group";
|
|
132
|
+
logicType: "AND" | "OR";
|
|
133
|
+
children: JsonValue[];
|
|
134
|
+
};
|
|
135
|
+
};
|
|
136
|
+
type PlainTextValue = {
|
|
137
|
+
viewed: boolean;
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
export { type BuilderRegistry as B, type CompleteLogicRegistry as C, type DataType as D, type ExtractedValue as E, type JsonValue as J, type LogicRegistry as L, type NodeLogic as N, type PlainTextData as P, type QuestionNodeDefinition as Q, type RunnerRegistry as R, type SelectOption as S, type ValidationResult as V, type PlainTextValue as a, type ExtractionContext as b, defineQuestionNode as c, defineLogicRegistry as d, type NodeRunnerProps as e, type CompleteRunnerRegistry as f, type NodeRunner as g, defineRunnerRegistry as h, type NodeBuilderProps as i, type NodeCanvasProps as j, type CompleteBuilderRegistry as k, type NodeBuilder as l, type NodeManifest as m, type PropertyField as n, type PropertyFieldType as o, defineBuilderRegistry as p };
|
package/package.json
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@surveystudio/node-registery",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Typed survey question node registry with split builder, runner, and logic entrypoints.",
|
|
5
|
+
"main": "./dist/logic.mjs",
|
|
6
|
+
"types": "./dist/logic.d.mts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"import": "./dist/logic.mjs",
|
|
10
|
+
"types": "./dist/logic.d.mts"
|
|
11
|
+
},
|
|
12
|
+
"./logic": {
|
|
13
|
+
"import": "./dist/logic.mjs",
|
|
14
|
+
"types": "./dist/logic.d.mts"
|
|
15
|
+
},
|
|
16
|
+
"./runner": {
|
|
17
|
+
"import": "./dist/runner.mjs",
|
|
18
|
+
"types": "./dist/runner.d.mts"
|
|
19
|
+
},
|
|
20
|
+
"./builder": {
|
|
21
|
+
"import": "./dist/builder.mjs",
|
|
22
|
+
"types": "./dist/builder.d.mts"
|
|
23
|
+
},
|
|
24
|
+
"./package.json": "./package.json"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"survey",
|
|
28
|
+
"questionnaire",
|
|
29
|
+
"registry",
|
|
30
|
+
"nodes",
|
|
31
|
+
"react"
|
|
32
|
+
],
|
|
33
|
+
"author": "",
|
|
34
|
+
"license": "ISC",
|
|
35
|
+
"packageManager": "pnpm@10.28.2",
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/node": "^25.2.2",
|
|
38
|
+
"@types/react": "^19.2.13",
|
|
39
|
+
"tsup": "^8.5.1",
|
|
40
|
+
"typescript": "^5.9.3",
|
|
41
|
+
"react": "^19.2.3",
|
|
42
|
+
"react-dom": "^19.2.3"
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"test": "node --test test/*.test.mjs",
|
|
46
|
+
"typecheck": "tsc --noEmit",
|
|
47
|
+
"build": "tsup",
|
|
48
|
+
"prepack": "pnpm build",
|
|
49
|
+
"pack:dry-run": "pnpm pack --dry-run"
|
|
50
|
+
},
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"react": ">=18",
|
|
53
|
+
"react-dom": ">=18"
|
|
54
|
+
},
|
|
55
|
+
"peerDependenciesMeta": {
|
|
56
|
+
"react": {
|
|
57
|
+
"optional": true
|
|
58
|
+
},
|
|
59
|
+
"react-dom": {
|
|
60
|
+
"optional": true
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
"sideEffects": false,
|
|
64
|
+
"files": [
|
|
65
|
+
"dist",
|
|
66
|
+
"README.md"
|
|
67
|
+
],
|
|
68
|
+
"publishConfig": {
|
|
69
|
+
"access": "public"
|
|
70
|
+
}
|
|
71
|
+
}
|