@qoretechnologies/reqraft 0.10.31-pr.92.g2abe73e → 0.10.31-pr.92.g5ac2ac2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qoretechnologies/reqraft",
3
- "version": "0.10.31-pr.92.g2abe73e",
3
+ "version": "0.10.31-pr.92.g5ac2ac2",
4
4
  "description": "ReQraft is a collection of React components and hooks that are used across Qore Technologies' products made using the ReQore component library from Qore.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -22,6 +22,7 @@ import {
22
22
  import { startDpqlMockLsp } from '../expressions/dpqlMockLsp';
23
23
  import { mockExpressions } from '../expressions/mockExpressions';
24
24
  import { mockPopulatedDefinition } from '../fields/schema-definition/mockDefinition';
25
+ import { defaultMarkdownRenderer } from '../fields/markdown/MarkdownView';
25
26
  import {
26
27
  FormEngine,
27
28
  IFormEngineGroup,
@@ -322,7 +323,7 @@ export const DescriptionIsShown: Story = {
322
323
  docs: {
323
324
  description: {
324
325
  story:
325
- 'Renders the Basic FormEngine and clicks the Option with description label — the help panel opens with the option\'s long-form description.',
326
+ "Renders the Basic FormEngine and clicks the Option with description label — the help panel opens with the option's long-form description.",
326
327
  },
327
328
  },
328
329
  },
@@ -442,7 +443,7 @@ export const WithRequiredGroups: Story = {
442
443
  docs: {
443
444
  description: {
444
445
  story:
445
- '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.',
446
+ "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.",
446
447
  },
447
448
  },
448
449
  },
@@ -462,7 +463,7 @@ export const WithRequiredGroupsFulfilled: Story = {
462
463
  docs: {
463
464
  description: {
464
465
  story:
465
- '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.',
466
+ "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.",
466
467
  },
467
468
  },
468
469
  },
@@ -698,7 +699,7 @@ export const OptionsWithOnChangeTriggerEvents: Story = {
698
699
  docs: {
699
700
  description: {
700
701
  story:
701
- '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.',
702
+ "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.",
702
703
  },
703
704
  },
704
705
  },
@@ -790,7 +791,7 @@ export const OptionInheritsRenderPropFromSibling: Story = {
790
791
  docs: {
791
792
  description: {
792
793
  story:
793
- '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.',
794
+ "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.",
794
795
  },
795
796
  },
796
797
  },
@@ -827,8 +828,7 @@ export const OptionInheritsRenderPropFromSibling: Story = {
827
828
 
828
829
  // Initial state: lang = "qore" → editor renderer receives language="qore"
829
830
  await waitFor(
830
- () =>
831
- expect(canvas.getByTestId('code-editor-language')).toHaveTextContent('syntax: qore'),
831
+ () => expect(canvas.getByTestId('code-editor-language')).toHaveTextContent('syntax: qore'),
832
832
  { timeout: 5000 }
833
833
  );
834
834
 
@@ -844,8 +844,7 @@ export const OptionInheritsRenderPropFromSibling: Story = {
844
844
  await userEvent.click(pythonItem);
845
845
 
846
846
  await waitFor(
847
- () =>
848
- expect(canvas.getByTestId('code-editor-language')).toHaveTextContent('syntax: python'),
847
+ () => expect(canvas.getByTestId('code-editor-language')).toHaveTextContent('syntax: python'),
849
848
  { timeout: 5000 }
850
849
  );
851
850
  },
@@ -900,10 +899,9 @@ export const OptionInheritsRenderPropFromSiblingCompact: Story = {
900
899
  // schema arrives intact + the source-code row is present. The full
901
900
  // interaction (lang flip -> language prop updates) is covered by the
902
901
  // classic `OptionInheritsRenderPropFromSibling` story.
903
- await waitFor(
904
- () => expect(canvas.getAllByText('Source Code').length).toBeGreaterThan(0),
905
- { timeout: 5000 }
906
- );
902
+ await waitFor(() => expect(canvas.getAllByText('Source Code').length).toBeGreaterThan(0), {
903
+ timeout: 5000,
904
+ });
907
905
  },
908
906
  };
909
907
 
@@ -987,13 +985,19 @@ export const CompactRowMarkdownPreview: Story = {
987
985
  docs: {
988
986
  description: {
989
987
  story:
990
- "Renders compact-mode markdown rows over a service description — the multi-line row summarises its value as prose (no `##`, no `**`) with a line-count tag and mounts the rendered document under the row, while the one-line row keeps its single rendered line and no preview.",
988
+ 'Renders compact-mode markdown rows over a service description, with a host markdown renderer supplied — the multi-line row summarises its value as prose (no `##`, no `**`) with a line-count tag and mounts the rendered document under the row, while the one-line row keeps its single rendered line and no preview.',
991
989
  },
992
990
  },
993
991
  },
994
992
  args: {
995
993
  compact: true,
996
994
  minColumnWidth: '360px',
995
+ // The row inset draws through the HOST's renderer and has no built-in
996
+ // fallback: a form that picks its own markdown dialect renders the same
997
+ // description differently from the page it belongs to, which is the whole
998
+ // problem this seam exists to avoid. `defaultMarkdownRenderer` is reqraft's
999
+ // own view, supplied here the way a host supplies its own.
1000
+ markdownRenderer: defaultMarkdownRenderer,
997
1001
  value: {
998
1002
  desc: {
999
1003
  type: 'string',
@@ -1066,7 +1070,7 @@ export const NestedOptionInheritsRenderPropFromAncestor: Story = {
1066
1070
  docs: {
1067
1071
  description: {
1068
1072
  story:
1069
- '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.',
1073
+ "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.",
1070
1074
  },
1071
1075
  },
1072
1076
  },
@@ -1154,7 +1158,7 @@ export const NestedOptionInheritsRenderPropFromAncestorCompact: Story = {
1154
1158
  docs: {
1155
1159
  description: {
1156
1160
  story:
1157
- 'Renders the NestedOptionInheritsRenderPropFromAncestor schema with compact=true — the compact renderer summarises the list-of-hash rows as \'init, run\' rather than [object Object].',
1161
+ "Renders the NestedOptionInheritsRenderPropFromAncestor schema with compact=true — the compact renderer summarises the list-of-hash rows as 'init, run' rather than [object Object].",
1158
1162
  },
1159
1163
  },
1160
1164
  },
@@ -1216,14 +1220,14 @@ export const NestedOptionInheritsRenderPropFromAncestorCompact: Story = {
1216
1220
  // already exercise), assert on the STRUCTURAL element: the schema
1217
1221
  // arrived intact through `inheritedFromParent` and the row-level
1218
1222
  // options include the body field wired to the code-editor override.
1219
- await waitFor(
1220
- () => expect(canvas.getAllByText('Methods').length).toBeGreaterThan(0),
1221
- { timeout: 5000 }
1222
- );
1223
+ await waitFor(() => expect(canvas.getAllByText('Methods').length).toBeGreaterThan(0), {
1224
+ timeout: 5000,
1225
+ });
1223
1226
  // The list-of-hashes value summarises by the items' names — never a raw
1224
1227
  // "[object Object]" (regression: it used to stringify each hash envelope).
1225
- await expect(await canvas.findByText('init, run', undefined, { timeout: 5000 }))
1226
- .toBeInTheDocument();
1228
+ await expect(
1229
+ await canvas.findByText('init, run', undefined, { timeout: 5000 })
1230
+ ).toBeInTheDocument();
1227
1231
  await expect(canvasElement.textContent ?? '').not.toContain('[object Object]');
1228
1232
  },
1229
1233
  };
@@ -1242,7 +1246,7 @@ export const CompactNestedListRowsStayCompact: Story = {
1242
1246
  docs: {
1243
1247
  description: {
1244
1248
  story:
1245
- 'Expands a list-of-hash option inside a compact form — each row\'s arg_schema sub-form renders as compact read-first rows, matching the parent, instead of falling back to the classic stacked-label form.',
1249
+ "Expands a list-of-hash option inside a compact form — each row's arg_schema sub-form renders as compact read-first rows, matching the parent, instead of falling back to the classic stacked-label form.",
1246
1250
  },
1247
1251
  },
1248
1252
  },
@@ -1324,7 +1328,7 @@ export const CompactNestedListRowsStayCompactMobile: Story = {
1324
1328
  docs: {
1325
1329
  description: {
1326
1330
  story:
1327
- 'Renders the expanded list-of-hash rows at a ~360px mobile viewport — each row\'s compact sub-form stacks into a single column rather than overflowing.',
1331
+ "Renders the expanded list-of-hash rows at a ~360px mobile viewport — each row's compact sub-form stacks into a single column rather than overflowing.",
1328
1332
  },
1329
1333
  },
1330
1334
  },
@@ -1364,7 +1368,7 @@ export const DependantsResetWhenParentChanges: Story = {
1364
1368
  docs: {
1365
1369
  description: {
1366
1370
  story:
1367
- '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.',
1371
+ "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.",
1368
1372
  },
1369
1373
  },
1370
1374
  },
@@ -1956,7 +1960,7 @@ export const CompactEditingShowsDescription: Story = {
1956
1960
  docs: {
1957
1961
  description: {
1958
1962
  story:
1959
- "Renders the compact form with the descriptions toggle off — a collapsed row hides its short description, and opening the row for editing reveals it under the field name along with the `?` help affordance.",
1963
+ 'Renders the compact form with the descriptions toggle off — a collapsed row hides its short description, and opening the row for editing reveals it under the field name along with the `?` help affordance.',
1960
1964
  },
1961
1965
  },
1962
1966
  },
@@ -2069,7 +2073,7 @@ export const CompactBasic: Story = {
2069
2073
  docs: {
2070
2074
  description: {
2071
2075
  story:
2072
- '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.',
2076
+ "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.",
2073
2077
  },
2074
2078
  },
2075
2079
  chromatic: { disable: true },
@@ -2413,7 +2417,7 @@ export const CompactBatchedCommit: Story = {
2413
2417
  docs: {
2414
2418
  description: {
2415
2419
  story:
2416
- '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.',
2420
+ "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.",
2417
2421
  },
2418
2422
  },
2419
2423
  chromatic: { disable: true },
@@ -2487,7 +2491,7 @@ export const CompactBatchedCommitInvalid: Story = {
2487
2491
  docs: {
2488
2492
  description: {
2489
2493
  story:
2490
- 'Renders an invalid form in commitMode=\'batched\' — staging an edit shows the unsaved-changes bar but Save is disabled and onCommit never fires.',
2494
+ "Renders an invalid form in commitMode='batched' — staging an edit shows the unsaved-changes bar but Save is disabled and onCommit never fires.",
2491
2495
  },
2492
2496
  },
2493
2497
  },
@@ -2861,7 +2865,7 @@ export const CompactPanelChangeScroll: Story = {
2861
2865
  docs: {
2862
2866
  description: {
2863
2867
  story:
2864
- 'Renders a compact form inside a scrollable panel — opening a row keeps the panel\'s scroll position pinned rather than jumping to the top.',
2868
+ "Renders a compact form inside a scrollable panel — opening a row keeps the panel's scroll position pinned rather than jumping to the top.",
2865
2869
  },
2866
2870
  },
2867
2871
  chromatic: { disable: true },
@@ -2907,9 +2911,9 @@ export const CompactPanelChangeScroll: Story = {
2907
2911
  // …and flashed, signalling the engine located/scrolled to its new panel.
2908
2912
  await waitFor(
2909
2913
  () =>
2910
- expect(
2911
- document.querySelector('.readfirst-row[data-field="opt"]')?.className
2912
- ).toContain('readfirst-row-flash'),
2914
+ expect(document.querySelector('.readfirst-row[data-field="opt"]')?.className).toContain(
2915
+ 'readfirst-row-flash'
2916
+ ),
2913
2917
  { timeout: 4000 }
2914
2918
  );
2915
2919
  },
@@ -3011,10 +3015,9 @@ export const CompactFieldsMenu: Story = {
3011
3015
  // Only Notes is expanded, so the single More (⋮) menu in the DOM is its own.
3012
3016
  // (ReqoreDropdown's trigger isn't a DOM descendant of the row, so don't scope
3013
3017
  // the selector to [data-field].)
3014
- await waitFor(
3015
- () => expect(document.querySelector('.options-readfirst-more')).toBeTruthy(),
3016
- { timeout: 10000 }
3017
- );
3018
+ await waitFor(() => expect(document.querySelector('.options-readfirst-more')).toBeTruthy(), {
3019
+ timeout: 10000,
3020
+ });
3018
3021
  await _testsClickButton({ selector: '.options-readfirst-more' });
3019
3022
  let removeItem: Element | undefined;
3020
3023
  await waitFor(
@@ -3099,10 +3102,7 @@ export const CompactDescriptionsToggle: Story = {
3099
3102
  // Collapse back to the read row (Done) before toggling descriptions off.
3100
3103
  await _testsClickButton({ selector: '[data-field="host"] .options-readfirst-done' });
3101
3104
  await waitFor(
3102
- () =>
3103
- expect(
3104
- document.querySelector('.readfirst-row-editing[data-field="host"]')
3105
- ).toBeFalsy(),
3105
+ () => expect(document.querySelector('.readfirst-row-editing[data-field="host"]')).toBeFalsy(),
3106
3106
  { timeout: 10000 }
3107
3107
  );
3108
3108
 
@@ -3803,7 +3803,7 @@ export const CompactSingleExpand: Story = {
3803
3803
  docs: {
3804
3804
  description: {
3805
3805
  story:
3806
- 'Renders a compact form with expandMode=\'single\' — opening one row automatically collapses whichever row was open before.',
3806
+ "Renders a compact form with expandMode='single' — opening one row automatically collapses whichever row was open before.",
3807
3807
  },
3808
3808
  },
3809
3809
  chromatic: { disable: true },
@@ -3837,7 +3837,7 @@ export const CompactMultiExpand: Story = {
3837
3837
  docs: {
3838
3838
  description: {
3839
3839
  story:
3840
- '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.',
3840
+ "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.",
3841
3841
  },
3842
3842
  },
3843
3843
  chromatic: { disable: true },
@@ -4456,9 +4456,7 @@ export const CompactFieldTypesEditing: Story = {
4456
4456
  },
4457
4457
  { timeout: 10000 }
4458
4458
  );
4459
- await userEvent.click(
4460
- within(confirmationModal!).getByRole('button', { name: 'Clear value' })
4461
- );
4459
+ await userEvent.click(within(confirmationModal!).getByRole('button', { name: 'Clear value' }));
4462
4460
  await waitFor(() => {
4463
4461
  expect(editRow('enabled').querySelector('.options-readfirst-clear')).not.toBeInTheDocument();
4464
4462
  expect(editRow('enabled').querySelector('.options-readfirst-revert')).toBeInTheDocument();
@@ -4475,7 +4473,7 @@ export const CompactRequiredGroups: Story = {
4475
4473
  docs: {
4476
4474
  description: {
4477
4475
  story:
4478
- '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.',
4476
+ "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.",
4479
4477
  },
4480
4478
  },
4481
4479
  },
@@ -4891,7 +4889,7 @@ export const CompactNonExistentFiltered: Story = {
4891
4889
  docs: {
4892
4890
  description: {
4893
4891
  story:
4894
- '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.',
4892
+ "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.",
4895
4893
  },
4896
4894
  },
4897
4895
  chromatic: { disable: true },
@@ -4919,7 +4917,7 @@ export const CompactHelpDialog: Story = {
4919
4917
  docs: {
4920
4918
  description: {
4921
4919
  story:
4922
- 'Renders a compact form and clicks a row\'s Help action — the help dialog opens with the option\'s long-form description.',
4920
+ "Renders a compact form and clicks a row's Help action — the help dialog opens with the option's long-form description.",
4923
4921
  },
4924
4922
  },
4925
4923
  chromatic: { disable: true },
@@ -5218,9 +5216,7 @@ export const CompactShowcase: Story = {
5218
5216
  // Schema message panels render inside the value cell of the row itself,
5219
5217
  // directly beneath the value.
5220
5218
  const infoPanel = (field: string) =>
5221
- document.querySelector(
5222
- `.readfirst-row[data-field="${field}"] .options-readfirst-info-panel`
5223
- );
5219
+ document.querySelector(`.readfirst-row[data-field="${field}"] .options-readfirst-info-panel`);
5224
5220
 
5225
5221
  // Default-value notes and validation/dependency hints now render as a compact
5226
5222
  // INLINE reason (no ⓘ, no panel) — visible without any interaction.
@@ -5272,7 +5268,7 @@ export const CompactRequiredGroupRails: Story = {
5272
5268
  docs: {
5273
5269
  description: {
5274
5270
  story:
5275
- '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.',
5271
+ "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.",
5276
5272
  },
5277
5273
  },
5278
5274
  },
@@ -5758,3 +5754,41 @@ export const CompactReadFirstRichtextTemplateBaseline: Story = {
5758
5754
  await expect(centreOffset).toBeLessThanOrEqual(1);
5759
5755
  },
5760
5756
  };
5757
+
5758
+ /**
5759
+ * The other half of the markdown contract: with NO host renderer there is no
5760
+ * inset at all. The row is not left empty though — its one line still carries
5761
+ * the document's prose, summarised. Losing the RENDERING without a renderer is
5762
+ * the design; losing the CONTENT would be a bug.
5763
+ */
5764
+ export const CompactRowMarkdownWithoutRenderer: Story = {
5765
+ parameters: {
5766
+ docs: {
5767
+ description: {
5768
+ story:
5769
+ 'Renders the same compact markdown rows with no host renderer supplied — no rendered document mounts under the row, and the row still shows the description as prose rather than as markdown source.',
5770
+ },
5771
+ },
5772
+ },
5773
+ args: {
5774
+ ...CompactRowMarkdownPreview.args,
5775
+ markdownRenderer: undefined,
5776
+ },
5777
+ play: async ({ canvasElement }) => {
5778
+ const descRow = await waitFor(() => {
5779
+ const row = canvasElement.querySelector('[data-field="desc"]');
5780
+ expect(row).toBeTruthy();
5781
+ return row!;
5782
+ });
5783
+
5784
+ // No renderer, no inset — reqraft does not fall back to a dialect the host
5785
+ // never chose.
5786
+ expect(descRow.querySelector('.options-readfirst-markdown')).toBeNull();
5787
+
5788
+ // ...but the prose survives: the markers are stripped, not the content.
5789
+ const descText = descRow.querySelector('.options-readfirst-valuetext')?.textContent ?? '';
5790
+ expect(descText).toContain('Order intake');
5791
+ expect(descText).not.toContain('##');
5792
+ expect(descText).not.toContain('**');
5793
+ },
5794
+ };