@things-factory/figure-ui 10.1.74 → 10.1.75
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/client/modeller/v3-editor.ts +21 -10
- package/client/modeller/v3-refusals.ts +62 -13
- package/dist-client/modeller/v3-clips.d.ts +1 -1
- package/dist-client/modeller/v3-editor.d.ts +5 -0
- package/dist-client/modeller/v3-editor.js +21 -10
- package/dist-client/modeller/v3-editor.js.map +1 -1
- package/dist-client/modeller/v3-product-session.d.ts +31 -0
- package/dist-client/modeller/v3-refusals.d.ts +37 -5
- package/dist-client/modeller/v3-refusals.js +59 -16
- package/dist-client/modeller/v3-refusals.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/test/browser/modeller.check.mjs +3 -2
- package/test/v3-parts-wiring.test.ts +6 -2
- package/test/v3-recipes.test.ts +1 -1
- package/test/v3-refusals.test.ts +35 -5
- package/translations/en.json +13 -5
- package/translations/ja.json +13 -5
- package/translations/ko.json +13 -5
- package/translations/ms.json +13 -5
- package/translations/zh.json +13 -5
|
@@ -31,7 +31,7 @@ import type { V3PaletteKind, V3PartRow } from './figure-v3-parts.js'
|
|
|
31
31
|
import { paletteRecipe } from './v3-palette.js'
|
|
32
32
|
import type { FigureV3Canvas } from './v3-canvas.js'
|
|
33
33
|
import { nudgeOf } from './v3-stage-model.js'
|
|
34
|
-
import { inDeclaredRoom, inputRangeRefusalOf, narrowingRetryOf, partRefusalOf, placementRefusalOf, sizeRangeRefusalOf } from './v3-refusals.js'
|
|
34
|
+
import { editRefusalOf, inDeclaredRoom, inputRangeRefusalOf, narrowingRetryOf, partRefusalOf, placementRefusalOf, recipeRefusalOf, removalNoticeOf, sizeRangeRefusalOf } from './v3-refusals.js'
|
|
35
35
|
import type { V3RenderPart } from './v3-renderer.js'
|
|
36
36
|
import type { V3BudgetLine } from './v3-maturity.js'
|
|
37
37
|
import { instanceRangeOf, instanceRangeToDeclare, proportionToFollow, rangeDiffers, rangeWith, turnsAboutAJoint, valueNow } from './v3-links.js'
|
|
@@ -402,14 +402,23 @@ export class FigureV3Editor extends LitElement {
|
|
|
402
402
|
this.renderRoot.querySelector<FigureV3Canvas>('figure-v3-canvas')?.gizmo(mode)
|
|
403
403
|
this.gizmoMode = this.gizmoMode === mode ? undefined : mode
|
|
404
404
|
}
|
|
405
|
+
/**
|
|
406
|
+
* A refusal no particular sentence knows: figure-model's code said as a refusal, never its English; any other error
|
|
407
|
+
* (the network, the server) as it came.
|
|
408
|
+
*/
|
|
409
|
+
private said(error: unknown): string {
|
|
410
|
+
return (error as { code?: string })?.code ? editRefusalOf(error, (key, params) => i18next.t(key, params)) : error instanceof Error ? error.message : String(error)
|
|
411
|
+
}
|
|
405
412
|
private run(action: () => unknown) {
|
|
406
413
|
try {
|
|
407
414
|
action()
|
|
408
415
|
this.error = ''
|
|
416
|
+
/* The next step stands on its own: what the last removal let go of is no longer the news. */
|
|
417
|
+
this.notice = ''
|
|
409
418
|
this.changed()
|
|
410
419
|
} catch (error) {
|
|
411
420
|
const say = (key: string, params: Record<string, string>) => i18next.t(key, params)
|
|
412
|
-
this.error = sizeRangeRefusalOf(error, say) ?? inputRangeRefusalOf(error, say) ??
|
|
421
|
+
this.error = sizeRangeRefusalOf(error, say) ?? inputRangeRefusalOf(error, say) ?? this.said(error)
|
|
413
422
|
} finally {
|
|
414
423
|
/* Committed or refused, the value in hand is gone: the figure as it stands is drawn again. */
|
|
415
424
|
this.live = NOTHING_LIVE
|
|
@@ -475,7 +484,7 @@ export class FigureV3Editor extends LitElement {
|
|
|
475
484
|
await promise
|
|
476
485
|
this.error = ''
|
|
477
486
|
} catch (error) {
|
|
478
|
-
this.error =
|
|
487
|
+
this.error = this.said(error)
|
|
479
488
|
} finally {
|
|
480
489
|
this.changed()
|
|
481
490
|
}
|
|
@@ -508,13 +517,15 @@ export class FigureV3Editor extends LitElement {
|
|
|
508
517
|
private removePart(id: string, refitRoom = false) {
|
|
509
518
|
this.retry = undefined
|
|
510
519
|
try {
|
|
511
|
-
this.session!.edit({ kind: 'remove-part', target: id, ...(refitRoom ? { refitRoom: true } : {}) })
|
|
520
|
+
const view = this.session!.edit({ kind: 'remove-part', target: id, ...(refitRoom ? { refitRoom: true } : {}) }) as { removal?: Parameters<typeof removalNoticeOf>[0] }
|
|
512
521
|
this.error = ''
|
|
522
|
+
/* What else the removal let go of, named (chief architect, 2026-09-27); undo brings it back. */
|
|
523
|
+
this.notice = removalNoticeOf(view.removal, (key, params) => i18next.t(key, params)) ?? ''
|
|
513
524
|
if (this.selected === id) this.selected = ''
|
|
514
525
|
this.changed()
|
|
515
526
|
} catch (error) {
|
|
516
527
|
/* The refusal a person meets most: another part stands on this one or follows its size. Said in their words. */
|
|
517
|
-
this.error = partRefusalOf(error, id, (key, params) => i18next.t(key, params)) ??
|
|
528
|
+
this.error = partRefusalOf(error, id, (key, params) => i18next.t(key, params)) ?? this.said(error)
|
|
518
529
|
/* In the declared room only: the way on is to delete it and fit the room to the parts left, in one step. */
|
|
519
530
|
if (!refitRoom && inDeclaredRoom(error)) this.retry = { label: i18next.t('figure.button.remove-and-refit-room', { part: id }), run: () => this.removePart(id, true) }
|
|
520
531
|
}
|
|
@@ -546,7 +557,7 @@ export class FigureV3Editor extends LitElement {
|
|
|
546
557
|
this.error = ''
|
|
547
558
|
this.changed()
|
|
548
559
|
} catch (error) {
|
|
549
|
-
this.recipeError = error
|
|
560
|
+
this.recipeError = recipeRefusalOf(error, (key, params) => i18next.t(key, params)) ?? this.said(error)
|
|
550
561
|
}
|
|
551
562
|
}
|
|
552
563
|
/** The design values of the asset being edited. */
|
|
@@ -630,7 +641,7 @@ export class FigureV3Editor extends LitElement {
|
|
|
630
641
|
? i18next.t('figure.text.gizmo-joint-places', { part: partLabelOf(id) })
|
|
631
642
|
: /is fastened to/.test(message)
|
|
632
643
|
? i18next.t('figure.text.gizmo-fastening-places', { part: partLabelOf(id) })
|
|
633
|
-
:
|
|
644
|
+
: this.said(error)
|
|
634
645
|
this.requestUpdate()
|
|
635
646
|
}
|
|
636
647
|
}
|
|
@@ -803,7 +814,7 @@ export class FigureV3Editor extends LitElement {
|
|
|
803
814
|
? i18next.t('figure.text.fasten-would-loop')
|
|
804
815
|
: sizeRangeRefusalOf(error, (key, params) => i18next.t(key, params)) ??
|
|
805
816
|
placementRefusalOf(error, (key, params) => i18next.t(key, params)) ??
|
|
806
|
-
|
|
817
|
+
this.said(error)
|
|
807
818
|
}
|
|
808
819
|
}
|
|
809
820
|
private changeField(field: { id: string; unit: V3InputChange['unit']; role?: string }, event: Event) {
|
|
@@ -1095,7 +1106,7 @@ export class FigureV3Editor extends LitElement {
|
|
|
1095
1106
|
this.error = ''
|
|
1096
1107
|
this.changed()
|
|
1097
1108
|
} catch (error) {
|
|
1098
|
-
this.error =
|
|
1109
|
+
this.error = this.said(error)
|
|
1099
1110
|
}
|
|
1100
1111
|
}
|
|
1101
1112
|
return html`<div public-pitch>
|
|
@@ -1152,7 +1163,7 @@ export class FigureV3Editor extends LitElement {
|
|
|
1152
1163
|
this.error =
|
|
1153
1164
|
code === 'INPUT_RANGE' && found
|
|
1154
1165
|
? i18next.t('figure.text.repeat-pitch-too-small', { length: Number(found[1]).toLocaleString(), min: found[2], limit: found[3] })
|
|
1155
|
-
:
|
|
1166
|
+
: this.said(error)
|
|
1156
1167
|
}
|
|
1157
1168
|
}
|
|
1158
1169
|
/** Choose a part, from the list, the canvas or a place row. A figure-level tab gives way to the part's properties. */
|
|
@@ -39,11 +39,6 @@ export function narrowingRetryOf<A extends { kind: string }>(action: A, error: u
|
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
/**
|
|
43
|
-
* Why a part cannot be deleted, in the author's words -- figure-model names four reasons (PART_REFERENCED): parts hang
|
|
44
|
-
* from it, the declared space holds it, another part follows its size or place, or a joint moves with its joint. One
|
|
45
|
-
* sentence for all of them told the author to undo a link that was not there (the architect's workbench, 2026-09-25).
|
|
46
|
-
*/
|
|
47
42
|
/**
|
|
48
43
|
* A placement refused because a part is fastened to the mounting plane by a face the new plane does not take (a bottom
|
|
49
44
|
* on the floor, when the figure is to hang on a wall), said in the author's words with the parts it names.
|
|
@@ -61,20 +56,74 @@ export function inDeclaredRoom(error: unknown): boolean {
|
|
|
61
56
|
return (error as { code?: string })?.code === 'PART_REFERENCED' && /is in the space the figure declares/.test(error instanceof Error ? error.message : String(error))
|
|
62
57
|
}
|
|
63
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Why a part cannot be deleted, in the author's words. Since the chief architect's ruling of 2026-09-27 a part that
|
|
61
|
+
* holds others, leads a motion or is followed goes, and what depended on it is let go of (`removalNoticeOf`); what is
|
|
62
|
+
* left is the declared space (with a way on: fit it again) and a row -- one laid along the part, or hanging in its row.
|
|
63
|
+
*/
|
|
64
64
|
export function partRefusalOf(error: unknown, part: string, say: Say): string | null {
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
const code = (error as { code?: string })?.code
|
|
66
|
+
if (code !== 'PART_REFERENCED' && code !== 'PART_ROW') return null
|
|
67
|
+
/* figure-model's sentence after its code and path: 「PART_ROW: bed: roller is a row laid along bed; …」. */
|
|
67
68
|
const message = (error instanceof Error ? error.message : String(error)).replace(/^[A-Z_]+: [^:]+: /, '')
|
|
68
|
-
const holds = / holds (.+?); take (?:them|it) off first/.exec(message)
|
|
69
|
-
if (holds) return say('figure.text.part-holds-others', { part, others: holds[1]! })
|
|
70
69
|
if (/is in the space the figure declares/.test(message)) return say('figure.text.part-in-declared-space', { part })
|
|
71
|
-
const
|
|
72
|
-
if (
|
|
73
|
-
const
|
|
74
|
-
if (
|
|
70
|
+
const along = /^(.+?) (?:is a row|are rows) laid along /.exec(message)
|
|
71
|
+
if (along) return say('figure.text.part-row-along', { part, rows: along[1]! })
|
|
72
|
+
const carried = /^(.+?) hangs? in the row /.exec(message)
|
|
73
|
+
if (carried) return say('figure.text.part-row-carries', { part, others: carried[1]! })
|
|
75
74
|
return say('figure.text.part-is-referenced', { part })
|
|
76
75
|
}
|
|
77
76
|
|
|
77
|
+
/** What removing a part let go of (figure-model's `RemovalNotice`), said in one line, or nothing when it let go of nothing. */
|
|
78
|
+
export function removalNoticeOf(
|
|
79
|
+
notice:
|
|
80
|
+
| {
|
|
81
|
+
released: Array<{ part: string; control?: string }>
|
|
82
|
+
fixed: Array<{ part: string }>
|
|
83
|
+
controls: Array<{ part: string; control: string; min: number; max: number }>
|
|
84
|
+
mountingFace?: boolean
|
|
85
|
+
bindings?: Array<{ id: string; label?: string }>
|
|
86
|
+
}
|
|
87
|
+
| undefined,
|
|
88
|
+
say: Say
|
|
89
|
+
): string | null {
|
|
90
|
+
if (!notice) return null
|
|
91
|
+
const number = (v: number) => v.toLocaleString(undefined, { maximumFractionDigits: 3 })
|
|
92
|
+
const lines: string[] = []
|
|
93
|
+
const still = notice.released.filter(r => !r.control).map(r => r.part)
|
|
94
|
+
if (still.length) lines.push(say('figure.text.removal-released', { parts: still.join(', ') }))
|
|
95
|
+
for (const r of notice.released.filter(r => r.control)) lines.push(say('figure.text.removal-released-motion', { part: r.part, control: r.control! }))
|
|
96
|
+
for (const c of notice.controls) lines.push(say('figure.text.removal-own-control', { part: c.part, control: c.control, min: number(c.min), max: number(c.max) }))
|
|
97
|
+
const fixed = [...new Set(notice.fixed.map(f => f.part))]
|
|
98
|
+
if (fixed.length) lines.push(say('figure.text.removal-fixed', { parts: fixed.join(', ') }))
|
|
99
|
+
if (notice.bindings?.length) lines.push(say('figure.text.removal-bindings', { places: notice.bindings.map(b => b.label ?? b.id).join(', ') }))
|
|
100
|
+
if (notice.mountingFace) lines.push(say('figure.text.removal-mounting-face', {}))
|
|
101
|
+
return lines.length ? lines.join(' ') : null
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* A recipe refused at one of its steps: which step, and why -- the particular sentence when there is one (a size
|
|
106
|
+
* range, a value's range, a placement), otherwise the kernel's code. The kernel says 「steps[2]: attach: …」.
|
|
107
|
+
*/
|
|
108
|
+
export function recipeRefusalOf(error: unknown, say: Say): string | null {
|
|
109
|
+
const step = /^steps\[(\d+)\]$/.exec((error as { path?: string })?.path ?? '')
|
|
110
|
+
if (!step) return null
|
|
111
|
+
const why = sizeRangeRefusalOf(error, say) ?? inputRangeRefusalOf(error, say) ?? placementRefusalOf(error, say)
|
|
112
|
+
return say('figure.text.recipe-step-refused', { step: String(Number(step[1]) + 1), why: why ?? '', code: (error as { code?: string })?.code ?? '' })
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* A refusal no sentence above knows, said as a refusal with its code -- never the kernel's English on the screen (the
|
|
117
|
+
* duplicate of a row's part showed 「EDIT_TARGET: … not a repeated template」, 2026-09-27). The figure's node limit
|
|
118
|
+
* is said with its number.
|
|
119
|
+
*/
|
|
120
|
+
export function editRefusalOf(error: unknown, say: Say): string {
|
|
121
|
+
const code = (error as { code?: string })?.code
|
|
122
|
+
const message = error instanceof Error ? error.message : String(error)
|
|
123
|
+
if (code === 'DOCUMENT_LIMIT') return say('figure.text.edit-refused-node-limit', { max: /maximum (\d+) nodes/.exec(message)?.[1] ?? '' })
|
|
124
|
+
return say('figure.text.edit-refused', { code: code ?? '' })
|
|
125
|
+
}
|
|
126
|
+
|
|
78
127
|
/**
|
|
79
128
|
* A value outside the range its input declares, with the range and the value given -- the kernel says
|
|
80
129
|
* 「size.x: 6021100 outside [300,1200]」. The figure's own size is named by its axis; any other input by its range only.
|
|
@@ -79,6 +79,11 @@ export declare class FigureV3Editor extends LitElement {
|
|
|
79
79
|
protected willUpdate(_changed: PropertyValues): void;
|
|
80
80
|
/** The scene toggles: the mode already shown takes the gizmo away. */
|
|
81
81
|
private useGizmo;
|
|
82
|
+
/**
|
|
83
|
+
* A refusal no particular sentence knows: figure-model's code said as a refusal, never its English; any other error
|
|
84
|
+
* (the network, the server) as it came.
|
|
85
|
+
*/
|
|
86
|
+
private said;
|
|
82
87
|
private run;
|
|
83
88
|
/** What the canvas draws: the figure with the value in hand when there is one, and without the parts hidden on the workbench. */
|
|
84
89
|
private drawnParts;
|
|
@@ -27,7 +27,7 @@ import { ScrollbarStyles } from '@operato/styles';
|
|
|
27
27
|
import { alignChanges, boxOf, canMirror, mirrorChanges } from './v3-align.js';
|
|
28
28
|
import { paletteRecipe } from './v3-palette.js';
|
|
29
29
|
import { nudgeOf } from './v3-stage-model.js';
|
|
30
|
-
import { inDeclaredRoom, inputRangeRefusalOf, narrowingRetryOf, partRefusalOf, placementRefusalOf, sizeRangeRefusalOf } from './v3-refusals.js';
|
|
30
|
+
import { editRefusalOf, inDeclaredRoom, inputRangeRefusalOf, narrowingRetryOf, partRefusalOf, placementRefusalOf, recipeRefusalOf, removalNoticeOf, sizeRangeRefusalOf } from './v3-refusals.js';
|
|
31
31
|
import { instanceRangeOf, instanceRangeToDeclare, proportionToFollow, rangeDiffers, rangeWith, turnsAboutAJoint, valueNow } from './v3-links.js';
|
|
32
32
|
import { jointFanOf } from './v3-joint-fan.js';
|
|
33
33
|
import { jointDragOf } from './v3-joint-drag.js';
|
|
@@ -376,15 +376,24 @@ let FigureV3Editor = class FigureV3Editor extends LitElement {
|
|
|
376
376
|
this.renderRoot.querySelector('figure-v3-canvas')?.gizmo(mode);
|
|
377
377
|
this.gizmoMode = this.gizmoMode === mode ? undefined : mode;
|
|
378
378
|
}
|
|
379
|
+
/**
|
|
380
|
+
* A refusal no particular sentence knows: figure-model's code said as a refusal, never its English; any other error
|
|
381
|
+
* (the network, the server) as it came.
|
|
382
|
+
*/
|
|
383
|
+
said(error) {
|
|
384
|
+
return error?.code ? editRefusalOf(error, (key, params) => i18next.t(key, params)) : error instanceof Error ? error.message : String(error);
|
|
385
|
+
}
|
|
379
386
|
run(action) {
|
|
380
387
|
try {
|
|
381
388
|
action();
|
|
382
389
|
this.error = '';
|
|
390
|
+
/* The next step stands on its own: what the last removal let go of is no longer the news. */
|
|
391
|
+
this.notice = '';
|
|
383
392
|
this.changed();
|
|
384
393
|
}
|
|
385
394
|
catch (error) {
|
|
386
395
|
const say = (key, params) => i18next.t(key, params);
|
|
387
|
-
this.error = sizeRangeRefusalOf(error, say) ?? inputRangeRefusalOf(error, say) ??
|
|
396
|
+
this.error = sizeRangeRefusalOf(error, say) ?? inputRangeRefusalOf(error, say) ?? this.said(error);
|
|
388
397
|
}
|
|
389
398
|
finally {
|
|
390
399
|
/* Committed or refused, the value in hand is gone: the figure as it stands is drawn again. */
|
|
@@ -456,7 +465,7 @@ let FigureV3Editor = class FigureV3Editor extends LitElement {
|
|
|
456
465
|
this.error = '';
|
|
457
466
|
}
|
|
458
467
|
catch (error) {
|
|
459
|
-
this.error =
|
|
468
|
+
this.error = this.said(error);
|
|
460
469
|
}
|
|
461
470
|
finally {
|
|
462
471
|
this.changed();
|
|
@@ -492,15 +501,17 @@ let FigureV3Editor = class FigureV3Editor extends LitElement {
|
|
|
492
501
|
removePart(id, refitRoom = false) {
|
|
493
502
|
this.retry = undefined;
|
|
494
503
|
try {
|
|
495
|
-
this.session.edit({ kind: 'remove-part', target: id, ...(refitRoom ? { refitRoom: true } : {}) });
|
|
504
|
+
const view = this.session.edit({ kind: 'remove-part', target: id, ...(refitRoom ? { refitRoom: true } : {}) });
|
|
496
505
|
this.error = '';
|
|
506
|
+
/* What else the removal let go of, named (chief architect, 2026-09-27); undo brings it back. */
|
|
507
|
+
this.notice = removalNoticeOf(view.removal, (key, params) => i18next.t(key, params)) ?? '';
|
|
497
508
|
if (this.selected === id)
|
|
498
509
|
this.selected = '';
|
|
499
510
|
this.changed();
|
|
500
511
|
}
|
|
501
512
|
catch (error) {
|
|
502
513
|
/* The refusal a person meets most: another part stands on this one or follows its size. Said in their words. */
|
|
503
|
-
this.error = partRefusalOf(error, id, (key, params) => i18next.t(key, params)) ??
|
|
514
|
+
this.error = partRefusalOf(error, id, (key, params) => i18next.t(key, params)) ?? this.said(error);
|
|
504
515
|
/* In the declared room only: the way on is to delete it and fit the room to the parts left, in one step. */
|
|
505
516
|
if (!refitRoom && inDeclaredRoom(error))
|
|
506
517
|
this.retry = { label: i18next.t('figure.button.remove-and-refit-room', { part: id }), run: () => this.removePart(id, true) };
|
|
@@ -536,7 +547,7 @@ let FigureV3Editor = class FigureV3Editor extends LitElement {
|
|
|
536
547
|
this.changed();
|
|
537
548
|
}
|
|
538
549
|
catch (error) {
|
|
539
|
-
this.recipeError = error
|
|
550
|
+
this.recipeError = recipeRefusalOf(error, (key, params) => i18next.t(key, params)) ?? this.said(error);
|
|
540
551
|
}
|
|
541
552
|
}
|
|
542
553
|
/** The design values of the asset being edited. */
|
|
@@ -629,7 +640,7 @@ let FigureV3Editor = class FigureV3Editor extends LitElement {
|
|
|
629
640
|
? i18next.t('figure.text.gizmo-joint-places', { part: partLabelOf(id) })
|
|
630
641
|
: /is fastened to/.test(message)
|
|
631
642
|
? i18next.t('figure.text.gizmo-fastening-places', { part: partLabelOf(id) })
|
|
632
|
-
:
|
|
643
|
+
: this.said(error);
|
|
633
644
|
this.requestUpdate();
|
|
634
645
|
}
|
|
635
646
|
}
|
|
@@ -810,7 +821,7 @@ let FigureV3Editor = class FigureV3Editor extends LitElement {
|
|
|
810
821
|
? i18next.t('figure.text.fasten-would-loop')
|
|
811
822
|
: sizeRangeRefusalOf(error, (key, params) => i18next.t(key, params)) ??
|
|
812
823
|
placementRefusalOf(error, (key, params) => i18next.t(key, params)) ??
|
|
813
|
-
|
|
824
|
+
this.said(error);
|
|
814
825
|
}
|
|
815
826
|
}
|
|
816
827
|
changeField(field, event) {
|
|
@@ -1104,7 +1115,7 @@ let FigureV3Editor = class FigureV3Editor extends LitElement {
|
|
|
1104
1115
|
this.changed();
|
|
1105
1116
|
}
|
|
1106
1117
|
catch (error) {
|
|
1107
|
-
this.error =
|
|
1118
|
+
this.error = this.said(error);
|
|
1108
1119
|
}
|
|
1109
1120
|
};
|
|
1110
1121
|
return html `<div public-pitch>
|
|
@@ -1162,7 +1173,7 @@ let FigureV3Editor = class FigureV3Editor extends LitElement {
|
|
|
1162
1173
|
this.error =
|
|
1163
1174
|
code === 'INPUT_RANGE' && found
|
|
1164
1175
|
? i18next.t('figure.text.repeat-pitch-too-small', { length: Number(found[1]).toLocaleString(), min: found[2], limit: found[3] })
|
|
1165
|
-
:
|
|
1176
|
+
: this.said(error);
|
|
1166
1177
|
}
|
|
1167
1178
|
}
|
|
1168
1179
|
/** Choose a part, from the list, the canvas or a place row. A figure-level tab gives way to the part's properties. */
|