@things-factory/figure-ui 10.1.222 → 10.1.224
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/modeller/canvas.ts +2 -2
- package/client/modeller/consumer-capabilities.ts +66 -0
- package/client/modeller/data-interface.ts +230 -80
- package/client/modeller/editor.ts +14 -7
- package/client/modeller/figure-capability-panel.ts +145 -1
- package/client/modeller/figure-data-panel.ts +495 -188
- package/client/modeller/figure-links.ts +130 -12
- package/client/modeller/figure-preview.ts +19 -2
- package/client/modeller/figure-slot-layout-panel.ts +7 -3
- package/client/modeller/links.ts +58 -0
- package/client/modeller/refusals.ts +12 -4
- package/client/modeller/slot-layout-host.ts +76 -5
- package/dist-client/modeller/canvas.js +2 -2
- package/dist-client/modeller/canvas.js.map +1 -1
- package/dist-client/modeller/consumer-capabilities.d.ts +29 -0
- package/dist-client/modeller/consumer-capabilities.js +60 -0
- package/dist-client/modeller/consumer-capabilities.js.map +1 -0
- package/dist-client/modeller/data-interface.d.ts +83 -17
- package/dist-client/modeller/data-interface.js +194 -82
- package/dist-client/modeller/data-interface.js.map +1 -1
- package/dist-client/modeller/editor.d.ts +5 -2
- package/dist-client/modeller/editor.js +16 -5
- package/dist-client/modeller/editor.js.map +1 -1
- package/dist-client/modeller/figure-capability-panel.d.ts +12 -0
- package/dist-client/modeller/figure-capability-panel.js +123 -1
- package/dist-client/modeller/figure-capability-panel.js.map +1 -1
- package/dist-client/modeller/figure-data-panel.d.ts +57 -13
- package/dist-client/modeller/figure-data-panel.js +461 -180
- package/dist-client/modeller/figure-data-panel.js.map +1 -1
- package/dist-client/modeller/figure-links.d.ts +11 -0
- package/dist-client/modeller/figure-links.js +137 -16
- package/dist-client/modeller/figure-links.js.map +1 -1
- package/dist-client/modeller/figure-preview.d.ts +4 -0
- package/dist-client/modeller/figure-preview.js +19 -1
- package/dist-client/modeller/figure-preview.js.map +1 -1
- package/dist-client/modeller/figure-slot-layout-panel.js +6 -4
- package/dist-client/modeller/figure-slot-layout-panel.js.map +1 -1
- package/dist-client/modeller/links.d.ts +22 -0
- package/dist-client/modeller/links.js +48 -0
- package/dist-client/modeller/links.js.map +1 -1
- package/dist-client/modeller/refusals.js +14 -6
- package/dist-client/modeller/refusals.js.map +1 -1
- package/dist-client/modeller/slot-layout-host.d.ts +28 -3
- package/dist-client/modeller/slot-layout-host.js +68 -6
- package/dist-client/modeller/slot-layout-host.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/package.json +9 -9
- package/test/browser/data-table-page.js +9 -0
- package/test/browser/links.check.mjs +25 -3
- package/test/consumer-capabilities.test.ts +116 -0
- package/test/data-motion.test.ts +94 -27
- package/test/links.test.ts +15 -0
- package/test/slot-layout-host.test.ts +63 -5
- package/translations/en.json +81 -23
- package/translations/es.json +81 -23
- package/translations/ja.json +81 -23
- package/translations/ko.json +81 -23
- package/translations/ms.json +81 -23
- package/translations/zh.json +81 -23
|
@@ -8,6 +8,20 @@ import type { FigureAsset } from '@hatiolab/figure-model'
|
|
|
8
8
|
import { RUNGS, rungOf, type Rung } from '@things-factory/figure-viewer/dist-client/capability-rung.js'
|
|
9
9
|
import { SidePanelStyles } from '@things-factory/figure-viewer/dist-client/side-panel-styles.js'
|
|
10
10
|
import { placeTerms } from '@things-factory/figure-viewer/dist-client/detail-facts.js'
|
|
11
|
+
import { onFigureCapabilitiesChanged, type FigureCapabilityDescriptor, type FigureCapabilitySetting } from '@hatiolab/things-scene'
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
consumerDescriptors,
|
|
15
|
+
inputTableAt,
|
|
16
|
+
namesWith,
|
|
17
|
+
needsMissing,
|
|
18
|
+
partsAt,
|
|
19
|
+
settingsIssues,
|
|
20
|
+
settingsOf,
|
|
21
|
+
unknownConsumerNames,
|
|
22
|
+
withInputTable,
|
|
23
|
+
withParts
|
|
24
|
+
} from './consumer-capabilities.js'
|
|
11
25
|
|
|
12
26
|
/**
|
|
13
27
|
* 자리·능력 — what the figure does on a board: the ladder from drawing only, to
|
|
@@ -15,6 +29,10 @@ import { placeTerms } from '@things-factory/figure-viewer/dist-client/detail-fac
|
|
|
15
29
|
* so the list is the only way to find one; choosing a row selects its part, where the place is edited. Whether the
|
|
16
30
|
* figure is the look of an item a holder carries is said here too (ADR-0155 amendment 2): a tag, apart from the ladder,
|
|
17
31
|
* since an item may hold things as well.
|
|
32
|
+
*
|
|
33
|
+
* Below the ladder, the products' capabilities this modeller has descriptors for (ADR-0167 9, 12): each put on or off,
|
|
34
|
+
* what it still needs, and its settings as its descriptor draws them -- parts picked (the part chosen here by one
|
|
35
|
+
* button), an input and a value per fixed key, never a row added or taken away -- with what its check says.
|
|
18
36
|
*/
|
|
19
37
|
@customElement('figure-capability-panel')
|
|
20
38
|
export class FigureCapabilityPanel extends localize(i18next)(LitElement) {
|
|
@@ -70,8 +88,42 @@ export class FigureCapabilityPanel extends localize(i18next)(LitElement) {
|
|
|
70
88
|
font-size: var(--ui-t-small, 11.5px);
|
|
71
89
|
color: var(--md-sys-color-on-surface-variant);
|
|
72
90
|
}
|
|
91
|
+
div[chips] {
|
|
92
|
+
display: flex;
|
|
93
|
+
flex-wrap: wrap;
|
|
94
|
+
gap: 4px 10px;
|
|
95
|
+
align-items: center;
|
|
96
|
+
}
|
|
97
|
+
div[chips] label {
|
|
98
|
+
display: inline-flex;
|
|
99
|
+
gap: 4px;
|
|
100
|
+
align-items: center;
|
|
101
|
+
}
|
|
102
|
+
div[table] {
|
|
103
|
+
display: grid;
|
|
104
|
+
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
|
105
|
+
gap: 4px 6px;
|
|
106
|
+
align-items: center;
|
|
107
|
+
}
|
|
108
|
+
p[warn] {
|
|
109
|
+
margin: 0;
|
|
110
|
+
color: var(--md-sys-color-error);
|
|
111
|
+
}
|
|
73
112
|
`]
|
|
74
113
|
|
|
114
|
+
private unlisten?: () => void
|
|
115
|
+
|
|
116
|
+
connectedCallback() {
|
|
117
|
+
super.connectedCallback()
|
|
118
|
+
/* A product's descriptors may be registered after the panel stands. */
|
|
119
|
+
this.unlisten = onFigureCapabilitiesChanged(() => this.requestUpdate())
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
disconnectedCallback() {
|
|
123
|
+
super.disconnectedCallback()
|
|
124
|
+
this.unlisten?.()
|
|
125
|
+
}
|
|
126
|
+
|
|
75
127
|
@property({ attribute: false }) asset?: FigureAsset
|
|
76
128
|
/** The selected part, whose places are marked. */
|
|
77
129
|
@property() selected = ''
|
|
@@ -97,6 +149,7 @@ export class FigureCapabilityPanel extends localize(i18next)(LitElement) {
|
|
|
97
149
|
${rung === null ? html`<p hint>${i18next.t('figure.text.capability-hand-written')}</p>` : nothing}
|
|
98
150
|
${names.length ? html`<code>${names.join(' · ')}</code>` : nothing}
|
|
99
151
|
</section>
|
|
152
|
+
${this.renderConsumers(asset)}
|
|
100
153
|
<section>
|
|
101
154
|
<h3>${i18next.t('figure.label.places')}</h3>
|
|
102
155
|
${places.length
|
|
@@ -125,8 +178,99 @@ export class FigureCapabilityPanel extends localize(i18next)(LitElement) {
|
|
|
125
178
|
`
|
|
126
179
|
}
|
|
127
180
|
|
|
181
|
+
/** The products' capabilities: those this modeller knows, each on or off with its settings, and those it does not know. */
|
|
182
|
+
private renderConsumers(asset: FigureAsset) {
|
|
183
|
+
const known = consumerDescriptors()
|
|
184
|
+
const unknown = unknownConsumerNames(asset)
|
|
185
|
+
if (!known.length && !unknown.length) return nothing
|
|
186
|
+
const names = asset.document.capabilities.names ?? []
|
|
187
|
+
return html`<section>
|
|
188
|
+
<h3>${i18next.t('figure.label.product-capabilities')}</h3>
|
|
189
|
+
${known.map(d => {
|
|
190
|
+
const on = names.includes(d.name)
|
|
191
|
+
const missing = needsMissing(d, asset)
|
|
192
|
+
return html`<label rung ?on=${on}>
|
|
193
|
+
<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)} />
|
|
194
|
+
<span>
|
|
195
|
+
<strong>${d.label}</strong>
|
|
196
|
+
<em>${d.note}</em>
|
|
197
|
+
<code>${d.name} · ${d.version}</code>
|
|
198
|
+
</span>
|
|
199
|
+
</label>
|
|
200
|
+
${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}
|
|
201
|
+
${on ? this.renderSettings(asset, d) : nothing}`
|
|
202
|
+
})}
|
|
203
|
+
${unknown.map(
|
|
204
|
+
name => html`<p hint>
|
|
205
|
+
${i18next.t('figure.text.product-capability-unknown', { name })}
|
|
206
|
+
<button quiet ?disabled=${this.locked} @click=${() => this.setConsumer(asset, name, false)}>${i18next.t('figure.button.product-capability-remove')}</button>
|
|
207
|
+
</p>`
|
|
208
|
+
)}
|
|
209
|
+
</section>`
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/** A capability's settings as its descriptor draws them, and what its check says of them. */
|
|
213
|
+
private renderSettings(asset: FigureAsset, d: FigureCapabilityDescriptor) {
|
|
214
|
+
const settings = settingsOf(asset, d.name)
|
|
215
|
+
const write = (next: Record<string, unknown>) =>
|
|
216
|
+
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 }))
|
|
217
|
+
const parts = [...new Set(asset.appearance.map(a => a.target))]
|
|
218
|
+
const inputs = asset.document.model.inputs.filter(i => i.role === 'state')
|
|
219
|
+
const issues = settingsIssues(d, asset)
|
|
220
|
+
return html`<div form>
|
|
221
|
+
${(d.settings ?? []).map((setting: FigureCapabilitySetting) => {
|
|
222
|
+
if (setting.kind === 'parts') {
|
|
223
|
+
const chosen = partsAt(settings, setting.key)
|
|
224
|
+
const toggle = (part: string, on: boolean) => write(withParts(settings, setting.key, on ? [...chosen, part] : chosen.filter(p => p !== part)))
|
|
225
|
+
return html`<span>${setting.label}</span>
|
|
226
|
+
<div chips>
|
|
227
|
+
${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>`)}
|
|
228
|
+
${this.selected && parts.includes(this.selected) && !chosen.includes(this.selected)
|
|
229
|
+
? html`<button quiet ?disabled=${this.locked} @click=${() => toggle(this.selected, true)}>${i18next.t('figure.button.data-add-selected-part', { part: this.selected })}</button>`
|
|
230
|
+
: nothing}
|
|
231
|
+
</div>`
|
|
232
|
+
}
|
|
233
|
+
const table = inputTableAt(settings, setting)
|
|
234
|
+
const input = inputs.find(i => i.id === table.input)
|
|
235
|
+
return html`<span>${setting.label}</span>
|
|
236
|
+
<select ?disabled=${this.locked} @change=${(e: Event) => write(withInputTable(settings, setting, (e.target as HTMLSelectElement).value || undefined, table.values))}>
|
|
237
|
+
<option value="" ?selected=${!table.input}>${i18next.t('figure.label.data-none')}</option>
|
|
238
|
+
${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>`)}
|
|
239
|
+
</select>
|
|
240
|
+
${table.input
|
|
241
|
+
? html`<span></span>
|
|
242
|
+
<div table>
|
|
243
|
+
${setting.keys.map(
|
|
244
|
+
key => html`<span>${key}</span>
|
|
245
|
+
<input
|
|
246
|
+
type="number"
|
|
247
|
+
step="any"
|
|
248
|
+
min=${input?.min ?? ''}
|
|
249
|
+
max=${input?.max ?? ''}
|
|
250
|
+
.value=${String(table.values[key])}
|
|
251
|
+
?disabled=${this.locked}
|
|
252
|
+
@change=${(e: Event) => {
|
|
253
|
+
const n = (e.target as HTMLInputElement).valueAsNumber
|
|
254
|
+
if (!Number.isFinite(n)) return this.requestUpdate()
|
|
255
|
+
write(withInputTable(settings, setting, table.input, { ...table.values, [key]: n }))
|
|
256
|
+
}}
|
|
257
|
+
/>`
|
|
258
|
+
)}
|
|
259
|
+
</div>`
|
|
260
|
+
: nothing}`
|
|
261
|
+
})}
|
|
262
|
+
</div>
|
|
263
|
+
${issues.map(reason => html`<p warn>${reason}</p>`)}`
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
private setConsumer(asset: FigureAsset, name: string, on: boolean) {
|
|
267
|
+
this.dispatchEvent(new CustomEvent('part-edit', { detail: { edit: { kind: 'set-capabilities', names: namesWith(asset, name, on) } }, bubbles: true, composed: true }))
|
|
268
|
+
}
|
|
269
|
+
|
|
128
270
|
private setRung(which: Rung) {
|
|
129
|
-
|
|
271
|
+
/* The ladder sets the shared names; a product's capabilities stay as they are. */
|
|
272
|
+
const consumers = (this.asset?.document.capabilities.names ?? []).filter(n => n.includes('.'))
|
|
273
|
+
this.dispatchEvent(new CustomEvent('part-edit', { detail: { edit: { kind: 'set-capabilities', names: [...RUNGS[which], ...consumers] } }, bubbles: true, composed: true }))
|
|
130
274
|
}
|
|
131
275
|
|
|
132
276
|
private setItem(item: boolean) {
|