@things-factory/figure-ui 10.1.155 → 10.1.157
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/clips.ts +43 -4
- package/client/modeller/data-interface.ts +110 -0
- package/client/modeller/editor.ts +16 -2
- package/client/modeller/figure-clips.ts +125 -12
- package/client/modeller/figure-data-panel.ts +308 -0
- package/client/modeller/figure-preview.ts +41 -4
- package/client/modeller/refusals.ts +46 -0
- package/dist-client/modeller/clips.d.ts +32 -2
- package/dist-client/modeller/clips.js +32 -4
- package/dist-client/modeller/clips.js.map +1 -1
- package/dist-client/modeller/data-interface.d.ts +42 -0
- package/dist-client/modeller/data-interface.js +95 -0
- package/dist-client/modeller/data-interface.js.map +1 -0
- package/dist-client/modeller/editor.d.ts +3 -0
- package/dist-client/modeller/editor.js +18 -0
- package/dist-client/modeller/editor.js.map +1 -1
- package/dist-client/modeller/figure-clips.d.ts +10 -0
- package/dist-client/modeller/figure-clips.js +125 -10
- package/dist-client/modeller/figure-clips.js.map +1 -1
- package/dist-client/modeller/figure-data-panel.d.ts +39 -0
- package/dist-client/modeller/figure-data-panel.js +317 -0
- package/dist-client/modeller/figure-data-panel.js.map +1 -0
- package/dist-client/modeller/figure-preview.d.ts +7 -0
- package/dist-client/modeller/figure-preview.js +49 -4
- package/dist-client/modeller/figure-preview.js.map +1 -1
- package/dist-client/modeller/refusals.d.ts +5 -0
- package/dist-client/modeller/refusals.js +58 -0
- package/dist-client/modeller/refusals.js.map +1 -1
- package/dist-client/route.d.ts +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -6
- package/test/data-motion.test.ts +135 -0
- package/translations/en.json +85 -2
- package/translations/es.json +84 -1
- package/translations/ja.json +85 -2
- package/translations/ko.json +85 -2
- package/translations/ms.json +85 -2
- package/translations/zh.json +85 -2
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* The figure's public data properties and what each moves (ADR-0051 §2.2): what the data tab offers and shows. Every
|
|
3
|
+
* rule is figure-model's -- which transform a property may take, whether a connection holds, what a sample moves; this
|
|
4
|
+
* only lists what there is to choose and drafts a first connection the kernel then checks. Kept apart from the element so
|
|
5
|
+
* it is tested without a browser.
|
|
6
|
+
*/
|
|
7
|
+
import { compileFigureDataInterface, evaluateFigureDataInterface, validateFigureDataValues, FIGURE_PART_ID } from '@hatiolab/figure-model';
|
|
8
|
+
export const targetKeyOf = (t) => t.kind === 'state' ? `state:${t.input}` : t.kind === 'palette' ? `palette:${t.token}` : `${t.kind}:${t.group}`;
|
|
9
|
+
/**
|
|
10
|
+
* What a property of this kind can be connected to: a number moves a control or a group's speed; an enum or a boolean
|
|
11
|
+
* moves a control, a colour or which clip of a group plays (through a case per value). A control is offered observed: a
|
|
12
|
+
* value read from the machine applies as it comes.
|
|
13
|
+
*/
|
|
14
|
+
export function dataTargetsOf(asset, kind) {
|
|
15
|
+
const out = [];
|
|
16
|
+
for (const input of asset.document.model.inputs) {
|
|
17
|
+
if (input.role !== 'state')
|
|
18
|
+
continue;
|
|
19
|
+
const target = { kind: 'state', input: input.id, sourceMode: 'observed' };
|
|
20
|
+
out.push({ key: targetKeyOf(target), target, name: asset.stateInputs?.[input.id]?.label ?? input.id, unit: input.unit, min: input.min, max: input.max });
|
|
21
|
+
}
|
|
22
|
+
if (kind !== 'number')
|
|
23
|
+
for (const token of Object.keys(asset.palette)) {
|
|
24
|
+
const target = { kind: 'palette', token };
|
|
25
|
+
out.push({ key: targetKeyOf(target), target, name: token });
|
|
26
|
+
}
|
|
27
|
+
for (const group of asset.motionGroups ?? []) {
|
|
28
|
+
const target = kind === 'number' ? { kind: 'motion-speed', group: group.id } : { kind: 'motion-clip', group: group.id };
|
|
29
|
+
out.push({ key: targetKeyOf(target), target, name: group.label });
|
|
30
|
+
}
|
|
31
|
+
return out;
|
|
32
|
+
}
|
|
33
|
+
/** The values a lookup has a case for: an enum's values, or both booleans. Nothing for a number. */
|
|
34
|
+
export const domainOf = (property) => property.kind === 'enum' ? [...property.values] : property.kind === 'boolean' ? [false, true] : [];
|
|
35
|
+
/** An id not taken among `taken`: `base`, then `base-2`, `base-3`, … made into the kernel's id shape. */
|
|
36
|
+
export function freeDataIdOf(taken, base) {
|
|
37
|
+
const used = new Set(taken);
|
|
38
|
+
const cleaned = base.replace(/[^a-zA-Z0-9_-]+/g, '-').replace(/^[^a-zA-Z]+/, '').replace(/-+$/, '') || 'data';
|
|
39
|
+
const id = FIGURE_PART_ID.test(cleaned) ? cleaned : 'data';
|
|
40
|
+
if (!used.has(id))
|
|
41
|
+
return id;
|
|
42
|
+
let n = 2;
|
|
43
|
+
while (used.has(`${id}-${n}`))
|
|
44
|
+
n++;
|
|
45
|
+
return `${id}-${n}`;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* A first connection of a property to a target, for the author to adjust: a number as it is in the control's own unit,
|
|
49
|
+
* or scaled from another; an enum or a boolean case by case, each case at what the target shows now -- the control's
|
|
50
|
+
* rest value, the colour, the group's first clip. The kernel says whether it holds.
|
|
51
|
+
*/
|
|
52
|
+
export function connectionDraftOf(asset, property, choice) {
|
|
53
|
+
const taken = (asset.dataInterface?.connections ?? []).map(c => c.id);
|
|
54
|
+
const id = freeDataIdOf(taken, `${property.id}-${choice.target.kind === 'state' ? choice.target.input : choice.target.kind === 'palette' ? 'colour' : choice.target.group}`);
|
|
55
|
+
const target = choice.target;
|
|
56
|
+
if (property.kind === 'number') {
|
|
57
|
+
const same = target.kind === 'motion-speed' || (target.kind === 'state' && choice.unit === property.unit);
|
|
58
|
+
return { id, property: property.id, transform: same ? { kind: 'identity' } : { kind: 'affine', scale: 1, offset: 0 }, target };
|
|
59
|
+
}
|
|
60
|
+
const now = target.kind === 'state'
|
|
61
|
+
? (asset.stateDefaults[target.input] ?? 0)
|
|
62
|
+
: target.kind === 'palette'
|
|
63
|
+
? (asset.palette[target.token] ?? '#000000')
|
|
64
|
+
: ((asset.motionGroups ?? []).find(g => g.id === target.group)?.defaultClip ?? '');
|
|
65
|
+
return { id, property: property.id, transform: { kind: 'lookup', cases: domainOf(property).map(when => ({ when, value: now })) }, target };
|
|
66
|
+
}
|
|
67
|
+
/** What a property looks like when first made: a number 0 to 1, a boolean off, an enum of two values. */
|
|
68
|
+
export function propertyDraftOf(asset, label, kind) {
|
|
69
|
+
const id = freeDataIdOf((asset.dataInterface?.properties ?? []).map(p => p.id), label);
|
|
70
|
+
if (kind === 'number')
|
|
71
|
+
return { id, label, kind, unit: 'ratio', min: 0, max: 1, default: 0 };
|
|
72
|
+
if (kind === 'boolean')
|
|
73
|
+
return { id, label, kind, default: false };
|
|
74
|
+
return { id, label, kind, values: ['off', 'on'], default: 'off' };
|
|
75
|
+
}
|
|
76
|
+
/** A value typed in a sample field, as the property takes it: a number, true or false, or the enum value. */
|
|
77
|
+
export function sampleValueOf(property, typed) {
|
|
78
|
+
if (property.kind === 'number')
|
|
79
|
+
return typed.trim() === '' ? Number.NaN : Number(typed);
|
|
80
|
+
if (property.kind === 'boolean')
|
|
81
|
+
return typed === 'true';
|
|
82
|
+
return typed;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* What a sample of values would move, as the figure would run it: the kernel's check and evaluation of the interface.
|
|
86
|
+
* Refused whole when one value cannot be taken, with each one's reason, as a live snapshot is.
|
|
87
|
+
*/
|
|
88
|
+
export function dataSampleOf(asset, values) {
|
|
89
|
+
const plan = compileFigureDataInterface(asset);
|
|
90
|
+
if (!plan)
|
|
91
|
+
return { issues: [] };
|
|
92
|
+
const issues = validateFigureDataValues(plan, values);
|
|
93
|
+
return issues.length ? { issues } : { result: evaluateFigureDataInterface(plan, values) };
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=data-interface.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-interface.js","sourceRoot":"","sources":["../../client/modeller/data-interface.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * The figure's public data properties and what each moves (ADR-0051 §2.2): what the data tab offers and shows. Every\n * rule is figure-model's -- which transform a property may take, whether a connection holds, what a sample moves; this\n * only lists what there is to choose and drafts a first connection the kernel then checks. Kept apart from the element so\n * it is tested without a browser.\n */\nimport { compileFigureDataInterface, evaluateFigureDataInterface, validateFigureDataValues, FIGURE_PART_ID } from '@hatiolab/figure-model'\nimport type { FigureAsset, FigureDataConnection, FigureDataProperty, FigureDataResult, FigureDataTarget, FigureDataValue, FigureDataValueIssue } from '@hatiolab/figure-model'\n\n/** Something a connection can write, with what the screen shows of it. */\nexport interface DataTargetChoice {\n /** One string per target, for a select's value. */\n key: string\n target: FigureDataTarget\n /** The control's label, the colour token, or the group's label. */\n name: string\n unit?: string\n min?: number\n max?: number\n}\n\nexport const targetKeyOf = (t: FigureDataTarget): string =>\n t.kind === 'state' ? `state:${t.input}` : t.kind === 'palette' ? `palette:${t.token}` : `${t.kind}:${t.group}`\n\n/**\n * What a property of this kind can be connected to: a number moves a control or a group's speed; an enum or a boolean\n * moves a control, a colour or which clip of a group plays (through a case per value). A control is offered observed: a\n * value read from the machine applies as it comes.\n */\nexport function dataTargetsOf(asset: FigureAsset, kind: FigureDataProperty['kind']): DataTargetChoice[] {\n const out: DataTargetChoice[] = []\n for (const input of asset.document.model.inputs) {\n if (input.role !== 'state') continue\n const target: FigureDataTarget = { kind: 'state', input: input.id, sourceMode: 'observed' }\n out.push({ key: targetKeyOf(target), target, name: asset.stateInputs?.[input.id]?.label ?? input.id, unit: input.unit, min: input.min, max: input.max })\n }\n if (kind !== 'number')\n for (const token of Object.keys(asset.palette)) {\n const target: FigureDataTarget = { kind: 'palette', token }\n out.push({ key: targetKeyOf(target), target, name: token })\n }\n for (const group of asset.motionGroups ?? []) {\n const target: FigureDataTarget = kind === 'number' ? { kind: 'motion-speed', group: group.id } : { kind: 'motion-clip', group: group.id }\n out.push({ key: targetKeyOf(target), target, name: group.label })\n }\n return out\n}\n\n/** The values a lookup has a case for: an enum's values, or both booleans. Nothing for a number. */\nexport const domainOf = (property: FigureDataProperty): FigureDataValue[] =>\n property.kind === 'enum' ? [...property.values] : property.kind === 'boolean' ? [false, true] : []\n\n/** An id not taken among `taken`: `base`, then `base-2`, `base-3`, … made into the kernel's id shape. */\nexport function freeDataIdOf(taken: Iterable<string>, base: string): string {\n const used = new Set(taken)\n const cleaned = base.replace(/[^a-zA-Z0-9_-]+/g, '-').replace(/^[^a-zA-Z]+/, '').replace(/-+$/, '') || 'data'\n const id = FIGURE_PART_ID.test(cleaned) ? cleaned : 'data'\n if (!used.has(id)) return id\n let n = 2\n while (used.has(`${id}-${n}`)) n++\n return `${id}-${n}`\n}\n\n/**\n * A first connection of a property to a target, for the author to adjust: a number as it is in the control's own unit,\n * or scaled from another; an enum or a boolean case by case, each case at what the target shows now -- the control's\n * rest value, the colour, the group's first clip. The kernel says whether it holds.\n */\nexport function connectionDraftOf(asset: FigureAsset, property: FigureDataProperty, choice: DataTargetChoice): FigureDataConnection {\n const taken = (asset.dataInterface?.connections ?? []).map(c => c.id)\n const id = freeDataIdOf(taken, `${property.id}-${choice.target.kind === 'state' ? choice.target.input : choice.target.kind === 'palette' ? 'colour' : choice.target.group}`)\n const target = choice.target\n if (property.kind === 'number') {\n const same = target.kind === 'motion-speed' || (target.kind === 'state' && choice.unit === property.unit)\n return { id, property: property.id, transform: same ? { kind: 'identity' } : { kind: 'affine', scale: 1, offset: 0 }, target }\n }\n const now: FigureDataValue =\n target.kind === 'state'\n ? (asset.stateDefaults[target.input] ?? 0)\n : target.kind === 'palette'\n ? (asset.palette[target.token] ?? '#000000')\n : ((asset.motionGroups ?? []).find(g => g.id === target.group)?.defaultClip ?? '')\n return { id, property: property.id, transform: { kind: 'lookup', cases: domainOf(property).map(when => ({ when, value: now })) }, target }\n}\n\n/** What a property looks like when first made: a number 0 to 1, a boolean off, an enum of two values. */\nexport function propertyDraftOf(asset: FigureAsset, label: string, kind: FigureDataProperty['kind']): FigureDataProperty {\n const id = freeDataIdOf((asset.dataInterface?.properties ?? []).map(p => p.id), label)\n if (kind === 'number') return { id, label, kind, unit: 'ratio', min: 0, max: 1, default: 0 }\n if (kind === 'boolean') return { id, label, kind, default: false }\n return { id, label, kind, values: ['off', 'on'], default: 'off' }\n}\n\n/** A value typed in a sample field, as the property takes it: a number, true or false, or the enum value. */\nexport function sampleValueOf(property: FigureDataProperty, typed: string): FigureDataValue {\n if (property.kind === 'number') return typed.trim() === '' ? Number.NaN : Number(typed)\n if (property.kind === 'boolean') return typed === 'true'\n return typed\n}\n\n/**\n * What a sample of values would move, as the figure would run it: the kernel's check and evaluation of the interface.\n * Refused whole when one value cannot be taken, with each one's reason, as a live snapshot is.\n */\nexport function dataSampleOf(asset: FigureAsset, values: Record<string, FigureDataValue>): { result: FigureDataResult } | { issues: FigureDataValueIssue[] } {\n const plan = compileFigureDataInterface(asset)\n if (!plan) return { issues: [] }\n const issues = validateFigureDataValues(plan, values)\n return issues.length ? { issues } : { result: evaluateFigureDataInterface(plan, values) }\n}\n"]}
|
|
@@ -11,6 +11,7 @@ import './figure-section-editor.js';
|
|
|
11
11
|
import './figure-links.js';
|
|
12
12
|
import './figure-controls.js';
|
|
13
13
|
import './figure-clips.js';
|
|
14
|
+
import './figure-data-panel.js';
|
|
14
15
|
import './figure-preview.js';
|
|
15
16
|
import './figure-settings.js';
|
|
16
17
|
import './figure-capability-panel.js';
|
|
@@ -193,6 +194,8 @@ export declare class FigureEditor extends LitElement {
|
|
|
193
194
|
*/
|
|
194
195
|
private anchorsOf;
|
|
195
196
|
private lastAnchors;
|
|
197
|
+
/** Data values tried in the data tab, run by the preview's figure; null when none are (ADR-0051 §2.2). */
|
|
198
|
+
private dataSample;
|
|
196
199
|
/** The figure's controls: try a value, name it, set its range and travel time, keep the pose. */
|
|
197
200
|
private renderControls;
|
|
198
201
|
/** One command, one step of the history. A refusal a person can meet here is said in their words. */
|
|
@@ -22,6 +22,7 @@ import { motionEndsOf } from './motion-ends.js';
|
|
|
22
22
|
import './figure-links.js';
|
|
23
23
|
import './figure-controls.js';
|
|
24
24
|
import './figure-clips.js';
|
|
25
|
+
import './figure-data-panel.js';
|
|
25
26
|
import './figure-preview.js';
|
|
26
27
|
import './figure-settings.js';
|
|
27
28
|
import { DEFAULT_VIEW } from '@things-factory/figure-viewer/dist-client/figure-view.js';
|
|
@@ -121,6 +122,8 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
121
122
|
/** The preview is made when first asked for, and kept (hidden) after that; it is taken down with the editor. */
|
|
122
123
|
this.previewMounted = false;
|
|
123
124
|
this.lastAnchors = {};
|
|
125
|
+
/** Data values tried in the data tab, run by the preview's figure; null when none are (ADR-0051 §2.2). */
|
|
126
|
+
this.dataSample = null;
|
|
124
127
|
/** To the release that exists: the history tab's release section, not a second one here. */
|
|
125
128
|
this.goRelease = async () => {
|
|
126
129
|
this.tab = 'history';
|
|
@@ -1576,6 +1579,7 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
1576
1579
|
.context=${view.context ?? ''}
|
|
1577
1580
|
.view=${this.view}
|
|
1578
1581
|
.selected=${this.selected}
|
|
1582
|
+
.sample=${this.dataSample}
|
|
1579
1583
|
@configure-size=${async (e) => {
|
|
1580
1584
|
this.middle = 'edit';
|
|
1581
1585
|
this.selected = e.detail.part;
|
|
@@ -1612,6 +1616,7 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
1612
1616
|
${this.renderTab('properties', 'tune', i18next.t('figure.label.properties'))}
|
|
1613
1617
|
${this.renderTab('capability', 'conveyor_belt', i18next.t('figure.label.tab-capability'))}
|
|
1614
1618
|
${this.renderTab('motion', 'animation', i18next.t('figure.label.motion'))}
|
|
1619
|
+
${this.renderTab('data', 'sensors', i18next.t('figure.label.tab-data'))}
|
|
1615
1620
|
${this.renderTab('verdict', 'insights', i18next.t('figure.label.maturity'), this.instances)}
|
|
1616
1621
|
${this.renderTab('view', 'wb_sunny', i18next.t('figure.label.tab-environment'))}
|
|
1617
1622
|
${this.renderTab('history', 'history', i18next.t('figure.label.history'))}
|
|
@@ -1683,6 +1688,15 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
1683
1688
|
${this.selected && part ? this.renderLinks(unavailable, 'motion') : html `<section><p hint>${i18next.t('figure.text.choose-a-part-to-move')}</p></section>`}
|
|
1684
1689
|
${this.renderControls(view, unavailable)}
|
|
1685
1690
|
</div>
|
|
1691
|
+
<div panel ?off=${tab !== 'data'}>
|
|
1692
|
+
${this.renderSubject()}
|
|
1693
|
+
<figure-data-panel
|
|
1694
|
+
.asset=${asset}
|
|
1695
|
+
?locked=${unavailable}
|
|
1696
|
+
@data-sample=${(e) => (this.dataSample = e.detail.values)}
|
|
1697
|
+
@part-edit=${(e) => this.run(() => this.session.edit(e.detail.edit))}
|
|
1698
|
+
></figure-data-panel>
|
|
1699
|
+
</div>
|
|
1686
1700
|
<div panel flush ?off=${tab !== 'verdict'}><slot name="verdict"></slot></div>
|
|
1687
1701
|
<div panel flush ?off=${tab !== 'view'}>
|
|
1688
1702
|
<figure-settings .view=${this.view} @update-view=${(e) => this.setView(e.detail.view)}></figure-settings>
|
|
@@ -1940,6 +1954,10 @@ __decorate([
|
|
|
1940
1954
|
state(),
|
|
1941
1955
|
__metadata("design:type", Object)
|
|
1942
1956
|
], FigureEditor.prototype, "sectionEditing", void 0);
|
|
1957
|
+
__decorate([
|
|
1958
|
+
state(),
|
|
1959
|
+
__metadata("design:type", Object)
|
|
1960
|
+
], FigureEditor.prototype, "dataSample", void 0);
|
|
1943
1961
|
FigureEditor = FigureEditor_1 = __decorate([
|
|
1944
1962
|
customElement('figure-editor')
|
|
1945
1963
|
], FigureEditor);
|