@qoretechnologies/reqraft 0.10.10 → 0.10.12

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.
Files changed (41) hide show
  1. package/dist/providers/StorageProvider.d.ts.map +1 -1
  2. package/dist/providers/StorageProvider.js +14 -4
  3. package/dist/providers/StorageProvider.js.map +1 -1
  4. package/package.json +1 -1
  5. package/src/components/dpqlEditor/DpqlEditor.stories.tsx +74 -2
  6. package/src/components/form/engine/FormEngine.stories.tsx +654 -32
  7. package/src/components/form/engine/FormEngineRemote.stories.tsx +48 -0
  8. package/src/components/form/engine/_structuredData/StructuredDataView.stories.tsx +8 -0
  9. package/src/components/form/engine/variants/FormEngineVariants.stories.tsx +40 -0
  10. package/src/components/form/expressions/ExpressionField.stories.tsx +74 -2
  11. package/src/components/form/expressions/builder/ExpressionBuilder.stories.tsx +187 -0
  12. package/src/components/form/fields/Field.stories.tsx +40 -0
  13. package/src/components/form/fields/array/ArrayAutoField.stories.tsx +64 -0
  14. package/src/components/form/fields/auto/AutoFormField.stories.tsx +136 -0
  15. package/src/components/form/fields/binary/Binary.stories.tsx +32 -0
  16. package/src/components/form/fields/boolean/Boolean.stories.tsx +24 -0
  17. package/src/components/form/fields/byte-size/ByteSize.stories.tsx +24 -0
  18. package/src/components/form/fields/color/Color.stories.tsx +30 -0
  19. package/src/components/form/fields/cron/Cron.stories.tsx +8 -0
  20. package/src/components/form/fields/date/Date.stories.tsx +22 -0
  21. package/src/components/form/fields/file/File.stories.tsx +48 -0
  22. package/src/components/form/fields/long-string/LongString.stories.tsx +24 -0
  23. package/src/components/form/fields/markdown/Markdown.stories.tsx +8 -0
  24. package/src/components/form/fields/number/Number.stories.tsx +31 -0
  25. package/src/components/form/fields/object/Object.stories.tsx +88 -0
  26. package/src/components/form/fields/radio-group/RadioGroup.stories.tsx +24 -0
  27. package/src/components/form/fields/rich-text/RichText.stories.tsx +23 -0
  28. package/src/components/form/fields/schema-definition/SchemaDefinitionField.stories.tsx +72 -0
  29. package/src/components/form/fields/select/Select.stories.tsx +104 -0
  30. package/src/components/form/fields/string/String.stories.tsx +16 -0
  31. package/src/components/form/fields/template/TemplateField.stories.tsx +160 -0
  32. package/src/components/form/fields/url/Url.stories.tsx +24 -0
  33. package/src/components/log/Log.stories.tsx +96 -0
  34. package/src/components/menu/Menu.stories.tsx +54 -0
  35. package/src/components/qonsoleSmartInput/QonsoleSmartInput.stories.tsx +14 -0
  36. package/src/components/smartEditor/SmartEditor.stories.tsx +32 -0
  37. package/src/hooks/useFetch/useFetch.stories.tsx +30 -0
  38. package/src/hooks/useStorage/useStorage.stories.tsx +82 -0
  39. package/src/hooks/useWebSocket/useWebsocket.stories.tsx +127 -1
  40. package/src/providers/StorageProvider.tsx +12 -4
  41. package/src/stores/currentUser/currentUser.stories.tsx +17 -0
@@ -40,6 +40,14 @@ export const SoftInteger: Story = {
40
40
  type: 'softint',
41
41
  value: 5,
42
42
  },
43
+ parameters: {
44
+ docs: {
45
+ description: {
46
+ story:
47
+ 'Renders FormField for a softint value — the dispatcher resolves the soft type to int and mounts the numeric input.',
48
+ },
49
+ },
50
+ },
43
51
  async play({ canvasElement }) {
44
52
  // NumberFormField renders an input (a `softint` resolves to `int`).
45
53
  await expect(canvasElement.querySelector('input')).toBeInTheDocument();
@@ -52,6 +60,14 @@ export const Binary: Story = {
52
60
  type: 'binary',
53
61
  value: 'deadbeef',
54
62
  },
63
+ parameters: {
64
+ docs: {
65
+ description: {
66
+ story:
67
+ 'Renders FormField for a binary value — the dispatcher mounts a textarea holding the encoded content.',
68
+ },
69
+ },
70
+ },
55
71
  async play({ canvasElement }) {
56
72
  await expect(canvasElement.querySelector('textarea')).toBeInTheDocument();
57
73
  },
@@ -63,6 +79,14 @@ export const ByteSize: Story = {
63
79
  type: 'byte-size',
64
80
  value: '512MiB',
65
81
  },
82
+ parameters: {
83
+ docs: {
84
+ description: {
85
+ story:
86
+ 'Renders FormField for a byte-size value — the dispatcher mounts the amount input and the MiB unit selector, split from "512MiB".',
87
+ },
88
+ },
89
+ },
66
90
  async play({ canvasElement }) {
67
91
  const canvas = within(canvasElement);
68
92
  await expect(canvas.getByDisplayValue('512')).toBeInTheDocument();
@@ -76,6 +100,14 @@ export const Url: Story = {
76
100
  type: 'url',
77
101
  value: 'https://example.com',
78
102
  },
103
+ parameters: {
104
+ docs: {
105
+ description: {
106
+ story:
107
+ 'Renders FormField for a url value — the dispatcher mounts the https protocol selector and the example.com address input, split from "https://example.com".',
108
+ },
109
+ },
110
+ },
79
111
  async play({ canvasElement }) {
80
112
  const canvas = within(canvasElement);
81
113
  await expect(await canvas.findByDisplayValue('example.com')).toBeInTheDocument();
@@ -94,6 +126,14 @@ export const MultiSelect: Story = {
94
126
  ],
95
127
  value: ['red', 'blue'],
96
128
  },
129
+ parameters: {
130
+ docs: {
131
+ description: {
132
+ story:
133
+ 'Renders FormField for a multi-select value — the two picked values (Red and Blue) render as chips using their display_name labels.',
134
+ },
135
+ },
136
+ },
97
137
  async play({ canvasElement }) {
98
138
  const canvas = within(canvasElement);
99
139
  // The two selected values render as chips (by their display_name).
@@ -83,6 +83,14 @@ export const CompactEmpty: Story = {
83
83
  type: 'string',
84
84
  value: [],
85
85
  },
86
+ parameters: {
87
+ docs: {
88
+ description: {
89
+ story:
90
+ 'Renders ArrayAutoField in compact string mode with no items — only the entry input and a disabled confirm button are visible.',
91
+ },
92
+ },
93
+ },
86
94
  async play({ canvasElement }) {
87
95
  const canvas = within(canvasElement);
88
96
 
@@ -102,6 +110,14 @@ export const CompactWithValues: Story = {
102
110
  type: 'string',
103
111
  value: ['hello', 'world'],
104
112
  },
113
+ parameters: {
114
+ docs: {
115
+ description: {
116
+ story:
117
+ 'Renders ArrayAutoField in compact string mode with two existing items — the values are shown as tags above the entry input.',
118
+ },
119
+ },
120
+ },
105
121
  async play({ canvasElement }) {
106
122
  const canvas = within(canvasElement);
107
123
 
@@ -122,6 +138,14 @@ export const CompactAddItem: Story = {
122
138
  type: 'string',
123
139
  value: ['existing'],
124
140
  },
141
+ parameters: {
142
+ docs: {
143
+ description: {
144
+ story:
145
+ 'Renders ArrayAutoField in compact string mode with one existing item. Typing into the input and clicking confirm appends the new item and fires onChange with the full list.',
146
+ },
147
+ },
148
+ },
125
149
  async play({ args }) {
126
150
  await waitFor(
127
151
  () => expect(document.querySelectorAll('.array-auto-compact-tag').length).toBe(1),
@@ -157,6 +181,14 @@ export const CompactEditItem: Story = {
157
181
  type: 'string',
158
182
  value: ['alpha', 'beta'],
159
183
  },
184
+ parameters: {
185
+ docs: {
186
+ description: {
187
+ story:
188
+ 'Renders ArrayAutoField in compact string mode with two items. Clicking a tag\'s edit action loads its value into the input; editing and confirming replaces the tag in place.',
189
+ },
190
+ },
191
+ },
160
192
  async play({ args }) {
161
193
  await waitFor(
162
194
  () => expect(document.querySelectorAll('.array-auto-compact-tag').length).toBe(2),
@@ -199,6 +231,14 @@ export const CompactRemoveItem: Story = {
199
231
  type: 'string',
200
232
  value: ['one', 'two', 'three'],
201
233
  },
234
+ parameters: {
235
+ docs: {
236
+ description: {
237
+ story:
238
+ 'Renders ArrayAutoField in compact string mode with three items. Clicking the middle tag\'s remove action drops it from the list and fires onChange with the remaining two.',
239
+ },
240
+ },
241
+ },
202
242
  async play({ args }) {
203
243
  await waitFor(
204
244
  () => expect(document.querySelectorAll('.array-auto-compact-tag').length).toBe(3),
@@ -230,6 +270,14 @@ export const CompactWithNumbers: Story = {
230
270
  value: [10, 20, 30],
231
271
  renderItem: numberRenderItem,
232
272
  },
273
+ parameters: {
274
+ docs: {
275
+ description: {
276
+ story:
277
+ 'Renders ArrayAutoField in compact int mode with three numeric items — the tags show 10, 20 and 30 and the entry input uses the Number field.',
278
+ },
279
+ },
280
+ },
233
281
  async play() {
234
282
  await waitFor(
235
283
  () => expect(document.querySelectorAll('.array-auto-compact-tag').length).toBe(3),
@@ -244,6 +292,14 @@ export const CompactDisabled: Story = {
244
292
  value: ['locked'],
245
293
  disabled: true,
246
294
  },
295
+ parameters: {
296
+ docs: {
297
+ description: {
298
+ story:
299
+ 'Renders ArrayAutoField in compact string mode with one item but disabled — the tag is visible without edit/remove actions and no entry input is shown.',
300
+ },
301
+ },
302
+ },
247
303
  async play() {
248
304
  await waitFor(
249
305
  () => expect(document.querySelectorAll('.array-auto-compact-tag').length).toBe(1),
@@ -267,6 +323,14 @@ export const ComplexHashItems: Story = {
267
323
  value: [{ key: 'value' }],
268
324
  display_name: 'Hash Items',
269
325
  },
326
+ parameters: {
327
+ docs: {
328
+ description: {
329
+ story:
330
+ 'Renders ArrayAutoField in hash mode with one hash item — the field switches to the panel-based layout rather than compact tags.',
331
+ },
332
+ },
333
+ },
270
334
  async play() {
271
335
  // Should render panel-based UI, not compact tags
272
336
  await waitFor(() => expect(document.querySelectorAll('.array-auto-item').length).toBe(1), {
@@ -57,6 +57,14 @@ const waitForText = async (text: string | RegExp) => {
57
57
  /** Auto type, no value — the picker is shown and the field area prompts for a type. */
58
58
  export const Empty: Story = {
59
59
  args: {},
60
+ parameters: {
61
+ docs: {
62
+ description: {
63
+ story:
64
+ 'Renders AutoFormField with no value or defaultType — the type picker is shown and the field area prompts the operator to pick a data type.',
65
+ },
66
+ },
67
+ },
60
68
  async play({ canvasElement }) {
61
69
  const canvas = within(canvasElement);
62
70
  // The IDE auto resolves its type in a mount effect — assert asynchronously.
@@ -71,6 +79,14 @@ export const InferredInteger: Story = {
71
79
  args: {
72
80
  value: 42,
73
81
  },
82
+ parameters: {
83
+ docs: {
84
+ description: {
85
+ story:
86
+ 'Renders AutoFormField with a pre-existing numeric value of 42 — the type is inferred as int and the numeric input is shown without prompting for a type.',
87
+ },
88
+ },
89
+ },
74
90
  async play({ canvasElement }) {
75
91
  const canvas = within(canvasElement);
76
92
  // Resolved → a concrete field renders (post mount effect) and no prompt.
@@ -86,6 +102,14 @@ export const InferredText: Story = {
86
102
  args: {
87
103
  value: 'hello world',
88
104
  },
105
+ parameters: {
106
+ docs: {
107
+ description: {
108
+ story:
109
+ 'Renders AutoFormField with a pre-existing string value — the type is inferred as string and the text field is shown holding "hello world".',
110
+ },
111
+ },
112
+ },
89
113
  async play({ canvasElement }) {
90
114
  const canvas = within(canvasElement);
91
115
  await expect(await canvas.findByDisplayValue('hello world')).toBeInTheDocument();
@@ -97,6 +121,14 @@ export const ConcreteString: Story = {
97
121
  args: {
98
122
  defaultType: 'string',
99
123
  },
124
+ parameters: {
125
+ docs: {
126
+ description: {
127
+ story:
128
+ 'Renders AutoFormField with a concrete defaultType of string — the text field is shown directly, no type picker. Typing "abc" fires onChange with the value and inferred type.',
129
+ },
130
+ },
131
+ },
100
132
  async play({ canvasElement, args }) {
101
133
  const canvas = within(canvasElement);
102
134
  // string renders the IDE's LongString field — a textarea. The verbatim
@@ -121,6 +153,14 @@ export const Nullable: Story = {
121
153
  value: 'some text',
122
154
  canBeNull: true,
123
155
  },
156
+ parameters: {
157
+ docs: {
158
+ description: {
159
+ story:
160
+ 'Renders AutoFormField with canBeNull enabled. Clicking "Set as null" clears the value to null, hides the field editor and flips the toggle to "Unset null".',
161
+ },
162
+ },
163
+ },
124
164
  async play({ canvasElement, args }) {
125
165
  const canvas = within(canvasElement);
126
166
 
@@ -147,6 +187,14 @@ export const AllowedTypesSubset: Story = {
147
187
  { name: 'string', display_name: 'Text' },
148
188
  ],
149
189
  },
190
+ parameters: {
191
+ docs: {
192
+ description: {
193
+ story:
194
+ 'Renders AutoFormField with allowedTypes restricted to Integer and Text — the picker badge shows 2 available types instead of the full 14.',
195
+ },
196
+ },
197
+ },
150
198
  async play() {
151
199
  // The picker badge reflects the restricted list — 2 instead of 14.
152
200
  await waitForText('Please select data type');
@@ -159,6 +207,14 @@ export const NoSoftTypes: Story = {
159
207
  args: {
160
208
  noSoft: true,
161
209
  },
210
+ parameters: {
211
+ docs: {
212
+ description: {
213
+ story:
214
+ 'Renders AutoFormField with noSoft enabled — the soft* type variants are hidden and the picker badge reads 9 instead of 14.',
215
+ },
216
+ },
217
+ },
162
218
  async play() {
163
219
  await waitForText('Please select data type');
164
220
  await waitForText('9');
@@ -170,6 +226,14 @@ export const NoSoftTypes: Story = {
170
226
  * `auto` renders the picker for free, via FormEngine → TemplateField → auto.
171
227
  */
172
228
  export const ViaFormEngine: Story = {
229
+ parameters: {
230
+ docs: {
231
+ description: {
232
+ story:
233
+ 'Renders a FormEngine schema whose single option is typed as auto — the engine flows through TemplateField and renders the AutoFormField picker without any extra wiring.',
234
+ },
235
+ },
236
+ },
173
237
  render: () => {
174
238
  const [val, setVal] = useState<any>({});
175
239
  return (
@@ -222,6 +286,14 @@ export const StringWithAllowedValues: Story = {
222
286
  },
223
287
  ],
224
288
  },
289
+ parameters: {
290
+ docs: {
291
+ description: {
292
+ story:
293
+ 'Renders AutoFormField for a string with two allowed values — the operator picks from the constrained list rather than typing freely.',
294
+ },
295
+ },
296
+ },
225
297
  };
226
298
 
227
299
  export const RichText: Story = {
@@ -231,6 +303,14 @@ export const RichText: Story = {
231
303
  allowTemplates: true,
232
304
  templates: buildTemplates(templates as any),
233
305
  },
306
+ parameters: {
307
+ docs: {
308
+ description: {
309
+ story:
310
+ 'Renders AutoFormField in richtext mode with templates enabled. Typing appends to the existing value inside the contenteditable editor.',
311
+ },
312
+ },
313
+ },
234
314
  play: async ({ canvasElement }) => {
235
315
  await waitFor(() => canvasElement.querySelector('div[contenteditable]'), {
236
316
  timeout: 15000,
@@ -264,6 +344,14 @@ export const ConnectionWithAllowedValues: Story = {
264
344
  },
265
345
  ],
266
346
  },
347
+ parameters: {
348
+ docs: {
349
+ description: {
350
+ story:
351
+ 'Renders AutoFormField for a connection with two allowed values — clicking "Please select" opens the item picker modal titled "Select from items".',
352
+ },
353
+ },
354
+ },
267
355
  play: async () => {
268
356
  // connection is a no-compact type → the allowed values render as the
269
357
  // select with the item collection (the IDE asserts the same modal title).
@@ -277,6 +365,14 @@ export const Hash: Story = {
277
365
  args: {
278
366
  value: jsyaml.dump({ key: 'value' }),
279
367
  },
368
+ parameters: {
369
+ docs: {
370
+ description: {
371
+ story:
372
+ 'Renders AutoFormField with a YAML-serialized hash value — the type is inferred as hash and the object editor is shown holding the parsed data.',
373
+ },
374
+ },
375
+ },
280
376
  };
281
377
 
282
378
  export const File: Story = {
@@ -288,6 +384,14 @@ export const File: Story = {
288
384
  size: 1234,
289
385
  },
290
386
  },
387
+ parameters: {
388
+ docs: {
389
+ description: {
390
+ story:
391
+ 'Renders AutoFormField in file mode holding a text-file value — the file field shows the file name in place of the drop zone.',
392
+ },
393
+ },
394
+ },
291
395
  };
292
396
 
293
397
  export const AutoDoesNotChangeTypeBackToAuto: Story = {
@@ -295,6 +399,14 @@ export const AutoDoesNotChangeTypeBackToAuto: Story = {
295
399
  defaultType: 'auto',
296
400
  value: 'test',
297
401
  },
402
+ parameters: {
403
+ docs: {
404
+ description: {
405
+ story:
406
+ 'Renders AutoFormField in auto mode with a string value — the inferred type ("string") is shown and the picker still exposes all 14 types so the operator can switch away from auto without the field snapping back.',
407
+ },
408
+ },
409
+ },
298
410
  play: async () => {
299
411
  await waitForText('string');
300
412
  await waitForText('14');
@@ -317,6 +429,14 @@ export const ListWithAllowedValues: Story = {
317
429
  },
318
430
  ],
319
431
  },
432
+ parameters: {
433
+ docs: {
434
+ description: {
435
+ story:
436
+ 'Renders AutoFormField in list mode restricted to two allowed list values — the operator picks one of the pre-defined lists rather than composing their own.',
437
+ },
438
+ },
439
+ },
320
440
  };
321
441
 
322
442
  export const ListWithCreatableAllowedValues: Story = {
@@ -337,6 +457,14 @@ export const ListWithCreatableAllowedValues: Story = {
337
457
  },
338
458
  ],
339
459
  },
460
+ parameters: {
461
+ docs: {
462
+ description: {
463
+ story:
464
+ 'Renders AutoFormField in list mode with two allowed values but with allowed_values_creatable enabled — the operator can pick a canned list or compose a custom one.',
465
+ },
466
+ },
467
+ },
340
468
  };
341
469
 
342
470
  export const ListWithElementType: Story = {
@@ -344,4 +472,12 @@ export const ListWithElementType: Story = {
344
472
  defaultType: 'list',
345
473
  element_type: 'int',
346
474
  },
475
+ parameters: {
476
+ docs: {
477
+ description: {
478
+ story:
479
+ 'Renders AutoFormField in list mode with an int element type — new items are added as integers rather than requiring the operator to pick a per-item type.',
480
+ },
481
+ },
482
+ },
347
483
  };
@@ -38,6 +38,14 @@ export const WithValue: Story = {
38
38
  args: {
39
39
  value: 'cGFzc3dvcmQ=',
40
40
  },
41
+ parameters: {
42
+ docs: {
43
+ description: {
44
+ story:
45
+ 'Renders the Binary field pre-populated with a base64 payload — the textarea shows the encoded string.',
46
+ },
47
+ },
48
+ },
41
49
  async play({ canvasElement }) {
42
50
  const canvas = within(canvasElement);
43
51
  const textarea = canvas.getByLabelText('Binary');
@@ -48,6 +56,14 @@ export const WithValue: Story = {
48
56
  };
49
57
 
50
58
  export const TypingUpdatesValue: Story = {
59
+ parameters: {
60
+ docs: {
61
+ description: {
62
+ story:
63
+ 'Renders the empty Binary field. Typing a base64 string into the textarea updates the value and fires onChange after the debounce.',
64
+ },
65
+ },
66
+ },
51
67
  async play({ canvasElement, args }) {
52
68
  const canvas = within(canvasElement);
53
69
  const textarea = canvas.getByLabelText('Binary');
@@ -61,6 +77,14 @@ export const TypingUpdatesValue: Story = {
61
77
  };
62
78
 
63
79
  export const UploadEncodesFileAsBase64: Story = {
80
+ parameters: {
81
+ docs: {
82
+ description: {
83
+ story:
84
+ 'Renders the Binary field with its file drop zone. Uploading a file encodes it as base64 (data-URL prefix stripped) and fires onChange with the encoded string.',
85
+ },
86
+ },
87
+ },
64
88
  async play({ canvasElement, args }) {
65
89
  const file = new File(['hello'], 'test.bin', { type: 'application/octet-stream' });
66
90
  // the hidden file input rendered by the reused ReqraftFileFormField drop zone
@@ -81,6 +105,14 @@ export const Disabled: Story = {
81
105
  value: 'cGFzc3dvcmQ=',
82
106
  disabled: true,
83
107
  },
108
+ parameters: {
109
+ docs: {
110
+ description: {
111
+ story:
112
+ 'Renders the Binary field with a base64 value but disabled — the textarea is non-interactive.',
113
+ },
114
+ },
115
+ },
84
116
  async play({ canvasElement }) {
85
117
  const canvas = within(canvasElement);
86
118
  const textarea = canvas.getByLabelText('Binary');
@@ -34,6 +34,14 @@ export const Checked: Story = {
34
34
  args: {
35
35
  checked: true,
36
36
  },
37
+ parameters: {
38
+ docs: {
39
+ description: {
40
+ story:
41
+ 'Renders the Boolean field in the checked state. Clicking the toggle flips it to unchecked and fires onChange with false.',
42
+ },
43
+ },
44
+ },
37
45
  async play({ canvasElement, args }) {
38
46
  const canvas = within(canvasElement);
39
47
 
@@ -49,6 +57,14 @@ export const Unchecked: Story = {
49
57
  args: {
50
58
  checked: false,
51
59
  },
60
+ parameters: {
61
+ docs: {
62
+ description: {
63
+ story:
64
+ 'Renders the Boolean field in the unchecked state. Clicking the toggle flips it to checked and fires onChange with true.',
65
+ },
66
+ },
67
+ },
52
68
  async play({ canvasElement, args }) {
53
69
  const canvas = within(canvasElement);
54
70
 
@@ -64,4 +80,12 @@ export const Disabled: Story = {
64
80
  checked: true,
65
81
  disabled: true,
66
82
  },
83
+ parameters: {
84
+ docs: {
85
+ description: {
86
+ story:
87
+ 'Renders the Boolean field checked and disabled — the toggle is visible but non-interactive.',
88
+ },
89
+ },
90
+ },
67
91
  };
@@ -30,6 +30,14 @@ export default meta;
30
30
  type Story = StoryObj<typeof meta>;
31
31
 
32
32
  export const Default: Story = {
33
+ parameters: {
34
+ docs: {
35
+ description: {
36
+ story:
37
+ 'Renders the ByteSize field with no value. Typing a number into the amount input fires onChange with the composed byte-size expression.',
38
+ },
39
+ },
40
+ },
33
41
  play: async ({ canvasElement, args }) => {
34
42
  const canvas = within(canvasElement);
35
43
  const input = canvas.getByLabelText('Byte size amount');
@@ -43,6 +51,14 @@ export const WithValue: Story = {
43
51
  args: {
44
52
  value: '512MiB',
45
53
  },
54
+ parameters: {
55
+ docs: {
56
+ description: {
57
+ story:
58
+ 'Renders the ByteSize field pre-populated with "512MiB" — the amount and unit are split across the number input and the MiB unit selector.',
59
+ },
60
+ },
61
+ },
46
62
  play: async ({ canvasElement }) => {
47
63
  const canvas = within(canvasElement);
48
64
  await expect(await canvas.findByDisplayValue('512')).toBeInTheDocument();
@@ -55,6 +71,14 @@ export const ReadOnly: Story = {
55
71
  value: '512MiB',
56
72
  readOnly: true,
57
73
  },
74
+ parameters: {
75
+ docs: {
76
+ description: {
77
+ story:
78
+ 'Renders the ByteSize field with "512MiB" in read-only mode — the amount input is marked readonly and rejects further edits.',
79
+ },
80
+ },
81
+ },
58
82
  play: async ({ canvasElement }) => {
59
83
  const canvas = within(canvasElement);
60
84
  const input = await canvas.findByDisplayValue('512');
@@ -34,6 +34,14 @@ export const WithValue: Story = {
34
34
  args: {
35
35
  value: { r: 100, g: 149, b: 237, a: 1 },
36
36
  },
37
+ parameters: {
38
+ docs: {
39
+ description: {
40
+ story:
41
+ 'Renders the Color field with a cornflower-blue RGBA value pre-selected in the sketch picker.',
42
+ },
43
+ },
44
+ },
37
45
  async play({ canvasElement }) {
38
46
  const picker = canvasElement.querySelector('.sketch-picker');
39
47
  const colorPanel = canvasElement.querySelector('.saturation-white');
@@ -47,12 +55,26 @@ export const Red: Story = {
47
55
  args: {
48
56
  value: { r: 220, g: 53, b: 69, a: 1 },
49
57
  },
58
+ parameters: {
59
+ docs: {
60
+ description: {
61
+ story: 'Renders the Color field with a red RGBA value pre-selected in the sketch picker.',
62
+ },
63
+ },
64
+ },
50
65
  async play({ canvasElement }) {
51
66
  await expect(canvasElement.querySelector('.sketch-picker')).toBeInTheDocument();
52
67
  },
53
68
  };
54
69
 
55
70
  export const Empty: Story = {
71
+ parameters: {
72
+ docs: {
73
+ description: {
74
+ story: 'Renders the Color field with no value — the sketch picker mounts empty.',
75
+ },
76
+ },
77
+ },
56
78
  async play({ canvasElement }) {
57
79
  await expect(canvasElement.querySelector('.sketch-picker')).toBeInTheDocument();
58
80
  },
@@ -63,6 +85,14 @@ export const Disabled: Story = {
63
85
  value: { r: 100, g: 149, b: 237, a: 1 },
64
86
  disabled: true,
65
87
  },
88
+ parameters: {
89
+ docs: {
90
+ description: {
91
+ story:
92
+ 'Renders the Color field with a value but disabled — the sketch picker is visible but non-interactive.',
93
+ },
94
+ },
95
+ },
66
96
  async play({ canvasElement }) {
67
97
  await expect(canvasElement.querySelector('.sketch-picker')).toBeInTheDocument();
68
98
  },
@@ -39,6 +39,14 @@ export const Default: Story = {
39
39
  'aria-label': label,
40
40
  })),
41
41
  },
42
+ parameters: {
43
+ docs: {
44
+ description: {
45
+ story:
46
+ 'Renders the Cron field with a "1 1 1 1 1" schedule split across the Minute / Hour / Day / Month / Weekday inputs. Typing into a segment fires onChange with the recomposed expression; the clear button resets the value.',
47
+ },
48
+ },
49
+ },
42
50
 
43
51
  async play({ args, canvasElement }) {
44
52
  const canvas = within(canvasElement);
@@ -30,6 +30,13 @@ export default meta;
30
30
  type Story = StoryObj<typeof meta>;
31
31
 
32
32
  export const Empty: Story = {
33
+ parameters: {
34
+ docs: {
35
+ description: {
36
+ story: 'Renders the Date field with no value — the input mounts empty.',
37
+ },
38
+ },
39
+ },
33
40
  async play({ canvasElement }) {
34
41
  const input = canvasElement.querySelector('input');
35
42
  await expect(input).toBeInTheDocument();
@@ -40,6 +47,14 @@ export const WithValue: Story = {
40
47
  args: {
41
48
  value: '2025-01-15',
42
49
  },
50
+ parameters: {
51
+ docs: {
52
+ description: {
53
+ story:
54
+ 'Renders the Date field pre-populated with 2025-01-15 — the input shows the initial value without firing onChange.',
55
+ },
56
+ },
57
+ },
43
58
  async play({ canvasElement, args }) {
44
59
  const input = canvasElement.querySelector('input');
45
60
  await expect(input).toBeInTheDocument();
@@ -52,4 +67,11 @@ export const Disabled: Story = {
52
67
  value: '2025-06-01',
53
68
  disabled: true,
54
69
  },
70
+ parameters: {
71
+ docs: {
72
+ description: {
73
+ story: 'Renders the Date field with a value but disabled — the input is non-interactive.',
74
+ },
75
+ },
76
+ },
55
77
  };