@things-factory/figure-library 10.1.218 → 10.1.222

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 (57) hide show
  1. package/dist-client/bootstrap.d.ts +5 -3
  2. package/dist-client/bootstrap.js +6 -3
  3. package/dist-client/bootstrap.js.map +1 -1
  4. package/dist-client/editors/ox-property-editor-figure-status.d.ts +41 -0
  5. package/dist-client/editors/ox-property-editor-figure-status.js +290 -0
  6. package/dist-client/editors/ox-property-editor-figure-status.js.map +1 -0
  7. package/dist-client/figure-palette-group.d.ts +9 -4
  8. package/dist-client/figure-palette-group.js +2 -1
  9. package/dist-client/figure-palette-group.js.map +1 -1
  10. package/dist-client/figure-palette.js +2 -1
  11. package/dist-client/figure-palette.js.map +1 -1
  12. package/dist-client/item-types/item-types-rows.d.ts +8 -0
  13. package/dist-client/item-types/item-types-rows.js +11 -0
  14. package/dist-client/item-types/item-types-rows.js.map +1 -1
  15. package/dist-client/item-types/ox-item-types-input.d.ts +5 -1
  16. package/dist-client/item-types/ox-item-types-input.js +144 -112
  17. package/dist-client/item-types/ox-item-types-input.js.map +1 -1
  18. package/dist-client/pages/figure-library-page.js +0 -1
  19. package/dist-client/pages/figure-library-page.js.map +1 -1
  20. package/dist-client/status-looks/ox-figure-status-looks.d.ts +58 -0
  21. package/dist-client/status-looks/ox-figure-status-looks.js +489 -0
  22. package/dist-client/status-looks/ox-figure-status-looks.js.map +1 -0
  23. package/dist-client/status-looks/status-looks.d.ts +99 -0
  24. package/dist-client/status-looks/status-looks.js +134 -0
  25. package/dist-client/status-looks/status-looks.js.map +1 -0
  26. package/dist-client/tsconfig.tsbuildinfo +1 -1
  27. package/dist-client/viewparts/figure-releases-popup.d.ts +1 -4
  28. package/dist-client/viewparts/figure-releases-popup.js +3 -21
  29. package/dist-client/viewparts/figure-releases-popup.js.map +1 -1
  30. package/dist-server/service/figure-library-release/figure-library-release.d.ts +3 -1
  31. package/dist-server/service/figure-library-release/figure-library-release.js +11 -1
  32. package/dist-server/service/figure-library-release/figure-library-release.js.map +1 -1
  33. package/dist-server/service/figure-library-resolver.d.ts +0 -1
  34. package/dist-server/service/figure-library-resolver.js +0 -15
  35. package/dist-server/service/figure-library-resolver.js.map +1 -1
  36. package/dist-server/service/figure-library-types.js +1 -1
  37. package/dist-server/service/figure-library-types.js.map +1 -1
  38. package/dist-server/service/figure-type-map/figure-type-map-entry.d.ts +0 -1
  39. package/dist-server/service/figure-type-map/figure-type-map-entry.js +1 -12
  40. package/dist-server/service/figure-type-map/figure-type-map-entry.js.map +1 -1
  41. package/dist-server/service/library/derived.d.ts +6 -2
  42. package/dist-server/service/library/derived.js +4 -2
  43. package/dist-server/service/library/derived.js.map +1 -1
  44. package/dist-server/service/library/figures.d.ts +2 -2
  45. package/dist-server/service/library/figures.js +2 -2
  46. package/dist-server/service/library/figures.js.map +1 -1
  47. package/dist-server/service/library/type-map.d.ts +0 -5
  48. package/dist-server/service/library/type-map.js +0 -14
  49. package/dist-server/service/library/type-map.js.map +1 -1
  50. package/dist-server/tsconfig.tsbuildinfo +1 -1
  51. package/package.json +5 -5
  52. package/translations/en.json +49 -5
  53. package/translations/es.json +49 -5
  54. package/translations/ja.json +49 -5
  55. package/translations/ko.json +49 -5
  56. package/translations/ms.json +49 -5
  57. package/translations/zh.json +49 -5
@@ -0,0 +1,489 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ import { css, html, LitElement, nothing } from 'lit';
3
+ import { customElement, property, state } from 'lit/decorators.js';
4
+ import { i18next } from '@operato/i18n';
5
+ import { inputsGivenIn, withCode, withLook, withLookValue, withoutCode } from './status-looks.js';
6
+ const DEFAULT = 'default';
7
+ /**
8
+ * A status template's looks, one card per code (ADR-0051 2.3): its colour, its effect, a value for each state input a
9
+ * figure's port offers -- with the input's name, unit and range -- and the clip of the port's motion group. The code the
10
+ * data gives now is marked; a part the figure did not take is said under the card, by the field that gave it. Every
11
+ * change sends `looks-change` with the whole looks; the host writes them where the template lives.
12
+ *
13
+ * A value outside its input's range is not taken from the field (as the property panel's number maps); a value written
14
+ * elsewhere that the figure refused shows with the reason, to be fixed here. Values for inputs not shown -- another
15
+ * figure's, in a table shared by many -- are kept as they are.
16
+ *
17
+ * Shared by the board's 「상태 표현」 section and fmsim's legend editor, which shows colour and values only.
18
+ */
19
+ let OxFigureStatusLooks = class OxFigureStatusLooks extends LitElement {
20
+ constructor() {
21
+ super(...arguments);
22
+ this.looks = {};
23
+ /** The state inputs shown, one field each: the figure's offered inputs, or those a legend gives values to. */
24
+ this.inputs = [];
25
+ /** Inputs that can be added as a field (a legend's editor: the inputs the carrier figures offer). */
26
+ this.addable = [];
27
+ /**
28
+ * Whether every input a look gives a value to has a field, offered or not: a legend, which no one figure reads. A
29
+ * figure's own section leaves the values of inputs it does not offer to the figures that do.
30
+ */
31
+ this.showGiven = false;
32
+ /** The clips a look may choose; none, no clip field. */
33
+ this.clips = [];
34
+ this.effects = false;
35
+ /** Whether a look may give no colour (a board's template); a legend's entry always has one. */
36
+ this.colorOptional = false;
37
+ /** The rows the data gives now, with the ports that read them. */
38
+ this.now = {};
39
+ /** What the figure did not take, by row. */
40
+ this.issues = new Map();
41
+ this.disabled = false;
42
+ this.added = [];
43
+ this.newCode = '';
44
+ }
45
+ static { this.styles = css `
46
+ :host {
47
+ display: grid;
48
+ gap: 6px;
49
+ font: var(--property-editor-field-font, 0.76rem var(--theme-font, Roboto, sans-serif));
50
+ color: var(--md-sys-color-on-surface);
51
+ }
52
+
53
+ [cards] {
54
+ display: grid;
55
+ grid-template-columns: repeat(auto-fill, minmax(var(--status-looks-card-min, 220px), 1fr));
56
+ gap: 6px;
57
+ }
58
+
59
+ section {
60
+ display: grid;
61
+ gap: 3px;
62
+ padding: 4px 6px 6px;
63
+ border: 1px solid var(--md-sys-color-outline-variant);
64
+ border-radius: 6px;
65
+ }
66
+
67
+ section[now] {
68
+ border-color: var(--md-sys-color-primary);
69
+ }
70
+
71
+ section[refused] {
72
+ border-color: var(--md-sys-color-error);
73
+ }
74
+
75
+ header {
76
+ display: flex;
77
+ align-items: center;
78
+ gap: 6px;
79
+ min-height: 24px;
80
+ }
81
+
82
+ header b {
83
+ font-weight: 600;
84
+ overflow: hidden;
85
+ text-overflow: ellipsis;
86
+ white-space: nowrap;
87
+ }
88
+
89
+ [now-tag] {
90
+ padding: 0 4px;
91
+ border-radius: 4px;
92
+ background: var(--md-sys-color-primary-container);
93
+ color: var(--md-sys-color-on-primary-container);
94
+ font-size: 0.68rem;
95
+ white-space: nowrap;
96
+ }
97
+
98
+ header [end] {
99
+ margin-left: auto;
100
+ display: flex;
101
+ gap: 2px;
102
+ }
103
+
104
+ input[type='color'] {
105
+ flex: none;
106
+ width: 22px;
107
+ height: 18px;
108
+ padding: 0;
109
+ border: 1px solid var(--md-sys-color-outline-variant);
110
+ border-radius: 4px;
111
+ background: none;
112
+ cursor: pointer;
113
+ }
114
+
115
+ input[type='color']::-webkit-color-swatch-wrapper {
116
+ padding: 1px;
117
+ }
118
+
119
+ input[type='color']::-webkit-color-swatch {
120
+ border: none;
121
+ border-radius: 3px;
122
+ }
123
+
124
+ /*
125
+ * No colour given: the swatch is an empty dashed box until one is picked. A colour the field cannot show, it shows
126
+ * black, as the browser does; the figure's refusal says why.
127
+ */
128
+ input[type='color'][unset] {
129
+ border-style: dashed;
130
+ opacity: 0.6;
131
+ }
132
+
133
+ input[type='color'][unset]::-webkit-color-swatch {
134
+ background: transparent !important;
135
+ }
136
+
137
+ [fields] {
138
+ display: grid;
139
+ grid-template-columns: minmax(0, 1fr) minmax(56px, 72px) minmax(0, auto);
140
+ gap: 3px 6px;
141
+ align-items: center;
142
+ }
143
+
144
+ [fields] > [name] {
145
+ color: var(--md-sys-color-on-surface-variant);
146
+ overflow: hidden;
147
+ text-overflow: ellipsis;
148
+ white-space: nowrap;
149
+ }
150
+
151
+ [fields] > [unit] {
152
+ color: var(--md-sys-color-outline);
153
+ font-size: 0.68rem;
154
+ white-space: nowrap;
155
+ }
156
+
157
+ input:not([type='color']),
158
+ select {
159
+ box-sizing: border-box;
160
+ width: 100%;
161
+ min-width: 0;
162
+ height: var(--property-editor-field-height, 24px);
163
+ padding: 0 4px;
164
+ font: inherit;
165
+ color: inherit;
166
+ border: var(--property-editor-border, 1px solid var(--md-sys-color-outline-variant));
167
+ border-radius: var(--property-editor-border-radius, 6px);
168
+ background: var(--property-editor-background, var(--md-sys-color-surface-container-high));
169
+ }
170
+
171
+ input[type='number'] {
172
+ text-align: right;
173
+ font-variant-numeric: tabular-nums;
174
+ }
175
+
176
+ input:hover,
177
+ select:hover {
178
+ border-color: var(--property-editor-border-color-hover, var(--md-sys-color-outline-variant));
179
+ }
180
+
181
+ input:focus,
182
+ select:focus {
183
+ outline: none;
184
+ border-color: var(--property-editor-border-color-focus, var(--md-sys-color-primary));
185
+ }
186
+
187
+ [aria-invalid='true'] {
188
+ border-color: var(--md-sys-color-error) !important;
189
+ }
190
+
191
+ /* The effect's choice takes the field and the unit columns; a blink's rate takes the field after it. */
192
+ [fields] > select[wide] {
193
+ grid-column: 2 / -1;
194
+ }
195
+
196
+ [issue] {
197
+ margin: 0;
198
+ color: var(--md-sys-color-error);
199
+ font-size: 0.7rem;
200
+ }
201
+
202
+ button {
203
+ height: 24px;
204
+ padding: 0 8px;
205
+ font: inherit;
206
+ color: var(--md-sys-color-primary);
207
+ border: none;
208
+ border-radius: 6px;
209
+ background: transparent;
210
+ cursor: pointer;
211
+ white-space: nowrap;
212
+ }
213
+
214
+ button:hover {
215
+ background: var(--md-sys-color-surface-container-high);
216
+ }
217
+
218
+ button[icon] {
219
+ width: 22px;
220
+ padding: 0;
221
+ color: var(--md-sys-color-on-surface-variant);
222
+ }
223
+
224
+ footer {
225
+ display: flex;
226
+ flex-wrap: wrap;
227
+ gap: 4px;
228
+ align-items: center;
229
+ }
230
+
231
+ footer input {
232
+ flex: 1 1 80px;
233
+ width: auto;
234
+ }
235
+
236
+ footer select {
237
+ flex: 1 1 120px;
238
+ width: auto;
239
+ }
240
+
241
+ [empty] {
242
+ margin: 0;
243
+ color: var(--md-sys-color-on-surface-variant);
244
+ }
245
+ `; }
246
+ render() {
247
+ const codes = Object.keys(this.looks).sort((a, b) => Number(a === DEFAULT) - Number(b === DEFAULT));
248
+ const shown = this.shownInputs();
249
+ const addable = this.addable.filter(a => !shown.some(s => s.input === a.input));
250
+ return html `
251
+ ${codes.length
252
+ ? html `<div cards>${codes.map(code => this.renderCard(code, shown))}</div>`
253
+ : html `<p empty>${i18next.t('figure.text.status-looks-empty')}</p>`}
254
+ <footer>
255
+ <input
256
+ aria-label=${i18next.t('figure.label.status-code')}
257
+ placeholder=${i18next.t('figure.label.status-code')}
258
+ .value=${this.newCode}
259
+ ?disabled=${this.disabled}
260
+ @input=${(e) => (this.newCode = e.target.value)}
261
+ @keydown=${(e) => e.key === 'Enter' && this.addCode(this.newCode)}
262
+ />
263
+ <button ?disabled=${this.disabled || !this.newCode.trim()} @click=${() => this.addCode(this.newCode)}>${i18next.t('figure.button.status-add-code')}</button>
264
+ ${DEFAULT in this.looks ? nothing : html `<button ?disabled=${this.disabled} @click=${() => this.addCode(DEFAULT)}>${i18next.t('figure.button.status-add-default')}</button>`}
265
+ ${addable.length
266
+ ? html `<select
267
+ aria-label=${i18next.t('figure.button.status-add-value')}
268
+ ?disabled=${this.disabled}
269
+ @change=${(e) => {
270
+ const select = e.target;
271
+ const picked = addable.find(a => a.input === select.value);
272
+ if (picked)
273
+ this.added = [...this.added, picked];
274
+ select.value = '';
275
+ }}
276
+ >
277
+ <option value="">${i18next.t('figure.button.status-add-value')}</option>
278
+ ${addable.map(a => html `<option value=${a.input}>${describeInput(a)}</option>`)}
279
+ </select>`
280
+ : nothing}
281
+ </footer>
282
+ `;
283
+ }
284
+ /** The inputs shown: those given, those added here, and, with `showGiven`, any a look gives a value to. */
285
+ shownInputs() {
286
+ const shown = [...this.inputs];
287
+ for (const one of this.added)
288
+ if (!shown.some(s => s.input === one.input))
289
+ shown.push(one);
290
+ if (this.showGiven)
291
+ for (const input of inputsGivenIn(this.looks))
292
+ if (!shown.some(s => s.input === input))
293
+ shown.push(this.addable.find(a => a.input === input) ?? { input, label: input });
294
+ return shown;
295
+ }
296
+ renderCard(code, inputs) {
297
+ const look = this.looks[code] ?? {};
298
+ const issues = this.issues.get(code) ?? [];
299
+ const said = (target, id) => issues.filter(i => i.target === target && (id === undefined || i.id === id));
300
+ const ports = this.now[code];
301
+ const values = look.values && typeof look.values === 'object' ? look.values : {};
302
+ const effect = look.effect && typeof look.effect === 'object' ? look.effect : undefined;
303
+ return html `<section ?now=${!!ports} ?refused=${issues.length > 0} data-code=${code}>
304
+ <header>
305
+ <input
306
+ type="color"
307
+ aria-label=${i18next.t('figure.label.status-color')}
308
+ title=${look.color === undefined ? i18next.t('figure.label.status-color-none') : String(look.color)}
309
+ ?unset=${look.color === undefined}
310
+ aria-invalid=${said('color').length ? 'true' : 'false'}
311
+ .value=${typeof look.color === 'string' ? look.color : '#000000'}
312
+ ?disabled=${this.disabled}
313
+ @change=${(e) => this.change(withLook(this.looks, code, { color: e.target.value.toUpperCase() }))}
314
+ />
315
+ <b title=${code}>${code === DEFAULT ? i18next.t('figure.label.status-default-code') : code}</b>
316
+ ${ports ? html `<span now-tag title=${ports.join(', ')}>${i18next.t('figure.label.status-now')}</span>` : nothing}
317
+ <span end>
318
+ ${this.colorOptional && look.color !== undefined
319
+ ? html `<button icon title=${i18next.t('figure.button.status-clear-color')} ?disabled=${this.disabled} @click=${() => this.change(withLook(this.looks, code, { color: undefined }))}>⌀</button>`
320
+ : nothing}
321
+ <button icon title=${i18next.t('figure.button.status-remove-code')} ?disabled=${this.disabled} @click=${() => this.change(withoutCode(this.looks, code))}>×</button>
322
+ </span>
323
+ </header>
324
+ <div fields>
325
+ ${this.effects
326
+ ? html `<span name>${i18next.t('figure.label.status-effect')}</span>
327
+ <select
328
+ ?wide=${effect?.kind !== 'blink'}
329
+ aria-label=${i18next.t('figure.label.status-effect')}
330
+ aria-invalid=${said('effect').length ? 'true' : 'false'}
331
+ ?disabled=${this.disabled}
332
+ @change=${(e) => {
333
+ const kind = e.target.value;
334
+ this.change(withLook(this.looks, code, { effect: kind === 'blink' ? { kind, hz: effect?.hz ?? 1 } : kind === 'glow' ? { kind } : undefined }));
335
+ }}
336
+ >
337
+ ${['', 'blink', 'glow'].map(k => html `<option value=${k} ?selected=${(effect?.kind ?? '') === k}>${i18next.t('figure.label.status-effect-' + (k || 'none'))}</option>`)}
338
+ </select>
339
+ ${effect?.kind === 'blink'
340
+ ? html `<input
341
+ type="number"
342
+ step="any"
343
+ aria-label=${i18next.t('figure.label.status-effect-hz')}
344
+ .value=${String(effect.hz ?? 1)}
345
+ ?disabled=${this.disabled}
346
+ @change=${(e) => {
347
+ const hz = e.target.valueAsNumber;
348
+ if (!(Number.isFinite(hz) && hz > 0))
349
+ return this.requestUpdate();
350
+ this.change(withLook(this.looks, code, { effect: { kind: 'blink', hz } }));
351
+ }}
352
+ />`
353
+ : nothing}`
354
+ : nothing}
355
+ ${inputs.map(input => {
356
+ const held = values[input.input];
357
+ const refused = said('state', input.input);
358
+ return html `<span name title=${describeInput(input)}>${input.label}</span>
359
+ <input
360
+ type="number"
361
+ step="any"
362
+ data-input=${input.input}
363
+ aria-label=${input.label}
364
+ aria-invalid=${refused.length ? 'true' : 'false'}
365
+ placeholder=${rangeOf(input) ?? ''}
366
+ .value=${held === undefined ? '' : String(held)}
367
+ ?disabled=${this.disabled}
368
+ @change=${(e) => this.changeValue(code, input, e.target)}
369
+ />
370
+ <span unit>${[input.unit, rangeOf(input)].filter(Boolean).join(' ')}</span>`;
371
+ })}
372
+ ${this.clips.length
373
+ ? html `<span name>${i18next.t('figure.label.status-clip')}</span>
374
+ <select
375
+ wide
376
+ aria-label=${i18next.t('figure.label.status-clip')}
377
+ aria-invalid=${said('motion-clip').length ? 'true' : 'false'}
378
+ ?disabled=${this.disabled}
379
+ @change=${(e) => this.change(withLook(this.looks, code, { clip: e.target.value || undefined }))}
380
+ >
381
+ <option value="" ?selected=${look.clip === undefined}>${i18next.t('figure.label.status-clip-none')}</option>
382
+ ${[...new Set([...this.clips, ...(look.clip !== undefined && !this.clips.includes(look.clip) ? [look.clip] : [])])].map(clip => html `<option value=${clip} ?selected=${look.clip === clip}>${clip}</option>`)}
383
+ </select>`
384
+ : nothing}
385
+ </div>
386
+ ${issues.map(issue => html `<p issue>${issueSentence(issue, inputs)}</p>`)}
387
+ </section>`;
388
+ }
389
+ addCode(code) {
390
+ const trimmed = code.trim();
391
+ if (!trimmed)
392
+ return;
393
+ this.newCode = '';
394
+ if (trimmed in this.looks)
395
+ return;
396
+ this.change(this.defaultColor ? withLook(this.looks, trimmed, { color: this.defaultColor }) : withCode(this.looks, trimmed));
397
+ }
398
+ /** A number in range is taken; an empty field takes the value away (the next source gives it); anything else is not taken. */
399
+ changeValue(code, input, field) {
400
+ if (field.value.trim() === '')
401
+ return this.change(withLookValue(this.looks, code, input.input, undefined));
402
+ const value = field.valueAsNumber;
403
+ const outside = !Number.isFinite(value) || (input.min !== undefined && value < input.min) || (input.max !== undefined && value > input.max);
404
+ if (outside) {
405
+ const held = this.looks[code]?.values?.[input.input];
406
+ field.value = held === undefined ? '' : String(held);
407
+ return;
408
+ }
409
+ this.change(withLookValue(this.looks, code, input.input, value));
410
+ }
411
+ change(looks) {
412
+ this.looks = looks;
413
+ this.dispatchEvent(new CustomEvent('looks-change', { bubbles: true, composed: true, detail: { looks } }));
414
+ }
415
+ };
416
+ __decorate([
417
+ property({ type: Object }),
418
+ __metadata("design:type", Object)
419
+ ], OxFigureStatusLooks.prototype, "looks", void 0);
420
+ __decorate([
421
+ property({ type: Array }),
422
+ __metadata("design:type", Array)
423
+ ], OxFigureStatusLooks.prototype, "inputs", void 0);
424
+ __decorate([
425
+ property({ type: Array }),
426
+ __metadata("design:type", Array)
427
+ ], OxFigureStatusLooks.prototype, "addable", void 0);
428
+ __decorate([
429
+ property({ type: Boolean, attribute: 'show-given' }),
430
+ __metadata("design:type", Object)
431
+ ], OxFigureStatusLooks.prototype, "showGiven", void 0);
432
+ __decorate([
433
+ property({ type: Array }),
434
+ __metadata("design:type", Array)
435
+ ], OxFigureStatusLooks.prototype, "clips", void 0);
436
+ __decorate([
437
+ property({ type: Boolean }),
438
+ __metadata("design:type", Object)
439
+ ], OxFigureStatusLooks.prototype, "effects", void 0);
440
+ __decorate([
441
+ property({ type: Boolean, attribute: 'color-optional' }),
442
+ __metadata("design:type", Object)
443
+ ], OxFigureStatusLooks.prototype, "colorOptional", void 0);
444
+ __decorate([
445
+ property({ type: String, attribute: 'default-color' }),
446
+ __metadata("design:type", String)
447
+ ], OxFigureStatusLooks.prototype, "defaultColor", void 0);
448
+ __decorate([
449
+ property({ type: Object }),
450
+ __metadata("design:type", Object)
451
+ ], OxFigureStatusLooks.prototype, "now", void 0);
452
+ __decorate([
453
+ property({ type: Object }),
454
+ __metadata("design:type", Map)
455
+ ], OxFigureStatusLooks.prototype, "issues", void 0);
456
+ __decorate([
457
+ property({ type: Boolean }),
458
+ __metadata("design:type", Object)
459
+ ], OxFigureStatusLooks.prototype, "disabled", void 0);
460
+ __decorate([
461
+ state(),
462
+ __metadata("design:type", Array)
463
+ ], OxFigureStatusLooks.prototype, "added", void 0);
464
+ __decorate([
465
+ state(),
466
+ __metadata("design:type", Object)
467
+ ], OxFigureStatusLooks.prototype, "newCode", void 0);
468
+ OxFigureStatusLooks = __decorate([
469
+ customElement('ox-figure-status-looks')
470
+ ], OxFigureStatusLooks);
471
+ export { OxFigureStatusLooks };
472
+ /** An input as the choice and the tooltip say it: its name, unit and range, and the port that offers it. */
473
+ export function describeInput(input) {
474
+ const tail = [input.unit, rangeOf(input)].filter(Boolean).join(' ');
475
+ return `${input.label}${tail ? ` (${tail})` : ''}${input.portLabel ? ` · ${input.portLabel}` : ''}`;
476
+ }
477
+ function rangeOf(input) {
478
+ return input.min !== undefined || input.max !== undefined ? `${input.min ?? ''}~${input.max ?? ''}` : undefined;
479
+ }
480
+ /** Why a part was not taken, in the person's words, with the value refused. */
481
+ export function issueSentence(issue, inputs = []) {
482
+ const input = issue.id !== undefined ? inputs.find(i => i.input === issue.id) : undefined;
483
+ return i18next.t('figure.text.status-issue-' + issue.reason, {
484
+ name: input?.label ?? issue.id ?? '',
485
+ value: typeof issue.value === 'string' ? issue.value : JSON.stringify(issue.value),
486
+ range: input ? (rangeOf(input) ?? '') : ''
487
+ });
488
+ }
489
+ //# sourceMappingURL=ox-figure-status-looks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ox-figure-status-looks.js","sourceRoot":"","sources":["../../client/status-looks/ox-figure-status-looks.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { i18next } from '@operato/i18n'\n\nimport { inputsGivenIn, withCode, withLook, withLookValue, withoutCode, type LookInput, type StatusIssue, type StatusLooks } from './status-looks.js'\n\nconst DEFAULT = 'default'\n\n/**\n * A status template's looks, one card per code (ADR-0051 2.3): its colour, its effect, a value for each state input a\n * figure's port offers -- with the input's name, unit and range -- and the clip of the port's motion group. The code the\n * data gives now is marked; a part the figure did not take is said under the card, by the field that gave it. Every\n * change sends `looks-change` with the whole looks; the host writes them where the template lives.\n *\n * A value outside its input's range is not taken from the field (as the property panel's number maps); a value written\n * elsewhere that the figure refused shows with the reason, to be fixed here. Values for inputs not shown -- another\n * figure's, in a table shared by many -- are kept as they are.\n *\n * Shared by the board's 「상태 표현」 section and fmsim's legend editor, which shows colour and values only.\n */\n@customElement('ox-figure-status-looks')\nexport class OxFigureStatusLooks extends LitElement {\n static styles = css`\n :host {\n display: grid;\n gap: 6px;\n font: var(--property-editor-field-font, 0.76rem var(--theme-font, Roboto, sans-serif));\n color: var(--md-sys-color-on-surface);\n }\n\n [cards] {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(var(--status-looks-card-min, 220px), 1fr));\n gap: 6px;\n }\n\n section {\n display: grid;\n gap: 3px;\n padding: 4px 6px 6px;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 6px;\n }\n\n section[now] {\n border-color: var(--md-sys-color-primary);\n }\n\n section[refused] {\n border-color: var(--md-sys-color-error);\n }\n\n header {\n display: flex;\n align-items: center;\n gap: 6px;\n min-height: 24px;\n }\n\n header b {\n font-weight: 600;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n [now-tag] {\n padding: 0 4px;\n border-radius: 4px;\n background: var(--md-sys-color-primary-container);\n color: var(--md-sys-color-on-primary-container);\n font-size: 0.68rem;\n white-space: nowrap;\n }\n\n header [end] {\n margin-left: auto;\n display: flex;\n gap: 2px;\n }\n\n input[type='color'] {\n flex: none;\n width: 22px;\n height: 18px;\n padding: 0;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 4px;\n background: none;\n cursor: pointer;\n }\n\n input[type='color']::-webkit-color-swatch-wrapper {\n padding: 1px;\n }\n\n input[type='color']::-webkit-color-swatch {\n border: none;\n border-radius: 3px;\n }\n\n /*\n * No colour given: the swatch is an empty dashed box until one is picked. A colour the field cannot show, it shows\n * black, as the browser does; the figure's refusal says why.\n */\n input[type='color'][unset] {\n border-style: dashed;\n opacity: 0.6;\n }\n\n input[type='color'][unset]::-webkit-color-swatch {\n background: transparent !important;\n }\n\n [fields] {\n display: grid;\n grid-template-columns: minmax(0, 1fr) minmax(56px, 72px) minmax(0, auto);\n gap: 3px 6px;\n align-items: center;\n }\n\n [fields] > [name] {\n color: var(--md-sys-color-on-surface-variant);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n [fields] > [unit] {\n color: var(--md-sys-color-outline);\n font-size: 0.68rem;\n white-space: nowrap;\n }\n\n input:not([type='color']),\n select {\n box-sizing: border-box;\n width: 100%;\n min-width: 0;\n height: var(--property-editor-field-height, 24px);\n padding: 0 4px;\n font: inherit;\n color: inherit;\n border: var(--property-editor-border, 1px solid var(--md-sys-color-outline-variant));\n border-radius: var(--property-editor-border-radius, 6px);\n background: var(--property-editor-background, var(--md-sys-color-surface-container-high));\n }\n\n input[type='number'] {\n text-align: right;\n font-variant-numeric: tabular-nums;\n }\n\n input:hover,\n select:hover {\n border-color: var(--property-editor-border-color-hover, var(--md-sys-color-outline-variant));\n }\n\n input:focus,\n select:focus {\n outline: none;\n border-color: var(--property-editor-border-color-focus, var(--md-sys-color-primary));\n }\n\n [aria-invalid='true'] {\n border-color: var(--md-sys-color-error) !important;\n }\n\n /* The effect's choice takes the field and the unit columns; a blink's rate takes the field after it. */\n [fields] > select[wide] {\n grid-column: 2 / -1;\n }\n\n [issue] {\n margin: 0;\n color: var(--md-sys-color-error);\n font-size: 0.7rem;\n }\n\n button {\n height: 24px;\n padding: 0 8px;\n font: inherit;\n color: var(--md-sys-color-primary);\n border: none;\n border-radius: 6px;\n background: transparent;\n cursor: pointer;\n white-space: nowrap;\n }\n\n button:hover {\n background: var(--md-sys-color-surface-container-high);\n }\n\n button[icon] {\n width: 22px;\n padding: 0;\n color: var(--md-sys-color-on-surface-variant);\n }\n\n footer {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n align-items: center;\n }\n\n footer input {\n flex: 1 1 80px;\n width: auto;\n }\n\n footer select {\n flex: 1 1 120px;\n width: auto;\n }\n\n [empty] {\n margin: 0;\n color: var(--md-sys-color-on-surface-variant);\n }\n `\n\n @property({ type: Object }) looks: StatusLooks = {}\n /** The state inputs shown, one field each: the figure's offered inputs, or those a legend gives values to. */\n @property({ type: Array }) inputs: LookInput[] = []\n /** Inputs that can be added as a field (a legend's editor: the inputs the carrier figures offer). */\n @property({ type: Array }) addable: LookInput[] = []\n /**\n * Whether every input a look gives a value to has a field, offered or not: a legend, which no one figure reads. A\n * figure's own section leaves the values of inputs it does not offer to the figures that do.\n */\n @property({ type: Boolean, attribute: 'show-given' }) showGiven = false\n /** The clips a look may choose; none, no clip field. */\n @property({ type: Array }) clips: string[] = []\n @property({ type: Boolean }) effects = false\n /** Whether a look may give no colour (a board's template); a legend's entry always has one. */\n @property({ type: Boolean, attribute: 'color-optional' }) colorOptional = false\n /** The colour a new code starts with (a legend's entry has one from the start). */\n @property({ type: String, attribute: 'default-color' }) defaultColor?: string\n /** The rows the data gives now, with the ports that read them. */\n @property({ type: Object }) now: Record<string, string[]> = {}\n /** What the figure did not take, by row. */\n @property({ type: Object }) issues: Map<string, StatusIssue[]> = new Map()\n @property({ type: Boolean }) disabled = false\n\n @state() private added: LookInput[] = []\n @state() private newCode = ''\n\n render() {\n const codes = Object.keys(this.looks).sort((a, b) => Number(a === DEFAULT) - Number(b === DEFAULT))\n const shown = this.shownInputs()\n const addable = this.addable.filter(a => !shown.some(s => s.input === a.input))\n return html`\n ${codes.length\n ? html`<div cards>${codes.map(code => this.renderCard(code, shown))}</div>`\n : html`<p empty>${i18next.t('figure.text.status-looks-empty')}</p>`}\n <footer>\n <input\n aria-label=${i18next.t('figure.label.status-code')}\n placeholder=${i18next.t('figure.label.status-code')}\n .value=${this.newCode}\n ?disabled=${this.disabled}\n @input=${(e: Event) => (this.newCode = (e.target as HTMLInputElement).value)}\n @keydown=${(e: KeyboardEvent) => e.key === 'Enter' && this.addCode(this.newCode)}\n />\n <button ?disabled=${this.disabled || !this.newCode.trim()} @click=${() => this.addCode(this.newCode)}>${i18next.t('figure.button.status-add-code')}</button>\n ${DEFAULT in this.looks ? nothing : html`<button ?disabled=${this.disabled} @click=${() => this.addCode(DEFAULT)}>${i18next.t('figure.button.status-add-default')}</button>`}\n ${addable.length\n ? html`<select\n aria-label=${i18next.t('figure.button.status-add-value')}\n ?disabled=${this.disabled}\n @change=${(e: Event) => {\n const select = e.target as HTMLSelectElement\n const picked = addable.find(a => a.input === select.value)\n if (picked) this.added = [...this.added, picked]\n select.value = ''\n }}\n >\n <option value=\"\">${i18next.t('figure.button.status-add-value')}</option>\n ${addable.map(a => html`<option value=${a.input}>${describeInput(a)}</option>`)}\n </select>`\n : nothing}\n </footer>\n `\n }\n\n /** The inputs shown: those given, those added here, and, with `showGiven`, any a look gives a value to. */\n private shownInputs(): LookInput[] {\n const shown = [...this.inputs]\n for (const one of this.added) if (!shown.some(s => s.input === one.input)) shown.push(one)\n if (this.showGiven)\n for (const input of inputsGivenIn(this.looks))\n if (!shown.some(s => s.input === input)) shown.push(this.addable.find(a => a.input === input) ?? { input, label: input })\n return shown\n }\n\n private renderCard(code: string, inputs: LookInput[]) {\n const look = this.looks[code] ?? {}\n const issues = this.issues.get(code) ?? []\n const said = (target: string, id?: string) => issues.filter(i => i.target === target && (id === undefined || i.id === id))\n const ports = this.now[code]\n const values = look.values && typeof look.values === 'object' ? (look.values as Record<string, unknown>) : {}\n const effect = look.effect && typeof look.effect === 'object' ? look.effect : undefined\n return html`<section ?now=${!!ports} ?refused=${issues.length > 0} data-code=${code}>\n <header>\n <input\n type=\"color\"\n aria-label=${i18next.t('figure.label.status-color')}\n title=${look.color === undefined ? i18next.t('figure.label.status-color-none') : String(look.color)}\n ?unset=${look.color === undefined}\n aria-invalid=${said('color').length ? 'true' : 'false'}\n .value=${typeof look.color === 'string' ? look.color : '#000000'}\n ?disabled=${this.disabled}\n @change=${(e: Event) => this.change(withLook(this.looks, code, { color: (e.target as HTMLInputElement).value.toUpperCase() }))}\n />\n <b title=${code}>${code === DEFAULT ? i18next.t('figure.label.status-default-code') : code}</b>\n ${ports ? html`<span now-tag title=${ports.join(', ')}>${i18next.t('figure.label.status-now')}</span>` : nothing}\n <span end>\n ${this.colorOptional && look.color !== undefined\n ? html`<button icon title=${i18next.t('figure.button.status-clear-color')} ?disabled=${this.disabled} @click=${() => this.change(withLook(this.looks, code, { color: undefined }))}>⌀</button>`\n : nothing}\n <button icon title=${i18next.t('figure.button.status-remove-code')} ?disabled=${this.disabled} @click=${() => this.change(withoutCode(this.looks, code))}>×</button>\n </span>\n </header>\n <div fields>\n ${this.effects\n ? html`<span name>${i18next.t('figure.label.status-effect')}</span>\n <select\n ?wide=${effect?.kind !== 'blink'}\n aria-label=${i18next.t('figure.label.status-effect')}\n aria-invalid=${said('effect').length ? 'true' : 'false'}\n ?disabled=${this.disabled}\n @change=${(e: Event) => {\n const kind = (e.target as HTMLSelectElement).value\n this.change(withLook(this.looks, code, { effect: kind === 'blink' ? { kind, hz: effect?.hz ?? 1 } : kind === 'glow' ? { kind } : undefined }))\n }}\n >\n ${['', 'blink', 'glow'].map(k => html`<option value=${k} ?selected=${(effect?.kind ?? '') === k}>${i18next.t('figure.label.status-effect-' + (k || 'none'))}</option>`)}\n </select>\n ${effect?.kind === 'blink'\n ? html`<input\n type=\"number\"\n step=\"any\"\n aria-label=${i18next.t('figure.label.status-effect-hz')}\n .value=${String(effect.hz ?? 1)}\n ?disabled=${this.disabled}\n @change=${(e: Event) => {\n const hz = (e.target as HTMLInputElement).valueAsNumber\n if (!(Number.isFinite(hz) && hz > 0)) return this.requestUpdate()\n this.change(withLook(this.looks, code, { effect: { kind: 'blink', hz } }))\n }}\n />`\n : nothing}`\n : nothing}\n ${inputs.map(input => {\n const held = values[input.input]\n const refused = said('state', input.input)\n return html`<span name title=${describeInput(input)}>${input.label}</span>\n <input\n type=\"number\"\n step=\"any\"\n data-input=${input.input}\n aria-label=${input.label}\n aria-invalid=${refused.length ? 'true' : 'false'}\n placeholder=${rangeOf(input) ?? ''}\n .value=${held === undefined ? '' : String(held)}\n ?disabled=${this.disabled}\n @change=${(e: Event) => this.changeValue(code, input, e.target as HTMLInputElement)}\n />\n <span unit>${[input.unit, rangeOf(input)].filter(Boolean).join(' ')}</span>`\n })}\n ${this.clips.length\n ? html`<span name>${i18next.t('figure.label.status-clip')}</span>\n <select\n wide\n aria-label=${i18next.t('figure.label.status-clip')}\n aria-invalid=${said('motion-clip').length ? 'true' : 'false'}\n ?disabled=${this.disabled}\n @change=${(e: Event) => this.change(withLook(this.looks, code, { clip: (e.target as HTMLSelectElement).value || undefined }))}\n >\n <option value=\"\" ?selected=${look.clip === undefined}>${i18next.t('figure.label.status-clip-none')}</option>\n ${[...new Set([...this.clips, ...(look.clip !== undefined && !this.clips.includes(look.clip) ? [look.clip] : [])])].map(\n clip => html`<option value=${clip} ?selected=${look.clip === clip}>${clip}</option>`\n )}\n </select>`\n : nothing}\n </div>\n ${issues.map(issue => html`<p issue>${issueSentence(issue, inputs)}</p>`)}\n </section>`\n }\n\n private addCode(code: string) {\n const trimmed = code.trim()\n if (!trimmed) return\n this.newCode = ''\n if (trimmed in this.looks) return\n this.change(this.defaultColor ? withLook(this.looks, trimmed, { color: this.defaultColor }) : withCode(this.looks, trimmed))\n }\n\n /** A number in range is taken; an empty field takes the value away (the next source gives it); anything else is not taken. */\n private changeValue(code: string, input: LookInput, field: HTMLInputElement) {\n if (field.value.trim() === '') return this.change(withLookValue(this.looks, code, input.input, undefined))\n const value = field.valueAsNumber\n const outside = !Number.isFinite(value) || (input.min !== undefined && value < input.min) || (input.max !== undefined && value > input.max)\n if (outside) {\n const held = this.looks[code]?.values?.[input.input]\n field.value = held === undefined ? '' : String(held)\n return\n }\n this.change(withLookValue(this.looks, code, input.input, value))\n }\n\n private change(looks: StatusLooks) {\n this.looks = looks\n this.dispatchEvent(new CustomEvent('looks-change', { bubbles: true, composed: true, detail: { looks } }))\n }\n}\n\n/** An input as the choice and the tooltip say it: its name, unit and range, and the port that offers it. */\nexport function describeInput(input: LookInput): string {\n const tail = [input.unit, rangeOf(input)].filter(Boolean).join(' ')\n return `${input.label}${tail ? ` (${tail})` : ''}${input.portLabel ? ` · ${input.portLabel}` : ''}`\n}\n\nfunction rangeOf(input: LookInput): string | undefined {\n return input.min !== undefined || input.max !== undefined ? `${input.min ?? ''}~${input.max ?? ''}` : undefined\n}\n\n/** Why a part was not taken, in the person's words, with the value refused. */\nexport function issueSentence(issue: StatusIssue, inputs: readonly LookInput[] = []): string {\n const input = issue.id !== undefined ? inputs.find(i => i.input === issue.id) : undefined\n return i18next.t('figure.text.status-issue-' + issue.reason, {\n name: input?.label ?? issue.id ?? '',\n value: typeof issue.value === 'string' ? issue.value : JSON.stringify(issue.value),\n range: input ? (rangeOf(input) ?? '') : ''\n })\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ox-figure-status-looks': OxFigureStatusLooks\n }\n}\n"]}
@@ -0,0 +1,99 @@
1
+ import type { FigureAsset } from '@hatiolab/figure-model';
2
+ export interface StatusLookEffect {
3
+ kind: 'blink' | 'glow';
4
+ hz?: number;
5
+ }
6
+ /** One code's look, as a template holds it. Any part may be missing; a value is in its input's own unit. */
7
+ export interface StatusLook {
8
+ color?: string;
9
+ effect?: StatusLookEffect | null;
10
+ values?: Record<string, number>;
11
+ clip?: string;
12
+ }
13
+ /** A template's states: code → look, `default` for a code the template does not name. */
14
+ export type StatusLooks = Record<string, StatusLook>;
15
+ /** A state input a template may give a value to: the input, its name, unit and range, and the port that offers it. */
16
+ export interface LookInput {
17
+ input: string;
18
+ label: string;
19
+ unit?: string;
20
+ min?: number;
21
+ max?: number;
22
+ sourceMode?: 'observed' | 'commanded';
23
+ port?: string;
24
+ portLabel?: string;
25
+ }
26
+ /** A motion group a template may choose a clip of, through the port that holds it. */
27
+ export interface LookGroup {
28
+ id: string;
29
+ label: string;
30
+ clips: string[];
31
+ port: string;
32
+ }
33
+ /** What one status port of a placed figure said of the last look it was given, as things-scene's `statusIssues` holds it. */
34
+ export interface StatusIssue {
35
+ port: string;
36
+ code: string;
37
+ source: 'resolver' | 'placement' | 'board';
38
+ target: 'state' | 'motion-clip' | 'color' | 'effect' | 'values' | 'resolver';
39
+ id?: string;
40
+ reason: string;
41
+ value: unknown;
42
+ }
43
+ /** The state inputs the figure's status ports offer a template, in port order, with the input's unit and range. */
44
+ export declare function offeredInputsOf(asset: FigureAsset): LookInput[];
45
+ /** The motion groups the figure's status ports let a template choose a clip of. */
46
+ export declare function offeredGroupsOf(asset: FigureAsset): LookGroup[];
47
+ /** A template's looks as they are stored; anything not a record of records reads as no looks. */
48
+ export declare function looksOf(states: unknown): StatusLooks;
49
+ /**
50
+ * One code's look with some parts changed: a part given as undefined is taken away, so the template no longer gives it
51
+ * and the next source does (ADR-0051 2.3, 4). A look left with nothing stays, as a code the template names.
52
+ */
53
+ export declare function withLook(looks: StatusLooks, code: string, patch: Partial<StatusLook>): StatusLooks;
54
+ /**
55
+ * One value of one code's look: a number sets it, undefined takes it away. The values of inputs this figure does not
56
+ * offer -- another figure's, in a table shared by many (ADR-0051 2.3, 9) -- stay as they were.
57
+ */
58
+ export declare function withLookValue(looks: StatusLooks, code: string, input: string, value: number | undefined): StatusLooks;
59
+ export declare function withCode(looks: StatusLooks, code: string): StatusLooks;
60
+ export declare function withoutCode(looks: StatusLooks, code: string): StatusLooks;
61
+ /** The inputs some look gives a value to, in the order first met. */
62
+ export declare function inputsGivenIn(looks: StatusLooks): string[];
63
+ export interface BoardTemplates {
64
+ statusTemplate?: unknown;
65
+ statusTemplates?: Record<string, unknown>;
66
+ }
67
+ export type TemplatePlace = {
68
+ at: 'placement';
69
+ } | {
70
+ at: 'named';
71
+ name: string;
72
+ chosenBy: 'placement' | 'board';
73
+ } | {
74
+ at: 'board';
75
+ } | {
76
+ at: 'none';
77
+ };
78
+ /**
79
+ * The template a placement's 「상태 표현」 edits: the one its own `statusTemplate` names or holds, else the board's
80
+ * default. A name with no template behind it is still that name: writing to it makes the template.
81
+ */
82
+ export declare function templatePlaceOf(placement: unknown, board: BoardTemplates): TemplatePlace;
83
+ /** The looks of the template at a place; none yet is no looks. */
84
+ export declare function looksAt(place: TemplatePlace, placement: unknown, board: BoardTemplates): StatusLooks;
85
+ /**
86
+ * What to write so the template at a place holds these looks: the placement's own value, or the board's. A board with
87
+ * no template yet gets its default, held whole. The rest of a template (anything beside `states`) is kept.
88
+ */
89
+ export declare function writeLooksAt(place: TemplatePlace, looks: StatusLooks, placement: unknown, board: BoardTemplates): {
90
+ placement?: Record<string, unknown>;
91
+ board?: BoardTemplates;
92
+ };
93
+ /** The board's templates with a new, empty one by this name; undefined when the name is empty or taken. */
94
+ export declare function withNewTemplate(board: BoardTemplates, name: string): BoardTemplates | undefined;
95
+ /**
96
+ * The parts of a code's look a port did not take, by the row of the table that gave it: the look the template looked
97
+ * up (`lookedUp`, the code's own or `default`). Issues of another source than the table shown are not the table's.
98
+ */
99
+ export declare function issuesByRow(issues: readonly StatusIssue[], source: StatusIssue['source'] | undefined, rowOf: (code: string) => string | undefined): Map<string, StatusIssue[]>;