@things-factory/figure-library 10.1.165 → 10.1.166
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/dist-client/bootstrap.d.ts +7 -0
- package/dist-client/bootstrap.js +13 -1
- package/dist-client/bootstrap.js.map +1 -1
- package/dist-client/editors/ox-property-editor-figure-data.d.ts +22 -0
- package/dist-client/editors/ox-property-editor-figure-data.js +143 -0
- package/dist-client/editors/ox-property-editor-figure-data.js.map +1 -0
- package/dist-client/figure-data-report.d.ts +48 -0
- package/dist-client/figure-data-report.js +83 -0
- package/dist-client/figure-data-report.js.map +1 -0
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -3
- package/translations/en.json +35 -1
- package/translations/es.json +35 -1
- package/translations/ja.json +35 -1
- package/translations/ko.json +35 -1
- package/translations/ms.json +35 -1
- package/translations/zh.json +35 -1
|
@@ -1 +1,8 @@
|
|
|
1
|
+
import './editors/ox-property-editor-figure-data.js';
|
|
2
|
+
/**
|
|
3
|
+
* The editors the board's property panel needs for the properties a placed figure names: its data -- shape, each value
|
|
4
|
+
* and where it came from (`figure-data`) -- and its slot layout, which a placement may override (`slot-layout`, ADR-0118
|
|
5
|
+
* decision 8). Registered here, where every app that places library figures on its boards loads this module; the scene
|
|
6
|
+
* component list does not carry figure packages, and without these the panel skips the two properties.
|
|
7
|
+
*/
|
|
1
8
|
export default function bootstrap(): void;
|
package/dist-client/bootstrap.js
CHANGED
|
@@ -1,2 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
import { OxPropertyEditor } from '@operato/property-editor';
|
|
2
|
+
import { SLOT_LAYOUT_EDITORS } from '@operato/slot-layout-editor';
|
|
3
|
+
import './editors/ox-property-editor-figure-data.js';
|
|
4
|
+
/**
|
|
5
|
+
* The editors the board's property panel needs for the properties a placed figure names: its data -- shape, each value
|
|
6
|
+
* and where it came from (`figure-data`) -- and its slot layout, which a placement may override (`slot-layout`, ADR-0118
|
|
7
|
+
* decision 8). Registered here, where every app that places library figures on its boards loads this module; the scene
|
|
8
|
+
* component list does not carry figure packages, and without these the panel skips the two properties.
|
|
9
|
+
*/
|
|
10
|
+
export default function bootstrap() {
|
|
11
|
+
OxPropertyEditor.register({ 'figure-data': 'ox-property-editor-figure-data' });
|
|
12
|
+
OxPropertyEditor.register(Object.fromEntries(SLOT_LAYOUT_EDITORS.map(e => [e.type, e.element])));
|
|
13
|
+
}
|
|
2
14
|
//# sourceMappingURL=bootstrap.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../client/bootstrap.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,UAAU,SAAS,
|
|
1
|
+
{"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../client/bootstrap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AAEjE,OAAO,6CAA6C,CAAA;AAEpD;;;;;GAKG;AACH,MAAM,CAAC,OAAO,UAAU,SAAS;IAC/B,gBAAgB,CAAC,QAAQ,CAAC,EAAE,aAAa,EAAE,gCAAgC,EAAE,CAAC,CAAA;IAC9E,gBAAgB,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAA;AAClG,CAAC","sourcesContent":["import { OxPropertyEditor } from '@operato/property-editor'\nimport { SLOT_LAYOUT_EDITORS } from '@operato/slot-layout-editor'\n\nimport './editors/ox-property-editor-figure-data.js'\n\n/**\n * The editors the board's property panel needs for the properties a placed figure names: its data -- shape, each value\n * and where it came from (`figure-data`) -- and its slot layout, which a placement may override (`slot-layout`, ADR-0118\n * decision 8). Registered here, where every app that places library figures on its boards loads this module; the scene\n * component list does not carry figure packages, and without these the panel skips the two properties.\n */\nexport default function bootstrap() {\n OxPropertyEditor.register({ 'figure-data': 'ox-property-editor-figure-data' })\n OxPropertyEditor.register(Object.fromEntries(SLOT_LAYOUT_EDITORS.map(e => [e.type, e.element])))\n}\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { OxPropertyEditor, type PropertySpec } from '@operato/property-editor';
|
|
2
|
+
/**
|
|
3
|
+
* 「Figure 데이터」 on the board's property panel (data binding design, decision 3): what the selected figure is given
|
|
4
|
+
* and what it makes of it -- its data shape as a tree, each value now and where it came from, what each moves, a control
|
|
5
|
+
* the board's own state values hold, why data was refused, the fields the data has that the shape does not name, and an
|
|
6
|
+
* example to copy. It changes nothing: the figure's data comes from the board's data source or a mapping, its saved
|
|
7
|
+
* values from 「데이터 값」 above.
|
|
8
|
+
*/
|
|
9
|
+
export declare class OxPropertyEditorFigureData extends OxPropertyEditor {
|
|
10
|
+
static styles: import("lit").CSSResult[];
|
|
11
|
+
private copied;
|
|
12
|
+
editorTemplate(value: unknown, spec: PropertySpec): import("lit-html").TemplateResult<1>;
|
|
13
|
+
private renderRow;
|
|
14
|
+
/** The selected figure's report; none for a figure with no data shape, or a selection of several. */
|
|
15
|
+
private reportOf;
|
|
16
|
+
private copy;
|
|
17
|
+
}
|
|
18
|
+
declare global {
|
|
19
|
+
interface HTMLElementTagNameMap {
|
|
20
|
+
'ox-property-editor-figure-data': OxPropertyEditorFigureData;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { __decorate, __metadata } from "tslib";
|
|
2
|
+
import { css, html, nothing } from 'lit';
|
|
3
|
+
import { customElement, state } from 'lit/decorators.js';
|
|
4
|
+
import { i18next } from '@operato/i18n';
|
|
5
|
+
import { OxPropertyEditor } from '@operato/property-editor';
|
|
6
|
+
import { behaviorTargetOf, figureDataReportOf } from '../figure-data-report.js';
|
|
7
|
+
/**
|
|
8
|
+
* 「Figure 데이터」 on the board's property panel (data binding design, decision 3): what the selected figure is given
|
|
9
|
+
* and what it makes of it -- its data shape as a tree, each value now and where it came from, what each moves, a control
|
|
10
|
+
* the board's own state values hold, why data was refused, the fields the data has that the shape does not name, and an
|
|
11
|
+
* example to copy. It changes nothing: the figure's data comes from the board's data source or a mapping, its saved
|
|
12
|
+
* values from 「데이터 값」 above.
|
|
13
|
+
*/
|
|
14
|
+
let OxPropertyEditorFigureData = class OxPropertyEditorFigureData extends OxPropertyEditor {
|
|
15
|
+
constructor() {
|
|
16
|
+
super(...arguments);
|
|
17
|
+
this.copied = false;
|
|
18
|
+
}
|
|
19
|
+
static { this.styles = [
|
|
20
|
+
...OxPropertyEditor.styles,
|
|
21
|
+
css `
|
|
22
|
+
[report] {
|
|
23
|
+
grid-column: 1 / -1;
|
|
24
|
+
display: grid;
|
|
25
|
+
gap: 6px;
|
|
26
|
+
font-size: var(--ui-t-small, 11.5px);
|
|
27
|
+
}
|
|
28
|
+
ul {
|
|
29
|
+
margin: 0;
|
|
30
|
+
padding: 0;
|
|
31
|
+
list-style: none;
|
|
32
|
+
display: grid;
|
|
33
|
+
gap: 2px;
|
|
34
|
+
}
|
|
35
|
+
li {
|
|
36
|
+
display: flex;
|
|
37
|
+
flex-wrap: wrap;
|
|
38
|
+
gap: 0 6px;
|
|
39
|
+
align-items: baseline;
|
|
40
|
+
}
|
|
41
|
+
li [meta] {
|
|
42
|
+
margin-left: auto;
|
|
43
|
+
color: var(--md-sys-color-on-surface-variant);
|
|
44
|
+
text-align: right;
|
|
45
|
+
}
|
|
46
|
+
[source] {
|
|
47
|
+
padding: 0 4px;
|
|
48
|
+
border-radius: 4px;
|
|
49
|
+
background: var(--md-sys-color-surface-container-high);
|
|
50
|
+
color: var(--md-sys-color-on-surface-variant);
|
|
51
|
+
}
|
|
52
|
+
[moves],
|
|
53
|
+
[hint] {
|
|
54
|
+
width: 100%;
|
|
55
|
+
color: var(--md-sys-color-on-surface-variant);
|
|
56
|
+
}
|
|
57
|
+
[warn] {
|
|
58
|
+
color: var(--md-sys-color-error);
|
|
59
|
+
}
|
|
60
|
+
button {
|
|
61
|
+
justify-self: start;
|
|
62
|
+
}
|
|
63
|
+
`
|
|
64
|
+
]; }
|
|
65
|
+
editorTemplate(value, spec) {
|
|
66
|
+
const report = this.reportOf(value);
|
|
67
|
+
if (!report)
|
|
68
|
+
return html `<div report><p hint>${i18next.t('figure.text.board-data-none')}</p></div>`;
|
|
69
|
+
return html `<div report>
|
|
70
|
+
<ul>
|
|
71
|
+
${report.rows.map(row => this.renderRow(row))}
|
|
72
|
+
</ul>
|
|
73
|
+
${report.refused.length
|
|
74
|
+
? html `<p warn>
|
|
75
|
+
${report.refused.map(r => r.issues?.length
|
|
76
|
+
? r.issues.map(i => i18next.t('figure.text.board-data-value-' + i.reason, { path: i.path || '-' })).join(' · ')
|
|
77
|
+
: i18next.t('figure.text.board-data-refused', { reason: r.reason }))}
|
|
78
|
+
</p>`
|
|
79
|
+
: nothing}
|
|
80
|
+
${report.unused.length ? html `<p hint>${i18next.t('figure.text.board-data-unused', { fields: report.unused.join(', ') })}</p>` : nothing}
|
|
81
|
+
<button @click=${() => this.copy(report)}>${i18next.t(this.copied ? 'figure.button.board-data-copied' : 'figure.button.board-data-copy-example')}</button>
|
|
82
|
+
</div>`;
|
|
83
|
+
}
|
|
84
|
+
renderRow(row) {
|
|
85
|
+
const shown = (v) => (typeof v === 'boolean' ? i18next.t(v ? 'figure.label.board-data-true' : 'figure.label.board-data-false') : String(v));
|
|
86
|
+
return html `<li style="padding-left: ${row.depth * 12}px">
|
|
87
|
+
<span>${row.name}${row.label ? html ` <small>${row.label}</small>` : nothing}</span>
|
|
88
|
+
<span meta>
|
|
89
|
+
${row.value !== undefined ? html `<b>${shown(row.value)}</b>` : row.count !== undefined ? html `<b>${i18next.t('figure.label.board-data-count', { count: row.count })}</b>` : nothing}
|
|
90
|
+
${row.source ? html `<span source>${i18next.t('figure.label.board-data-source-' + row.source)}</span>` : nothing}
|
|
91
|
+
${row.value === undefined && row.count === undefined ? kindWord(row.node) : nothing}
|
|
92
|
+
</span>
|
|
93
|
+
${row.behaviors.length
|
|
94
|
+
? html `<span moves>→ ${row.behaviors.map(b => i18next.t('figure.label.board-data-behavior-' + b.kind, { name: behaviorTargetOf(b) })).join(', ')}</span>`
|
|
95
|
+
: nothing}
|
|
96
|
+
${row.heldByBoard.length ? html `<span warn moves>${i18next.t('figure.text.board-data-held', { controls: row.heldByBoard.join(', ') })}</span>` : nothing}
|
|
97
|
+
</li>`;
|
|
98
|
+
}
|
|
99
|
+
/** The selected figure's report; none for a figure with no data shape, or a selection of several. */
|
|
100
|
+
reportOf(value) {
|
|
101
|
+
let selected;
|
|
102
|
+
this.dispatchEvent(new CustomEvent('i-need-selected', { bubbles: true, composed: true, detail: { callback: (s) => (selected = s) } }));
|
|
103
|
+
const figure = selected?.length === 1 ? selected[0] : undefined;
|
|
104
|
+
const inputs = figure?.figureInputs;
|
|
105
|
+
if (!inputs)
|
|
106
|
+
return null;
|
|
107
|
+
return figureDataReportOf({
|
|
108
|
+
asset: inputs.asset,
|
|
109
|
+
data: value ?? figure.state?.data,
|
|
110
|
+
parameters: figure.state?.parameters ?? null,
|
|
111
|
+
values: inputs.dataValues,
|
|
112
|
+
refused: inputs.diagnostics()
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
async copy(report) {
|
|
116
|
+
try {
|
|
117
|
+
await navigator.clipboard.writeText(JSON.stringify(report.example, null, 2));
|
|
118
|
+
this.copied = true;
|
|
119
|
+
setTimeout(() => (this.copied = false), 1500);
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
/* No clipboard here (an insecure page): the button stays as it was. */
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
__decorate([
|
|
127
|
+
state(),
|
|
128
|
+
__metadata("design:type", Object)
|
|
129
|
+
], OxPropertyEditorFigureData.prototype, "copied", void 0);
|
|
130
|
+
OxPropertyEditorFigureData = __decorate([
|
|
131
|
+
customElement('ox-property-editor-figure-data')
|
|
132
|
+
], OxPropertyEditorFigureData);
|
|
133
|
+
export { OxPropertyEditorFigureData };
|
|
134
|
+
/** A field's kind as the section says it, with a number's unit and range and a closed text's values. */
|
|
135
|
+
function kindWord(node) {
|
|
136
|
+
const kind = i18next.t('figure.label.board-data-kind-' + node.kind);
|
|
137
|
+
if (node.kind === 'number')
|
|
138
|
+
return [kind, node.unit, node.min !== undefined || node.max !== undefined ? `${node.min ?? ''}~${node.max ?? ''}` : ''].filter(Boolean).join(' ');
|
|
139
|
+
if (node.kind === 'text' && node.values)
|
|
140
|
+
return `${kind} (${node.values.join(', ')})`;
|
|
141
|
+
return kind;
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=ox-property-editor-figure-data.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ox-property-editor-figure-data.js","sourceRoot":"","sources":["../../client/editors/ox-property-editor-figure-data.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, nothing } from 'lit'\nimport { customElement, state } from 'lit/decorators.js'\n\nimport { i18next } from '@operato/i18n'\nimport { OxPropertyEditor, type PropertySpec } from '@operato/property-editor'\nimport type { FigureAsset, FigureDataNode, FigureDataValue } from '@hatiolab/figure-model'\n\nimport { behaviorTargetOf, figureDataReportOf, type FigureDataReport, type FigureDataSnapshot } from '../figure-data-report.js'\n\n/** The parts of a placed figure the section reads: things-scene's FigureInstance, as the property panel holds it. */\ninterface PlacedFigure {\n state?: { data?: unknown; parameters?: Record<string, unknown> }\n figureInputs?: {\n asset: FigureAsset\n dataValues: FigureDataSnapshot['values']\n diagnostics(): FigureDataSnapshot['refused']\n }\n}\n\n/**\n * 「Figure 데이터」 on the board's property panel (data binding design, decision 3): what the selected figure is given\n * and what it makes of it -- its data shape as a tree, each value now and where it came from, what each moves, a control\n * the board's own state values hold, why data was refused, the fields the data has that the shape does not name, and an\n * example to copy. It changes nothing: the figure's data comes from the board's data source or a mapping, its saved\n * values from 「데이터 값」 above.\n */\n@customElement('ox-property-editor-figure-data')\nexport class OxPropertyEditorFigureData extends OxPropertyEditor {\n static styles = [\n ...OxPropertyEditor.styles,\n css`\n [report] {\n grid-column: 1 / -1;\n display: grid;\n gap: 6px;\n font-size: var(--ui-t-small, 11.5px);\n }\n ul {\n margin: 0;\n padding: 0;\n list-style: none;\n display: grid;\n gap: 2px;\n }\n li {\n display: flex;\n flex-wrap: wrap;\n gap: 0 6px;\n align-items: baseline;\n }\n li [meta] {\n margin-left: auto;\n color: var(--md-sys-color-on-surface-variant);\n text-align: right;\n }\n [source] {\n padding: 0 4px;\n border-radius: 4px;\n background: var(--md-sys-color-surface-container-high);\n color: var(--md-sys-color-on-surface-variant);\n }\n [moves],\n [hint] {\n width: 100%;\n color: var(--md-sys-color-on-surface-variant);\n }\n [warn] {\n color: var(--md-sys-color-error);\n }\n button {\n justify-self: start;\n }\n `\n ]\n\n @state() private copied = false\n\n editorTemplate(value: unknown, spec: PropertySpec) {\n const report = this.reportOf(value)\n if (!report) return html`<div report><p hint>${i18next.t('figure.text.board-data-none')}</p></div>`\n return html`<div report>\n <ul>\n ${report.rows.map(row => this.renderRow(row))}\n </ul>\n ${report.refused.length\n ? html`<p warn>\n ${report.refused.map(r =>\n r.issues?.length\n ? r.issues.map(i => i18next.t('figure.text.board-data-value-' + i.reason, { path: i.path || '-' })).join(' · ')\n : i18next.t('figure.text.board-data-refused', { reason: r.reason })\n )}\n </p>`\n : nothing}\n ${report.unused.length ? html`<p hint>${i18next.t('figure.text.board-data-unused', { fields: report.unused.join(', ') })}</p>` : nothing}\n <button @click=${() => this.copy(report)}>${i18next.t(this.copied ? 'figure.button.board-data-copied' : 'figure.button.board-data-copy-example')}</button>\n </div>`\n }\n\n private renderRow(row: FigureDataReport['rows'][number]) {\n const shown = (v: FigureDataValue) => (typeof v === 'boolean' ? i18next.t(v ? 'figure.label.board-data-true' : 'figure.label.board-data-false') : String(v))\n return html`<li style=\"padding-left: ${row.depth * 12}px\">\n <span>${row.name}${row.label ? html` <small>${row.label}</small>` : nothing}</span>\n <span meta>\n ${row.value !== undefined ? html`<b>${shown(row.value)}</b>` : row.count !== undefined ? html`<b>${i18next.t('figure.label.board-data-count', { count: row.count })}</b>` : nothing}\n ${row.source ? html`<span source>${i18next.t('figure.label.board-data-source-' + row.source)}</span>` : nothing}\n ${row.value === undefined && row.count === undefined ? kindWord(row.node) : nothing}\n </span>\n ${row.behaviors.length\n ? html`<span moves>→ ${row.behaviors.map(b => i18next.t('figure.label.board-data-behavior-' + b.kind, { name: behaviorTargetOf(b) })).join(', ')}</span>`\n : nothing}\n ${row.heldByBoard.length ? html`<span warn moves>${i18next.t('figure.text.board-data-held', { controls: row.heldByBoard.join(', ') })}</span>` : nothing}\n </li>`\n }\n\n /** The selected figure's report; none for a figure with no data shape, or a selection of several. */\n private reportOf(value: unknown): FigureDataReport | null {\n let selected: unknown[] | undefined\n this.dispatchEvent(new CustomEvent('i-need-selected', { bubbles: true, composed: true, detail: { callback: (s: unknown[]) => (selected = s) } }))\n const figure = selected?.length === 1 ? (selected[0] as PlacedFigure) : undefined\n const inputs = figure?.figureInputs\n if (!inputs) return null\n return figureDataReportOf({\n asset: inputs.asset,\n data: value ?? figure!.state?.data,\n parameters: figure!.state?.parameters ?? null,\n values: inputs.dataValues,\n refused: inputs.diagnostics()\n })\n }\n\n private async copy(report: FigureDataReport) {\n try {\n await navigator.clipboard.writeText(JSON.stringify(report.example, null, 2))\n this.copied = true\n setTimeout(() => (this.copied = false), 1500)\n } catch {\n /* No clipboard here (an insecure page): the button stays as it was. */\n }\n }\n}\n\n/** A field's kind as the section says it, with a number's unit and range and a closed text's values. */\nfunction kindWord(node: FigureDataNode): string {\n const kind = i18next.t('figure.label.board-data-kind-' + node.kind)\n if (node.kind === 'number') return [kind, node.unit, node.min !== undefined || node.max !== undefined ? `${node.min ?? ''}~${node.max ?? ''}` : ''].filter(Boolean).join(' ')\n if (node.kind === 'text' && node.values) return `${kind} (${node.values.join(', ')})`\n return kind\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ox-property-editor-figure-data': OxPropertyEditorFigureData\n }\n}\n"]}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { FigureAsset, FigureDataBehavior, FigureDataNode, FigureDataValue, FigureDataValueIssue } from '@hatiolab/figure-model';
|
|
2
|
+
/** Where a value came from, as things-scene's figure inputs say. */
|
|
3
|
+
export type FigureDataSource = 'live' | 'manual' | 'default' | 'absent';
|
|
4
|
+
/** A placed figure as the section reads it: its asset, its state, and what its figure inputs worked out. */
|
|
5
|
+
export interface FigureDataSnapshot {
|
|
6
|
+
asset: FigureAsset;
|
|
7
|
+
/** The component's data, as the board's data source or a mapping gave it. */
|
|
8
|
+
data: unknown;
|
|
9
|
+
/** The board's own state values (`parameters`), by control. */
|
|
10
|
+
parameters?: Record<string, unknown> | null;
|
|
11
|
+
/** Each binding's value now and its source, by binding id (figure inputs' `dataValues`). */
|
|
12
|
+
values: Readonly<Record<string, {
|
|
13
|
+
value: FigureDataValue | undefined;
|
|
14
|
+
source: FigureDataSource;
|
|
15
|
+
}>>;
|
|
16
|
+
/** Why the last things given were refused (figure inputs' `diagnostics()`). */
|
|
17
|
+
refused: ReadonlyArray<{
|
|
18
|
+
source: string;
|
|
19
|
+
reason: string;
|
|
20
|
+
issues?: FigureDataValueIssue[];
|
|
21
|
+
}>;
|
|
22
|
+
}
|
|
23
|
+
export interface FigureDataReportRow {
|
|
24
|
+
path: string;
|
|
25
|
+
depth: number;
|
|
26
|
+
name: string;
|
|
27
|
+
label?: string;
|
|
28
|
+
node: FigureDataNode;
|
|
29
|
+
/** A value field's value now; a list's element count in the data. */
|
|
30
|
+
value?: FigureDataValue;
|
|
31
|
+
count?: number;
|
|
32
|
+
source?: FigureDataSource;
|
|
33
|
+
/** What the bindings reading it move. */
|
|
34
|
+
behaviors: FigureDataBehavior[];
|
|
35
|
+
/** Controls it moves that the board's state values hold instead. */
|
|
36
|
+
heldByBoard: string[];
|
|
37
|
+
}
|
|
38
|
+
export interface FigureDataReport {
|
|
39
|
+
rows: FigureDataReportRow[];
|
|
40
|
+
/** Fields the data has that the shape does not name, as paths (`[]` for a list's elements). */
|
|
41
|
+
unused: string[];
|
|
42
|
+
refused: FigureDataSnapshot['refused'];
|
|
43
|
+
/** Data with every field of the shape, to copy. */
|
|
44
|
+
example: Record<string, unknown>;
|
|
45
|
+
}
|
|
46
|
+
export declare function figureDataReportOf(s: FigureDataSnapshot): FigureDataReport | null;
|
|
47
|
+
/** The thing a behavior moves, as one id: the control, the colour token, the group, the port, the axis, the place. */
|
|
48
|
+
export declare const behaviorTargetOf: (b: FigureDataBehavior) => string;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* What the board's 「Figure 데이터」 section shows of a placed figure (data binding design, decision 3): the figure's data
|
|
3
|
+
* shape as a tree, each value now and where it came from -- the component's data, a value saved on the board, the
|
|
4
|
+
* shape's default, or none -- what it moves, a control the board's own state values hold over the data, why data was
|
|
5
|
+
* refused, the fields the data has that the shape does not name, and an example to copy.
|
|
6
|
+
*
|
|
7
|
+
* Nothing here reads data: the values and their sources are things-scene's figure inputs', given in. Kept apart from the
|
|
8
|
+
* element so it is tested without a board.
|
|
9
|
+
*/
|
|
10
|
+
import { figureDataExample, figureDataRows } from '@hatiolab/figure-model';
|
|
11
|
+
const isRecord = (v) => !!v && typeof v === 'object' && !Array.isArray(v);
|
|
12
|
+
/** The value at a path with no list in it (`A.B`), or undefined. */
|
|
13
|
+
function valueAt(data, path) {
|
|
14
|
+
let at = data;
|
|
15
|
+
for (const name of path.split('.')) {
|
|
16
|
+
if (!isRecord(at))
|
|
17
|
+
return undefined;
|
|
18
|
+
at = at[name];
|
|
19
|
+
}
|
|
20
|
+
return at;
|
|
21
|
+
}
|
|
22
|
+
/** Every field path the data has that the shape does not name. A JSON text in place of an object or a list is not looked into. */
|
|
23
|
+
function unusedOf(data, fields, at, out) {
|
|
24
|
+
if (!isRecord(data))
|
|
25
|
+
return;
|
|
26
|
+
for (const [key, value] of Object.entries(data)) {
|
|
27
|
+
const path = at ? `${at}.${key}` : key;
|
|
28
|
+
const field = fields.find(f => f.name === key);
|
|
29
|
+
if (!field) {
|
|
30
|
+
out.add(path);
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
let node = field;
|
|
34
|
+
let value_ = value;
|
|
35
|
+
let p = path;
|
|
36
|
+
while (node.kind === 'list' && Array.isArray(value_)) {
|
|
37
|
+
const item = node.item;
|
|
38
|
+
p = `${p}[]`;
|
|
39
|
+
for (const element of value_)
|
|
40
|
+
if (item.kind === 'object')
|
|
41
|
+
unusedOf(element, item.fields, p, out);
|
|
42
|
+
value_ = undefined;
|
|
43
|
+
node = item;
|
|
44
|
+
}
|
|
45
|
+
if (node.kind === 'object' && isRecord(value_))
|
|
46
|
+
unusedOf(value_, node.fields, p, out);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
export function figureDataReportOf(s) {
|
|
50
|
+
const di = s.asset.dataInterface;
|
|
51
|
+
if (!di)
|
|
52
|
+
return null;
|
|
53
|
+
const bindings = new Map(di.bindings.map(b => [b.id, b]));
|
|
54
|
+
const held = new Set(Object.keys(s.parameters ?? {}));
|
|
55
|
+
const rows = figureDataRows(di).map((row) => {
|
|
56
|
+
const reading = row.bindings.map(id => bindings.get(id)).filter(b => !!b);
|
|
57
|
+
const behaviors = reading.map(b => b.behavior);
|
|
58
|
+
const heldByBoard = behaviors.flatMap(b => (b.kind === 'state' && held.has(b.input) ? [b.input] : []));
|
|
59
|
+
const out = { path: row.path, depth: row.depth, name: row.name, ...(row.label ? { label: row.label } : {}), node: row.node, behaviors, heldByBoard };
|
|
60
|
+
if (row.node.kind === 'list') {
|
|
61
|
+
const list = row.path.includes('[]') ? undefined : valueAt(s.data, row.path);
|
|
62
|
+
if (Array.isArray(list))
|
|
63
|
+
out.count = list.length;
|
|
64
|
+
}
|
|
65
|
+
else if (row.node.kind !== 'object') {
|
|
66
|
+
/* The value a binding read: the first that reads this place and is not an items binding (items read the list). */
|
|
67
|
+
const read = reading.find(b => b.behavior.kind !== 'items' && s.values[b.id]);
|
|
68
|
+
if (read) {
|
|
69
|
+
const { value, source } = s.values[read.id];
|
|
70
|
+
out.source = source;
|
|
71
|
+
if (value !== undefined)
|
|
72
|
+
out.value = value;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return out;
|
|
76
|
+
});
|
|
77
|
+
const unused = new Set();
|
|
78
|
+
unusedOf(s.data, di.schema, '', unused);
|
|
79
|
+
return { rows, unused: [...unused], refused: s.refused, example: figureDataExample(di) };
|
|
80
|
+
}
|
|
81
|
+
/** The thing a behavior moves, as one id: the control, the colour token, the group, the port, the axis, the place. */
|
|
82
|
+
export const behaviorTargetOf = (b) => b.kind === 'state' ? b.input : b.kind === 'palette' ? b.token : b.kind === 'status' ? b.port : b.kind === 'pose' ? b.axis : b.kind === 'items' ? (b.slot ?? '') : b.group;
|
|
83
|
+
//# sourceMappingURL=figure-data-report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"figure-data-report.js","sourceRoot":"","sources":["../client/figure-data-report.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * What the board's 「Figure 데이터」 section shows of a placed figure (data binding design, decision 3): the figure's data\n * shape as a tree, each value now and where it came from -- the component's data, a value saved on the board, the\n * shape's default, or none -- what it moves, a control the board's own state values hold over the data, why data was\n * refused, the fields the data has that the shape does not name, and an example to copy.\n *\n * Nothing here reads data: the values and their sources are things-scene's figure inputs', given in. Kept apart from the\n * element so it is tested without a board.\n */\nimport { figureDataExample, figureDataRows } from '@hatiolab/figure-model'\nimport type { FigureAsset, FigureDataBehavior, FigureDataNode, FigureDataValue, FigureDataValueIssue } from '@hatiolab/figure-model'\n\n/** Where a value came from, as things-scene's figure inputs say. */\nexport type FigureDataSource = 'live' | 'manual' | 'default' | 'absent'\n\n/** A placed figure as the section reads it: its asset, its state, and what its figure inputs worked out. */\nexport interface FigureDataSnapshot {\n asset: FigureAsset\n /** The component's data, as the board's data source or a mapping gave it. */\n data: unknown\n /** The board's own state values (`parameters`), by control. */\n parameters?: Record<string, unknown> | null\n /** Each binding's value now and its source, by binding id (figure inputs' `dataValues`). */\n values: Readonly<Record<string, { value: FigureDataValue | undefined; source: FigureDataSource }>>\n /** Why the last things given were refused (figure inputs' `diagnostics()`). */\n refused: ReadonlyArray<{ source: string; reason: string; issues?: FigureDataValueIssue[] }>\n}\n\nexport interface FigureDataReportRow {\n path: string\n depth: number\n name: string\n label?: string\n node: FigureDataNode\n /** A value field's value now; a list's element count in the data. */\n value?: FigureDataValue\n count?: number\n source?: FigureDataSource\n /** What the bindings reading it move. */\n behaviors: FigureDataBehavior[]\n /** Controls it moves that the board's state values hold instead. */\n heldByBoard: string[]\n}\n\nexport interface FigureDataReport {\n rows: FigureDataReportRow[]\n /** Fields the data has that the shape does not name, as paths (`[]` for a list's elements). */\n unused: string[]\n refused: FigureDataSnapshot['refused']\n /** Data with every field of the shape, to copy. */\n example: Record<string, unknown>\n}\n\nconst isRecord = (v: unknown): v is Record<string, unknown> => !!v && typeof v === 'object' && !Array.isArray(v)\n\n/** The value at a path with no list in it (`A.B`), or undefined. */\nfunction valueAt(data: unknown, path: string): unknown {\n let at: unknown = data\n for (const name of path.split('.')) {\n if (!isRecord(at)) return undefined\n at = at[name]\n }\n return at\n}\n\n/** Every field path the data has that the shape does not name. A JSON text in place of an object or a list is not looked into. */\nfunction unusedOf(data: unknown, fields: ReadonlyArray<{ name: string } & FigureDataNode>, at: string, out: Set<string>): void {\n if (!isRecord(data)) return\n for (const [key, value] of Object.entries(data)) {\n const path = at ? `${at}.${key}` : key\n const field = fields.find(f => f.name === key)\n if (!field) {\n out.add(path)\n continue\n }\n let node: FigureDataNode = field\n let value_: unknown = value\n let p = path\n while (node.kind === 'list' && Array.isArray(value_)) {\n const item: FigureDataNode = node.item\n p = `${p}[]`\n for (const element of value_) if (item.kind === 'object') unusedOf(element, item.fields, p, out)\n value_ = undefined\n node = item\n }\n if (node.kind === 'object' && isRecord(value_)) unusedOf(value_, node.fields, p, out)\n }\n}\n\nexport function figureDataReportOf(s: FigureDataSnapshot): FigureDataReport | null {\n const di = s.asset.dataInterface\n if (!di) return null\n const bindings = new Map(di.bindings.map(b => [b.id, b] as const))\n const held = new Set(Object.keys(s.parameters ?? {}))\n const rows = figureDataRows(di).map((row): FigureDataReportRow => {\n const reading = row.bindings.map(id => bindings.get(id)).filter(b => !!b)\n const behaviors = reading.map(b => b.behavior)\n const heldByBoard = behaviors.flatMap(b => (b.kind === 'state' && held.has(b.input) ? [b.input] : []))\n const out: FigureDataReportRow = { path: row.path, depth: row.depth, name: row.name, ...(row.label ? { label: row.label } : {}), node: row.node, behaviors, heldByBoard }\n if (row.node.kind === 'list') {\n const list = row.path.includes('[]') ? undefined : valueAt(s.data, row.path)\n if (Array.isArray(list)) out.count = list.length\n } else if (row.node.kind !== 'object') {\n /* The value a binding read: the first that reads this place and is not an items binding (items read the list). */\n const read = reading.find(b => b.behavior.kind !== 'items' && s.values[b.id])\n if (read) {\n const { value, source } = s.values[read.id]!\n out.source = source\n if (value !== undefined) out.value = value\n }\n }\n return out\n })\n const unused = new Set<string>()\n unusedOf(s.data, di.schema, '', unused)\n return { rows, unused: [...unused], refused: s.refused, example: figureDataExample(di) }\n}\n\n/** The thing a behavior moves, as one id: the control, the colour token, the group, the port, the axis, the place. */\nexport const behaviorTargetOf = (b: FigureDataBehavior): string =>\n b.kind === 'state' ? b.input : b.kind === 'palette' ? b.token : b.kind === 'status' ? b.port : b.kind === 'pose' ? b.axis : b.kind === 'items' ? (b.slot ?? '') : b.group\n"]}
|