@qoretechnologies/reqraft 0.10.9 → 0.10.11

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 (38) hide show
  1. package/.claude/CLAUDE.md +39 -18
  2. package/package.json +1 -1
  3. package/src/components/dpqlEditor/DpqlEditor.stories.tsx +74 -2
  4. package/src/components/form/engine/FormEngine.stories.tsx +654 -32
  5. package/src/components/form/engine/FormEngineRemote.stories.tsx +48 -0
  6. package/src/components/form/engine/_structuredData/StructuredDataView.stories.tsx +8 -0
  7. package/src/components/form/engine/variants/FormEngineVariants.stories.tsx +40 -0
  8. package/src/components/form/expressions/ExpressionField.stories.tsx +74 -2
  9. package/src/components/form/expressions/builder/ExpressionBuilder.stories.tsx +187 -0
  10. package/src/components/form/fields/Field.stories.tsx +40 -0
  11. package/src/components/form/fields/array/ArrayAutoField.stories.tsx +64 -0
  12. package/src/components/form/fields/auto/AutoFormField.stories.tsx +136 -0
  13. package/src/components/form/fields/binary/Binary.stories.tsx +32 -0
  14. package/src/components/form/fields/boolean/Boolean.stories.tsx +24 -0
  15. package/src/components/form/fields/byte-size/ByteSize.stories.tsx +24 -0
  16. package/src/components/form/fields/color/Color.stories.tsx +30 -0
  17. package/src/components/form/fields/cron/Cron.stories.tsx +8 -0
  18. package/src/components/form/fields/date/Date.stories.tsx +22 -0
  19. package/src/components/form/fields/file/File.stories.tsx +48 -0
  20. package/src/components/form/fields/long-string/LongString.stories.tsx +24 -0
  21. package/src/components/form/fields/markdown/Markdown.stories.tsx +8 -0
  22. package/src/components/form/fields/number/Number.stories.tsx +31 -0
  23. package/src/components/form/fields/object/Object.stories.tsx +88 -0
  24. package/src/components/form/fields/radio-group/RadioGroup.stories.tsx +24 -0
  25. package/src/components/form/fields/rich-text/RichText.stories.tsx +23 -0
  26. package/src/components/form/fields/schema-definition/SchemaDefinitionField.stories.tsx +72 -0
  27. package/src/components/form/fields/select/Select.stories.tsx +104 -0
  28. package/src/components/form/fields/string/String.stories.tsx +16 -0
  29. package/src/components/form/fields/template/TemplateField.stories.tsx +160 -0
  30. package/src/components/form/fields/url/Url.stories.tsx +24 -0
  31. package/src/components/log/Log.stories.tsx +96 -0
  32. package/src/components/menu/Menu.stories.tsx +54 -0
  33. package/src/components/qonsoleSmartInput/QonsoleSmartInput.stories.tsx +14 -0
  34. package/src/components/smartEditor/SmartEditor.stories.tsx +32 -0
  35. package/src/hooks/useFetch/useFetch.stories.tsx +30 -0
  36. package/src/hooks/useStorage/useStorage.stories.tsx +30 -0
  37. package/src/hooks/useWebSocket/useWebsocket.stories.tsx +127 -1
  38. package/src/stores/currentUser/currentUser.stories.tsx +17 -0
@@ -152,6 +152,14 @@ type Story = StoryObj<typeof meta>;
152
152
  // stories
153
153
 
154
154
  export const Basic: Story = {
155
+ parameters: {
156
+ docs: {
157
+ description: {
158
+ story:
159
+ 'Renders FormEngine over the shared basic-schema fixture — every option and value the classic layout exercises (booleans, strings with values, templates, invalid types) is present.',
160
+ },
161
+ },
162
+ },
155
163
  args: {
156
164
  minColumnWidth: '300px',
157
165
  options: getOptions(),
@@ -188,6 +196,14 @@ export const Basic: Story = {
188
196
 
189
197
  export const Small: Story = {
190
198
  ...Basic,
199
+ parameters: {
200
+ docs: {
201
+ description: {
202
+ story:
203
+ 'Renders the Basic FormEngine at size=small — the same fixture but with the compact size preset applied to every control.',
204
+ },
205
+ },
206
+ },
191
207
  args: {
192
208
  ...Basic.args,
193
209
  size: 'small',
@@ -196,6 +212,14 @@ export const Small: Story = {
196
212
 
197
213
  export const InvalidShownOnly: Story = {
198
214
  ...Basic,
215
+ parameters: {
216
+ docs: {
217
+ description: {
218
+ story:
219
+ 'Renders the Basic FormEngine, then clicks the invalid-fields message chip in the header — only the invalid options stay visible.',
220
+ },
221
+ },
222
+ },
199
223
  play: async (args) => {
200
224
  await Basic.play!(args);
201
225
  await fireEvent.click(document.querySelector('.reqore-message')!);
@@ -211,6 +235,14 @@ export const InvalidShownOnly: Story = {
211
235
  };
212
236
 
213
237
  export const Optional: Story = {
238
+ parameters: {
239
+ docs: {
240
+ description: {
241
+ story:
242
+ 'Renders FormEngine with only the optional half of the basic schema — the More Options Available collapsible box is shown but not opened.',
243
+ },
244
+ },
245
+ },
214
246
  args: {
215
247
  minColumnWidth: '300px',
216
248
  options: getOptions(true),
@@ -218,6 +250,14 @@ export const Optional: Story = {
218
250
  };
219
251
 
220
252
  export const OptionalOpened: Story = {
253
+ parameters: {
254
+ docs: {
255
+ description: {
256
+ story:
257
+ 'Renders FormEngine with only the optional half of the basic schema, then clicks the More Options Available banner — the optional fields drop down into the form.',
258
+ },
259
+ },
260
+ },
221
261
  args: {
222
262
  minColumnWidth: '300px',
223
263
  options: getOptions(true),
@@ -236,6 +276,14 @@ export const OptionalOpened: Story = {
236
276
 
237
277
  export const FocusedEditing: Story = {
238
278
  ...Basic,
279
+ parameters: {
280
+ docs: {
281
+ description: {
282
+ story:
283
+ 'Renders the Basic FormEngine, hovers an option and clicks its fullscreen action — the Focused Editing modal opens over that single field.',
284
+ },
285
+ },
286
+ },
239
287
  play: async (args) => {
240
288
  await Basic.play!(args);
241
289
  await userEvent.hover(document.querySelectorAll('.system-option')[0]);
@@ -246,6 +294,14 @@ export const FocusedEditing: Story = {
246
294
 
247
295
  export const DescriptionIsShown: Story = {
248
296
  ...Basic,
297
+ parameters: {
298
+ docs: {
299
+ description: {
300
+ story:
301
+ 'Renders the Basic FormEngine and clicks the Option with description label — the help panel opens with the option\'s long-form description.',
302
+ },
303
+ },
304
+ },
249
305
  play: async ({ canvasElement, ...rest }) => {
250
306
  const canvas = within(canvasElement);
251
307
  await Basic.play!({ canvasElement, ...rest });
@@ -256,6 +312,14 @@ export const DescriptionIsShown: Story = {
256
312
  };
257
313
 
258
314
  export const ValueCanBeRemoved: Story = {
315
+ parameters: {
316
+ docs: {
317
+ description: {
318
+ story:
319
+ 'Renders FormEngine holding a text option and a file option, both with values. Hovering each row and clicking its remove action clears the value and marks the row as revertable.',
320
+ },
321
+ },
322
+ },
259
323
  args: {
260
324
  options: {
261
325
  textOption: {
@@ -300,6 +364,14 @@ export const ValueCanBeRemoved: Story = {
300
364
 
301
365
  export const ChangeCanBeReverted: Story = {
302
366
  ...ValueCanBeRemoved,
367
+ parameters: {
368
+ docs: {
369
+ description: {
370
+ story:
371
+ 'Renders the ValueCanBeRemoved fixture after both values are removed, then clicks the per-row revert action — the file value comes back.',
372
+ },
373
+ },
374
+ },
303
375
  play: async (args) => {
304
376
  await ValueCanBeRemoved.play!(args);
305
377
  await _testsClickButton({ selector: '.options-item-revert', nth: 1 });
@@ -309,6 +381,14 @@ export const ChangeCanBeReverted: Story = {
309
381
 
310
382
  export const AllChangesCanBeReverted: Story = {
311
383
  ...ValueCanBeRemoved,
384
+ parameters: {
385
+ docs: {
386
+ description: {
387
+ story:
388
+ 'Renders the ValueCanBeRemoved fixture after both values are removed, then clicks the form-level revert action — the entire form goes back to its original values.',
389
+ },
390
+ },
391
+ },
312
392
  play: async (args) => {
313
393
  await ValueCanBeRemoved.play!(args);
314
394
  await _testsClickButton({ selector: '.fields-revert' });
@@ -318,6 +398,14 @@ export const AllChangesCanBeReverted: Story = {
318
398
 
319
399
  export const WithTypesShown: Story = {
320
400
  ...Basic,
401
+ parameters: {
402
+ docs: {
403
+ description: {
404
+ story:
405
+ 'Renders the Basic FormEngine and clicks the show-types header action — every option label picks up its Qore type badge (e.g. <rgbcolor>).',
406
+ },
407
+ },
408
+ },
321
409
  play: async (args) => {
322
410
  await Basic.play!(args);
323
411
  await _testsClickButton({ selector: '.fields-show-types' });
@@ -326,6 +414,14 @@ export const WithTypesShown: Story = {
326
414
  };
327
415
 
328
416
  export const WithRequiredGroups: Story = {
417
+ parameters: {
418
+ docs: {
419
+ description: {
420
+ story:
421
+ 'Renders FormEngine with five options that all belong to one required_groups group — every row mounts and the group\'s one-of-required indicator is shown.',
422
+ },
423
+ },
424
+ },
329
425
  args: {
330
426
  minColumnWidth: '300px',
331
427
  options: TestOptionsWithRequiredGroups,
@@ -338,6 +434,14 @@ export const WithRequiredGroups: Story = {
338
434
  };
339
435
 
340
436
  export const WithRequiredGroupsFulfilled: Story = {
437
+ parameters: {
438
+ docs: {
439
+ description: {
440
+ story:
441
+ 'Renders the required-group schema with one of the group\'s options already filled — the group\'s one-of-required indicator marks the group as satisfied.',
442
+ },
443
+ },
444
+ },
341
445
  args: {
342
446
  minColumnWidth: '300px',
343
447
  options: TestOptionsWithRequiredGroups,
@@ -353,6 +457,14 @@ export const WithRequiredGroupsFulfilled: Story = {
353
457
  };
354
458
 
355
459
  export const OptionDependsOnOptionOrAnotherOption: Story = {
460
+ parameters: {
461
+ docs: {
462
+ description: {
463
+ story:
464
+ 'Renders FormEngine with a required option that depends on Required Option 2 OR Required Option 5 — the field is disabled until either dependency is filled, then the disabled note clears.',
465
+ },
466
+ },
467
+ },
356
468
  args: {
357
469
  minColumnWidth: '300px',
358
470
  options: {
@@ -383,6 +495,14 @@ export const OptionDependsOnOptionOrAnotherOption: Story = {
383
495
  };
384
496
 
385
497
  export const OptionDependsOnOptionInRequiredGroup: Story = {
498
+ parameters: {
499
+ docs: {
500
+ description: {
501
+ story:
502
+ 'Renders FormEngine with a required option that depends on Required Option 2 alone — filling Required Option 2 clears the disabled note.',
503
+ },
504
+ },
505
+ },
386
506
  args: {
387
507
  minColumnWidth: '300px',
388
508
  options: {
@@ -413,6 +533,14 @@ export const OptionDependsOnOptionInRequiredGroup: Story = {
413
533
  };
414
534
 
415
535
  export const OptionalWithValues: Story = {
536
+ parameters: {
537
+ docs: {
538
+ description: {
539
+ story:
540
+ 'Renders FormEngine with only the optional half of the basic schema plus pre-existing values — the optional fields are already populated and the More Options Available banner is hidden.',
541
+ },
542
+ },
543
+ },
416
544
  args: {
417
545
  minColumnWidth: '300px',
418
546
  options: getOptions(true),
@@ -425,6 +553,14 @@ export const OptionalWithValues: Story = {
425
553
  };
426
554
 
427
555
  export const OptionWithAnyType: Story = {
556
+ parameters: {
557
+ docs: {
558
+ description: {
559
+ story:
560
+ 'Renders four options typed as any with templates enabled — empty ones show a Select Template dropdown, the pre-typed number field renders as a Number input and the operator can switch types via the More menu.',
561
+ },
562
+ },
563
+ },
428
564
  args: {
429
565
  options: {
430
566
  optionWithAnyType: {
@@ -491,6 +627,14 @@ export const OptionWithAnyType: Story = {
491
627
  };
492
628
 
493
629
  export const NonExistentOptionsFiltered: Story = {
630
+ parameters: {
631
+ docs: {
632
+ description: {
633
+ story:
634
+ 'Renders FormEngine with a value that carries three fields but a schema that declares only two — the extra option is filtered out and onChange fires without it.',
635
+ },
636
+ },
637
+ },
494
638
  args: {
495
639
  value: {
496
640
  option1: { type: 'long-string', value: 'option1' },
@@ -526,6 +670,14 @@ export const NonExistentOptionsFiltered: Story = {
526
670
  };
527
671
 
528
672
  export const OptionsWithOnChangeTriggerEvents: Story = {
673
+ parameters: {
674
+ docs: {
675
+ description: {
676
+ story:
677
+ 'Renders FormEngine with an option that declares on_change: [\'refetch\']. Editing the field fires onChange with meta.events set to [\'refetch\'] so the host can re-fetch dependent options.',
678
+ },
679
+ },
680
+ },
529
681
  args: {
530
682
  value: {
531
683
  optionWithRefetchAndReset: { type: 'long-string', value: 'option1' },
@@ -610,6 +762,14 @@ const CodeEditorStandin = ({
610
762
  // a sibling `lang` picker, so flipping the picker live-changes the
611
763
  // editor's syntax highlighting with no refetch.
612
764
  export const OptionInheritsRenderPropFromSibling: Story = {
765
+ parameters: {
766
+ docs: {
767
+ description: {
768
+ story:
769
+ 'Renders FormEngine with a code-editor field that declares inherit_props: { language: \'lang\' } — the sibling language picker feeds the editor\'s language prop at render time, and flipping the picker live-updates the syntax without any refetch.',
770
+ },
771
+ },
772
+ },
613
773
  args: {
614
774
  componentOverrides: { 'code-editor': CodeEditorStandin },
615
775
  value: {
@@ -675,6 +835,14 @@ export const OptionInheritsRenderPropFromSibling: Story = {
675
835
  // in both modes. This story locks that in so a future refactor of the
676
836
  // compact path can't silently break inherit_props for read-first surfaces.
677
837
  export const OptionInheritsRenderPropFromSiblingCompact: Story = {
838
+ parameters: {
839
+ docs: {
840
+ description: {
841
+ story:
842
+ 'Renders the OptionInheritsRenderPropFromSibling schema with compact=true — the same inherit_props forwarding runs through the compact renderer.',
843
+ },
844
+ },
845
+ },
678
846
  args: {
679
847
  compact: true,
680
848
  minColumnWidth: '300px',
@@ -723,6 +891,14 @@ export const OptionInheritsRenderPropFromSiblingCompact: Story = {
723
891
  // CompactRow refactor can't silently reduce a Qorus source-code field to an
724
892
  // ellipsised one-liner again.
725
893
  export const CompactRowCodeEditorPreview: Story = {
894
+ parameters: {
895
+ docs: {
896
+ description: {
897
+ story:
898
+ 'Renders a compact-mode code-editor row over a multi-line Qore source value — the value cell replaces the truncated string with a lines/chars summary tag and a collapsible monospace preview mounts under the row.',
899
+ },
900
+ },
901
+ },
726
902
  args: {
727
903
  compact: true,
728
904
  minColumnWidth: '360px',
@@ -796,6 +972,14 @@ export const CompactRowCodeEditorPreview: Story = {
796
972
  // `language` prop. Flipping the top-level lang picker live-updates every
797
973
  // row's editor without any custom per-field wiring.
798
974
  export const NestedOptionInheritsRenderPropFromAncestor: Story = {
975
+ parameters: {
976
+ docs: {
977
+ description: {
978
+ story:
979
+ 'Renders FormEngine with a list-of-hash methods option whose row sub-schema declares inherit_props: { language: \'language\' } — the parent-level forwarding threads the top-level language down to every row\'s code-editor body sub-field.',
980
+ },
981
+ },
982
+ },
799
983
  args: {
800
984
  componentOverrides: { 'code-editor': CodeEditorStandin },
801
985
  value: {
@@ -876,6 +1060,14 @@ export const NestedOptionInheritsRenderPropFromAncestor: Story = {
876
1060
  // list-of-hash whose sub-fields still resolve `language` from the top-level
877
1061
  // picker through the same two-hop chain.
878
1062
  export const NestedOptionInheritsRenderPropFromAncestorCompact: Story = {
1063
+ parameters: {
1064
+ docs: {
1065
+ description: {
1066
+ story:
1067
+ 'Renders the NestedOptionInheritsRenderPropFromAncestor schema with compact=true — the compact renderer summarises the list-of-hash rows as \'init, run\' rather than [object Object].',
1068
+ },
1069
+ },
1070
+ },
879
1071
  args: {
880
1072
  compact: true,
881
1073
  minColumnWidth: '300px',
@@ -947,6 +1139,14 @@ export const NestedOptionInheritsRenderPropFromAncestorCompact: Story = {
947
1139
  };
948
1140
 
949
1141
  export const DependantsResetWhenParentChanges: Story = {
1142
+ parameters: {
1143
+ docs: {
1144
+ description: {
1145
+ story:
1146
+ 'Renders FormEngine with two dependent options plus two has-dependents parents. Changing the parent\'s value clears every dependent\'s value while leaving the unrelated sibling untouched.',
1147
+ },
1148
+ },
1149
+ },
950
1150
  args: {
951
1151
  minColumnWidth: '300px',
952
1152
  options: {
@@ -1023,6 +1223,14 @@ export const DependantsResetWhenParentChanges: Story = {
1023
1223
  };
1024
1224
 
1025
1225
  export const ValueIsFixedWhenDefaultValueDoesNotMatchAndReadOnlyIsTrue: Story = {
1226
+ parameters: {
1227
+ docs: {
1228
+ description: {
1229
+ story:
1230
+ 'Renders FormEngine with a read-only option whose stored value differs from its default_value — the value is auto-corrected to the default at mount and the wrong value never renders.',
1231
+ },
1232
+ },
1233
+ },
1026
1234
  args: {
1027
1235
  minColumnWidth: '300px',
1028
1236
  options: {
@@ -1066,6 +1274,14 @@ export const ValueIsFixedWhenDefaultValueDoesNotMatchAndReadOnlyIsTrue: Story =
1066
1274
  };
1067
1275
 
1068
1276
  export const DoesNotCauseInfiniteRerenders: Story = {
1277
+ parameters: {
1278
+ docs: {
1279
+ description: {
1280
+ story:
1281
+ 'Renders FormEngine with a refetch-triggering parent and a list-of-hash dependent — the schema mounts cleanly and adding a new list item does not cause the form to re-render infinitely.',
1282
+ },
1283
+ },
1284
+ },
1069
1285
  args: {
1070
1286
  minColumnWidth: '300px',
1071
1287
  options: {
@@ -1126,6 +1342,14 @@ export const DoesNotCauseInfiniteRerenders: Story = {
1126
1342
  };
1127
1343
 
1128
1344
  export const AllowedValuesOptionWithTemplateValueShowsWarning: Story = {
1345
+ parameters: {
1346
+ docs: {
1347
+ description: {
1348
+ story:
1349
+ 'Renders FormEngine with an allowed_values option that holds a template value ($local:test) instead of one of the allowed values — the option shows a warning that the template value is outside the allowed set.',
1350
+ },
1351
+ },
1352
+ },
1129
1353
  args: {
1130
1354
  minColumnWidth: '300px',
1131
1355
  options: {
@@ -1168,6 +1392,12 @@ export const AllowedValuesOptionWithTemplateValueShowsWarning: Story = {
1168
1392
  export const OnValidityChange: Story = {
1169
1393
  // chromatic off: async validity-callback timing.
1170
1394
  parameters: {
1395
+ docs: {
1396
+ description: {
1397
+ story:
1398
+ 'Renders FormEngine wired to an onValidityChange callback — the callback fires with per-field validity data as the overall form validity changes.',
1399
+ },
1400
+ },
1171
1401
  chromatic: { disable: true },
1172
1402
  },
1173
1403
  args: {
@@ -1419,6 +1649,14 @@ const CompactFieldsMenuSchema: Record<string, TCompactField> = {
1419
1649
  };
1420
1650
 
1421
1651
  export const Compact: Story = {
1652
+ parameters: {
1653
+ docs: {
1654
+ description: {
1655
+ story:
1656
+ 'Renders FormEngine in compact mode over the CompactSchema fixture with groups — options collapse to read-first rows grouped under labelled group headers, with formatted value summaries per row.',
1657
+ },
1658
+ },
1659
+ },
1422
1660
  args: {
1423
1661
  compact: true,
1424
1662
  minColumnWidth: '300px',
@@ -1443,7 +1681,15 @@ export const Compact: Story = {
1443
1681
  };
1444
1682
 
1445
1683
  export const CompactReadOnly: Story = {
1446
- parameters: { chromatic: { disable: true } },
1684
+ parameters: {
1685
+ docs: {
1686
+ description: {
1687
+ story:
1688
+ 'Renders the Compact fixture with readOnly enabled — the Draft/Ready progress badge is hidden and rows open in view (non-editable) mode.',
1689
+ },
1690
+ },
1691
+ chromatic: { disable: true },
1692
+ },
1447
1693
  args: {
1448
1694
  ...Compact.args,
1449
1695
  readOnly: true,
@@ -1462,6 +1708,14 @@ export const CompactReadOnly: Story = {
1462
1708
  };
1463
1709
 
1464
1710
  export const CompactEmpty: Story = {
1711
+ parameters: {
1712
+ docs: {
1713
+ description: {
1714
+ story:
1715
+ 'Renders the Compact fixture with no value — all six empty fields render a dash placeholder and the four optional fields sit in the collapsed Optional box.',
1716
+ },
1717
+ },
1718
+ },
1465
1719
  args: {
1466
1720
  compact: true,
1467
1721
  minColumnWidth: '300px',
@@ -1482,7 +1736,15 @@ export const CompactEmpty: Story = {
1482
1736
  // Compact mode on the EXACT shared fixture behind `Basic` — every option and
1483
1737
  // state the classic layout exercises.
1484
1738
  export const CompactBasic: Story = {
1485
- parameters: { chromatic: { disable: true } },
1739
+ parameters: {
1740
+ docs: {
1741
+ description: {
1742
+ story:
1743
+ 'Renders FormEngine in compact mode over the full Basic fixture — every value renders in its read-first form (templates by name, colours as hex, hashes as field-count summaries), disabled and dependency-locked rows stay non-interactive, and the dependency lock\'s popover navigates to blockers.',
1744
+ },
1745
+ },
1746
+ chromatic: { disable: true },
1747
+ },
1486
1748
  args: {
1487
1749
  compact: true,
1488
1750
  minColumnWidth: '300px',
@@ -1631,7 +1893,15 @@ export const CompactBasic: Story = {
1631
1893
  // ($-token + resolved name). Regression cover for the review note "this should
1632
1894
  // show as a readonly richtext or a readonly template picker".
1633
1895
  export const CompactReadOnlyRichText: Story = {
1634
- parameters: { chromatic: { disable: true } },
1896
+ parameters: {
1897
+ docs: {
1898
+ description: {
1899
+ story:
1900
+ 'Renders the CompactBasic fixture with readOnly enabled — opening the Rich Text row shows a non-editable Slate surface, and the Template row renders as a read-only template-picker chip showing the resolved template name (never the raw $local reference).',
1901
+ },
1902
+ },
1903
+ chromatic: { disable: true },
1904
+ },
1635
1905
  args: {
1636
1906
  ...CompactBasic.args,
1637
1907
  readOnly: true,
@@ -1704,6 +1974,14 @@ const ORDER_STATE_SAMPLE = {
1704
1974
  // Hash rows render the IDE workflow-orders `StructuredDataView` under the
1705
1975
  // fade/"Show more" wrapper; doubles as the raw-vs-envelope data contrast.
1706
1976
  export const CompactHashStructuredView: Story = {
1977
+ parameters: {
1978
+ docs: {
1979
+ description: {
1980
+ story:
1981
+ 'Renders CompactBasic with an extra orderState hash option holding a raw payload — the hash row uses the StructuredDataView tree renderer with type-aware value cells; clicking a value chip opens the hash editor.',
1982
+ },
1983
+ },
1984
+ },
1707
1985
  args: {
1708
1986
  ...CompactBasic.args,
1709
1987
  options: {
@@ -1802,7 +2080,15 @@ export const CompactHashStructuredView: Story = {
1802
2080
  // grows a Save/Discard bar, Save emits `onCommit` (gated on validity), and
1803
2081
  // every staged edit still emits `onChange` flagged `meta.draft`.
1804
2082
  export const CompactBatchedCommit: Story = {
1805
- parameters: { chromatic: { disable: true } },
2083
+ parameters: {
2084
+ docs: {
2085
+ description: {
2086
+ story:
2087
+ 'Renders a valid form in commitMode=\'batched\'. Staging an edit adds the Draft chip and \'unsaved changes\' bar without committing; Save fires onCommit and clears the chips; Discard reverts the staged edit.',
2088
+ },
2089
+ },
2090
+ chromatic: { disable: true },
2091
+ },
1806
2092
  args: {
1807
2093
  compact: true,
1808
2094
  commitMode: 'batched',
@@ -1868,6 +2154,14 @@ export const CompactBatchedCommit: Story = {
1868
2154
 
1869
2155
  // While any field is invalid, the bar shows but Save refuses to commit.
1870
2156
  export const CompactBatchedCommitInvalid: Story = {
2157
+ parameters: {
2158
+ docs: {
2159
+ description: {
2160
+ story:
2161
+ 'Renders an invalid form in commitMode=\'batched\' — staging an edit shows the unsaved-changes bar but Save is disabled and onCommit never fires.',
2162
+ },
2163
+ },
2164
+ },
1871
2165
  args: {
1872
2166
  compact: true,
1873
2167
  commitMode: 'batched',
@@ -1903,6 +2197,14 @@ export const CompactBatchedCommitInvalid: Story = {
1903
2197
  // `sensitive`: the read row masks the value (and its hover title) — the secret
1904
2198
  // never renders as page text, in read or edit state.
1905
2199
  export const CompactSensitive: Story = {
2200
+ parameters: {
2201
+ docs: {
2202
+ description: {
2203
+ story:
2204
+ 'Renders a compact form with a sensitive: true API-token field — the read row masks the value (and its hover title) and the edit input renders as type=password.',
2205
+ },
2206
+ },
2207
+ },
1906
2208
  args: {
1907
2209
  compact: true,
1908
2210
  minColumnWidth: '300px',
@@ -1942,6 +2244,14 @@ export const CompactSensitive: Story = {
1942
2244
  // `rules: ['valid_identifier']` flows from the schema into validation: a bad
1943
2245
  // identifier marks the form invalid (banner + Draft badge).
1944
2246
  export const CompactValidIdentifierRule: Story = {
2247
+ parameters: {
2248
+ docs: {
2249
+ description: {
2250
+ story:
2251
+ 'Renders a compact form with an option that carries a valid-identifier validation rule — invalid input surfaces the identifier-format error inline.',
2252
+ },
2253
+ },
2254
+ },
1945
2255
  args: {
1946
2256
  compact: true,
1947
2257
  minColumnWidth: '300px',
@@ -1969,6 +2279,14 @@ export const CompactValidIdentifierRule: Story = {
1969
2279
  // Operators (filter/mapper-style forms): the `operators` prop renders the
1970
2280
  // operator selector + the WHERE/IS summary in the card editor.
1971
2281
  export const CompactOperators: Story = {
2282
+ parameters: {
2283
+ docs: {
2284
+ description: {
2285
+ story:
2286
+ 'Renders a compact form with per-option operator support — each row shows the operator select alongside the value and the WHERE/IS summary tags.',
2287
+ },
2288
+ },
2289
+ },
1972
2290
  args: {
1973
2291
  compact: true,
1974
2292
  minColumnWidth: '300px',
@@ -2012,7 +2330,15 @@ export const CompactOperators: Story = {
2012
2330
  // focusedEditing in compact: the card's fullscreen affordance opens the same
2013
2331
  // focused-editing modal the classic layout has, with the field's descriptions.
2014
2332
  export const CompactFocusedEditing: Story = {
2015
- parameters: { chromatic: { disable: true } },
2333
+ parameters: {
2334
+ docs: {
2335
+ description: {
2336
+ story:
2337
+ 'Renders the compact form, opens a row and switches to focused-editing mode — the row expands into a modal-style editing surface.',
2338
+ },
2339
+ },
2340
+ chromatic: { disable: true },
2341
+ },
2016
2342
  args: {
2017
2343
  compact: true,
2018
2344
  minColumnWidth: '300px',
@@ -2050,7 +2376,15 @@ export const CompactFocusedEditing: Story = {
2050
2376
  // multi-select editor in the card.
2051
2377
  export const CompactMultiSelectEditing: Story = {
2052
2378
  // chromatic off: ends with an open multi-select editor card (live editor state).
2053
- parameters: { chromatic: { disable: true } },
2379
+ parameters: {
2380
+ docs: {
2381
+ description: {
2382
+ story:
2383
+ 'Renders a compact form with a multi-select option — editing the row exposes the chip picker and multiple values can be added and removed.',
2384
+ },
2385
+ },
2386
+ chromatic: { disable: true },
2387
+ },
2054
2388
  args: {
2055
2389
  compact: true,
2056
2390
  minColumnWidth: '300px',
@@ -2085,7 +2419,15 @@ export const CompactMultiSelectEditing: Story = {
2085
2419
 
2086
2420
  // Field-level `sort` orders compact rows (schema declared out of order).
2087
2421
  export const CompactSortOrder: Story = {
2088
- parameters: { chromatic: { disable: true } },
2422
+ parameters: {
2423
+ docs: {
2424
+ description: {
2425
+ story:
2426
+ 'Renders a compact form whose options carry sort ordinals — the rows render in sort order rather than schema-declaration order.',
2427
+ },
2428
+ },
2429
+ chromatic: { disable: true },
2430
+ },
2089
2431
  args: {
2090
2432
  compact: true,
2091
2433
  minColumnWidth: '300px',
@@ -2127,7 +2469,15 @@ export const CompactSortOrder: Story = {
2127
2469
  };
2128
2470
 
2129
2471
  export const CompactReadFirstEditing: Story = {
2130
- parameters: { chromatic: { disable: true } },
2472
+ parameters: {
2473
+ docs: {
2474
+ description: {
2475
+ story:
2476
+ 'Renders the compact form and opens a row for editing — the row transitions from the read-first summary to the inline or card editor.',
2477
+ },
2478
+ },
2479
+ chromatic: { disable: true },
2480
+ },
2131
2481
  args: {
2132
2482
  compact: true,
2133
2483
  minColumnWidth: '300px',
@@ -2178,7 +2528,15 @@ export const CompactReadFirstEditing: Story = {
2178
2528
  // easy to keep track of. The flash is the observable signal that the panel-change
2179
2529
  // locate fired (the scroll itself, scrollIntoView, isn't assertable in the runner).
2180
2530
  export const CompactPanelChangeScroll: Story = {
2181
- parameters: { chromatic: { disable: true } },
2531
+ parameters: {
2532
+ docs: {
2533
+ description: {
2534
+ story:
2535
+ 'Renders a compact form inside a scrollable panel — opening a row keeps the panel\'s scroll position pinned rather than jumping to the top.',
2536
+ },
2537
+ },
2538
+ chromatic: { disable: true },
2539
+ },
2182
2540
  args: {
2183
2541
  compact: true,
2184
2542
  minColumnWidth: '300px',
@@ -2229,7 +2587,15 @@ export const CompactPanelChangeScroll: Story = {
2229
2587
  };
2230
2588
 
2231
2589
  export const CompactRequiredOnlyAndSearch: Story = {
2232
- parameters: { chromatic: { disable: true } },
2590
+ parameters: {
2591
+ docs: {
2592
+ description: {
2593
+ story:
2594
+ 'Renders a compact form with the required-only filter and the search input enabled — filtering by requirement and typing a query narrows the visible rows.',
2595
+ },
2596
+ },
2597
+ chromatic: { disable: true },
2598
+ },
2233
2599
  args: {
2234
2600
  compact: true,
2235
2601
  minColumnWidth: '300px',
@@ -2266,7 +2632,15 @@ export const CompactRequiredOnlyAndSearch: Story = {
2266
2632
  };
2267
2633
 
2268
2634
  export const CompactFieldsMenu: Story = {
2269
- parameters: { chromatic: { disable: true } },
2635
+ parameters: {
2636
+ docs: {
2637
+ description: {
2638
+ story:
2639
+ 'Renders a compact form and opens the Fields menu — the menu exposes show-types, show-descriptions and required-only toggles.',
2640
+ },
2641
+ },
2642
+ chromatic: { disable: true },
2643
+ },
2270
2644
  args: {
2271
2645
  compact: true,
2272
2646
  minColumnWidth: '300px',
@@ -2337,7 +2711,15 @@ export const CompactFieldsMenu: Story = {
2337
2711
  // Toolbar ⓘ: a global toggle that reveals every field's short_desc at once,
2338
2712
  // without opening each row's info panel by hand.
2339
2713
  export const CompactDescriptionsToggle: Story = {
2340
- parameters: { chromatic: { disable: true } },
2714
+ parameters: {
2715
+ docs: {
2716
+ description: {
2717
+ story:
2718
+ 'Renders a compact form and toggles show-descriptions from the Fields menu — every row picks up its short_desc / desc text under the label.',
2719
+ },
2720
+ },
2721
+ chromatic: { disable: true },
2722
+ },
2341
2723
  args: {
2342
2724
  compact: true,
2343
2725
  minColumnWidth: '300px',
@@ -2402,7 +2784,15 @@ export const CompactDescriptionsToggle: Story = {
2402
2784
  };
2403
2785
 
2404
2786
  export const CompactSearchHidden: Story = {
2405
- parameters: { chromatic: { disable: true } },
2787
+ parameters: {
2788
+ docs: {
2789
+ description: {
2790
+ story:
2791
+ 'Renders a compact form with searchHidden set — the search input and header search action are hidden from the toolbar.',
2792
+ },
2793
+ },
2794
+ chromatic: { disable: true },
2795
+ },
2406
2796
  args: {
2407
2797
  compact: true,
2408
2798
  minColumnWidth: '300px',
@@ -2501,7 +2891,15 @@ const OAuth2ScopesSchema = {
2501
2891
  } as any;
2502
2892
 
2503
2893
  export const CompactListYamlField: Story = {
2504
- parameters: { chromatic: { disable: true } },
2894
+ parameters: {
2895
+ docs: {
2896
+ description: {
2897
+ story:
2898
+ 'Renders a compact form with a list-of-YAML option — the row summary shows the item count and opening the row exposes the YAML editor.',
2899
+ },
2900
+ },
2901
+ chromatic: { disable: true },
2902
+ },
2505
2903
  args: {
2506
2904
  compact: true,
2507
2905
  minColumnWidth: '300px',
@@ -2544,7 +2942,15 @@ export const CompactListYamlField: Story = {
2544
2942
  // value column became `minmax(0, 1fr)` + `min-width: 0`; plus the sticky
2545
2943
  // completion + search + Fields toolbar.
2546
2944
  export const CompactOverflowAndStickyHeader: Story = {
2547
- parameters: { chromatic: { disable: true } },
2945
+ parameters: {
2946
+ docs: {
2947
+ description: {
2948
+ story:
2949
+ 'Renders a compact form tall enough to scroll — the group headers stick to the top of the panel as the form scrolls under them.',
2950
+ },
2951
+ },
2952
+ chromatic: { disable: true },
2953
+ },
2548
2954
  // A fixed-height scroll host so the sticky behaviour is observable (and
2549
2955
  // testable) regardless of viewport size.
2550
2956
  decorators: [
@@ -2598,7 +3004,15 @@ export const CompactOverflowAndStickyHeader: Story = {
2598
3004
  // on_change/refetch + has_dependents flow through the same handleValueChange
2599
3005
  // as classic — the read-first editor must fire and reset the same way.
2600
3006
  export const CompactOnChangeAndDependents: Story = {
2601
- parameters: { chromatic: { disable: true } },
3007
+ parameters: {
3008
+ docs: {
3009
+ description: {
3010
+ story:
3011
+ 'Renders a compact form with dependency chains — editing a parent option resets its dependents and the dependent rows re-render in their fresh state.',
3012
+ },
3013
+ },
3014
+ chromatic: { disable: true },
3015
+ },
2602
3016
  args: {
2603
3017
  compact: true,
2604
3018
  minColumnWidth: '300px',
@@ -2655,7 +3069,15 @@ export const CompactOnChangeAndDependents: Story = {
2655
3069
  };
2656
3070
 
2657
3071
  export const CompactRevertAndShowTypes: Story = {
2658
- parameters: { chromatic: { disable: true } },
3072
+ parameters: {
3073
+ docs: {
3074
+ description: {
3075
+ story:
3076
+ 'Renders a compact form and exercises the per-row revert action alongside the show-types Fields menu toggle.',
3077
+ },
3078
+ },
3079
+ chromatic: { disable: true },
3080
+ },
2659
3081
  args: {
2660
3082
  compact: true,
2661
3083
  minColumnWidth: '300px',
@@ -2736,7 +3158,15 @@ const FieldTypeCatalogGroups: Record<string, IFormEngineGroup> = {
2736
3158
  */
2737
3159
  export const CompactExpressions: Story = {
2738
3160
  // chromatic off: ends with the live ExpressionField editor (Text mode) open.
2739
- parameters: { chromatic: { disable: true } },
3161
+ parameters: {
3162
+ docs: {
3163
+ description: {
3164
+ story:
3165
+ 'Renders a compact form with an expression-supporting option — the row opens the ExpressionField shell with the Visual builder and the Visual/Text mode toggle.',
3166
+ },
3167
+ },
3168
+ chromatic: { disable: true },
3169
+ },
2740
3170
  args: {
2741
3171
  name: 'exprForm',
2742
3172
  compact: true,
@@ -2833,7 +3263,15 @@ const langImg = (color: string, letter: string): string =>
2833
3263
  */
2834
3264
  export const CompactEnumWithImages: Story = {
2835
3265
  // chromatic off: ends with the radio editor open in the card.
2836
- parameters: { chromatic: { disable: true } },
3266
+ parameters: {
3267
+ docs: {
3268
+ description: {
3269
+ story:
3270
+ 'Renders a compact form with an enum option whose allowed values carry images — the read row shows the image alongside the label and the picker mounts the images in the collection.',
3271
+ },
3272
+ },
3273
+ chromatic: { disable: true },
3274
+ },
2837
3275
  args: {
2838
3276
  name: 'langForm',
2839
3277
  compact: true,
@@ -2891,7 +3329,15 @@ export const CompactEnumWithImages: Story = {
2891
3329
  * instead of the language radio.
2892
3330
  */
2893
3331
  export const CompactEnumRichtextValue: Story = {
2894
- parameters: { chromatic: { disable: true } },
3332
+ parameters: {
3333
+ docs: {
3334
+ description: {
3335
+ story:
3336
+ 'Renders a compact form with an enum option whose value is a richtext template — the read row shows the resolved template chip rather than the raw reference.',
3337
+ },
3338
+ },
3339
+ chromatic: { disable: true },
3340
+ },
2895
3341
  args: {
2896
3342
  name: 'langForm',
2897
3343
  compact: true,
@@ -2971,7 +3417,15 @@ const _isRowOpen = (field: string): boolean =>
2971
3417
  * first — the accordion model that keeps the read-first list scannable.
2972
3418
  */
2973
3419
  export const CompactSingleExpand: Story = {
2974
- parameters: { chromatic: { disable: true } },
3420
+ parameters: {
3421
+ docs: {
3422
+ description: {
3423
+ story:
3424
+ 'Renders a compact form with expandMode=\'single\' — opening one row automatically collapses whichever row was open before.',
3425
+ },
3426
+ },
3427
+ chromatic: { disable: true },
3428
+ },
2975
3429
  args: { name: 'expandSingle', compact: true, ...expandModeFixture },
2976
3430
  play: async () => {
2977
3431
  await waitFor(
@@ -2997,7 +3451,15 @@ export const CompactSingleExpand: Story = {
2997
3451
 
2998
3452
  /** `expandMode: 'multi'`: several rows can stay open at once (form-fill flow). */
2999
3453
  export const CompactMultiExpand: Story = {
3000
- parameters: { chromatic: { disable: true } },
3454
+ parameters: {
3455
+ docs: {
3456
+ description: {
3457
+ story:
3458
+ 'Renders a compact form with expandMode=\'multi\' — every opened row stays open until it is explicitly done, so several editors can be on screen at once.',
3459
+ },
3460
+ },
3461
+ chromatic: { disable: true },
3462
+ },
3001
3463
  args: { name: 'expandMulti', compact: true, expandMode: 'multi', ...expandModeFixture },
3002
3464
  play: async () => {
3003
3465
  await waitFor(
@@ -3046,6 +3508,14 @@ const HostProvidedEditor = ({
3046
3508
  );
3047
3509
 
3048
3510
  export const CompactFieldTypes: Story = {
3511
+ parameters: {
3512
+ docs: {
3513
+ description: {
3514
+ story:
3515
+ 'Renders a compact form that exercises the full catalogue of ui_type renderers — every type (string, richtext, hash, list, file, colour, byte-size, cron, connection, enum, etc.) is present with a representative value.',
3516
+ },
3517
+ },
3518
+ },
3049
3519
  args: {
3050
3520
  compact: true,
3051
3521
  minColumnWidth: '300px',
@@ -3550,7 +4020,15 @@ const _compactExpandAllRows = async () => {
3550
4020
 
3551
4021
  export const CompactFieldTypesEditing: Story = {
3552
4022
  // chromatic off: every catalog editor mounts live (async) — flaky and snapshot-heavy.
3553
- parameters: { chromatic: { disable: true } },
4023
+ parameters: {
4024
+ docs: {
4025
+ description: {
4026
+ story:
4027
+ 'Renders CompactFieldTypes and opens every row — the edit surface for each ui_type mounts and the row-level Clear / built-in clear affordances are wired per input.',
4028
+ },
4029
+ },
4030
+ chromatic: { disable: true },
4031
+ },
3554
4032
  // multi: this story expands every row at once (single-open would collapse them).
3555
4033
  args: { ...CompactFieldTypes.args, expandMode: 'multi' as const },
3556
4034
  play: async () => {
@@ -3591,6 +4069,14 @@ export const CompactFieldTypesEditing: Story = {
3591
4069
  // to a muted-green "Covers" / "Covered by <X>" once satisfied. Members live in
3592
4070
  // DIFFERENT panels to prove cross-panel linkage.
3593
4071
  export const CompactRequiredGroups: Story = {
4072
+ parameters: {
4073
+ docs: {
4074
+ description: {
4075
+ story:
4076
+ 'Renders a compact form whose options belong to required_groups — the group\'s one-of-required indicator appears in the row rail and clears once any member is filled.',
4077
+ },
4078
+ },
4079
+ },
3594
4080
  args: {
3595
4081
  compact: true,
3596
4082
  minColumnWidth: '300px',
@@ -3732,7 +4218,15 @@ const _compactTypeIntoCardRichText = async (field: string, value: string) => {
3732
4218
  // (`[[a, b]]`) locks the row; the lock popover renders the "any of:" group;
3733
4219
  // fulfilling EITHER blocker unlocks (and flashes) the dependent row.
3734
4220
  export const CompactOptionDependsOnOptionOrAnotherOption: Story = {
3735
- parameters: { chromatic: { disable: true } },
4221
+ parameters: {
4222
+ docs: {
4223
+ description: {
4224
+ story:
4225
+ 'Renders a compact form with an option that depends on A OR B — the row is locked with a dependency popover listing both alternatives; fulfilling either unlocks the row.',
4226
+ },
4227
+ },
4228
+ chromatic: { disable: true },
4229
+ },
3736
4230
  args: {
3737
4231
  compact: true,
3738
4232
  minColumnWidth: '300px',
@@ -3841,7 +4335,15 @@ export const CompactOptionDependsOnOptionOrAnotherOption: Story = {
3841
4335
  // The dependency targets a required-group MEMBER: fulfilling it unlocks the
3842
4336
  // dependent row AND satisfies the group — both linkage systems on one form.
3843
4337
  export const CompactOptionDependsOnOptionInRequiredGroup: Story = {
3844
- parameters: { chromatic: { disable: true } },
4338
+ parameters: {
4339
+ docs: {
4340
+ description: {
4341
+ story:
4342
+ 'Renders a compact form with an option that depends on a required-group member — the row locks until the required-group option is filled.',
4343
+ },
4344
+ },
4345
+ chromatic: { disable: true },
4346
+ },
3845
4347
  args: {
3846
4348
  compact: true,
3847
4349
  minColumnWidth: '300px',
@@ -3922,7 +4424,15 @@ export const CompactOptionDependsOnOptionInRequiredGroup: Story = {
3922
4424
 
3923
4425
  // An `any`-typed option shows its value and expands to the type-aware editor.
3924
4426
  export const CompactAnyType: Story = {
3925
- parameters: { chromatic: { disable: true } },
4427
+ parameters: {
4428
+ docs: {
4429
+ description: {
4430
+ story:
4431
+ 'Renders a compact form with any-typed options — the read rows summarise the current value and the editor lets the operator pick the concrete type through the More menu.',
4432
+ },
4433
+ },
4434
+ chromatic: { disable: true },
4435
+ },
3926
4436
  args: {
3927
4437
  compact: true,
3928
4438
  minColumnWidth: '300px',
@@ -3943,7 +4453,15 @@ export const CompactAnyType: Story = {
3943
4453
  // A schema-level `readonly` field whose value differs from its default is fixed
3944
4454
  // back to the default (engine `fixOptions`); the read row shows the default.
3945
4455
  export const CompactReadonlyDefaultFix: Story = {
3946
- parameters: { chromatic: { disable: true } },
4456
+ parameters: {
4457
+ docs: {
4458
+ description: {
4459
+ story:
4460
+ 'Renders a compact form with a read-only option whose value differs from default_value — the value auto-corrects to the default at mount without the wrong value ever rendering.',
4461
+ },
4462
+ },
4463
+ chromatic: { disable: true },
4464
+ },
3947
4465
  args: {
3948
4466
  compact: true,
3949
4467
  minColumnWidth: '300px',
@@ -3967,7 +4485,15 @@ export const CompactReadonlyDefaultFix: Story = {
3967
4485
 
3968
4486
  // Values for options that aren't in the schema are filtered out, not rendered.
3969
4487
  export const CompactNonExistentFiltered: Story = {
3970
- parameters: { chromatic: { disable: true } },
4488
+ parameters: {
4489
+ docs: {
4490
+ description: {
4491
+ story:
4492
+ 'Renders a compact form with a value carrying an extra field that isn\'t in the schema — the extra field is filtered out and no row is rendered for it.',
4493
+ },
4494
+ },
4495
+ chromatic: { disable: true },
4496
+ },
3971
4497
  args: {
3972
4498
  compact: true,
3973
4499
  minColumnWidth: '300px',
@@ -3987,7 +4513,15 @@ export const CompactNonExistentFiltered: Story = {
3987
4513
 
3988
4514
  // A field with a long `desc` shows a help affordance that opens the help dialog.
3989
4515
  export const CompactHelpDialog: Story = {
3990
- parameters: { chromatic: { disable: true } },
4516
+ parameters: {
4517
+ docs: {
4518
+ description: {
4519
+ story:
4520
+ 'Renders a compact form and clicks a row\'s Help action — the help dialog opens with the option\'s long-form description.',
4521
+ },
4522
+ },
4523
+ chromatic: { disable: true },
4524
+ },
3991
4525
  args: {
3992
4526
  compact: true,
3993
4527
  minColumnWidth: '300px',
@@ -4013,7 +4547,15 @@ export const CompactHelpDialog: Story = {
4013
4547
 
4014
4548
  // Read-first rendering is render-stable — it doesn't emit a storm of onChanges.
4015
4549
  export const CompactDoesNotCauseInfiniteRerenders: Story = {
4016
- parameters: { chromatic: { disable: true } },
4550
+ parameters: {
4551
+ docs: {
4552
+ description: {
4553
+ story:
4554
+ 'Renders a compact form with a refetch-triggering parent and a list-of-hash dependent — mounting and interacting with the form does not trigger runaway re-renders.',
4555
+ },
4556
+ },
4557
+ chromatic: { disable: true },
4558
+ },
4017
4559
  args: {
4018
4560
  compact: true,
4019
4561
  minColumnWidth: '300px',
@@ -4042,7 +4584,15 @@ const loadCompactSchemaAsync = (): Promise<IQorusFormSchema> =>
4042
4584
  // the story earns its keep through the play test (the resolve path), not a
4043
4585
  // snapshot — the loading state has its own story below.
4044
4586
  export const CompactOptionsLoader: Story = {
4045
- parameters: { chromatic: { disable: true } },
4587
+ parameters: {
4588
+ docs: {
4589
+ description: {
4590
+ story:
4591
+ 'Renders a compact form whose options are fetched via a url — the loader skeleton is shown until the schema resolves, then the compact rows mount.',
4592
+ },
4593
+ },
4594
+ chromatic: { disable: true },
4595
+ },
4046
4596
  args: {
4047
4597
  compact: true,
4048
4598
  minColumnWidth: '300px',
@@ -4060,6 +4610,14 @@ export const CompactOptionsLoader: Story = {
4060
4610
 
4061
4611
  // A rejected load surfaces the engine's error state instead of the form.
4062
4612
  export const CompactOptionsLoaderError: Story = {
4613
+ parameters: {
4614
+ docs: {
4615
+ description: {
4616
+ story:
4617
+ 'Renders a compact form whose options fetch fails — the loader resolves into an error message rather than crashing.',
4618
+ },
4619
+ },
4620
+ },
4063
4621
  args: {
4064
4622
  compact: true,
4065
4623
  minColumnWidth: '300px',
@@ -4080,6 +4638,14 @@ export const CompactOptionsLoaderError: Story = {
4080
4638
  // and the snapshot Chromatic captures. The resolve path (load → form →
4081
4639
  // `onOptionsLoaded`) is exercised by `CompactOptionsLoader` above.
4082
4640
  export const OptionsLoader: Story = {
4641
+ parameters: {
4642
+ docs: {
4643
+ description: {
4644
+ story:
4645
+ 'Renders the classic FormEngine whose options are fetched via a url — the loader is shown until the schema resolves.',
4646
+ },
4647
+ },
4648
+ },
4083
4649
  args: {
4084
4650
  minColumnWidth: '300px',
4085
4651
  value: CompactValue,
@@ -4198,6 +4764,14 @@ const infoDisplayArgs = {
4198
4764
  // The flagship "real form" story: the Basic fixture + stress fields with full
4199
4765
  // descriptions — how compact mode looks and feels in actual use.
4200
4766
  export const CompactShowcase: Story = {
4767
+ parameters: {
4768
+ docs: {
4769
+ description: {
4770
+ story:
4771
+ 'Renders the flagship compact-mode showcase — the Basic fixture plus every stress field type across a real-form layout, used as the compact-mode reference screenshot.',
4772
+ },
4773
+ },
4774
+ },
4201
4775
  args: infoDisplayArgs,
4202
4776
  play: async () => {
4203
4777
  await _testsWaitForText('API endpoint');
@@ -4265,6 +4839,14 @@ export const CompactShowcase: Story = {
4265
4839
 
4266
4840
  // The same stress form in a 360 px container — stacked rows, panels full-width.
4267
4841
  export const CompactShowcaseMobile: Story = {
4842
+ parameters: {
4843
+ docs: {
4844
+ description: {
4845
+ story:
4846
+ 'Renders the compact showcase at a ~390px mobile viewport — the compact rows collapse into a single-column stack.',
4847
+ },
4848
+ },
4849
+ },
4268
4850
  args: infoDisplayArgs,
4269
4851
  decorators: [
4270
4852
  (StoryComponent: React.ComponentType) => (
@@ -4284,6 +4866,14 @@ export const CompactShowcaseMobile: Story = {
4284
4866
  // credential pair (one provided → green node + Provided badge) and a 4-member
4285
4867
  // notification group (none set → violet, pending).
4286
4868
  export const CompactRequiredGroupRails: Story = {
4869
+ parameters: {
4870
+ docs: {
4871
+ description: {
4872
+ story:
4873
+ 'Renders a compact form with several required_groups — each group\'s rail sits alongside its rows so the operator can see which one-of-required set the row belongs to.',
4874
+ },
4875
+ },
4876
+ },
4287
4877
  args: {
4288
4878
  compact: true,
4289
4879
  minColumnWidth: '320px',
@@ -4358,7 +4948,15 @@ export const CompactRequiredGroupRails: Story = {
4358
4948
  // keeps required-group clusters contiguous (rails intact) — never interleaving
4359
4949
  // across groups. Regression cover for the compact sort.
4360
4950
  export const CompactFieldSortWithinGroups: Story = {
4361
- parameters: { chromatic: { disable: true } },
4951
+ parameters: {
4952
+ docs: {
4953
+ description: {
4954
+ story:
4955
+ 'Renders a compact form with grouped options that carry sort ordinals — rows within each group render in sort order, not schema-declaration order.',
4956
+ },
4957
+ },
4958
+ chromatic: { disable: true },
4959
+ },
4362
4960
  args: CompactRequiredGroupRails.args,
4363
4961
  play: async () => {
4364
4962
  await _testsWaitForText('API key');
@@ -4408,6 +5006,14 @@ export const CompactFieldSortWithinGroups: Story = {
4408
5006
  // required-but-empty, so the engine expands the `description` row on mount and
4409
5007
  // its editor takes focus — no click, no DOM scraping.
4410
5008
  export const CompactAutoFocusFirstRequired: Story = {
5009
+ parameters: {
5010
+ docs: {
5011
+ description: {
5012
+ story:
5013
+ 'Renders a compact form with autoFocus enabled — the first unfilled required row opens for editing automatically on mount.',
5014
+ },
5015
+ },
5016
+ },
4411
5017
  args: {
4412
5018
  compact: true,
4413
5019
  minColumnWidth: '300px',
@@ -4480,6 +5086,14 @@ const CompactInvalidFilledValue: IOptions = {
4480
5086
  };
4481
5087
 
4482
5088
  export const CompactAutoFocusTargetsInvalidFilledField: Story = {
5089
+ parameters: {
5090
+ docs: {
5091
+ description: {
5092
+ story:
5093
+ 'Renders a compact form with autoFocus enabled and a required field holding an invalid value — the autofocus targets the invalid filled field rather than the next empty required.',
5094
+ },
5095
+ },
5096
+ },
4483
5097
  args: {
4484
5098
  compact: true,
4485
5099
  minColumnWidth: '300px',
@@ -4555,6 +5169,14 @@ const CompactNonFocusableFirstSchema: Record<string, TCompactField> = {
4555
5169
  const CompactNonFocusableFirstValue: IOptions = {}; // both unset → both need attention
4556
5170
 
4557
5171
  export const CompactAutoFocusNonFocusableFirstField: Story = {
5172
+ parameters: {
5173
+ docs: {
5174
+ description: {
5175
+ story:
5176
+ 'Renders a compact form with autoFocus enabled where the first needs-attention field is a boolean (not focusable) — the autofocus skips it and opens the next focusable field instead.',
5177
+ },
5178
+ },
5179
+ },
4558
5180
  args: {
4559
5181
  compact: true,
4560
5182
  minColumnWidth: '300px',