@things-factory/figure-ui 10.1.223 → 10.1.225

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.
Files changed (80) hide show
  1. package/client/modeller/canvas.ts +2 -2
  2. package/client/modeller/consumer-capabilities.ts +66 -0
  3. package/client/modeller/data-interface.ts +230 -80
  4. package/client/modeller/editor-styles.ts +3 -2
  5. package/client/modeller/editor.ts +17 -8
  6. package/client/modeller/figure-capability-panel.ts +151 -1
  7. package/client/modeller/figure-clips.ts +1 -1
  8. package/client/modeller/figure-data-panel.ts +509 -199
  9. package/client/modeller/figure-links.ts +130 -12
  10. package/client/modeller/figure-preview.ts +65 -8
  11. package/client/modeller/figure-slot-layout-panel.ts +7 -3
  12. package/client/modeller/links.ts +58 -0
  13. package/client/modeller/product-session.ts +3 -2
  14. package/client/modeller/refusals.ts +12 -4
  15. package/client/modeller/slot-layout-host.ts +76 -5
  16. package/client/pages/figure-modeller-page.ts +2 -2
  17. package/dist-client/modeller/canvas.js +2 -2
  18. package/dist-client/modeller/canvas.js.map +1 -1
  19. package/dist-client/modeller/consumer-capabilities.d.ts +29 -0
  20. package/dist-client/modeller/consumer-capabilities.js +60 -0
  21. package/dist-client/modeller/consumer-capabilities.js.map +1 -0
  22. package/dist-client/modeller/data-interface.d.ts +83 -17
  23. package/dist-client/modeller/data-interface.js +194 -82
  24. package/dist-client/modeller/data-interface.js.map +1 -1
  25. package/dist-client/modeller/editor-styles.js +3 -2
  26. package/dist-client/modeller/editor-styles.js.map +1 -1
  27. package/dist-client/modeller/editor.d.ts +5 -2
  28. package/dist-client/modeller/editor.js +21 -8
  29. package/dist-client/modeller/editor.js.map +1 -1
  30. package/dist-client/modeller/figure-capability-panel.d.ts +12 -0
  31. package/dist-client/modeller/figure-capability-panel.js +129 -1
  32. package/dist-client/modeller/figure-capability-panel.js.map +1 -1
  33. package/dist-client/modeller/figure-clips.js +1 -1
  34. package/dist-client/modeller/figure-clips.js.map +1 -1
  35. package/dist-client/modeller/figure-data-panel.d.ts +57 -13
  36. package/dist-client/modeller/figure-data-panel.js +476 -191
  37. package/dist-client/modeller/figure-data-panel.js.map +1 -1
  38. package/dist-client/modeller/figure-links.d.ts +11 -0
  39. package/dist-client/modeller/figure-links.js +137 -16
  40. package/dist-client/modeller/figure-links.js.map +1 -1
  41. package/dist-client/modeller/figure-preview.d.ts +4 -0
  42. package/dist-client/modeller/figure-preview.js +65 -7
  43. package/dist-client/modeller/figure-preview.js.map +1 -1
  44. package/dist-client/modeller/figure-slot-layout-panel.js +6 -4
  45. package/dist-client/modeller/figure-slot-layout-panel.js.map +1 -1
  46. package/dist-client/modeller/links.d.ts +22 -0
  47. package/dist-client/modeller/links.js +48 -0
  48. package/dist-client/modeller/links.js.map +1 -1
  49. package/dist-client/modeller/product-session.d.ts +4 -2
  50. package/dist-client/modeller/product-session.js +3 -2
  51. package/dist-client/modeller/product-session.js.map +1 -1
  52. package/dist-client/modeller/refusals.js +14 -6
  53. package/dist-client/modeller/refusals.js.map +1 -1
  54. package/dist-client/modeller/slot-layout-host.d.ts +28 -3
  55. package/dist-client/modeller/slot-layout-host.js +68 -6
  56. package/dist-client/modeller/slot-layout-host.js.map +1 -1
  57. package/dist-client/pages/figure-modeller-page.js +2 -2
  58. package/dist-client/pages/figure-modeller-page.js.map +1 -1
  59. package/dist-client/tsconfig.tsbuildinfo +1 -1
  60. package/package.json +8 -8
  61. package/test/ai-proposal.test.ts +2 -2
  62. package/test/browser/data-table-page.js +9 -0
  63. package/test/browser/links.check.mjs +25 -3
  64. package/test/browser/product-page.check.mjs +25 -0
  65. package/test/browser/side-panel-sweep.check.mjs +182 -0
  66. package/test/consumer-capabilities.test.ts +116 -0
  67. package/test/data-motion.test.ts +94 -27
  68. package/test/figure-assistant-surface.test.ts +1 -1
  69. package/test/first-save.test.ts +2 -2
  70. package/test/links.test.ts +15 -0
  71. package/test/product-session.test.ts +5 -5
  72. package/test/proposal-record.test.ts +3 -3
  73. package/test/revert-keeping.test.ts +1 -1
  74. package/test/slot-layout-host.test.ts +63 -5
  75. package/translations/en.json +82 -23
  76. package/translations/es.json +82 -23
  77. package/translations/ja.json +82 -23
  78. package/translations/ko.json +82 -23
  79. package/translations/ms.json +82 -23
  80. package/translations/zh.json +82 -23
@@ -7,14 +7,26 @@ declare const FigureCapabilityPanel_base: (new (...args: any[]) => LitElement) &
7
7
  * so the list is the only way to find one; choosing a row selects its part, where the place is edited. Whether the
8
8
  * figure is the look of an item a holder carries is said here too (ADR-0155 amendment 2): a tag, apart from the ladder,
9
9
  * since an item may hold things as well.
10
+ *
11
+ * Below the ladder, the products' capabilities this modeller has descriptors for (ADR-0167 9, 12): each put on or off,
12
+ * what it still needs, and its settings as its descriptor draws them -- parts picked (the part chosen here by one
13
+ * button), an input and a value per fixed key, never a row added or taken away -- with what its check says.
10
14
  */
11
15
  export declare class FigureCapabilityPanel extends FigureCapabilityPanel_base {
12
16
  static styles: import("lit").CSSResult[];
17
+ private unlisten?;
18
+ connectedCallback(): void;
19
+ disconnectedCallback(): void;
13
20
  asset?: FigureAsset;
14
21
  /** The selected part, whose places are marked. */
15
22
  selected: string;
16
23
  locked: boolean;
17
24
  render(): import("lit-html").TemplateResult<1> | typeof nothing;
25
+ /** The products' capabilities: those this modeller knows, each on or off with its settings, and those it does not know. */
26
+ private renderConsumers;
27
+ /** A capability's settings as its descriptor draws them, and what its check says of them. */
28
+ private renderSettings;
29
+ private setConsumer;
18
30
  private setRung;
19
31
  private setItem;
20
32
  private pick;
@@ -7,12 +7,18 @@ import { figureBindingsOf } from '@hatiolab/figure-model';
7
7
  import { RUNGS, rungOf } from '@things-factory/figure-viewer/dist-client/capability-rung.js';
8
8
  import { SidePanelStyles } from '@things-factory/figure-viewer/dist-client/side-panel-styles.js';
9
9
  import { placeTerms } from '@things-factory/figure-viewer/dist-client/detail-facts.js';
10
+ import { onFigureCapabilitiesChanged } from '@hatiolab/things-scene';
11
+ import { consumerDescriptors, inputTableAt, namesWith, needsMissing, partsAt, settingsIssues, settingsOf, unknownConsumerNames, withInputTable, withParts } from './consumer-capabilities.js';
10
12
  /**
11
13
  * 자리·능력 — what the figure does on a board: the ladder from drawing only, to
12
14
  * holding things, to passing them on, and every place things are held, whatever part it is on. A place is not drawn,
13
15
  * so the list is the only way to find one; choosing a row selects its part, where the place is edited. Whether the
14
16
  * figure is the look of an item a holder carries is said here too (ADR-0155 amendment 2): a tag, apart from the ladder,
15
17
  * since an item may hold things as well.
18
+ *
19
+ * Below the ladder, the products' capabilities this modeller has descriptors for (ADR-0167 9, 12): each put on or off,
20
+ * what it still needs, and its settings as its descriptor draws them -- parts picked (the part chosen here by one
21
+ * button), an input and a value per fixed key, never a row added or taken away -- with what its check says.
16
22
  */
17
23
  let FigureCapabilityPanel = class FigureCapabilityPanel extends localize(i18next)(LitElement) {
18
24
  constructor() {
@@ -35,6 +41,12 @@ let FigureCapabilityPanel = class FigureCapabilityPanel extends localize(i18next
35
41
  border-radius: 8px;
36
42
  cursor: pointer;
37
43
  }
44
+ /* The box keeps its size beside a long note: squeezed by the flex row it read as a dot (sweep 2026-10-27 U1). */
45
+ label[rung] > input,
46
+ label[item] > input {
47
+ flex: none;
48
+ margin: 2px 0 0;
49
+ }
38
50
  label[rung][on],
39
51
  label[item][on] {
40
52
  border-color: var(--md-sys-color-primary);
@@ -73,7 +85,37 @@ let FigureCapabilityPanel = class FigureCapabilityPanel extends localize(i18next
73
85
  font-size: var(--ui-t-small, 11.5px);
74
86
  color: var(--md-sys-color-on-surface-variant);
75
87
  }
88
+ div[chips] {
89
+ display: flex;
90
+ flex-wrap: wrap;
91
+ gap: 4px 10px;
92
+ align-items: center;
93
+ }
94
+ div[chips] label {
95
+ display: inline-flex;
96
+ gap: 4px;
97
+ align-items: center;
98
+ }
99
+ div[table] {
100
+ display: grid;
101
+ grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
102
+ gap: 4px 6px;
103
+ align-items: center;
104
+ }
105
+ p[warn] {
106
+ margin: 0;
107
+ color: var(--md-sys-color-error);
108
+ }
76
109
  `]; }
110
+ connectedCallback() {
111
+ super.connectedCallback();
112
+ /* A product's descriptors may be registered after the panel stands. */
113
+ this.unlisten = onFigureCapabilitiesChanged(() => this.requestUpdate());
114
+ }
115
+ disconnectedCallback() {
116
+ super.disconnectedCallback();
117
+ this.unlisten?.();
118
+ }
77
119
  render() {
78
120
  const asset = this.asset;
79
121
  if (!asset)
@@ -93,6 +135,7 @@ let FigureCapabilityPanel = class FigureCapabilityPanel extends localize(i18next
93
135
  ${rung === null ? html `<p hint>${i18next.t('figure.text.capability-hand-written')}</p>` : nothing}
94
136
  ${names.length ? html `<code>${names.join(' · ')}</code>` : nothing}
95
137
  </section>
138
+ ${this.renderConsumers(asset)}
96
139
  <section>
97
140
  <h3>${i18next.t('figure.label.places')}</h3>
98
141
  ${places.length
@@ -118,8 +161,93 @@ let FigureCapabilityPanel = class FigureCapabilityPanel extends localize(i18next
118
161
  </section>
119
162
  `;
120
163
  }
164
+ /** The products' capabilities: those this modeller knows, each on or off with its settings, and those it does not know. */
165
+ renderConsumers(asset) {
166
+ const known = consumerDescriptors();
167
+ const unknown = unknownConsumerNames(asset);
168
+ if (!known.length && !unknown.length)
169
+ return nothing;
170
+ const names = asset.document.capabilities.names ?? [];
171
+ return html `<section>
172
+ <h3>${i18next.t('figure.label.product-capabilities')}</h3>
173
+ ${known.map(d => {
174
+ const on = names.includes(d.name);
175
+ const missing = needsMissing(d, asset);
176
+ return html `<label rung ?on=${on}>
177
+ <input type="checkbox" .checked=${live(on)} ?disabled=${this.locked || (!on && missing.length > 0)} @change=${(e) => this.setConsumer(asset, d.name, e.target.checked)} />
178
+ <span>
179
+ <strong>${d.label}</strong>
180
+ <em>${d.note}</em>
181
+ <code>${d.name} · ${d.version}</code>
182
+ </span>
183
+ </label>
184
+ ${missing.length ? html `<p hint>${i18next.t('figure.text.product-capability-needs', { needs: missing.map(m => (m === 'item' ? i18next.t('figure.label.is-item') : m)).join(', ') })}</p>` : nothing}
185
+ ${on ? this.renderSettings(asset, d) : nothing}`;
186
+ })}
187
+ ${unknown.map(name => html `<p hint>
188
+ ${i18next.t('figure.text.product-capability-unknown', { name })}
189
+ <button quiet ?disabled=${this.locked} @click=${() => this.setConsumer(asset, name, false)}>${i18next.t('figure.button.product-capability-remove')}</button>
190
+ </p>`)}
191
+ </section>`;
192
+ }
193
+ /** A capability's settings as its descriptor draws them, and what its check says of them. */
194
+ renderSettings(asset, d) {
195
+ const settings = settingsOf(asset, d.name);
196
+ const write = (next) => this.dispatchEvent(new CustomEvent('part-edit', { detail: { edit: { kind: 'set-capability-settings', name: d.name, settings: Object.keys(next).length ? next : null } }, bubbles: true, composed: true }));
197
+ const parts = [...new Set(asset.appearance.map(a => a.target))];
198
+ const inputs = asset.document.model.inputs.filter(i => i.role === 'state');
199
+ const issues = settingsIssues(d, asset);
200
+ return html `<div form>
201
+ ${(d.settings ?? []).map((setting) => {
202
+ if (setting.kind === 'parts') {
203
+ const chosen = partsAt(settings, setting.key);
204
+ const toggle = (part, on) => write(withParts(settings, setting.key, on ? [...chosen, part] : chosen.filter(p => p !== part)));
205
+ return html `<span>${setting.label}</span>
206
+ <div chips>
207
+ ${parts.map(p => html `<label><input type="checkbox" .checked=${live(chosen.includes(p))} ?disabled=${this.locked} @change=${(e) => toggle(p, e.target.checked)} />${p}</label>`)}
208
+ ${this.selected && parts.includes(this.selected) && !chosen.includes(this.selected)
209
+ ? html `<button quiet ?disabled=${this.locked} @click=${() => toggle(this.selected, true)}>${i18next.t('figure.button.data-add-selected-part', { part: this.selected })}</button>`
210
+ : nothing}
211
+ </div>`;
212
+ }
213
+ const table = inputTableAt(settings, setting);
214
+ const input = inputs.find(i => i.id === table.input);
215
+ return html `<span>${setting.label}</span>
216
+ <select ?disabled=${this.locked} @change=${(e) => write(withInputTable(settings, setting, e.target.value || undefined, table.values))}>
217
+ <option value="" ?selected=${!table.input}>${i18next.t('figure.label.data-none')}</option>
218
+ ${inputs.map(i => html `<option value=${i.id} ?selected=${i.id === table.input}>${asset.stateInputs?.[i.id]?.label ?? i.id}${i.unit ? ` (${i.unit} ${i.min ?? ''}~${i.max ?? ''})` : ''}</option>`)}
219
+ </select>
220
+ ${table.input
221
+ ? html `<span></span>
222
+ <div table>
223
+ ${setting.keys.map(key => html `<span>${key}</span>
224
+ <input
225
+ type="number"
226
+ step="any"
227
+ min=${input?.min ?? ''}
228
+ max=${input?.max ?? ''}
229
+ .value=${String(table.values[key])}
230
+ ?disabled=${this.locked}
231
+ @change=${(e) => {
232
+ const n = e.target.valueAsNumber;
233
+ if (!Number.isFinite(n))
234
+ return this.requestUpdate();
235
+ write(withInputTable(settings, setting, table.input, { ...table.values, [key]: n }));
236
+ }}
237
+ />`)}
238
+ </div>`
239
+ : nothing}`;
240
+ })}
241
+ </div>
242
+ ${issues.map(reason => html `<p warn>${reason}</p>`)}`;
243
+ }
244
+ setConsumer(asset, name, on) {
245
+ this.dispatchEvent(new CustomEvent('part-edit', { detail: { edit: { kind: 'set-capabilities', names: namesWith(asset, name, on) } }, bubbles: true, composed: true }));
246
+ }
121
247
  setRung(which) {
122
- this.dispatchEvent(new CustomEvent('part-edit', { detail: { edit: { kind: 'set-capabilities', names: [...RUNGS[which]] } }, bubbles: true, composed: true }));
248
+ /* The ladder sets the shared names; a product's capabilities stay as they are. */
249
+ const consumers = (this.asset?.document.capabilities.names ?? []).filter(n => n.includes('.'));
250
+ this.dispatchEvent(new CustomEvent('part-edit', { detail: { edit: { kind: 'set-capabilities', names: [...RUNGS[which], ...consumers] } }, bubbles: true, composed: true }));
123
251
  }
124
252
  setItem(item) {
125
253
  this.dispatchEvent(new CustomEvent('command', { detail: { action: { kind: 'set-item', item } }, bubbles: true, composed: true }));
@@ -1 +1 @@
1
- {"version":3,"file":"figure-capability-panel.js","sourceRoot":"","sources":["../../client/modeller/figure-capability-panel.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\nimport { live } from 'lit/directives/live.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { figureBindingsOf } from '@hatiolab/figure-model'\nimport type { FigureAsset } from '@hatiolab/figure-model'\nimport { RUNGS, rungOf, type Rung } from '@things-factory/figure-viewer/dist-client/capability-rung.js'\nimport { SidePanelStyles } from '@things-factory/figure-viewer/dist-client/side-panel-styles.js'\nimport { placeTerms } from '@things-factory/figure-viewer/dist-client/detail-facts.js'\n\n/**\n * 자리·능력 — what the figure does on a board: the ladder from drawing only, to\n * holding things, to passing them on, and every place things are held, whatever part it is on. A place is not drawn,\n * so the list is the only way to find one; choosing a row selects its part, where the place is edited. Whether the\n * figure is the look of an item a holder carries is said here too (ADR-0155 amendment 2): a tag, apart from the ladder,\n * since an item may hold things as well.\n */\n@customElement('figure-capability-panel')\nexport class FigureCapabilityPanel extends localize(i18next)(LitElement) {\n static styles = [SidePanelStyles, css`\n :host {\n display: block;\n }\n label[rung],\n label[item] {\n display: flex;\n gap: 8px;\n align-items: flex-start;\n padding: 8px;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 8px;\n cursor: pointer;\n }\n label[rung][on],\n label[item][on] {\n border-color: var(--md-sys-color-primary);\n background: var(--md-sys-color-secondary-container);\n color: var(--md-sys-color-on-secondary-container);\n }\n label[rung] span,\n label[item] span {\n display: grid;\n gap: 2px;\n }\n label[rung] em,\n label[item] em,\n p[hint],\n small {\n font-style: normal;\n margin: 0;\n color: var(--md-sys-color-on-surface-variant);\n }\n button[place] {\n display: grid;\n gap: 2px;\n text-align: left;\n padding: 6px 8px;\n font: inherit;\n color: inherit;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 8px;\n background: none;\n cursor: pointer;\n }\n button[place][on] {\n border-color: var(--md-sys-color-primary);\n }\n code {\n font-size: var(--ui-t-small, 11.5px);\n color: var(--md-sys-color-on-surface-variant);\n }\n `]\n\n @property({ attribute: false }) asset?: FigureAsset\n /** The selected part, whose places are marked. */\n @property() selected = ''\n @property({ type: Boolean }) locked = false\n\n render() {\n const asset = this.asset\n if (!asset) return nothing\n const names = asset.document.capabilities.names ?? []\n const rung = rungOf(names)\n const places = figureBindingsOf(asset)\n return html`<section>\n <h3>${i18next.t('figure.label.what-this-does')}</h3>\n ${(['none', 'hold', 'flow'] as const).map(\n which => html`<label rung ?on=${rung === which}>\n <input type=\"radio\" name=\"rung\" .checked=${live(rung === which)} ?disabled=${this.locked} @change=${() => this.setRung(which)} />\n <span>\n <strong>${i18next.t(`figure.label.rung-${which}`)}</strong>\n <em>${i18next.t(`figure.text.rung-${which}-note`)}</em>\n </span>\n </label>`\n )}\n ${rung === null ? html`<p hint>${i18next.t('figure.text.capability-hand-written')}</p>` : nothing}\n ${names.length ? html`<code>${names.join(' · ')}</code>` : nothing}\n </section>\n <section>\n <h3>${i18next.t('figure.label.places')}</h3>\n ${places.length\n ? places.map(\n one => html`<button place ?on=${one.part === this.selected} @click=${() => one.part && this.pick(one.part)}>\n <strong>${one.label}</strong>\n <small>\n ${one.part ?? '?'}${one.face ? ' · ' + i18next.t('figure.label.face-' + one.face) : ''} ·\n ${placeTerms(one, (key, params) => i18next.t(key, params))}\n </small>\n </button>`\n )\n : html`<p hint>${i18next.t('figure.text.no-places')}</p>`}\n ${places.length && rung === 'none' ? html`<p hint>${i18next.t('figure.text.place-needs-holding')}</p>` : nothing}\n </section>\n <section>\n <h3>${i18next.t('figure.label.item')}</h3>\n <label item ?on=${!!asset.item}>\n <input type=\"checkbox\" .checked=${live(!!asset.item)} ?disabled=${this.locked} @change=${(e: Event) => this.setItem((e.target as HTMLInputElement).checked)} />\n <span>\n <strong>${i18next.t('figure.label.is-item')}</strong>\n <em>${i18next.t('figure.text.is-item-note')}</em>\n </span>\n </label>\n </section>\n `\n }\n\n private setRung(which: Rung) {\n this.dispatchEvent(new CustomEvent('part-edit', { detail: { edit: { kind: 'set-capabilities', names: [...RUNGS[which]] } }, bubbles: true, composed: true }))\n }\n\n private setItem(item: boolean) {\n this.dispatchEvent(new CustomEvent('command', { detail: { action: { kind: 'set-item', item } }, bubbles: true, composed: true }))\n }\n\n private pick(part: string) {\n this.dispatchEvent(new CustomEvent('select-part', { detail: { id: part }, bubbles: true, composed: true }))\n }\n}\n"]}
1
+ {"version":3,"file":"figure-capability-panel.js","sourceRoot":"","sources":["../../client/modeller/figure-capability-panel.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\nimport { live } from 'lit/directives/live.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { figureBindingsOf } from '@hatiolab/figure-model'\nimport type { FigureAsset } from '@hatiolab/figure-model'\nimport { RUNGS, rungOf, type Rung } from '@things-factory/figure-viewer/dist-client/capability-rung.js'\nimport { SidePanelStyles } from '@things-factory/figure-viewer/dist-client/side-panel-styles.js'\nimport { placeTerms } from '@things-factory/figure-viewer/dist-client/detail-facts.js'\nimport { onFigureCapabilitiesChanged, type FigureCapabilityDescriptor, type FigureCapabilitySetting } from '@hatiolab/things-scene'\n\nimport {\n consumerDescriptors,\n inputTableAt,\n namesWith,\n needsMissing,\n partsAt,\n settingsIssues,\n settingsOf,\n unknownConsumerNames,\n withInputTable,\n withParts\n} from './consumer-capabilities.js'\n\n/**\n * 자리·능력 — what the figure does on a board: the ladder from drawing only, to\n * holding things, to passing them on, and every place things are held, whatever part it is on. A place is not drawn,\n * so the list is the only way to find one; choosing a row selects its part, where the place is edited. Whether the\n * figure is the look of an item a holder carries is said here too (ADR-0155 amendment 2): a tag, apart from the ladder,\n * since an item may hold things as well.\n *\n * Below the ladder, the products' capabilities this modeller has descriptors for (ADR-0167 9, 12): each put on or off,\n * what it still needs, and its settings as its descriptor draws them -- parts picked (the part chosen here by one\n * button), an input and a value per fixed key, never a row added or taken away -- with what its check says.\n */\n@customElement('figure-capability-panel')\nexport class FigureCapabilityPanel extends localize(i18next)(LitElement) {\n static styles = [SidePanelStyles, css`\n :host {\n display: block;\n }\n label[rung],\n label[item] {\n display: flex;\n gap: 8px;\n align-items: flex-start;\n padding: 8px;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 8px;\n cursor: pointer;\n }\n /* The box keeps its size beside a long note: squeezed by the flex row it read as a dot (sweep 2026-10-27 U1). */\n label[rung] > input,\n label[item] > input {\n flex: none;\n margin: 2px 0 0;\n }\n label[rung][on],\n label[item][on] {\n border-color: var(--md-sys-color-primary);\n background: var(--md-sys-color-secondary-container);\n color: var(--md-sys-color-on-secondary-container);\n }\n label[rung] span,\n label[item] span {\n display: grid;\n gap: 2px;\n }\n label[rung] em,\n label[item] em,\n p[hint],\n small {\n font-style: normal;\n margin: 0;\n color: var(--md-sys-color-on-surface-variant);\n }\n button[place] {\n display: grid;\n gap: 2px;\n text-align: left;\n padding: 6px 8px;\n font: inherit;\n color: inherit;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 8px;\n background: none;\n cursor: pointer;\n }\n button[place][on] {\n border-color: var(--md-sys-color-primary);\n }\n code {\n font-size: var(--ui-t-small, 11.5px);\n color: var(--md-sys-color-on-surface-variant);\n }\n div[chips] {\n display: flex;\n flex-wrap: wrap;\n gap: 4px 10px;\n align-items: center;\n }\n div[chips] label {\n display: inline-flex;\n gap: 4px;\n align-items: center;\n }\n div[table] {\n display: grid;\n grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);\n gap: 4px 6px;\n align-items: center;\n }\n p[warn] {\n margin: 0;\n color: var(--md-sys-color-error);\n }\n `]\n\n private unlisten?: () => void\n\n connectedCallback() {\n super.connectedCallback()\n /* A product's descriptors may be registered after the panel stands. */\n this.unlisten = onFigureCapabilitiesChanged(() => this.requestUpdate())\n }\n\n disconnectedCallback() {\n super.disconnectedCallback()\n this.unlisten?.()\n }\n\n @property({ attribute: false }) asset?: FigureAsset\n /** The selected part, whose places are marked. */\n @property() selected = ''\n @property({ type: Boolean }) locked = false\n\n render() {\n const asset = this.asset\n if (!asset) return nothing\n const names = asset.document.capabilities.names ?? []\n const rung = rungOf(names)\n const places = figureBindingsOf(asset)\n return html`<section>\n <h3>${i18next.t('figure.label.what-this-does')}</h3>\n ${(['none', 'hold', 'flow'] as const).map(\n which => html`<label rung ?on=${rung === which}>\n <input type=\"radio\" name=\"rung\" .checked=${live(rung === which)} ?disabled=${this.locked} @change=${() => this.setRung(which)} />\n <span>\n <strong>${i18next.t(`figure.label.rung-${which}`)}</strong>\n <em>${i18next.t(`figure.text.rung-${which}-note`)}</em>\n </span>\n </label>`\n )}\n ${rung === null ? html`<p hint>${i18next.t('figure.text.capability-hand-written')}</p>` : nothing}\n ${names.length ? html`<code>${names.join(' · ')}</code>` : nothing}\n </section>\n ${this.renderConsumers(asset)}\n <section>\n <h3>${i18next.t('figure.label.places')}</h3>\n ${places.length\n ? places.map(\n one => html`<button place ?on=${one.part === this.selected} @click=${() => one.part && this.pick(one.part)}>\n <strong>${one.label}</strong>\n <small>\n ${one.part ?? '?'}${one.face ? ' · ' + i18next.t('figure.label.face-' + one.face) : ''} ·\n ${placeTerms(one, (key, params) => i18next.t(key, params))}\n </small>\n </button>`\n )\n : html`<p hint>${i18next.t('figure.text.no-places')}</p>`}\n ${places.length && rung === 'none' ? html`<p hint>${i18next.t('figure.text.place-needs-holding')}</p>` : nothing}\n </section>\n <section>\n <h3>${i18next.t('figure.label.item')}</h3>\n <label item ?on=${!!asset.item}>\n <input type=\"checkbox\" .checked=${live(!!asset.item)} ?disabled=${this.locked} @change=${(e: Event) => this.setItem((e.target as HTMLInputElement).checked)} />\n <span>\n <strong>${i18next.t('figure.label.is-item')}</strong>\n <em>${i18next.t('figure.text.is-item-note')}</em>\n </span>\n </label>\n </section>\n `\n }\n\n /** The products' capabilities: those this modeller knows, each on or off with its settings, and those it does not know. */\n private renderConsumers(asset: FigureAsset) {\n const known = consumerDescriptors()\n const unknown = unknownConsumerNames(asset)\n if (!known.length && !unknown.length) return nothing\n const names = asset.document.capabilities.names ?? []\n return html`<section>\n <h3>${i18next.t('figure.label.product-capabilities')}</h3>\n ${known.map(d => {\n const on = names.includes(d.name)\n const missing = needsMissing(d, asset)\n return html`<label rung ?on=${on}>\n <input type=\"checkbox\" .checked=${live(on)} ?disabled=${this.locked || (!on && missing.length > 0)} @change=${(e: Event) => this.setConsumer(asset, d.name, (e.target as HTMLInputElement).checked)} />\n <span>\n <strong>${d.label}</strong>\n <em>${d.note}</em>\n <code>${d.name} · ${d.version}</code>\n </span>\n </label>\n ${missing.length ? html`<p hint>${i18next.t('figure.text.product-capability-needs', { needs: missing.map(m => (m === 'item' ? i18next.t('figure.label.is-item') : m)).join(', ') })}</p>` : nothing}\n ${on ? this.renderSettings(asset, d) : nothing}`\n })}\n ${unknown.map(\n name => html`<p hint>\n ${i18next.t('figure.text.product-capability-unknown', { name })}\n <button quiet ?disabled=${this.locked} @click=${() => this.setConsumer(asset, name, false)}>${i18next.t('figure.button.product-capability-remove')}</button>\n </p>`\n )}\n </section>`\n }\n\n /** A capability's settings as its descriptor draws them, and what its check says of them. */\n private renderSettings(asset: FigureAsset, d: FigureCapabilityDescriptor) {\n const settings = settingsOf(asset, d.name)\n const write = (next: Record<string, unknown>) =>\n this.dispatchEvent(new CustomEvent('part-edit', { detail: { edit: { kind: 'set-capability-settings', name: d.name, settings: Object.keys(next).length ? next : null } }, bubbles: true, composed: true }))\n const parts = [...new Set(asset.appearance.map(a => a.target))]\n const inputs = asset.document.model.inputs.filter(i => i.role === 'state')\n const issues = settingsIssues(d, asset)\n return html`<div form>\n ${(d.settings ?? []).map((setting: FigureCapabilitySetting) => {\n if (setting.kind === 'parts') {\n const chosen = partsAt(settings, setting.key)\n const toggle = (part: string, on: boolean) => write(withParts(settings, setting.key, on ? [...chosen, part] : chosen.filter(p => p !== part)))\n return html`<span>${setting.label}</span>\n <div chips>\n ${parts.map(p => html`<label><input type=\"checkbox\" .checked=${live(chosen.includes(p))} ?disabled=${this.locked} @change=${(e: Event) => toggle(p, (e.target as HTMLInputElement).checked)} />${p}</label>`)}\n ${this.selected && parts.includes(this.selected) && !chosen.includes(this.selected)\n ? html`<button quiet ?disabled=${this.locked} @click=${() => toggle(this.selected, true)}>${i18next.t('figure.button.data-add-selected-part', { part: this.selected })}</button>`\n : nothing}\n </div>`\n }\n const table = inputTableAt(settings, setting)\n const input = inputs.find(i => i.id === table.input)\n return html`<span>${setting.label}</span>\n <select ?disabled=${this.locked} @change=${(e: Event) => write(withInputTable(settings, setting, (e.target as HTMLSelectElement).value || undefined, table.values))}>\n <option value=\"\" ?selected=${!table.input}>${i18next.t('figure.label.data-none')}</option>\n ${inputs.map(i => html`<option value=${i.id} ?selected=${i.id === table.input}>${asset.stateInputs?.[i.id]?.label ?? i.id}${i.unit ? ` (${i.unit} ${i.min ?? ''}~${i.max ?? ''})` : ''}</option>`)}\n </select>\n ${table.input\n ? html`<span></span>\n <div table>\n ${setting.keys.map(\n key => html`<span>${key}</span>\n <input\n type=\"number\"\n step=\"any\"\n min=${input?.min ?? ''}\n max=${input?.max ?? ''}\n .value=${String(table.values[key])}\n ?disabled=${this.locked}\n @change=${(e: Event) => {\n const n = (e.target as HTMLInputElement).valueAsNumber\n if (!Number.isFinite(n)) return this.requestUpdate()\n write(withInputTable(settings, setting, table.input, { ...table.values, [key]: n }))\n }}\n />`\n )}\n </div>`\n : nothing}`\n })}\n </div>\n ${issues.map(reason => html`<p warn>${reason}</p>`)}`\n }\n\n private setConsumer(asset: FigureAsset, name: string, on: boolean) {\n this.dispatchEvent(new CustomEvent('part-edit', { detail: { edit: { kind: 'set-capabilities', names: namesWith(asset, name, on) } }, bubbles: true, composed: true }))\n }\n\n private setRung(which: Rung) {\n /* The ladder sets the shared names; a product's capabilities stay as they are. */\n const consumers = (this.asset?.document.capabilities.names ?? []).filter(n => n.includes('.'))\n this.dispatchEvent(new CustomEvent('part-edit', { detail: { edit: { kind: 'set-capabilities', names: [...RUNGS[which], ...consumers] } }, bubbles: true, composed: true }))\n }\n\n private setItem(item: boolean) {\n this.dispatchEvent(new CustomEvent('command', { detail: { action: { kind: 'set-item', item } }, bubbles: true, composed: true }))\n }\n\n private pick(part: string) {\n this.dispatchEvent(new CustomEvent('select-part', { detail: { id: part }, bubbles: true, composed: true }))\n }\n}\n"]}
@@ -112,7 +112,7 @@ let FigureClips = class FigureClips extends localize(i18next)(LitElement) {
112
112
  <h3>${i18next.t('figure.label.clips')}${this.help.button('figure.text.clips-explained')}</h3>
113
113
  ${this.help.hint('figure.text.clips-explained')}
114
114
  ${clips.map(clip => this.renderClip(clip))}
115
- ${empty ? html `<p hint>${i18next.t('figure.text.no-controls')}</p>` : nothing}
115
+ ${empty ? html `<p hint>${i18next.t('figure.text.no-clips')}</p>` : nothing}
116
116
  </section>
117
117
  ${empty ? nothing : this.renderAdd(asset, clips)} ${this.renderGroups(asset)}
118
118
  `;
@@ -1 +1 @@
1
- {"version":3,"file":"figure-clips.js","sourceRoot":"","sources":["../../client/modeller/figure-clips.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\n\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport type { FigureAsset } from '@hatiolab/figure-model'\n\nimport { clipGroupsOf, clipsOf, freeGroupIdOf, groupEdit, poseAt, trackEdit, undrivenOf, withKey, withoutKey, type Clip, type ClipGroup, type ClipTrack } from './clips.js'\nimport { SidePanelStyles } from '@things-factory/figure-viewer/dist-client/side-panel-styles.js'\nimport { HelpToggles } from './help.js'\n\n/** A value as a person reads it: at most three decimals, the float's last digits (14.399999999999999) left out. */\nconst shown = (value: number) => value.toLocaleString(undefined, { maximumFractionDigits: 3 })\n\n/**\n * 클립 — controls played by keys over time. A clip is one clock; each track plays one\n * control. Scrubbing a clip shows its pose at that moment (one batch of input changes, not saved as the default); a key\n * is added at the scrubbed moment with the control's value there, so a pose is made with the controls' sliders and\n * then kept as a key. Every change is one part edit.\n *\n * Clips of one motion group play one at a time on the same controls -- idle, walk, run (ADR-0051 §3.2): only clips of\n * one group may play the same control, so a new clip is put in a group as it is made when it is to take one.\n */\n@customElement('figure-clips')\nexport class FigureClips extends localize(i18next)(LitElement) {\n private readonly help = new HelpToggles(this)\n static styles = [SidePanelStyles, css`\n :host {\n display: block;\n }\n section[clip] {\n display: grid;\n gap: 8px;\n padding: 8px;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 8px;\n }\n div[row] {\n display: grid;\n grid-template-columns: minmax(0, 1fr) 72px;\n gap: 6px;\n align-items: center;\n }\n div[track] {\n display: grid;\n gap: 4px;\n padding-top: 6px;\n border-top: 1px dashed var(--md-sys-color-outline-variant);\n }\n /*\n The track's name on its own line, then how it repeats and the button that removes it. A flex row let the shared\n full-width select and button squeeze the name to one letter a line (user, 2026-09-24).\n */\n div[track-head] {\n display: grid;\n grid-template-columns: minmax(0, 1fr) 30px;\n gap: 4px 6px;\n align-items: center;\n }\n div[track-head] strong {\n grid-column: 1 / -1;\n min-width: 0;\n overflow-wrap: anywhere;\n }\n div[track-head] button[act] {\n width: 30px;\n min-height: var(--figure-control-height);\n margin: 0;\n padding: 0;\n }\n div[keys] {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n }\n span[key] {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n padding: 0 2px 0 8px;\n border-radius: 999em;\n background: var(--md-sys-color-surface-container);\n font-variant-numeric: tabular-nums;\n }\n span[key] button {\n width: 22px;\n height: 22px;\n padding: 0;\n border: none;\n background: none;\n }\n md-icon {\n font-size: 16px;\n width: 16px;\n height: 16px;\n }\n `]\n\n @property({ attribute: false }) asset?: FigureAsset\n /** The values the editor holds now, by input id -- what a new key takes. */\n @property({ attribute: false }) values: Record<string, number> = {}\n @property({ type: Boolean }) locked = false\n\n /** Where each clip is scrubbed to, in seconds. */\n @state() private at: Record<string, number> = {}\n @state() private adding = { state: '', clip: '', name: '', duration: 2, group: '' }\n @state() private grouping = { clip: '', label: '' }\n\n render() {\n const asset = this.asset\n if (!asset) return nothing\n const clips = clipsOf(asset)\n /* Nothing to play yet: said inside the section it belongs to, with the section's own margins. */\n const empty = !clips.length && !undrivenOf(asset).length && !asset.motionGroups?.length\n return html`\n <section>\n <h3>${i18next.t('figure.label.clips')}${this.help.button('figure.text.clips-explained')}</h3>\n ${this.help.hint('figure.text.clips-explained')}\n ${clips.map(clip => this.renderClip(clip))}\n ${empty ? html`<p hint>${i18next.t('figure.text.no-controls')}</p>` : nothing}\n </section>\n ${empty ? nothing : this.renderAdd(asset, clips)} ${this.renderGroups(asset)}\n `\n }\n\n private renderClip(clip: Clip) {\n const at = Math.min(this.at[clip.name] ?? 0, clip.duration)\n const number = (e: Event) => (e.target as HTMLInputElement).valueAsNumber\n return html`<section clip>\n <div form>\n <span>${i18next.t('figure.label.clip-name')}</span>\n <input .value=${clip.name} ?disabled=${this.locked} @change=${(e: Event) => this.edit({ kind: 'set-clip', clip: clip.name, name: (e.target as HTMLInputElement).value })} />\n <span>${i18next.t('figure.label.clip-duration')}</span>\n <input type=\"number\" min=\"0.1\" step=\"any\" .value=${String(clip.duration)} ?disabled=${this.locked} @change=${(e: Event) => this.edit({ kind: 'set-clip', clip: clip.name, duration: number(e) })} />\n </div>\n <div row>\n <input\n type=\"range\"\n min=\"0\"\n max=${clip.duration}\n step=${clip.duration / 100}\n .value=${String(at)}\n ?disabled=${this.locked}\n aria-label=${i18next.t('figure.label.clip-time')}\n @input=${(e: Event) => this.scrub(clip, number(e), true)}\n @change=${(e: Event) => this.scrub(clip, number(e))}\n />\n <small>${at.toFixed(2)} s</small>\n </div>\n ${clip.tracks.map(track => this.renderTrack(clip, track, at))}\n </section>`\n }\n\n private renderTrack(clip: Clip, track: ClipTrack, at: number) {\n const current = this.values[track.state]\n return html`<div track>\n <div track-head>\n <strong>${track.label} <small>(${track.unit})</small></strong>\n <select\n aria-label=${i18next.t('figure.label.clip-loop')}\n ?disabled=${this.locked}\n @change=${(e: Event) => this.edit(trackEdit(clip, track, { loop: (e.target as HTMLSelectElement).value as 'wrap' | 'hold' }))}\n >\n <option value=\"wrap\" ?selected=${track.loop === 'wrap'}>${i18next.t('figure.label.clip-loop-wrap')}</option>\n <option value=\"hold\" ?selected=${track.loop === 'hold'}>${i18next.t('figure.label.clip-loop-hold')}</option>\n </select>\n <button act ?disabled=${this.locked} title=${i18next.t('figure.button.remove-track')} @click=${() => this.edit({ kind: 'remove-driver', state: track.state, clip: clip.name })}>\n <md-icon>close</md-icon>\n </button>\n </div>\n <div keys>\n ${track.keys.map(\n (key, i) => html`<span key\n >${key.seconds}s → ${shown(key.value)}\n <button\n ?disabled=${this.locked || !withoutKey(track.keys, i)}\n title=${i18next.t('figure.button.remove-key')}\n aria-label=${i18next.t('figure.button.remove-key')}\n @click=${() => this.edit(trackEdit(clip, track, { keys: withoutKey(track.keys, i)! }))}\n >\n <md-icon>close</md-icon>\n </button></span\n >`\n )}\n </div>\n <button\n act\n ?disabled=${this.locked || current === undefined}\n @click=${() => this.edit(trackEdit(clip, track, { keys: withKey(track.keys, { seconds: Math.round(at * 1000) / 1000, value: current! }) }))}\n >\n <md-icon>add</md-icon>${i18next.t('figure.button.add-key-here', { seconds: at.toFixed(2), value: current === undefined ? '' : shown(current) })}\n </button>\n </div>`\n }\n\n private renderAdd(asset: FigureAsset, clips: Clip[]) {\n const a = this.adding\n const joining = clips.find(c => c.name === a.clip)\n const { groups } = clipGroupsOf(asset)\n const group = joining ? undefined : groups.find(g => g.id === a.group)\n /* The controls this clip may take: not played by it yet, and by no clip outside its group. */\n const free = undrivenOf(asset, joining?.name ?? '', group?.id)\n const stateId = free.includes(a.state) ? a.state : free[0]\n const name = joining ? joining.name : a.name.trim()\n const input = asset.document.model.inputs.find(i => i.id === stateId)\n const duration = joining ? joining.duration : a.duration\n /* A new clip takes a name no clip has: the same name would rewrite that clip's track, not add one. */\n const taken = !joining && clips.some(c => c.name === name)\n const ready = !!name && !taken && duration > 0 && !!input\n return html`<section><h3>${i18next.t('figure.label.add-track')}</h3>\n <div form>\n <span>${i18next.t('figure.label.controls')}</span>\n <select ?disabled=${!free.length} @change=${(e: Event) => (this.adding = { ...a, state: (e.target as HTMLSelectElement).value })}>\n ${free.map(id => html`<option value=${id} ?selected=${id === stateId}>${asset.stateInputs?.[id]?.label ?? id}</option>`)}\n </select>\n <span>${i18next.t('figure.label.clip')}</span>\n <select @change=${(e: Event) => (this.adding = { ...a, clip: (e.target as HTMLSelectElement).value })}>\n <option value=\"\" ?selected=${!joining}>${i18next.t('figure.label.new-clip')}</option>\n ${clips.map(c => html`<option value=${c.name} ?selected=${c === joining}>${c.name}</option>`)}\n </select>\n ${joining || !groups.length\n ? nothing\n : html`<span>${i18next.t('figure.label.motion-group')}</span>\n <select @change=${(e: Event) => (this.adding = { ...a, group: (e.target as HTMLSelectElement).value })}>\n <option value=\"\" ?selected=${!group}>${i18next.t('figure.label.no-motion-group')}</option>\n ${groups.map(g => html`<option value=${g.id} ?selected=${g === group}>${g.label}</option>`)}\n </select>`}\n ${joining\n ? nothing\n : html`<span>${i18next.t('figure.label.clip-name')}</span>\n <input .value=${a.name} placeholder=\"cycle\" @input=${(e: Event) => (this.adding = { ...a, name: (e.target as HTMLInputElement).value })} />\n <span>${i18next.t('figure.label.clip-duration')}</span>\n <input type=\"number\" min=\"0.1\" step=\"any\" .value=${String(a.duration)} @change=${(e: Event) => (this.adding = { ...a, duration: (e.target as HTMLInputElement).valueAsNumber })} />`}\n </div>\n <button\n act\n ?disabled=${this.locked || !ready}\n @click=${() => {\n this.edit({\n kind: 'set-driver',\n state: stateId,\n clip: name,\n ...(joining ? {} : { duration }),\n ...(group ? { group: group.id } : {}),\n keys: [\n { seconds: 0, value: input!.min },\n { seconds: duration, value: input!.max }\n ]\n })\n /* The name was this clip's; the next new clip is named again. */\n this.adding = { ...a, name: '', state: '' }\n }}\n >\n <md-icon>add</md-icon>${i18next.t('figure.button.add-track')}\n </button></section>`\n }\n\n /**\n * The motion groups: a name, the clip that plays until another is chosen, how long a change of clip blends, and the\n * clips each holds. A group is made from a clip in none; a clip in none joins one here. Every change is one edit.\n */\n private renderGroups(asset: FigureAsset) {\n const { groups, free } = clipGroupsOf(asset)\n if (!groups.length && !free.length) return nothing\n const g = this.grouping\n const first = free.includes(g.clip) ? g.clip : free[0]\n return html`<section>\n <h3>${i18next.t('figure.label.motion-groups')}${this.help.button('figure.text.motion-groups-explained')}</h3>\n ${this.help.hint('figure.text.motion-groups-explained')}\n ${groups.map(group => this.renderGroup(group, free))}\n ${free.length\n ? html`<div form>\n <span>${i18next.t('figure.label.motion-group-name')}</span>\n <input .value=${g.label} placeholder=${i18next.t('figure.label.motion-group')} @input=${(e: Event) => (this.grouping = { ...g, label: (e.target as HTMLInputElement).value })} />\n <span>${i18next.t('figure.label.clip')}</span>\n <select @change=${(e: Event) => (this.grouping = { ...g, clip: (e.target as HTMLSelectElement).value })}>\n ${free.map(c => html`<option value=${c} ?selected=${c === first}>${c}</option>`)}\n </select>\n </div>\n <button\n act\n ?disabled=${this.locked || !first || !g.label.trim()}\n @click=${() => {\n this.edit({ kind: 'set-motion-group', group: { id: freeGroupIdOf(asset), label: g.label.trim(), clips: [first!], defaultClip: first!, transitionSeconds: 0.2 } })\n this.grouping = { clip: '', label: '' }\n }}\n >\n <md-icon>add</md-icon>${i18next.t('figure.button.add-motion-group')}\n </button>`\n : nothing}\n </section>`\n }\n\n private renderGroup(group: ClipGroup, free: string[]) {\n const value = (e: Event) => (e.target as HTMLInputElement | HTMLSelectElement).value\n return html`<section clip>\n <div track-head>\n <strong>${group.label}</strong>\n <button act ?disabled=${this.locked} title=${i18next.t('figure.button.remove-motion-group')} @click=${() => this.edit({ kind: 'remove-motion-group', id: group.id })}>\n <md-icon>close</md-icon>\n </button>\n </div>\n <div form>\n <span>${i18next.t('figure.label.motion-group-name')}</span>\n <input .value=${group.label} ?disabled=${this.locked} @change=${(e: Event) => value(e).trim() && this.edit(groupEdit(group, { label: value(e).trim() }))} />\n <span>${i18next.t('figure.label.motion-group-default')}</span>\n <select ?disabled=${this.locked} @change=${(e: Event) => this.edit(groupEdit(group, { defaultClip: value(e) }))}>\n ${group.clips.map(c => html`<option value=${c} ?selected=${c === group.defaultClip}>${c}</option>`)}\n </select>\n <span>${i18next.t('figure.label.motion-group-transition')}</span>\n <input\n type=\"number\"\n min=\"0\"\n step=\"any\"\n .value=${String(group.transitionSeconds)}\n ?disabled=${this.locked}\n @change=${(e: Event) => this.edit(groupEdit(group, { transitionSeconds: (e.target as HTMLInputElement).valueAsNumber }))}\n />\n </div>\n <div keys>\n ${group.clips.map(\n c => html`<span key\n >${c}\n <button\n ?disabled=${this.locked || group.clips.length < 2}\n title=${i18next.t('figure.button.remove-clip-from-group')}\n aria-label=${i18next.t('figure.button.remove-clip-from-group')}\n @click=${() => {\n const clips = group.clips.filter(x => x !== c)\n this.edit(groupEdit(group, { clips, defaultClip: group.defaultClip === c ? clips[0]! : group.defaultClip }))\n }}\n >\n <md-icon>close</md-icon>\n </button></span\n >`\n )}\n </div>\n ${free.length\n ? html`<select\n aria-label=${i18next.t('figure.button.add-clip-to-group')}\n ?disabled=${this.locked}\n @change=${(e: Event) => {\n const c = value(e)\n if (c) this.edit(groupEdit(group, { clips: [...group.clips, c] }))\n ;(e.target as HTMLSelectElement).value = ''\n }}\n >\n <option value=\"\" selected>${i18next.t('figure.button.add-clip-to-group')}</option>\n ${free.map(c => html`<option value=${c}>${c}</option>`)}\n </select>`\n : nothing}\n </section>`\n }\n\n /** Show the clip's pose at a moment: one batch of input changes, not saved as the default. */\n /** Show the clip's pose at a moment. While the bar is dragged the pose is live (drawn, not recorded); the release\n * applies it as one batch of input changes. */\n private scrub(clip: Clip, seconds: number, live = false) {\n if (!this.asset || !Number.isFinite(seconds)) return\n this.at = { ...this.at, [clip.name]: seconds }\n const changes = poseAt(this.asset, clip.name, seconds)\n if (!changes.length) return\n if (live) {\n const values = Object.fromEntries(changes.map(c => [c.input, c.value]))\n this.dispatchEvent(new CustomEvent('states-live', { detail: { values }, bubbles: true, composed: true }))\n return\n }\n this.dispatchEvent(new CustomEvent('states', { detail: { changes }, bubbles: true, composed: true }))\n }\n\n private edit(edit: unknown) {\n this.dispatchEvent(new CustomEvent('part-edit', { detail: { edit }, bubbles: true, composed: true }))\n }\n}\n"]}
1
+ {"version":3,"file":"figure-clips.js","sourceRoot":"","sources":["../../client/modeller/figure-clips.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\n\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport type { FigureAsset } from '@hatiolab/figure-model'\n\nimport { clipGroupsOf, clipsOf, freeGroupIdOf, groupEdit, poseAt, trackEdit, undrivenOf, withKey, withoutKey, type Clip, type ClipGroup, type ClipTrack } from './clips.js'\nimport { SidePanelStyles } from '@things-factory/figure-viewer/dist-client/side-panel-styles.js'\nimport { HelpToggles } from './help.js'\n\n/** A value as a person reads it: at most three decimals, the float's last digits (14.399999999999999) left out. */\nconst shown = (value: number) => value.toLocaleString(undefined, { maximumFractionDigits: 3 })\n\n/**\n * 클립 — controls played by keys over time. A clip is one clock; each track plays one\n * control. Scrubbing a clip shows its pose at that moment (one batch of input changes, not saved as the default); a key\n * is added at the scrubbed moment with the control's value there, so a pose is made with the controls' sliders and\n * then kept as a key. Every change is one part edit.\n *\n * Clips of one motion group play one at a time on the same controls -- idle, walk, run (ADR-0051 §3.2): only clips of\n * one group may play the same control, so a new clip is put in a group as it is made when it is to take one.\n */\n@customElement('figure-clips')\nexport class FigureClips extends localize(i18next)(LitElement) {\n private readonly help = new HelpToggles(this)\n static styles = [SidePanelStyles, css`\n :host {\n display: block;\n }\n section[clip] {\n display: grid;\n gap: 8px;\n padding: 8px;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 8px;\n }\n div[row] {\n display: grid;\n grid-template-columns: minmax(0, 1fr) 72px;\n gap: 6px;\n align-items: center;\n }\n div[track] {\n display: grid;\n gap: 4px;\n padding-top: 6px;\n border-top: 1px dashed var(--md-sys-color-outline-variant);\n }\n /*\n The track's name on its own line, then how it repeats and the button that removes it. A flex row let the shared\n full-width select and button squeeze the name to one letter a line (user, 2026-09-24).\n */\n div[track-head] {\n display: grid;\n grid-template-columns: minmax(0, 1fr) 30px;\n gap: 4px 6px;\n align-items: center;\n }\n div[track-head] strong {\n grid-column: 1 / -1;\n min-width: 0;\n overflow-wrap: anywhere;\n }\n div[track-head] button[act] {\n width: 30px;\n min-height: var(--figure-control-height);\n margin: 0;\n padding: 0;\n }\n div[keys] {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n }\n span[key] {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n padding: 0 2px 0 8px;\n border-radius: 999em;\n background: var(--md-sys-color-surface-container);\n font-variant-numeric: tabular-nums;\n }\n span[key] button {\n width: 22px;\n height: 22px;\n padding: 0;\n border: none;\n background: none;\n }\n md-icon {\n font-size: 16px;\n width: 16px;\n height: 16px;\n }\n `]\n\n @property({ attribute: false }) asset?: FigureAsset\n /** The values the editor holds now, by input id -- what a new key takes. */\n @property({ attribute: false }) values: Record<string, number> = {}\n @property({ type: Boolean }) locked = false\n\n /** Where each clip is scrubbed to, in seconds. */\n @state() private at: Record<string, number> = {}\n @state() private adding = { state: '', clip: '', name: '', duration: 2, group: '' }\n @state() private grouping = { clip: '', label: '' }\n\n render() {\n const asset = this.asset\n if (!asset) return nothing\n const clips = clipsOf(asset)\n /* Nothing to play yet: said inside the section it belongs to, with the section's own margins. */\n const empty = !clips.length && !undrivenOf(asset).length && !asset.motionGroups?.length\n return html`\n <section>\n <h3>${i18next.t('figure.label.clips')}${this.help.button('figure.text.clips-explained')}</h3>\n ${this.help.hint('figure.text.clips-explained')}\n ${clips.map(clip => this.renderClip(clip))}\n ${empty ? html`<p hint>${i18next.t('figure.text.no-clips')}</p>` : nothing}\n </section>\n ${empty ? nothing : this.renderAdd(asset, clips)} ${this.renderGroups(asset)}\n `\n }\n\n private renderClip(clip: Clip) {\n const at = Math.min(this.at[clip.name] ?? 0, clip.duration)\n const number = (e: Event) => (e.target as HTMLInputElement).valueAsNumber\n return html`<section clip>\n <div form>\n <span>${i18next.t('figure.label.clip-name')}</span>\n <input .value=${clip.name} ?disabled=${this.locked} @change=${(e: Event) => this.edit({ kind: 'set-clip', clip: clip.name, name: (e.target as HTMLInputElement).value })} />\n <span>${i18next.t('figure.label.clip-duration')}</span>\n <input type=\"number\" min=\"0.1\" step=\"any\" .value=${String(clip.duration)} ?disabled=${this.locked} @change=${(e: Event) => this.edit({ kind: 'set-clip', clip: clip.name, duration: number(e) })} />\n </div>\n <div row>\n <input\n type=\"range\"\n min=\"0\"\n max=${clip.duration}\n step=${clip.duration / 100}\n .value=${String(at)}\n ?disabled=${this.locked}\n aria-label=${i18next.t('figure.label.clip-time')}\n @input=${(e: Event) => this.scrub(clip, number(e), true)}\n @change=${(e: Event) => this.scrub(clip, number(e))}\n />\n <small>${at.toFixed(2)} s</small>\n </div>\n ${clip.tracks.map(track => this.renderTrack(clip, track, at))}\n </section>`\n }\n\n private renderTrack(clip: Clip, track: ClipTrack, at: number) {\n const current = this.values[track.state]\n return html`<div track>\n <div track-head>\n <strong>${track.label} <small>(${track.unit})</small></strong>\n <select\n aria-label=${i18next.t('figure.label.clip-loop')}\n ?disabled=${this.locked}\n @change=${(e: Event) => this.edit(trackEdit(clip, track, { loop: (e.target as HTMLSelectElement).value as 'wrap' | 'hold' }))}\n >\n <option value=\"wrap\" ?selected=${track.loop === 'wrap'}>${i18next.t('figure.label.clip-loop-wrap')}</option>\n <option value=\"hold\" ?selected=${track.loop === 'hold'}>${i18next.t('figure.label.clip-loop-hold')}</option>\n </select>\n <button act ?disabled=${this.locked} title=${i18next.t('figure.button.remove-track')} @click=${() => this.edit({ kind: 'remove-driver', state: track.state, clip: clip.name })}>\n <md-icon>close</md-icon>\n </button>\n </div>\n <div keys>\n ${track.keys.map(\n (key, i) => html`<span key\n >${key.seconds}s → ${shown(key.value)}\n <button\n ?disabled=${this.locked || !withoutKey(track.keys, i)}\n title=${i18next.t('figure.button.remove-key')}\n aria-label=${i18next.t('figure.button.remove-key')}\n @click=${() => this.edit(trackEdit(clip, track, { keys: withoutKey(track.keys, i)! }))}\n >\n <md-icon>close</md-icon>\n </button></span\n >`\n )}\n </div>\n <button\n act\n ?disabled=${this.locked || current === undefined}\n @click=${() => this.edit(trackEdit(clip, track, { keys: withKey(track.keys, { seconds: Math.round(at * 1000) / 1000, value: current! }) }))}\n >\n <md-icon>add</md-icon>${i18next.t('figure.button.add-key-here', { seconds: at.toFixed(2), value: current === undefined ? '' : shown(current) })}\n </button>\n </div>`\n }\n\n private renderAdd(asset: FigureAsset, clips: Clip[]) {\n const a = this.adding\n const joining = clips.find(c => c.name === a.clip)\n const { groups } = clipGroupsOf(asset)\n const group = joining ? undefined : groups.find(g => g.id === a.group)\n /* The controls this clip may take: not played by it yet, and by no clip outside its group. */\n const free = undrivenOf(asset, joining?.name ?? '', group?.id)\n const stateId = free.includes(a.state) ? a.state : free[0]\n const name = joining ? joining.name : a.name.trim()\n const input = asset.document.model.inputs.find(i => i.id === stateId)\n const duration = joining ? joining.duration : a.duration\n /* A new clip takes a name no clip has: the same name would rewrite that clip's track, not add one. */\n const taken = !joining && clips.some(c => c.name === name)\n const ready = !!name && !taken && duration > 0 && !!input\n return html`<section><h3>${i18next.t('figure.label.add-track')}</h3>\n <div form>\n <span>${i18next.t('figure.label.controls')}</span>\n <select ?disabled=${!free.length} @change=${(e: Event) => (this.adding = { ...a, state: (e.target as HTMLSelectElement).value })}>\n ${free.map(id => html`<option value=${id} ?selected=${id === stateId}>${asset.stateInputs?.[id]?.label ?? id}</option>`)}\n </select>\n <span>${i18next.t('figure.label.clip')}</span>\n <select @change=${(e: Event) => (this.adding = { ...a, clip: (e.target as HTMLSelectElement).value })}>\n <option value=\"\" ?selected=${!joining}>${i18next.t('figure.label.new-clip')}</option>\n ${clips.map(c => html`<option value=${c.name} ?selected=${c === joining}>${c.name}</option>`)}\n </select>\n ${joining || !groups.length\n ? nothing\n : html`<span>${i18next.t('figure.label.motion-group')}</span>\n <select @change=${(e: Event) => (this.adding = { ...a, group: (e.target as HTMLSelectElement).value })}>\n <option value=\"\" ?selected=${!group}>${i18next.t('figure.label.no-motion-group')}</option>\n ${groups.map(g => html`<option value=${g.id} ?selected=${g === group}>${g.label}</option>`)}\n </select>`}\n ${joining\n ? nothing\n : html`<span>${i18next.t('figure.label.clip-name')}</span>\n <input .value=${a.name} placeholder=\"cycle\" @input=${(e: Event) => (this.adding = { ...a, name: (e.target as HTMLInputElement).value })} />\n <span>${i18next.t('figure.label.clip-duration')}</span>\n <input type=\"number\" min=\"0.1\" step=\"any\" .value=${String(a.duration)} @change=${(e: Event) => (this.adding = { ...a, duration: (e.target as HTMLInputElement).valueAsNumber })} />`}\n </div>\n <button\n act\n ?disabled=${this.locked || !ready}\n @click=${() => {\n this.edit({\n kind: 'set-driver',\n state: stateId,\n clip: name,\n ...(joining ? {} : { duration }),\n ...(group ? { group: group.id } : {}),\n keys: [\n { seconds: 0, value: input!.min },\n { seconds: duration, value: input!.max }\n ]\n })\n /* The name was this clip's; the next new clip is named again. */\n this.adding = { ...a, name: '', state: '' }\n }}\n >\n <md-icon>add</md-icon>${i18next.t('figure.button.add-track')}\n </button></section>`\n }\n\n /**\n * The motion groups: a name, the clip that plays until another is chosen, how long a change of clip blends, and the\n * clips each holds. A group is made from a clip in none; a clip in none joins one here. Every change is one edit.\n */\n private renderGroups(asset: FigureAsset) {\n const { groups, free } = clipGroupsOf(asset)\n if (!groups.length && !free.length) return nothing\n const g = this.grouping\n const first = free.includes(g.clip) ? g.clip : free[0]\n return html`<section>\n <h3>${i18next.t('figure.label.motion-groups')}${this.help.button('figure.text.motion-groups-explained')}</h3>\n ${this.help.hint('figure.text.motion-groups-explained')}\n ${groups.map(group => this.renderGroup(group, free))}\n ${free.length\n ? html`<div form>\n <span>${i18next.t('figure.label.motion-group-name')}</span>\n <input .value=${g.label} placeholder=${i18next.t('figure.label.motion-group')} @input=${(e: Event) => (this.grouping = { ...g, label: (e.target as HTMLInputElement).value })} />\n <span>${i18next.t('figure.label.clip')}</span>\n <select @change=${(e: Event) => (this.grouping = { ...g, clip: (e.target as HTMLSelectElement).value })}>\n ${free.map(c => html`<option value=${c} ?selected=${c === first}>${c}</option>`)}\n </select>\n </div>\n <button\n act\n ?disabled=${this.locked || !first || !g.label.trim()}\n @click=${() => {\n this.edit({ kind: 'set-motion-group', group: { id: freeGroupIdOf(asset), label: g.label.trim(), clips: [first!], defaultClip: first!, transitionSeconds: 0.2 } })\n this.grouping = { clip: '', label: '' }\n }}\n >\n <md-icon>add</md-icon>${i18next.t('figure.button.add-motion-group')}\n </button>`\n : nothing}\n </section>`\n }\n\n private renderGroup(group: ClipGroup, free: string[]) {\n const value = (e: Event) => (e.target as HTMLInputElement | HTMLSelectElement).value\n return html`<section clip>\n <div track-head>\n <strong>${group.label}</strong>\n <button act ?disabled=${this.locked} title=${i18next.t('figure.button.remove-motion-group')} @click=${() => this.edit({ kind: 'remove-motion-group', id: group.id })}>\n <md-icon>close</md-icon>\n </button>\n </div>\n <div form>\n <span>${i18next.t('figure.label.motion-group-name')}</span>\n <input .value=${group.label} ?disabled=${this.locked} @change=${(e: Event) => value(e).trim() && this.edit(groupEdit(group, { label: value(e).trim() }))} />\n <span>${i18next.t('figure.label.motion-group-default')}</span>\n <select ?disabled=${this.locked} @change=${(e: Event) => this.edit(groupEdit(group, { defaultClip: value(e) }))}>\n ${group.clips.map(c => html`<option value=${c} ?selected=${c === group.defaultClip}>${c}</option>`)}\n </select>\n <span>${i18next.t('figure.label.motion-group-transition')}</span>\n <input\n type=\"number\"\n min=\"0\"\n step=\"any\"\n .value=${String(group.transitionSeconds)}\n ?disabled=${this.locked}\n @change=${(e: Event) => this.edit(groupEdit(group, { transitionSeconds: (e.target as HTMLInputElement).valueAsNumber }))}\n />\n </div>\n <div keys>\n ${group.clips.map(\n c => html`<span key\n >${c}\n <button\n ?disabled=${this.locked || group.clips.length < 2}\n title=${i18next.t('figure.button.remove-clip-from-group')}\n aria-label=${i18next.t('figure.button.remove-clip-from-group')}\n @click=${() => {\n const clips = group.clips.filter(x => x !== c)\n this.edit(groupEdit(group, { clips, defaultClip: group.defaultClip === c ? clips[0]! : group.defaultClip }))\n }}\n >\n <md-icon>close</md-icon>\n </button></span\n >`\n )}\n </div>\n ${free.length\n ? html`<select\n aria-label=${i18next.t('figure.button.add-clip-to-group')}\n ?disabled=${this.locked}\n @change=${(e: Event) => {\n const c = value(e)\n if (c) this.edit(groupEdit(group, { clips: [...group.clips, c] }))\n ;(e.target as HTMLSelectElement).value = ''\n }}\n >\n <option value=\"\" selected>${i18next.t('figure.button.add-clip-to-group')}</option>\n ${free.map(c => html`<option value=${c}>${c}</option>`)}\n </select>`\n : nothing}\n </section>`\n }\n\n /** Show the clip's pose at a moment: one batch of input changes, not saved as the default. */\n /** Show the clip's pose at a moment. While the bar is dragged the pose is live (drawn, not recorded); the release\n * applies it as one batch of input changes. */\n private scrub(clip: Clip, seconds: number, live = false) {\n if (!this.asset || !Number.isFinite(seconds)) return\n this.at = { ...this.at, [clip.name]: seconds }\n const changes = poseAt(this.asset, clip.name, seconds)\n if (!changes.length) return\n if (live) {\n const values = Object.fromEntries(changes.map(c => [c.input, c.value]))\n this.dispatchEvent(new CustomEvent('states-live', { detail: { values }, bubbles: true, composed: true }))\n return\n }\n this.dispatchEvent(new CustomEvent('states', { detail: { changes }, bubbles: true, composed: true }))\n }\n\n private edit(edit: unknown) {\n this.dispatchEvent(new CustomEvent('part-edit', { detail: { edit }, bubbles: true, composed: true }))\n }\n}\n"]}
@@ -5,33 +5,41 @@ declare const FigureDataPanel_base: (new (...args: any[]) => LitElement) & typeo
5
5
  /**
6
6
  * 데이터 -- the data a site sends this figure, in its own names, and what each value moves (ADR-0051 §8, data binding
7
7
  * design decision 4). The schema is free: fields the author names, a tree of objects and lists. A binding reads one place
8
- * of it and moves one thing the figure can do -- a control, a colour, a motion group's clip, speed or pause, a status
9
- * port, its position, the items in its places -- by the board's rules (value, map, range, scale). Every change is one
10
- * part edit, and whether it holds is the kernel's check.
8
+ * of it and shows it in the figure (ADR-0166): as it is or scaled, it moves one thing -- a control, a colour, a motion
9
+ * group's clip, speed or pause, its position, the items in its places; by a code table or a range table, each value's
10
+ * look goes to several targets at once -- parts' colour and effect, controls' values, a motion group. The field's kind
11
+ * says which methods there are. Every change is one part edit, and whether it holds is the kernel's check.
11
12
  *
12
13
  * The sample is not saved: data tried here, read the one way a placed figure reads it, and -- in the preview -- the figure
13
- * running on it (`data-sample`).
14
+ * running on it (`data-sample`); a sample legend pasted for a table's role shows it as a board's legend would
15
+ * (`legend-sample`).
14
16
  */
15
17
  export declare class FigureDataPanel extends FigureDataPanel_base {
16
18
  private readonly help;
17
19
  static styles: import("lit").CSSResult[];
18
20
  asset?: FigureAsset;
19
21
  locked: boolean;
22
+ /** The part chosen in the modeller, put among a table's parts by one button. */
23
+ selected: string;
20
24
  /** The schema row chosen, by its path; its field is edited under it. */
21
25
  private chosen;
22
26
  private adding;
23
27
  /** A site's data pasted to start the schema from; nothing is kept until the author says so. */
24
28
  private pasted;
29
+ /** A binding as it is being added: the field (or a new field's name), the method, the behavior or the table's targets. */
25
30
  private connecting;
26
31
  /** The binding opened to edit its rule, by id. */
27
32
  private opened;
28
- private porting;
33
+ /** Sample legends by role, as JSON typed; not saved. */
34
+ private legendSample;
29
35
  /** The rotation card as filled in: the joint, and the fields for on, speed (and its most rpm) and direction. */
30
36
  private rotating;
31
37
  /** The sample as typed, JSON; empty until edited, the schema's example shown until then. */
32
38
  private sample;
33
39
  private sampling;
34
40
  render(): import("lit-html").TemplateResult<1> | typeof nothing;
41
+ /** The data a product's capability the figure wears reads itself (ADR-0167 14): said, read only. */
42
+ private renderCapabilityData;
35
43
  private renderSchema;
36
44
  private kindWord;
37
45
  /** The chosen field's own settings, and a field added under it when it holds fields. */
@@ -40,26 +48,62 @@ export declare class FigureDataPanel extends FigureDataPanel_base {
40
48
  /** A site's data pasted: the schema guessed from it, kept only when the author says so -- units, ranges and closed values are theirs to set. */
41
49
  private renderFromSample;
42
50
  private behaviorName;
51
+ /** What a table shows on, as one line: its parts, the controls it sets, its motion group. */
52
+ private targetsName;
43
53
  private renderBindings;
44
54
  private renderBinding;
45
- private renderBindingDetail;
46
- /** A result editor fitting what the behavior takes: a colour, a clip of the group, true or false, a code, a number. */
47
- private renderResult;
48
- /** A result per value of a closed field, and one for every other value. */
49
- private renderCases;
50
- /** Intervals of a number, each from (inclusive) to (exclusive), either end left open, and one result for the rest. */
51
- private renderRanges;
55
+ /**
56
+ * A binding a product's capability takes over where the product registers it (ADR-0167 17): there it rests, whole or for
57
+ * the targets named; elsewhere (a board without the product) it works.
58
+ */
59
+ private renderResting;
60
+ private renderValueDetail;
61
+ /**
62
+ * A table (ADR-0166 10): what it shows on -- parts, controls, a motion group -- its rows, a code or an interval each
63
+ * with a cell per column, the look of every other value, and whether a board may swap it for a legend.
64
+ */
65
+ private renderTable;
66
+ /** Which parts, controls and motion group a table shows on: chips to tick, and the part chosen in the modeller by one button. */
67
+ private renderTargets;
68
+ /** The column heads of a table's rows, after the key's own one or two. */
69
+ private columnHeads;
70
+ /** One look's cells, a column each: a colour, an effect, a control's value, a clip, a speed, a pause -- empty leaves the target as it is. */
71
+ private lookCells;
72
+ /** The look of every other value: a row like the others, added or taken away; kept when a closed field's values are not all rows. */
73
+ private renderOtherwise;
74
+ /**
75
+ * A code table's rows: a code each, typed, with its look. A closed text's values follow the codes (ADR-0166 risk 3):
76
+ * a code added, renamed or taken away is the field's value too; true and false are both rows.
77
+ */
78
+ private renderCodeRows;
79
+ /**
80
+ * A range table's rows: from (inclusive) and to (exclusive), either end open, with a look each. Giving the last row,
81
+ * open above, an end starts the next row there; a row open above is the last there can be.
82
+ */
83
+ private renderRangeRows;
52
84
  /** Which field of each element is its id, its type, its place, its height in the stack, its status. */
53
85
  private renderItemFields;
86
+ /**
87
+ * 「연결 추가」 (ADR-0166 10): a field there or a new name, then a method the field's kind allows. As it is or scaled,
88
+ * the one thing it moves; a table, the parts, controls and motion group it shows on -- a new name makes the field.
89
+ */
54
90
  private renderAddBinding;
55
91
  /**
56
92
  * 「+ 회전」: a joint that turns without end, turned by the data -- on, speed in rpm, direction -- in one step. The
57
93
  * clips, the group and the bindings it writes are ordinary ones, edited one by one afterwards.
58
94
  */
59
95
  private renderRotation;
60
- private renderPorts;
61
96
  /** Data to try, read the way a placed figure reads it: what it moves, or why it is refused; in the preview, the figure running on it. */
62
97
  private renderSample;
98
+ /** Which row of a table the sample's value matched, and from which table: the figure's own or the sample legend of its role. */
99
+ private renderTableUse;
100
+ /** The sample legends as read: by role, those that are JSON. */
101
+ private sampleLegends;
102
+ /**
103
+ * A legend pasted for each table role, to see the figure as a board's legend of that role would show it -- not saved.
104
+ * The preview shows it too, as a scene's legend named as the role.
105
+ */
106
+ private renderSampleLegends;
63
107
  private try;
64
108
  /** The sample to the preview while it is asked for; null lets the preview's figure go back to its own values. */
65
109
  private tell;