@qoretechnologies/reqraft 0.10.66-pr.145.g620503a → 0.10.66-pr.145.g7df2015

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.
@@ -286,15 +286,15 @@ export interface IFormEngineProps extends Omit<IReqoreCollectionProps, 'onChange
286
286
  */
287
287
  compact?: boolean;
288
288
  /**
289
- * How the form LOOKS — never what it does. `'calm'`, the default, draws the
290
- * status boxes as plain panels on the theme's panel surface with label/value
291
- * rows split by hairlines, grey labels, an amber "Required · add a value" in
292
- * place of red asterisks and messages, quiet counts, no dot on a healthy row,
293
- * Yes/No as words, and a readiness meter whose done part is grey. `'classic'`
294
- * is the earlier look (tinted boxes, a green meter, a dot on every row), for a
295
- * host that asks for it. See {@link TFormEngineAppearance}.
296
- *
297
- * Inherited: a nested (`arg_schema`) sub-form and every field editor the form mounts
289
+ * How the form LOOKS — never what it does. `'default'` keeps the established
290
+ * look; `'calm'` draws the status boxes as plain panels on the theme's panel
291
+ * surface with label/value rows split by hairlines, grey labels, an amber
292
+ * "Required · add a value" in place of red asterisks and messages, quiet
293
+ * counts, no dot on a healthy row, Yes/No as words, and a readiness meter
294
+ * whose done part is grey. See {@link TFormEngineAppearance}.
295
+ *
296
+ * Opt-in, so a consumer that does not pass it is unchanged. Inherited: a
297
+ * nested (`arg_schema`) sub-form and every field editor the form mounts
298
298
  * follow the form's appearance, and a form with no `appearance` of its own
299
299
  * follows a `FormAppearanceProvider` above it. Applies to compact mode; the
300
300
  * classic collection layout only passes it on to its field editors.
@@ -4,17 +4,16 @@ import { IReqoreTheme } from '@qoretechnologies/reqore/dist/constants/theme';
4
4
  * How a form looks. The look only: which fields exist, how they bucket, what a
5
5
  * click does and what is validated are identical in every appearance.
6
6
  *
7
- * - `'calm'` (the default) — colour only where something needs a person. The
8
- * status boxes are plain panels on the theme's panel surface with label/value
9
- * rows split by hairlines; labels are grey; a missing required value is an
10
- * amber word instead of a red asterisk and message; counts are quiet numbers;
11
- * a healthy row carries no dot; Yes/No are plain words; nothing is forced
12
- * into uppercase.
13
- * - `'classic'` — the earlier read-first look, for a host that asks for it:
14
- * tinted status boxes, an intent-coloured completion meter, a status dot on
15
- * every row.
7
+ * - `'default'` — the established read-first look: tinted status boxes, an
8
+ * intent-coloured completion meter, a status dot on every row.
9
+ * - `'calm'` — colour only where something needs a person. The status boxes are
10
+ * plain panels on the theme's panel surface with label/value rows split by
11
+ * hairlines; labels are grey; a missing required value is an amber word
12
+ * instead of a red asterisk and message; counts are quiet numbers; a healthy
13
+ * row carries no dot; Yes/No are plain words; nothing is forced into
14
+ * uppercase. Opt-in, so an app that has not asked for it does not change.
16
15
  */
17
- export type TFormEngineAppearance = 'calm' | 'classic';
16
+ export type TFormEngineAppearance = 'default' | 'calm';
18
17
  /**
19
18
  * The appearance in force for everything below it: the engine's own rows and
20
19
  * toolbar, every field editor it mounts, and every nested (`arg_schema`)
@@ -26,7 +25,7 @@ export type TFormEngineAppearance = 'calm' | 'classic';
26
25
  */
27
26
  export declare const FormAppearanceContext: import("react").Context<TFormEngineAppearance>;
28
27
  export declare const FormAppearanceProvider: import("react").Provider<TFormEngineAppearance>;
29
- /** The appearance in force here; `'calm'` when nothing set one. */
28
+ /** The appearance in force here; `'default'` when nothing set one. */
30
29
  export declare const useFormAppearance: () => TFormEngineAppearance;
31
30
  /** Shorthand for the one question most call sites ask. */
32
31
  export declare const useIsCalmForm: () => boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"formAppearance.d.ts","sourceRoot":"","sources":["../../../../src/components/form/engine/formAppearance.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,+CAA+C,CAAC;AAQ7E;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,qBAAqB,GAAG,MAAM,GAAG,SAAS,CAAC;AAEvD;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,gDAA8D,CAAC;AAEjG,eAAO,MAAM,sBAAsB,iDAAiC,CAAC;AAErE,mEAAmE;AACnE,eAAO,MAAM,iBAAiB,QAAO,qBACQ,CAAC;AAE9C,0DAA0D;AAC1D,eAAO,MAAM,aAAa,QAAO,OAAyC,CAAC;AAiB3E;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,UAAW,YAAY,KAAG,MACmC,CAAC;AAE9F,0EAA0E;AAC1E,eAAO,MAAM,oBAAoB,UAAW,YAAY,KAAG,MACqC,CAAC;AAEjG;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,gCAA2B,CAAC;AAC5D,eAAO,MAAM,wBAAwB,4BAAuB,CAAC"}
1
+ {"version":3,"file":"formAppearance.d.ts","sourceRoot":"","sources":["../../../../src/components/form/engine/formAppearance.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,+CAA+C,CAAC;AAQ7E;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,qBAAqB,GAAG,SAAS,GAAG,MAAM,CAAC;AAEvD;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,gDAA8D,CAAC;AAEjG,eAAO,MAAM,sBAAsB,iDAAiC,CAAC;AAErE,sEAAsE;AACtE,eAAO,MAAM,iBAAiB,QAAO,qBACW,CAAC;AAEjD,0DAA0D;AAC1D,eAAO,MAAM,aAAa,QAAO,OAAyC,CAAC;AAiB3E;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,UAAW,YAAY,KAAG,MACmC,CAAC;AAE9F,0EAA0E;AAC1E,eAAO,MAAM,oBAAoB,UAAW,YAAY,KAAG,MACqC,CAAC;AAEjG;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,gCAA2B,CAAC;AAC5D,eAAO,MAAM,wBAAwB,4BAAuB,CAAC"}
@@ -14,8 +14,8 @@ var react_1 = require("react");
14
14
  */
15
15
  exports.FormAppearanceContext = (0, react_1.createContext)(undefined);
16
16
  exports.FormAppearanceProvider = exports.FormAppearanceContext.Provider;
17
- /** The appearance in force here; `'calm'` when nothing set one. */
18
- var useFormAppearance = function () { var _a; return (_a = (0, react_1.useContext)(exports.FormAppearanceContext)) !== null && _a !== void 0 ? _a : 'calm'; };
17
+ /** The appearance in force here; `'default'` when nothing set one. */
18
+ var useFormAppearance = function () { var _a; return (_a = (0, react_1.useContext)(exports.FormAppearanceContext)) !== null && _a !== void 0 ? _a : 'default'; };
19
19
  exports.useFormAppearance = useFormAppearance;
20
20
  /** Shorthand for the one question most call sites ask. */
21
21
  var useIsCalmForm = function () { return (0, exports.useFormAppearance)() === 'calm'; };
@@ -1 +1 @@
1
- {"version":3,"file":"formAppearance.js","sourceRoot":"","sources":["../../../../src/components/form/engine/formAppearance.ts"],"names":[],"mappings":";;;AACA,uEAIsD;AACtD,+BAAkD;AAkBlD;;;;;;;;GAQG;AACU,QAAA,qBAAqB,GAAG,IAAA,qBAAa,EAAoC,SAAS,CAAC,CAAC;AAEpF,QAAA,sBAAsB,GAAG,6BAAqB,CAAC,QAAQ,CAAC;AAErE,mEAAmE;AAC5D,IAAM,iBAAiB,GAAG,sBAC/B,OAAA,MAAA,IAAA,kBAAU,EAAC,6BAAqB,CAAC,mCAAI,MAAM,CAAA,EAAA,CAAC;AADjC,QAAA,iBAAiB,qBACgB;AAE9C,0DAA0D;AACnD,IAAM,aAAa,GAAG,cAAe,OAAA,IAAA,yBAAiB,GAAE,KAAK,MAAM,EAA9B,CAA8B,CAAC;AAA9D,QAAA,aAAa,iBAAiD;AAE3E,8EAA8E;AAC9E,IAAM,uBAAuB,GAAG,UAC9B,KAAmB;IAEnB,IAAM,MAAM,GAAG,KAGd,CAAC;IACF,6EAA6E;IAC7E,6EAA6E;IAC7E,OAAO,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC,MAAM,CAAC,YAAY,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;QAClF,MAAM,CAAC,KAAK;QACd,CAAC,CAAC,SAAS,CAAC;AAChB,CAAC,CAAC;AAEF;;;;;GAKG;AACI,IAAM,mBAAmB,GAAG,UAAC,KAAmB,gBACrD,OAAA,MAAA,MAAA,uBAAuB,CAAC,KAAK,CAAC,0CAAE,IAAI,mCAAI,IAAA,uBAAc,EAAC,IAAA,+BAAsB,EAAC,KAAK,CAAC,EAAE,IAAI,CAAC,CAAA,EAAA,CAAC;AADjF,QAAA,mBAAmB,uBAC8D;AAE9F,0EAA0E;AACnE,IAAM,oBAAoB,GAAG,UAAC,KAAmB,gBACtD,OAAA,MAAA,MAAA,uBAAuB,CAAC,KAAK,CAAC,0CAAE,MAAM,mCAAI,IAAA,wBAAe,EAAC,IAAA,+BAAsB,EAAC,KAAK,CAAC,EAAE,IAAI,CAAC,CAAA,EAAA,CAAC;AADpF,QAAA,oBAAoB,wBACgE;AAEjG;;;;GAIG;AACU,QAAA,mBAAmB,GAAG,wBAAwB,CAAC;AAC/C,QAAA,wBAAwB,GAAG,oBAAoB,CAAC"}
1
+ {"version":3,"file":"formAppearance.js","sourceRoot":"","sources":["../../../../src/components/form/engine/formAppearance.ts"],"names":[],"mappings":";;;AACA,uEAIsD;AACtD,+BAAkD;AAiBlD;;;;;;;;GAQG;AACU,QAAA,qBAAqB,GAAG,IAAA,qBAAa,EAAoC,SAAS,CAAC,CAAC;AAEpF,QAAA,sBAAsB,GAAG,6BAAqB,CAAC,QAAQ,CAAC;AAErE,sEAAsE;AAC/D,IAAM,iBAAiB,GAAG,sBAC/B,OAAA,MAAA,IAAA,kBAAU,EAAC,6BAAqB,CAAC,mCAAI,SAAS,CAAA,EAAA,CAAC;AADpC,QAAA,iBAAiB,qBACmB;AAEjD,0DAA0D;AACnD,IAAM,aAAa,GAAG,cAAe,OAAA,IAAA,yBAAiB,GAAE,KAAK,MAAM,EAA9B,CAA8B,CAAC;AAA9D,QAAA,aAAa,iBAAiD;AAE3E,8EAA8E;AAC9E,IAAM,uBAAuB,GAAG,UAC9B,KAAmB;IAEnB,IAAM,MAAM,GAAG,KAGd,CAAC;IACF,6EAA6E;IAC7E,6EAA6E;IAC7E,OAAO,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC,MAAM,CAAC,YAAY,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;QAClF,MAAM,CAAC,KAAK;QACd,CAAC,CAAC,SAAS,CAAC;AAChB,CAAC,CAAC;AAEF;;;;;GAKG;AACI,IAAM,mBAAmB,GAAG,UAAC,KAAmB,gBACrD,OAAA,MAAA,MAAA,uBAAuB,CAAC,KAAK,CAAC,0CAAE,IAAI,mCAAI,IAAA,uBAAc,EAAC,IAAA,+BAAsB,EAAC,KAAK,CAAC,EAAE,IAAI,CAAC,CAAA,EAAA,CAAC;AADjF,QAAA,mBAAmB,uBAC8D;AAE9F,0EAA0E;AACnE,IAAM,oBAAoB,GAAG,UAAC,KAAmB,gBACtD,OAAA,MAAA,MAAA,uBAAuB,CAAC,KAAK,CAAC,0CAAE,MAAM,mCAAI,IAAA,wBAAe,EAAC,IAAA,+BAAsB,EAAC,KAAK,CAAC,EAAE,IAAI,CAAC,CAAA,EAAA,CAAC;AADpF,QAAA,oBAAoB,wBACgE;AAEjG;;;;GAIG;AACU,QAAA,mBAAmB,GAAG,wBAAwB,CAAC;AAC/C,QAAA,wBAAwB,GAAG,oBAAoB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qoretechnologies/reqraft",
3
- "version": "0.10.66-pr.145.g620503a",
3
+ "version": "0.10.66-pr.145.g7df2015",
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",
@@ -39,7 +39,6 @@ import {
39
39
  IOptionsSchemaArg,
40
40
  } from './FormEngine';
41
41
  import { basicFormValue, getBasicFormOptions as getOptions } from './__fixtures__/basicFormOptions';
42
- import { CALM_REQUIRED_LABEL, CALM_REQUIRED_READ_LABEL } from './formAppearance';
43
42
  import { chromeFieldBases, metaFieldBases } from './__fixtures__/fieldChromeOptions';
44
43
 
45
44
  /** The first status box: "To fill in" while nothing in it is a fault (a new form),
@@ -632,7 +631,7 @@ export const OptionDependsOnOptionInRequiredGroup: Story = {
632
631
  await waitFor(() =>
633
632
  expect(
634
633
  [...document.querySelectorAll('.system-option')].some(
635
- (row) => row.textContent?.includes('Required Option 6') && row.textContent?.includes(CALM_REQUIRED_LABEL)
634
+ (row) => row.textContent?.includes('Required Option 6') && row.textContent?.includes('This field is required')
636
635
  )
637
636
  ).toBe(true)
638
637
  );
@@ -2851,8 +2850,7 @@ export const Compact: Story = {
2851
2850
  await _testsWaitForText('order-fulfilment');
2852
2851
  await _testsWaitForText('orders, batch');
2853
2852
  await _testsWaitForText('Yes');
2854
- // The empty required Description says so where its value would be.
2855
- await _testsWaitForText(CALM_REQUIRED_LABEL);
2853
+ await _testsWaitForText('—');
2856
2854
  },
2857
2855
  };
2858
2856
 
@@ -3174,7 +3172,7 @@ export const CompactEmpty: Story = {
3174
3172
  docs: {
3175
3173
  description: {
3176
3174
  story:
3177
- 'Renders the Compact fixture with no value — the two empty required fields say "Required · add a value" where the value would be, the four empty optional fields render a dash placeholder, and those four sit in the collapsed Optional box.',
3175
+ '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.',
3178
3176
  },
3179
3177
  },
3180
3178
  },
@@ -3189,9 +3187,9 @@ export const CompactEmpty: Story = {
3189
3187
  // The four empty OPTIONAL fields live in the (collapsed) Optional box — open
3190
3188
  // it so all six empty fields are on screen.
3191
3189
  await _expandOptionalBox();
3192
- // Both required fields say what they need; the four optional ones read as a dash.
3193
- await _testsWaitForTextsCount(CALM_REQUIRED_LABEL, undefined, 2);
3194
- await _testsWaitForTextsCount('—', undefined, 4);
3190
+ // Both required fields read as unset; the four optional ones as "Not set".
3191
+ // All six empty fields read as a calm dash (the red asterisk marks required).
3192
+ await _testsWaitForTextsCount('—', undefined, 6);
3195
3193
  },
3196
3194
  };
3197
3195
 
@@ -3380,7 +3378,7 @@ export const CompactReadOnlyRichText: Story = {
3380
3378
  // A read view says what is wrong with the record, as an editable one does:
3381
3379
  // the fixture's invalid value and its empty required fields say so.
3382
3380
  await _testsWaitForText('Text value is empty');
3383
- await _testsWaitForText(CALM_REQUIRED_READ_LABEL);
3381
+ await _testsWaitForText('This field is required');
3384
3382
 
3385
3383
  const row = (name: string) => document.querySelector(`.readfirst-row[data-field="${name}"]`);
3386
3384
  // Richtext: the text and its chip, no Slate.
@@ -3539,7 +3537,7 @@ export const CompactReadOnlyValues: Story = {
3539
3537
  docs: {
3540
3538
  description: {
3541
3539
  story:
3542
- 'Read-only as a fact sheet, not a disabled editor: no completion meter, no Needs attention / Set / Optional boxes, no required asterisks; an optional field nobody set is not listed, a required one nobody set is listed and says "Required · not set"; every value is drawn in full in its row — long text wrapped under a Show more cap, the whole code block, every field of the hash, the chosen option with its description — and no row is a control: nothing is a button, and a click opens nothing.',
3540
+ 'Read-only as a fact sheet, not a disabled editor: no completion meter, no Needs attention / Set / Optional boxes, no required asterisks; an optional field nobody set is not listed, a required one nobody set reads as unset without the amber and says "This field is required"; every value is drawn in full in its row — long text wrapped under a Show more cap, the whole code block, every field of the hash, the chosen option with its description — and no row is a control: nothing is a button, and a click opens nothing.',
3543
3541
  },
3544
3542
  },
3545
3543
  chromatic: { disable: true },
@@ -3573,7 +3571,7 @@ export const CompactReadOnlyValues: Story = {
3573
3571
  )
3574
3572
  ).toBeNull();
3575
3573
  expect(document.querySelector('.readfirst-row[data-field="owner"]')?.textContent).toContain(
3576
- CALM_REQUIRED_READ_LABEL
3574
+ 'This field is required'
3577
3575
  );
3578
3576
 
3579
3577
  const row = (name: string) =>
@@ -4164,8 +4162,8 @@ export const CompactReadFirstEditing: Story = {
4164
4162
  // Booleans render as Yes/No, allowed_values as their display label.
4165
4163
  await _testsWaitForText('Yes');
4166
4164
  await _testsWaitForText('Python');
4167
- // The required-but-empty field says so instead of showing an editor.
4168
- await _testsWaitForText(CALM_REQUIRED_LABEL);
4165
+ // The required-but-empty field shows its placeholder instead of an editor.
4166
+ await _testsWaitForText('—');
4169
4167
  // No field editor (textarea) is mounted while everything is collapsed.
4170
4168
  await expect(document.querySelectorAll('.reqore-textarea')).toHaveLength(0);
4171
4169
 
@@ -8553,7 +8551,7 @@ export const CompactMaxFieldsShown: Story = {
8553
8551
  docs: {
8554
8552
  description: {
8555
8553
  story:
8556
- 'Renders a compact form with `maxFieldsShown: 3`, so each status box shows three rows and folds the rest behind a quiet "N more fields" last row. Clicking that row reveals the remainder and the label becomes "Show fewer".',
8554
+ 'Renders a compact form with `maxFieldsShown: 3`, so each status box shows three rows and folds the rest behind a dashed "N more fields" row. Clicking that row reveals the remainder and the label becomes "Show fewer".',
8557
8555
  },
8558
8556
  },
8559
8557
  },
@@ -8585,12 +8583,13 @@ export const CompactMaxFieldsShown: Story = {
8585
8583
  expect(more.classList.contains('readfirst-row')).toBe(true);
8586
8584
  expect(more.getAttribute('aria-expanded')).toBe('false');
8587
8585
 
8588
- // A quiet last row: the same 1px hairline above it as between the fields, and
8589
- // no dashed box around it (the classic look draws one).
8586
+ // The dashed edge is the thing that says "not a field". Asserting the
8587
+ // COMPUTED style, because the first cut of this took its colour from the
8588
+ // inter-row divider tint (~8% of the text colour) and rendered an invisible
8589
+ // border — the rule was there, the affordance was not.
8590
8590
  const edge = getComputedStyle(more);
8591
- expect(edge.borderTopStyle).toBe('solid');
8591
+ expect(edge.borderStyle).toBe('dashed');
8592
8592
  expect(edge.borderTopWidth).toBe('1px');
8593
- expect(edge.borderBottomStyle).toBe('none');
8594
8593
  // …and it inherits the rows' geometry rather than inventing its own
8595
8594
  expect(edge.paddingLeft).toBe(
8596
8595
  getComputedStyle(
@@ -9429,7 +9428,7 @@ export const ANewFormSaysWhatIsRequired: Story = {
9429
9428
  docs: {
9430
9429
  description: {
9431
9430
  story:
9432
- 'A brand-new form with two empty required fields. Each says "Required · add a value" from the start, including the first one, which opens for editing, without waiting for the author to visit it. Saying what is required is not saying something is wrong: the first box reads "To fill in", in the quiet colour, until a field has been visited and left empty.',
9431
+ 'A brand-new form with two empty required fields. Each says "This field is required" from the start, including the first one, which opens for editing, without waiting for the author to visit it. Saying what is required is not saying something is wrong: the first box reads "To fill in", in the quiet colour, until a field has been visited and left empty.',
9433
9432
  },
9434
9433
  },
9435
9434
  },
@@ -9446,8 +9445,8 @@ export const ANewFormSaysWhatIsRequired: Story = {
9446
9445
  await waitFor(() => {
9447
9446
  const title = canvasElement.querySelector('[data-field="title"]');
9448
9447
  const owner = canvasElement.querySelector('[data-field="owner"]');
9449
- expect(title?.textContent).toContain(CALM_REQUIRED_LABEL);
9450
- expect(owner?.textContent).toContain(CALM_REQUIRED_LABEL);
9448
+ expect(title?.textContent).toContain('This field is required');
9449
+ expect(owner?.textContent).toContain('This field is required');
9451
9450
  });
9452
9451
  },
9453
9452
  };
@@ -9457,7 +9456,7 @@ export const AReadOnlyFormShowsWhatIsWrong: Story = {
9457
9456
  docs: {
9458
9457
  description: {
9459
9458
  story:
9460
- 'A read-only form shows the same validation messages as an editable one: the empty required Title and Owner say "Required · not set" where the value would be, and Kind says its stored value is not one of the choices. Each requirement is stated once.',
9459
+ 'A read-only form shows the same validation messages as an editable one: the empty required Title and Owner say "This field is required", and Kind says its stored value is not one of the choices. Each empty value slot keeps its plain "—", so each requirement is stated once.',
9461
9460
  },
9462
9461
  },
9463
9462
  },
@@ -9472,12 +9471,11 @@ export const AReadOnlyFormShowsWhatIsWrong: Story = {
9472
9471
  await _testsWaitForText('"sideways" is not one of the choices');
9473
9472
  await waitFor(() => {
9474
9473
  const title = canvasElement.querySelector('[data-field="title"]');
9475
- expect(title?.textContent?.split(CALM_REQUIRED_READ_LABEL)).toHaveLength(2);
9476
- expect(title?.querySelector('.options-readfirst-valuetext')?.textContent).toBe(
9477
- CALM_REQUIRED_READ_LABEL
9478
- );
9474
+ expect(title?.textContent).toContain('This field is required');
9475
+ expect(title?.textContent?.split('This field is required')).toHaveLength(2);
9476
+ expect(title?.querySelector('.options-readfirst-valuetext')?.textContent).toBe('—');
9479
9477
  expect(canvasElement.querySelector('[data-field="owner"]')?.textContent).toContain(
9480
- CALM_REQUIRED_READ_LABEL
9478
+ 'This field is required'
9481
9479
  );
9482
9480
  });
9483
9481
  },
@@ -871,15 +871,15 @@ export interface IFormEngineProps extends Omit<IReqoreCollectionProps, 'onChange
871
871
  */
872
872
  compact?: boolean;
873
873
  /**
874
- * How the form LOOKS — never what it does. `'calm'`, the default, draws the
875
- * status boxes as plain panels on the theme's panel surface with label/value
876
- * rows split by hairlines, grey labels, an amber "Required · add a value" in
877
- * place of red asterisks and messages, quiet counts, no dot on a healthy row,
878
- * Yes/No as words, and a readiness meter whose done part is grey. `'classic'`
879
- * is the earlier look (tinted boxes, a green meter, a dot on every row), for a
880
- * host that asks for it. See {@link TFormEngineAppearance}.
874
+ * How the form LOOKS — never what it does. `'default'` keeps the established
875
+ * look; `'calm'` draws the status boxes as plain panels on the theme's panel
876
+ * surface with label/value rows split by hairlines, grey labels, an amber
877
+ * "Required · add a value" in place of red asterisks and messages, quiet
878
+ * counts, no dot on a healthy row, Yes/No as words, and a readiness meter
879
+ * whose done part is grey. See {@link TFormEngineAppearance}.
881
880
  *
882
- * Inherited: a nested (`arg_schema`) sub-form and every field editor the form mounts
881
+ * Opt-in, so a consumer that does not pass it is unchanged. Inherited: a
882
+ * nested (`arg_schema`) sub-form and every field editor the form mounts
883
883
  * follow the form's appearance, and a form with no `appearance` of its own
884
884
  * follows a `FormAppearanceProvider` above it. Applies to compact mode; the
885
885
  * classic collection layout only passes it on to its field editors.
@@ -17,7 +17,7 @@ import {
17
17
  import { CALM_REQUIRED_LABEL, CALM_REQUIRED_READ_LABEL } from './formAppearance';
18
18
 
19
19
  /*
20
- * The calm appearance (the default) against the classic one, over the fields a workflow
20
+ * The calm appearance against the default one, over the fields a workflow
21
21
  * creator actually serves (display names, groups and descriptions as the Qorus
22
22
  * server's workflow metadata gives them), so the comparison is about the look
23
23
  * and nothing else.
@@ -252,21 +252,18 @@ const expectNoDot = (field: string) => {
252
252
  * Stories
253
253
  * ------------------------------------------------------------------------ */
254
254
 
255
- export const ClassicLook: Story = {
256
- args: {
257
- appearance: 'classic',
258
- },
255
+ export const DefaultLook: Story = {
259
256
  parameters: {
260
257
  docs: {
261
258
  description: {
262
259
  story:
263
- '`appearance="classic"` over a filled workflow form, for comparison with **Calm**: tinted Set box, a green Ready and meter, a green dot on every filled row, upper-case group labels and a red/green Yes/No chip. Only a form that asks for it looks like this.',
260
+ 'The default appearance over a filled workflow form, for comparison with **Calm**: tinted Set box, a green Ready and meter, a green dot on every filled row, upper-case group labels and a red/green Yes/No chip.',
264
261
  },
265
262
  },
266
263
  },
267
264
  play: async () => {
268
265
  await _testsWaitForText('Supplier Payment Release');
269
- // The classic look is the one asked for: the tinted box and its count tag.
266
+ // The default look is untouched: the tinted box and its count tag.
270
267
  await waitFor(() => expect(box('set')).toBeTruthy());
271
268
  expect(box('set')!.querySelector('.reqore-panel-title .reqore-tag')).toBeTruthy();
272
269
  expect(row('display_name')!.querySelector('.options-readfirst-status-dot')).toBeTruthy();
@@ -274,11 +271,14 @@ export const ClassicLook: Story = {
274
271
  };
275
272
 
276
273
  export const Calm: Story = {
274
+ args: {
275
+ appearance: 'calm',
276
+ },
277
277
  parameters: {
278
278
  docs: {
279
279
  description: {
280
280
  story:
281
- 'The default appearance (calm) over the same filled form, with no `appearance` passed: the sections are plain panels on the theme’s panel surface with label/value rows split by hairlines, labels grey, group headings in sentence case, the count a quiet number, no dot on a healthy row, No as a word, and a short meter whose done part is grey.',
281
+ '`appearance="calm"` over the same filled form: the sections are plain panels on the theme’s panel surface with label/value rows split by hairlines, labels grey, group headings in sentence case, the count a quiet number, no dot on a healthy row, No as a word, and a short meter whose done part is grey.',
282
282
  },
283
283
  },
284
284
  },
@@ -350,6 +350,7 @@ export const Calm: Story = {
350
350
 
351
351
  export const CalmNeedsAttention: Story = {
352
352
  args: {
353
+ appearance: 'calm',
353
354
  value: newFormValue,
354
355
  // After a submit attempt: every empty required field is now a fault. A form nobody
355
356
  // has been to yet reads "To fill in" instead (CalmNewForm).
@@ -402,6 +403,9 @@ export const CalmNeedsAttention: Story = {
402
403
  };
403
404
 
404
405
  export const CalmChoiceHeading: Story = {
406
+ args: {
407
+ appearance: 'calm',
408
+ },
405
409
  parameters: {
406
410
  docs: {
407
411
  description: {
@@ -422,6 +426,7 @@ export const CalmChoiceHeading: Story = {
422
426
 
423
427
  export const CalmReadOnly: Story = {
424
428
  args: {
429
+ appearance: 'calm',
425
430
  readOnly: true,
426
431
  value: { ...filledValue, version: { type: 'string', value: '' } },
427
432
  },
@@ -447,6 +452,7 @@ export const CalmReadOnly: Story = {
447
452
 
448
453
  export const CalmNewForm: Story = {
449
454
  args: {
455
+ appearance: 'calm',
450
456
  value: newFormValue,
451
457
  },
452
458
  parameters: {
@@ -499,6 +505,7 @@ export const CalmNewForm: Story = {
499
505
 
500
506
  export const CalmOnAPhone: Story = {
501
507
  args: {
508
+ appearance: 'calm',
502
509
  value: newFormValue,
503
510
  },
504
511
  parameters: {
@@ -10,17 +10,16 @@ import { createContext, useContext } from 'react';
10
10
  * How a form looks. The look only: which fields exist, how they bucket, what a
11
11
  * click does and what is validated are identical in every appearance.
12
12
  *
13
- * - `'calm'` (the default) — colour only where something needs a person. The
14
- * status boxes are plain panels on the theme's panel surface with label/value
15
- * rows split by hairlines; labels are grey; a missing required value is an
16
- * amber word instead of a red asterisk and message; counts are quiet numbers;
17
- * a healthy row carries no dot; Yes/No are plain words; nothing is forced
18
- * into uppercase.
19
- * - `'classic'` — the earlier read-first look, for a host that asks for it:
20
- * tinted status boxes, an intent-coloured completion meter, a status dot on
21
- * every row.
13
+ * - `'default'` — the established read-first look: tinted status boxes, an
14
+ * intent-coloured completion meter, a status dot on every row.
15
+ * - `'calm'` — colour only where something needs a person. The status boxes are
16
+ * plain panels on the theme's panel surface with label/value rows split by
17
+ * hairlines; labels are grey; a missing required value is an amber word
18
+ * instead of a red asterisk and message; counts are quiet numbers; a healthy
19
+ * row carries no dot; Yes/No are plain words; nothing is forced into
20
+ * uppercase. Opt-in, so an app that has not asked for it does not change.
22
21
  */
23
- export type TFormEngineAppearance = 'calm' | 'classic';
22
+ export type TFormEngineAppearance = 'default' | 'calm';
24
23
 
25
24
  /**
26
25
  * The appearance in force for everything below it: the engine's own rows and
@@ -35,9 +34,9 @@ export const FormAppearanceContext = createContext<TFormEngineAppearance | undef
35
34
 
36
35
  export const FormAppearanceProvider = FormAppearanceContext.Provider;
37
36
 
38
- /** The appearance in force here; `'calm'` when nothing set one. */
37
+ /** The appearance in force here; `'default'` when nothing set one. */
39
38
  export const useFormAppearance = (): TFormEngineAppearance =>
40
- useContext(FormAppearanceContext) ?? 'calm';
39
+ useContext(FormAppearanceContext) ?? 'default';
41
40
 
42
41
  /** Shorthand for the one question most call sites ask. */
43
42
  export const useIsCalmForm = (): boolean => useFormAppearance() === 'calm';