@surveystudio/node-registery 1.1.0 → 1.2.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 CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Typed survey question node registry with separate entrypoints for pure logic, runner UI, and builder UI.
4
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.
5
+ This package is currently in early migration. It exports migrated node logic for server runtimes and selected builder/runner UI adapters while the remaining SurveyChamp question nodes are being moved into the registry.
6
6
 
7
7
  ## Entrypoints
8
8
 
@@ -38,6 +38,12 @@ Migrated nodes:
38
38
  - `dateInput`
39
39
  - `multiInput`
40
40
  - `zipCodeInput`
41
+ - `singleChoice` logic
42
+ - `multipleChoice` logic
43
+ - `dropdown` logic
44
+ - `ranking` logic
45
+ - `rating` logic
46
+ - `slider` logic
41
47
  - `plainText`
42
48
 
43
49
  The registry contract test intentionally fails until all planned question nodes are migrated.
@@ -1,7 +1,7 @@
1
- export { B as BuilderRegistry, C as CompleteBuilderRegistry, N as NodeBuilder, a as NodeBuilderProps, b as NodeCanvasProps, Q as QuestionNodeDefinition, d as defineBuilderRegistry, c as defineQuestionNode } from './types-CgiAR_DF.mjs';
2
- import { J as JsonValue } from './coreTypes-YSpR0Oyh.mjs';
3
- export { N as NodeManifest, P as PropertyField, a as PropertyFieldType, S as SelectOption } from './coreTypes-YSpR0Oyh.mjs';
4
- import { P as PlainTextData, B as BaseTextData, M as MultiInputData, N as NumberInputData, T as TextInputData, Z as ZipCodeInputData } from './types-CjF8-OZi.mjs';
1
+ export { B as BuilderRegistry, C as CompleteBuilderRegistry, N as NodeBuilder, a as NodeBuilderProps, b as NodeCanvasProps, Q as QuestionNodeDefinition, d as defineBuilderRegistry, c as defineQuestionNode } from './types-4zXsOMLb.mjs';
2
+ import { J as JsonValue } from './coreTypes-CyFAym5A.mjs';
3
+ export { N as NodeManifest, P as PropertyField, a as PropertyFieldType, S as SelectOption } from './coreTypes-CyFAym5A.mjs';
4
+ import { P as PlainTextData, B as BaseTextData, M as MultiInputData, N as NumberInputData, T as TextInputData, Z as ZipCodeInputData } from './types-BMnck1ag.mjs';
5
5
  import 'react';
6
6
 
7
7
  declare const plainTextBuilder: {
@@ -82,4 +82,4 @@ type RegistryKeySet = Readonly<Partial<Record<SurveyNodeType, unknown>>>;
82
82
  declare function defineLogicRegistry<const TRegistry extends RegistryKeySet>(registry: TRegistry): TRegistry;
83
83
  declare function createInitialData<TData extends NodeData>(manifest: NodeManifest<SurveyNodeType, TData>): TData;
84
84
 
85
- export { type CompleteLogicRegistry as C, type DataType as D, type ExtractedValue as E, type JsonValue as J, type LogicRegistry as L, type NodeManifest as N, type PropertyField as P, type QuestionNodeType as Q, type SelectOption as S, type ValidationContext as V, type PropertyFieldType as a, type NodeLogic as b, type ExtractionContext as c, type NodeLogicContext as d, type ValidationResult as e, createInitialData as f, defineLogicRegistry as g, type NodeData as h, type SurveyNodeType as i, type NodeValue as j };
85
+ export { type CompleteLogicRegistry as C, type DataType as D, type ExtractedValue as E, type JsonValue as J, type LogicRegistry as L, type NodeManifest as N, type PropertyField as P, type QuestionNodeType as Q, type SelectOption as S, type ValidationContext as V, type PropertyFieldType as a, type NodeData as b, type NodeLogic as c, type ExtractionContext as d, type NodeLogicContext as e, type ValidationResult as f, createInitialData as g, defineLogicRegistry as h, type SurveyNodeType as i, type NodeValue as j };
package/dist/logic.d.mts CHANGED
@@ -1,9 +1,87 @@
1
- import { P as PlainTextData, a as PlainTextValue, D as DateInputData, b as TextValue, E as EmailInputData, M as MultiInputData, c as MultiInputValue, N as NumberInputData, T as TextInputData, Z as ZipCodeInputData, B as BaseTextData } from './types-CjF8-OZi.mjs';
2
- import { b as NodeLogic } from './coreTypes-YSpR0Oyh.mjs';
3
- export { C as CompleteLogicRegistry, D as DataType, E as ExtractedValue, c as ExtractionContext, L as LogicRegistry, d as NodeLogicContext, V as ValidationContext, e as ValidationResult, f as createInitialData, g as defineLogicRegistry } from './coreTypes-YSpR0Oyh.mjs';
1
+ import { P as PlainTextData, a as PlainTextValue, D as DateInputData, b as TextValue, E as EmailInputData, M as MultiInputData, c as MultiInputValue, N as NumberInputData, T as TextInputData, Z as ZipCodeInputData, B as BaseTextData } from './types-BMnck1ag.mjs';
2
+ import { b as NodeData, J as JsonValue, c as NodeLogic } from './coreTypes-CyFAym5A.mjs';
3
+ export { C as CompleteLogicRegistry, D as DataType, E as ExtractedValue, d as ExtractionContext, L as LogicRegistry, e as NodeLogicContext, V as ValidationContext, f as ValidationResult, g as createInitialData, h as defineLogicRegistry } from './coreTypes-CyFAym5A.mjs';
4
+
5
+ type ConditionData$1 = {
6
+ id: string;
7
+ type: "group";
8
+ logicType: "AND" | "OR";
9
+ children: JsonValue[];
10
+ };
11
+ type ScaleItem = NodeData & {
12
+ id?: string;
13
+ exportId?: string;
14
+ technicalId?: string;
15
+ label?: string;
16
+ value?: string;
17
+ };
18
+ type ScaleResponseMode = "single" | "multi";
19
+ type BaseScaleData = NodeData & {
20
+ label: string;
21
+ description: string;
22
+ condition: ConditionData$1;
23
+ responseMode?: ScaleResponseMode;
24
+ items: ScaleItem[];
25
+ };
26
+ type RatingData = BaseScaleData & {
27
+ maxRating: number;
28
+ };
29
+ type SliderData = BaseScaleData & {
30
+ min: number;
31
+ max: number;
32
+ step: number;
33
+ startValue: number;
34
+ };
35
+ type ScaleValue = number | Record<string, number>;
36
+
37
+ type ConditionData = {
38
+ id: string;
39
+ type: "group";
40
+ logicType: "AND" | "OR";
41
+ children: JsonValue[];
42
+ };
43
+ type ChoiceOption = NodeData & {
44
+ id?: string;
45
+ label: string;
46
+ value: string;
47
+ imageUrl?: string;
48
+ };
49
+ type BaseChoiceData = NodeData & {
50
+ label: string;
51
+ description: string;
52
+ condition: ConditionData;
53
+ options: ChoiceOption[];
54
+ randomizeOptions?: boolean;
55
+ };
56
+ type SingleChoiceData = BaseChoiceData & {
57
+ allowOther?: boolean;
58
+ otherLabel?: string;
59
+ };
60
+ type DropdownData = BaseChoiceData & {
61
+ searchable?: boolean;
62
+ };
63
+ type MultipleChoiceData = BaseChoiceData & {
64
+ minChoices?: number;
65
+ maxChoices?: number;
66
+ };
67
+ type RankingData = BaseChoiceData & {
68
+ maxRank?: number;
69
+ displayMode?: "drag" | "select";
70
+ };
71
+ type SingleChoiceValue = string;
72
+ type MultipleChoiceValue = string[];
73
+ type RankingValue = string[];
4
74
 
5
75
  declare const plainTextLogic: NodeLogic<"plainText", PlainTextData, PlainTextValue>;
6
76
 
77
+ declare const ratingLogic: NodeLogic<"rating", RatingData, ScaleValue>;
78
+ declare const sliderLogic: NodeLogic<"slider", SliderData, ScaleValue>;
79
+
80
+ declare const singleChoiceLogic: NodeLogic<"singleChoice", SingleChoiceData, SingleChoiceValue>;
81
+ declare const dropdownLogic: NodeLogic<"dropdown", DropdownData, SingleChoiceValue>;
82
+ declare const multipleChoiceLogic: NodeLogic<"multipleChoice", MultipleChoiceData, MultipleChoiceValue>;
83
+ declare const rankingLogic: NodeLogic<"ranking", RankingData, RankingValue>;
84
+
7
85
  declare const textInputLogic: NodeLogic<"textInput", TextInputData, TextValue>;
8
86
  declare const emailInputLogic: NodeLogic<"emailInput", EmailInputData, TextValue>;
9
87
  declare const dateInputLogic: NodeLogic<"dateInput", DateInputData, TextValue>;
@@ -18,7 +96,13 @@ declare const logicRegistry: {
18
96
  readonly dateInput: NodeLogic<"dateInput", BaseTextData, string>;
19
97
  readonly multiInput: NodeLogic<"multiInput", MultiInputData, MultiInputValue>;
20
98
  readonly zipCodeInput: NodeLogic<"zipCodeInput", ZipCodeInputData, string>;
99
+ readonly singleChoice: NodeLogic<"singleChoice", SingleChoiceData, string>;
100
+ readonly multipleChoice: NodeLogic<"multipleChoice", MultipleChoiceData, MultipleChoiceValue>;
101
+ readonly dropdown: NodeLogic<"dropdown", DropdownData, string>;
102
+ readonly ranking: NodeLogic<"ranking", RankingData, RankingValue>;
103
+ readonly rating: NodeLogic<"rating", RatingData, ScaleValue>;
104
+ readonly slider: NodeLogic<"slider", SliderData, ScaleValue>;
21
105
  readonly plainText: NodeLogic<"plainText", PlainTextData, PlainTextValue>;
22
106
  };
23
107
 
24
- export { NodeLogic, dateInputLogic, emailInputLogic, logicRegistry, multiInputLogic, numberInputLogic, plainTextLogic, textInputLogic, zipCodeInputLogic };
108
+ export { NodeLogic, dateInputLogic, dropdownLogic, emailInputLogic, logicRegistry, multiInputLogic, multipleChoiceLogic, numberInputLogic, plainTextLogic, rankingLogic, ratingLogic, singleChoiceLogic, sliderLogic, textInputLogic, zipCodeInputLogic };
package/dist/logic.mjs CHANGED
@@ -67,30 +67,408 @@ var plainTextLogic = {
67
67
  ]
68
68
  };
69
69
 
70
- // src/nodes/textLike/manifest.ts
70
+ // src/nodes/scale/manifest.ts
71
71
  var defaultCondition = {
72
72
  id: "root",
73
73
  type: "group",
74
74
  logicType: "AND",
75
75
  children: []
76
76
  };
77
- var baseTextData = {
77
+ var baseScaleData = {
78
78
  label: "",
79
79
  description: "",
80
80
  condition: defaultCondition,
81
+ responseMode: "single",
82
+ items: []
83
+ };
84
+ var responseModeProperty = {
85
+ name: "responseMode",
86
+ label: "Response Mode",
87
+ type: "select",
88
+ defaultValue: "single",
89
+ options: [
90
+ { label: "Single Question", value: "single" },
91
+ { label: "Multiple Items", value: "multi" }
92
+ ]
93
+ };
94
+ var commonProperties = [
95
+ responseModeProperty,
96
+ { name: "label", label: "Question Label", type: "text" },
97
+ { name: "description", label: "Description", type: "textarea" },
98
+ {
99
+ name: "condition",
100
+ label: "Logic Rule",
101
+ type: "condition",
102
+ defaultValue: defaultCondition
103
+ },
104
+ { name: "items", label: "Items", type: "options", defaultValue: [] }
105
+ ];
106
+ var ratingDefaultData = {
107
+ ...baseScaleData,
108
+ label: "Rating",
109
+ maxRating: 5
110
+ };
111
+ var sliderDefaultData = {
112
+ ...baseScaleData,
113
+ label: "Slider / Scale",
114
+ min: 0,
115
+ max: 10,
116
+ step: 1,
117
+ startValue: 5
118
+ };
119
+ var ratingManifest = {
120
+ type: "rating",
121
+ label: "Rating",
122
+ description: "Star rating scale",
123
+ category: "choice",
124
+ dataType: "number",
125
+ defaultData: ratingDefaultData,
126
+ properties: [
127
+ ...commonProperties,
128
+ { name: "maxRating", label: "Max Stars", type: "number", defaultValue: 5 }
129
+ ]
130
+ };
131
+ var sliderManifest = {
132
+ type: "slider",
133
+ label: "Slider / Scale",
134
+ description: "Single or multi-item scale",
135
+ category: "choice",
136
+ dataType: "number",
137
+ defaultData: sliderDefaultData,
138
+ properties: [
139
+ ...commonProperties,
140
+ { name: "min", label: "Minimum", type: "number", defaultValue: 0 },
141
+ { name: "max", label: "Maximum", type: "number", defaultValue: 10 },
142
+ { name: "step", label: "Step", type: "number", defaultValue: 1, min: 0 },
143
+ { name: "startValue", label: "Start Value", type: "number", defaultValue: 5 }
144
+ ]
145
+ };
146
+
147
+ // src/nodes/scale/logic.ts
148
+ var isRecord = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
149
+ var numberValue = (value) => {
150
+ const parsed = Number(value);
151
+ return Number.isFinite(parsed) ? parsed : 0;
152
+ };
153
+ var positiveNumber = (value) => {
154
+ const parsed = Number(value);
155
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : 0;
156
+ };
157
+ var itemsFor = (nodeData) => Array.isArray(nodeData.items) ? nodeData.items : [];
158
+ var inferMode = (nodeData) => {
159
+ if (nodeData.responseMode === "single" || nodeData.responseMode === "multi") return nodeData.responseMode;
160
+ return itemsFor(nodeData).length > 0 ? "multi" : "single";
161
+ };
162
+ var itemKey = (item) => item.exportId || item.technicalId || item.value || item.id;
163
+ var itemLabel = (item, fallback) => item.label || fallback;
164
+ var firstItemKey = (nodeData) => {
165
+ const firstItem = itemsFor(nodeData)[0];
166
+ return firstItem ? itemKey(firstItem) : void 0;
167
+ };
168
+ var normalizeScaleValue = (rawValue, nodeData) => {
169
+ const mode = inferMode(nodeData);
170
+ if (mode === "multi") {
171
+ if (isRecord(rawValue)) {
172
+ return Object.fromEntries(Object.entries(rawValue).map(([key2, value]) => [key2, numberValue(value)]));
173
+ }
174
+ const key = firstItemKey(nodeData);
175
+ if (key) return { [key]: numberValue(rawValue) };
176
+ }
177
+ return numberValue(rawValue);
178
+ };
179
+ var validateFiniteScale = (value) => {
180
+ if (typeof value === "number") return Number.isFinite(value) ? { valid: true } : { valid: false, error: "Please enter a valid number" };
181
+ const invalidKey = Object.entries(value).find(([, itemValue]) => !Number.isFinite(itemValue))?.[0];
182
+ return invalidKey ? { valid: false, error: `${invalidKey}: Please enter a valid number` } : { valid: true };
183
+ };
184
+ var validateRatingValue = (value, nodeData) => {
185
+ const finiteResult = validateFiniteScale(value);
186
+ if (!finiteResult.valid) return finiteResult;
187
+ const maxRating = positiveNumber(nodeData.maxRating) || 5;
188
+ const values = typeof value === "number" ? [value] : Object.values(value);
189
+ const outOfRange = values.find((itemValue) => itemValue < 1 || itemValue > maxRating);
190
+ return typeof outOfRange === "number" ? { valid: false, error: `Rating must be between 1 and ${maxRating}` } : { valid: true };
191
+ };
192
+ var validateSliderValue = (value, nodeData) => {
193
+ const finiteResult = validateFiniteScale(value);
194
+ if (!finiteResult.valid) return finiteResult;
195
+ const min = numberValue(nodeData.min);
196
+ const max = Number.isFinite(Number(nodeData.max)) ? Number(nodeData.max) : 10;
197
+ const values = typeof value === "number" ? [value] : Object.values(value);
198
+ const outOfRange = values.find((itemValue) => itemValue < min || itemValue > max);
199
+ return typeof outOfRange === "number" ? { valid: false, error: `Value must be between ${min} and ${max}` } : { valid: true };
200
+ };
201
+ var extractScaleValue = (value, nodeData) => {
202
+ const mode = inferMode(nodeData);
203
+ if (mode === "multi" && isRecord(value)) {
204
+ const items = itemsFor(nodeData);
205
+ return Object.entries(value).map(([key, itemValue]) => {
206
+ const item = items.find((candidate) => itemKey(candidate) === key);
207
+ return {
208
+ columnKey: key,
209
+ columnLabel: item ? itemLabel(item, key) : key,
210
+ numberValue: itemValue,
211
+ textValue: String(itemValue)
212
+ };
213
+ });
214
+ }
215
+ const scalarValue = typeof value === "number" ? value : 0;
216
+ return [{ numberValue: scalarValue, textValue: String(scalarValue) }];
217
+ };
218
+ var ratingLogic = {
219
+ type: "rating",
220
+ dataType: "number",
221
+ defaultData: ratingDefaultData,
222
+ defaultValue: 0,
223
+ normalizeValue: normalizeScaleValue,
224
+ validate: validateRatingValue,
225
+ extractValue: extractScaleValue
226
+ };
227
+ var sliderLogic = {
228
+ type: "slider",
229
+ dataType: "number",
230
+ defaultData: sliderDefaultData,
231
+ defaultValue: 0,
232
+ normalizeValue: normalizeScaleValue,
233
+ validate: validateSliderValue,
234
+ extractValue: extractScaleValue
235
+ };
236
+
237
+ // src/nodes/choice/manifest.ts
238
+ var defaultCondition2 = {
239
+ id: "root",
240
+ type: "group",
241
+ logicType: "AND",
242
+ children: []
243
+ };
244
+ var baseChoiceData = {
245
+ label: "",
246
+ description: "",
247
+ condition: defaultCondition2,
248
+ options: [],
249
+ randomizeOptions: false
250
+ };
251
+ var commonProperties2 = [
252
+ { name: "label", label: "Question Label", type: "text" },
253
+ { name: "description", label: "Description", type: "textarea" },
254
+ {
255
+ name: "condition",
256
+ label: "Logic Rule",
257
+ type: "condition",
258
+ defaultValue: defaultCondition2
259
+ },
260
+ { name: "options", label: "Options", type: "options", defaultValue: [] },
261
+ { name: "bulkOptions", label: "Bulk Add (one per line)", type: "textarea", placeholder: "Option A\nOption B\nOption C..." }
262
+ ];
263
+ var singleChoiceDefaultData = {
264
+ ...baseChoiceData,
265
+ label: "Single Choice",
266
+ allowOther: false,
267
+ otherLabel: "Other"
268
+ };
269
+ var dropdownDefaultData = {
270
+ ...baseChoiceData,
271
+ label: "Dropdown",
272
+ searchable: true
273
+ };
274
+ var multipleChoiceDefaultData = {
275
+ ...baseChoiceData,
276
+ label: "Multiple Choice",
277
+ minChoices: 0,
278
+ maxChoices: 0
279
+ };
280
+ var rankingDefaultData = {
281
+ ...baseChoiceData,
282
+ label: "Ranking",
283
+ maxRank: 0,
284
+ displayMode: "drag"
285
+ };
286
+ var singleChoiceManifest = {
287
+ type: "singleChoice",
288
+ label: "Single Choice",
289
+ description: "Select one option",
290
+ category: "choice",
291
+ dataType: "option",
292
+ defaultData: singleChoiceDefaultData,
293
+ properties: [
294
+ ...commonProperties2,
295
+ { name: "allowOther", label: "Allow Other", type: "switch", defaultValue: false },
296
+ { name: "otherLabel", label: "Other Label", type: "text", defaultValue: "Other" },
297
+ { name: "randomizeOptions", label: "Randomize Options", type: "switch", defaultValue: false }
298
+ ]
299
+ };
300
+ var dropdownManifest = {
301
+ type: "dropdown",
302
+ label: "Dropdown",
303
+ description: "Select from a dropdown menu",
304
+ category: "choice",
305
+ dataType: "option",
306
+ defaultData: dropdownDefaultData,
307
+ properties: [
308
+ ...commonProperties2,
309
+ { name: "searchable", label: "Searchable", type: "switch", defaultValue: true }
310
+ ]
311
+ };
312
+ var multipleChoiceManifest = {
313
+ type: "multipleChoice",
314
+ label: "Multiple Choice",
315
+ description: "Select multiple options",
316
+ category: "choice",
317
+ dataType: "array",
318
+ defaultData: multipleChoiceDefaultData,
319
+ properties: [
320
+ ...commonProperties2,
321
+ { name: "minChoices", label: "Minimum Choices", type: "number", defaultValue: 0 },
322
+ { name: "maxChoices", label: "Maximum Choices", type: "number", defaultValue: 0 },
323
+ { name: "randomizeOptions", label: "Randomize Options", type: "switch", defaultValue: false }
324
+ ]
325
+ };
326
+ var rankingManifest = {
327
+ type: "ranking",
328
+ label: "Ranking",
329
+ description: "Rank options in order",
330
+ category: "choice",
331
+ dataType: "array",
332
+ defaultData: rankingDefaultData,
333
+ properties: [
334
+ ...commonProperties2,
335
+ { name: "maxRank", label: "Maximum Rank", type: "number", defaultValue: 0 },
336
+ {
337
+ name: "displayMode",
338
+ label: "Display Mode",
339
+ type: "select",
340
+ defaultValue: "drag",
341
+ options: [
342
+ { label: "Drag and Drop", value: "drag" },
343
+ { label: "Dropdown Selection", value: "select" }
344
+ ]
345
+ }
346
+ ]
347
+ };
348
+
349
+ // src/nodes/choice/logic.ts
350
+ var normalizeChoiceValue = (value) => {
351
+ if (typeof value === "string") return value;
352
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
353
+ return "";
354
+ };
355
+ var normalizeChoiceArray = (value) => {
356
+ if (!Array.isArray(value)) return [];
357
+ return value.map(normalizeChoiceValue).filter(Boolean);
358
+ };
359
+ var positiveNumber2 = (value) => {
360
+ const parsed = Number(value);
361
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : 0;
362
+ };
363
+ var optionsFor = (nodeData) => Array.isArray(nodeData.options) ? nodeData.options : [];
364
+ var optionForValue = (nodeData, value) => optionsFor(nodeData).find((option) => option.value === value || option.id === value);
365
+ var optionLabel = (nodeData, value) => optionForValue(nodeData, value)?.label || value;
366
+ var optionUuid = (nodeData, value) => optionForValue(nodeData, value)?.value || value;
367
+ var validateOptionExists = (value, nodeData) => {
368
+ if (!value) return { valid: true };
369
+ if (optionsFor(nodeData).length === 0) return { valid: true };
370
+ return optionForValue(nodeData, value) ? { valid: true } : { valid: false, error: "Selected option is not available" };
371
+ };
372
+ var validateOptionArray = (value, nodeData) => {
373
+ if (optionsFor(nodeData).length === 0) return { valid: true };
374
+ const invalid = value.find((item) => !optionForValue(nodeData, item));
375
+ return invalid ? { valid: false, error: "Selected option is not available" } : { valid: true };
376
+ };
377
+ var extractSingleChoiceValue = (value, nodeData) => [
378
+ {
379
+ optionUuid: optionUuid(nodeData, value),
380
+ optionText: optionLabel(nodeData, value),
381
+ textValue: optionLabel(nodeData, value)
382
+ }
383
+ ];
384
+ var singleChoiceLogic = {
385
+ type: "singleChoice",
386
+ dataType: "option",
387
+ defaultData: singleChoiceDefaultData,
388
+ defaultValue: "",
389
+ normalizeValue: normalizeChoiceValue,
390
+ validate: validateOptionExists,
391
+ extractValue: extractSingleChoiceValue
392
+ };
393
+ var dropdownLogic = {
394
+ type: "dropdown",
395
+ dataType: "option",
396
+ defaultData: dropdownDefaultData,
397
+ defaultValue: "",
398
+ normalizeValue: normalizeChoiceValue,
399
+ validate: validateOptionExists,
400
+ extractValue: extractSingleChoiceValue
401
+ };
402
+ var multipleChoiceLogic = {
403
+ type: "multipleChoice",
404
+ dataType: "array",
405
+ defaultData: multipleChoiceDefaultData,
406
+ defaultValue: [],
407
+ normalizeValue: normalizeChoiceArray,
408
+ validate: (value, nodeData) => {
409
+ const optionResult = validateOptionArray(value, nodeData);
410
+ if (!optionResult.valid) return optionResult;
411
+ const minChoices = positiveNumber2(nodeData.minChoices);
412
+ const maxChoices = positiveNumber2(nodeData.maxChoices);
413
+ if (minChoices && value.length < minChoices) return { valid: false, error: `Select at least ${minChoices} option(s)` };
414
+ if (maxChoices && value.length > maxChoices) return { valid: false, error: `Select at most ${maxChoices} option(s)` };
415
+ return { valid: true };
416
+ },
417
+ extractValue: (value, nodeData) => value.map((item) => ({
418
+ optionUuid: optionUuid(nodeData, item),
419
+ optionText: optionLabel(nodeData, item),
420
+ textValue: optionLabel(nodeData, item)
421
+ }))
422
+ };
423
+ var rankingLogic = {
424
+ type: "ranking",
425
+ dataType: "array",
426
+ defaultData: rankingDefaultData,
427
+ defaultValue: [],
428
+ normalizeValue: normalizeChoiceArray,
429
+ validate: (value, nodeData) => {
430
+ const optionResult = validateOptionArray(value, nodeData);
431
+ if (!optionResult.valid) return optionResult;
432
+ const maxRank = positiveNumber2(nodeData.maxRank);
433
+ if (maxRank && value.length > maxRank) return { valid: false, error: `Rank at most ${maxRank} option(s)` };
434
+ return { valid: true };
435
+ },
436
+ extractValue: (value, nodeData) => value.map((item, index) => {
437
+ const rank = index + 1;
438
+ const label = optionLabel(nodeData, item);
439
+ return {
440
+ optionUuid: optionUuid(nodeData, item),
441
+ optionText: label,
442
+ numberValue: rank,
443
+ textValue: `${rank}. ${label}`
444
+ };
445
+ })
446
+ };
447
+
448
+ // src/nodes/textLike/manifest.ts
449
+ var defaultCondition3 = {
450
+ id: "root",
451
+ type: "group",
452
+ logicType: "AND",
453
+ children: []
454
+ };
455
+ var baseTextData = {
456
+ label: "",
457
+ description: "",
458
+ condition: defaultCondition3,
81
459
  minChars: 0,
82
460
  maxChars: 0,
83
461
  minWords: 0,
84
462
  maxWords: 0
85
463
  };
86
- var commonProperties = [
464
+ var commonProperties3 = [
87
465
  { name: "label", label: "Field Label", type: "text" },
88
466
  { name: "description", label: "Description", type: "textarea" },
89
467
  {
90
468
  name: "condition",
91
469
  label: "Logic Rule",
92
470
  type: "condition",
93
- defaultValue: defaultCondition
471
+ defaultValue: defaultCondition3
94
472
  }
95
473
  ];
96
474
  var textLimitProperties = [
@@ -129,7 +507,7 @@ var textInputManifest = {
129
507
  dataType: "text",
130
508
  defaultData: textInputDefaultData,
131
509
  properties: [
132
- ...commonProperties,
510
+ ...commonProperties3,
133
511
  { name: "placeholder", label: "Placeholder", type: "text", placeholder: "e.g., Type here...", defaultValue: "" },
134
512
  { name: "longAnswer", label: "Long Answer (Multi-line)", type: "switch", defaultValue: false },
135
513
  ...textLimitProperties
@@ -143,7 +521,7 @@ var numberInputManifest = {
143
521
  dataType: "number",
144
522
  defaultData: numberInputDefaultData,
145
523
  properties: [
146
- ...commonProperties,
524
+ ...commonProperties3,
147
525
  { name: "min", label: "Minimum Value", type: "number" },
148
526
  { name: "max", label: "Maximum Value", type: "number" }
149
527
  ]
@@ -156,7 +534,7 @@ var zipCodeInputManifest = {
156
534
  dataType: "text",
157
535
  defaultData: zipCodeInputDefaultData,
158
536
  properties: [
159
- ...commonProperties,
537
+ ...commonProperties3,
160
538
  { name: "allowedZips", label: "Allowed Zip Codes", type: "fileTextarea", placeholder: "10001, 10002, 90210... (Leave empty to allow all)", helperText: "Validation: Only users entering these zip codes can proceed. Others will be blocked." }
161
539
  ]
162
540
  };
@@ -168,7 +546,7 @@ var multiInputManifest = {
168
546
  dataType: "object",
169
547
  defaultData: multiInputDefaultData,
170
548
  properties: [
171
- ...commonProperties,
549
+ ...commonProperties3,
172
550
  { name: "fields", label: "Input Fields", type: "options", defaultValue: [], helperText: "Value column represents input type (text, number, email)" },
173
551
  ...textLimitProperties
174
552
  ]
@@ -261,12 +639,12 @@ var numberInputLogic = {
261
639
  const limitResult = validateTextLimits(value, nodeData);
262
640
  if (!limitResult.valid) return limitResult;
263
641
  if (!value.trim()) return { valid: true };
264
- const numberValue = Number(value);
265
- if (Number.isNaN(numberValue)) return { valid: false, error: "Please enter a valid number" };
266
- if (typeof nodeData.min === "number" && numberValue < nodeData.min) {
642
+ const numberValue2 = Number(value);
643
+ if (Number.isNaN(numberValue2)) return { valid: false, error: "Please enter a valid number" };
644
+ if (typeof nodeData.min === "number" && numberValue2 < nodeData.min) {
267
645
  return { valid: false, error: `Minimum value is ${nodeData.min}` };
268
646
  }
269
- if (typeof nodeData.max === "number" && numberValue > nodeData.max) {
647
+ if (typeof nodeData.max === "number" && numberValue2 > nodeData.max) {
270
648
  return { valid: false, error: `Maximum value is ${nodeData.max}` };
271
649
  }
272
650
  return { valid: true };
@@ -337,17 +715,29 @@ var logicRegistry = defineLogicRegistry({
337
715
  dateInput: dateInputLogic,
338
716
  multiInput: multiInputLogic,
339
717
  zipCodeInput: zipCodeInputLogic,
718
+ singleChoice: singleChoiceLogic,
719
+ multipleChoice: multipleChoiceLogic,
720
+ dropdown: dropdownLogic,
721
+ ranking: rankingLogic,
722
+ rating: ratingLogic,
723
+ slider: sliderLogic,
340
724
  plainText: plainTextLogic
341
725
  });
342
726
  export {
343
727
  createInitialData,
344
728
  dateInputLogic,
345
729
  defineLogicRegistry,
730
+ dropdownLogic,
346
731
  emailInputLogic,
347
732
  logicRegistry,
348
733
  multiInputLogic,
734
+ multipleChoiceLogic,
349
735
  numberInputLogic,
350
736
  plainTextLogic,
737
+ rankingLogic,
738
+ ratingLogic,
739
+ singleChoiceLogic,
740
+ sliderLogic,
351
741
  textInputLogic,
352
742
  zipCodeInputLogic
353
743
  };
package/dist/runner.d.mts CHANGED
@@ -1,6 +1,6 @@
1
- export { e as CompleteRunnerRegistry, f as NodeRunner, g as NodeRunnerProps, Q as QuestionNodeDefinition, R as RunnerRegistry, c as defineQuestionNode, h as defineRunnerRegistry } from './types-CgiAR_DF.mjs';
1
+ export { e as CompleteRunnerRegistry, f as NodeRunner, g as NodeRunnerProps, Q as QuestionNodeDefinition, R as RunnerRegistry, c as defineQuestionNode, h as defineRunnerRegistry } from './types-4zXsOMLb.mjs';
2
2
  import 'react';
3
- import './coreTypes-YSpR0Oyh.mjs';
3
+ import './coreTypes-CyFAym5A.mjs';
4
4
 
5
5
  declare const plainTextRunner: {
6
6
  type: "plainText";
@@ -1,5 +1,5 @@
1
1
  import { ReactNode, ComponentType } from 'react';
2
- import { i as SurveyNodeType, h as NodeData, Q as QuestionNodeType, j as NodeValue, N as NodeManifest, b as NodeLogic } from './coreTypes-YSpR0Oyh.mjs';
2
+ import { i as SurveyNodeType, b as NodeData, Q as QuestionNodeType, j as NodeValue, N as NodeManifest, c as NodeLogic } from './coreTypes-CyFAym5A.mjs';
3
3
 
4
4
  interface NodeRunnerProps<TData extends NodeData = NodeData, TValue extends NodeValue = NodeValue> {
5
5
  readonly data: Readonly<TData>;
@@ -1,4 +1,4 @@
1
- import { h as NodeData, J as JsonValue } from './coreTypes-YSpR0Oyh.mjs';
1
+ import { b as NodeData, J as JsonValue } from './coreTypes-CyFAym5A.mjs';
2
2
 
3
3
  type PlainTextData = NodeData & {
4
4
  label: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@surveystudio/node-registery",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Typed survey question node registry with split builder, runner, and logic entrypoints.",
5
5
  "main": "./dist/logic.mjs",
6
6
  "types": "./dist/logic.d.mts",