@things-factory/figure-library 10.1.218 → 10.1.223

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 +8 -8
  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
@@ -1,8 +1,10 @@
1
1
  import './editors/ox-property-editor-figure-data.js';
2
+ import './editors/ox-property-editor-figure-status.js';
2
3
  /**
3
4
  * The editors the board's property panel needs for the properties a placed figure names: its data -- shape, each value
4
- * and where it came from (`figure-data`) -- and its slot layout, which a placement may override (`slot-layout`, ADR-0118
5
- * decision 8). Registered here, where every app that places library figures on its boards loads this module; the scene
6
- * component list does not carry figure packages, and without these the panel skips the two properties.
5
+ * and where it came from (`figure-data`) --, its status template and each code's look (`figure-status`, ADR-0051 2.3)
6
+ * and its slot layout, which a placement may override (`slot-layout`, ADR-0118 decision 8). Registered here, where every
7
+ * app that places library figures on its boards loads this module; the scene component list does not carry figure
8
+ * packages, and without these the panel skips the three properties.
7
9
  */
8
10
  export default function bootstrap(): void;
@@ -1,14 +1,17 @@
1
1
  import { OxPropertyEditor } from '@operato/property-editor';
2
2
  import { SLOT_LAYOUT_EDITORS } from '@operato/slot-layout-editor';
3
3
  import './editors/ox-property-editor-figure-data.js';
4
+ import './editors/ox-property-editor-figure-status.js';
4
5
  /**
5
6
  * The editors the board's property panel needs for the properties a placed figure names: its data -- shape, each value
6
- * and where it came from (`figure-data`) -- and its slot layout, which a placement may override (`slot-layout`, ADR-0118
7
- * decision 8). Registered here, where every app that places library figures on its boards loads this module; the scene
8
- * component list does not carry figure packages, and without these the panel skips the two properties.
7
+ * and where it came from (`figure-data`) --, its status template and each code's look (`figure-status`, ADR-0051 2.3)
8
+ * and its slot layout, which a placement may override (`slot-layout`, ADR-0118 decision 8). Registered here, where every
9
+ * app that places library figures on its boards loads this module; the scene component list does not carry figure
10
+ * packages, and without these the panel skips the three properties.
9
11
  */
10
12
  export default function bootstrap() {
11
13
  OxPropertyEditor.register({ 'figure-data': 'ox-property-editor-figure-data' });
14
+ OxPropertyEditor.register({ 'figure-status': 'ox-property-editor-figure-status' });
12
15
  OxPropertyEditor.register(Object.fromEntries(SLOT_LAYOUT_EDITORS.map(e => [e.type, e.element])));
13
16
  }
14
17
  //# sourceMappingURL=bootstrap.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../client/bootstrap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AAEjE,OAAO,6CAA6C,CAAA;AAEpD;;;;;GAKG;AACH,MAAM,CAAC,OAAO,UAAU,SAAS;IAC/B,gBAAgB,CAAC,QAAQ,CAAC,EAAE,aAAa,EAAE,gCAAgC,EAAE,CAAC,CAAA;IAC9E,gBAAgB,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAA;AAClG,CAAC","sourcesContent":["import { OxPropertyEditor } from '@operato/property-editor'\nimport { SLOT_LAYOUT_EDITORS } from '@operato/slot-layout-editor'\n\nimport './editors/ox-property-editor-figure-data.js'\n\n/**\n * The editors the board's property panel needs for the properties a placed figure names: its data -- shape, each value\n * and where it came from (`figure-data`) -- and its slot layout, which a placement may override (`slot-layout`, ADR-0118\n * decision 8). Registered here, where every app that places library figures on its boards loads this module; the scene\n * component list does not carry figure packages, and without these the panel skips the two properties.\n */\nexport default function bootstrap() {\n OxPropertyEditor.register({ 'figure-data': 'ox-property-editor-figure-data' })\n OxPropertyEditor.register(Object.fromEntries(SLOT_LAYOUT_EDITORS.map(e => [e.type, e.element])))\n}\n"]}
1
+ {"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../client/bootstrap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AAEjE,OAAO,6CAA6C,CAAA;AACpD,OAAO,+CAA+C,CAAA;AAEtD;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,UAAU,SAAS;IAC/B,gBAAgB,CAAC,QAAQ,CAAC,EAAE,aAAa,EAAE,gCAAgC,EAAE,CAAC,CAAA;IAC9E,gBAAgB,CAAC,QAAQ,CAAC,EAAE,eAAe,EAAE,kCAAkC,EAAE,CAAC,CAAA;IAClF,gBAAgB,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAA;AAClG,CAAC","sourcesContent":["import { OxPropertyEditor } from '@operato/property-editor'\nimport { SLOT_LAYOUT_EDITORS } from '@operato/slot-layout-editor'\n\nimport './editors/ox-property-editor-figure-data.js'\nimport './editors/ox-property-editor-figure-status.js'\n\n/**\n * The editors the board's property panel needs for the properties a placed figure names: its data -- shape, each value\n * and where it came from (`figure-data`) --, its status template and each code's look (`figure-status`, ADR-0051 2.3)\n * and its slot layout, which a placement may override (`slot-layout`, ADR-0118 decision 8). Registered here, where every\n * app that places library figures on its boards loads this module; the scene component list does not carry figure\n * packages, and without these the panel skips the three properties.\n */\nexport default function bootstrap() {\n OxPropertyEditor.register({ 'figure-data': 'ox-property-editor-figure-data' })\n OxPropertyEditor.register({ 'figure-status': 'ox-property-editor-figure-status' })\n OxPropertyEditor.register(Object.fromEntries(SLOT_LAYOUT_EDITORS.map(e => [e.type, e.element])))\n}\n"]}
@@ -0,0 +1,41 @@
1
+ import '../status-looks/ox-figure-status-looks.js';
2
+ import { type PropertyValues } from 'lit';
3
+ import { OxPropertyEditor, type PropertySpec } from '@operato/property-editor';
4
+ /**
5
+ * 「상태 표현」 on the board's property panel for a figure with status ports (ADR-0051 2.3, §8): the template this
6
+ * placement shows its codes through -- the board's default, one of the board's named templates, or its own -- and,
7
+ * per port, the code the data gives now and which source answered it (the app's legend, the placement's template, the
8
+ * board's). Below, the template's looks to read and change: colour, effect, a value for each state input the ports
9
+ * offer with its unit and range, the clip of a port's motion group. What the figure did not take is said by the field
10
+ * that gave it.
11
+ *
12
+ * The property is the placement's `statusTemplate`; a look of a board template is written on the board, in the same
13
+ * undoable change. The figure checks each look when it shows it (things-scene); this section reads what it said.
14
+ */
15
+ export declare class OxPropertyEditorFigureStatus extends OxPropertyEditor {
16
+ static styles: import("lit").CSSResult[];
17
+ private naming;
18
+ private watched?;
19
+ private readonly refresh;
20
+ private asked;
21
+ disconnectedCallback(): void;
22
+ willUpdate(changed: PropertyValues<this>): void;
23
+ editorTemplate(value: unknown, spec: PropertySpec): import("lit-html").TemplateResult<1>;
24
+ /** Which template: the board's default, one of the board's named ones, or the placement's own; a new named one. */
25
+ private renderChooser;
26
+ private renderPort;
27
+ _valueChanged(e: Event): void;
28
+ /** The looks written where the template lives: the placement's own value through the panel, a board's on the board. */
29
+ private writeLooks;
30
+ /** A new named template on the board, chosen for this placement, in one undoable change. */
31
+ private createTemplate;
32
+ private selectedFigure;
33
+ /** The one selected figure, given to `use` inside the panel's undoable change; none for a selection of several. */
34
+ private withSelected;
35
+ private watch;
36
+ }
37
+ declare global {
38
+ interface HTMLElementTagNameMap {
39
+ 'ox-property-editor-figure-status': OxPropertyEditorFigureStatus;
40
+ }
41
+ }
@@ -0,0 +1,290 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ import '../status-looks/ox-figure-status-looks.js';
3
+ import { css, html, nothing } from 'lit';
4
+ import { customElement, state } from 'lit/decorators.js';
5
+ import { resolveFigureStatus, resolveLegend } from '@hatiolab/things-scene';
6
+ import { i18next } from '@operato/i18n';
7
+ import { OxPropertyEditor } from '@operato/property-editor';
8
+ import { isFigureColour } from '@hatiolab/figure-model';
9
+ import { issueSentence } from '../status-looks/ox-figure-status-looks.js';
10
+ import { issuesByRow, looksAt, offeredGroupsOf, offeredInputsOf, templatePlaceOf, withNewTemplate, writeLooksAt } from '../status-looks/status-looks.js';
11
+ const OWN = '#own';
12
+ /**
13
+ * 「상태 표현」 on the board's property panel for a figure with status ports (ADR-0051 2.3, §8): the template this
14
+ * placement shows its codes through -- the board's default, one of the board's named templates, or its own -- and,
15
+ * per port, the code the data gives now and which source answered it (the app's legend, the placement's template, the
16
+ * board's). Below, the template's looks to read and change: colour, effect, a value for each state input the ports
17
+ * offer with its unit and range, the clip of a port's motion group. What the figure did not take is said by the field
18
+ * that gave it.
19
+ *
20
+ * The property is the placement's `statusTemplate`; a look of a board template is written on the board, in the same
21
+ * undoable change. The figure checks each look when it shows it (things-scene); this section reads what it said.
22
+ */
23
+ let OxPropertyEditorFigureStatus = class OxPropertyEditorFigureStatus extends OxPropertyEditor {
24
+ constructor() {
25
+ super(...arguments);
26
+ this.naming = null;
27
+ this.refresh = () => this.requestUpdate();
28
+ /*
29
+ Whether the selected figure was asked for since the value last came. The panel answers inside an undoable change,
30
+ and each answer leaves a snapshot to undo to even when nothing changed: the figure is asked for when the panel gives
31
+ a value (a new selection makes a new section), not again for each code or template the figure says changed.
32
+ */
33
+ this.asked = false;
34
+ }
35
+ static { this.styles = [
36
+ ...OxPropertyEditor.styles,
37
+ css `
38
+ [body] {
39
+ grid-column: 1 / -1;
40
+ display: grid;
41
+ gap: 6px;
42
+ font-size: var(--ui-t-small, 11.5px);
43
+ }
44
+ [choose] {
45
+ display: flex;
46
+ gap: 4px;
47
+ align-items: center;
48
+ }
49
+ [choose] select,
50
+ [choose] input {
51
+ flex: 1;
52
+ min-width: 0;
53
+ }
54
+ [choose] button,
55
+ [ports] button {
56
+ height: 24px;
57
+ padding: 0 8px;
58
+ font: inherit;
59
+ color: var(--md-sys-color-primary);
60
+ border: none;
61
+ border-radius: 6px;
62
+ background: transparent;
63
+ cursor: pointer;
64
+ white-space: nowrap;
65
+ }
66
+ [choose] button:hover {
67
+ background: var(--md-sys-color-surface-container-high);
68
+ }
69
+ ul {
70
+ margin: 0;
71
+ padding: 0;
72
+ list-style: none;
73
+ display: grid;
74
+ gap: 2px;
75
+ }
76
+ li {
77
+ display: flex;
78
+ flex-wrap: wrap;
79
+ gap: 0 6px;
80
+ align-items: baseline;
81
+ }
82
+ li [meta] {
83
+ margin-left: auto;
84
+ display: flex;
85
+ gap: 4px;
86
+ align-items: baseline;
87
+ }
88
+ [source] {
89
+ padding: 0 4px;
90
+ border-radius: 4px;
91
+ background: var(--md-sys-color-surface-container-high);
92
+ color: var(--md-sys-color-on-surface-variant);
93
+ }
94
+ [swatch] {
95
+ display: inline-block;
96
+ width: 10px;
97
+ height: 10px;
98
+ border-radius: 2px;
99
+ border: 1px solid var(--md-sys-color-outline-variant);
100
+ vertical-align: middle;
101
+ }
102
+ [hint] {
103
+ width: 100%;
104
+ margin: 0;
105
+ color: var(--md-sys-color-on-surface-variant);
106
+ }
107
+ [warn] {
108
+ width: 100%;
109
+ margin: 0;
110
+ color: var(--md-sys-color-error);
111
+ }
112
+ ox-figure-status-looks {
113
+ --status-looks-card-min: 100%;
114
+ }
115
+ `
116
+ ]; }
117
+ disconnectedCallback() {
118
+ super.disconnectedCallback();
119
+ this.watch(undefined);
120
+ }
121
+ willUpdate(changed) {
122
+ if (changed.has('value'))
123
+ this.asked = false;
124
+ }
125
+ editorTemplate(value, spec) {
126
+ const figure = this.asked ? this.watched?.figure : this.selectedFigure();
127
+ this.asked = true;
128
+ const inputs = figure?.figureInputs;
129
+ this.watch(figure);
130
+ if (!figure || !inputs)
131
+ return html `<div body><p hint>${i18next.t('figure.text.status-select-one')}</p></div>`;
132
+ const asset = inputs.asset;
133
+ const board = figure.rootModel?.state ?? {};
134
+ const place = templatePlaceOf(value, board);
135
+ const looks = looksAt(place, value, board);
136
+ const source = place.at === 'placement' || (place.at === 'named' && place.chosenBy === 'placement') ? 'placement' : place.at === 'none' ? undefined : 'board';
137
+ const ports = asset.dataInterface?.ports ?? [];
138
+ const issues = figure._realObject?.statusIssues ?? [];
139
+ const rowOf = (code) => {
140
+ const found = resolveLegend(code, looks);
141
+ return found === undefined ? undefined : Object.keys(looks).find(row => looks[row] === found);
142
+ };
143
+ const now = {};
144
+ const answers = ports.map(port => {
145
+ const code = inputs.data.status[port.id];
146
+ const found = code === undefined ? undefined : resolveFigureStatus(figure, port, code);
147
+ const row = found && found.source === source ? rowOf(code) : undefined;
148
+ if (row !== undefined)
149
+ now[row] = [...(now[row] ?? []), port.label];
150
+ return { port, code, found };
151
+ });
152
+ const groups = offeredGroupsOf(asset);
153
+ return html `<div body>
154
+ ${this.renderChooser(value, board, place)}
155
+ <ul ports>
156
+ ${answers.map(a => this.renderPort(a.port, a.code, a.found, issues))}
157
+ </ul>
158
+ ${answers.some(a => a.found) && !figure._realObject ? html `<p hint>${i18next.t('figure.text.status-checked-in-3d')}</p>` : nothing}
159
+ <ox-figure-status-looks
160
+ .looks=${looks}
161
+ .inputs=${offeredInputsOf(asset)}
162
+ .clips=${[...new Set(groups.flatMap(g => g.clips))]}
163
+ effects
164
+ color-optional
165
+ .now=${now}
166
+ .issues=${issuesByRow(issues, source, rowOf)}
167
+ @looks-change=${(e) => this.writeLooks(place, e.detail.looks)}
168
+ ></ox-figure-status-looks>
169
+ </div>`;
170
+ }
171
+ /** Which template: the board's default, one of the board's named ones, or the placement's own; a new named one. */
172
+ renderChooser(value, board, place) {
173
+ const names = Object.keys(board.statusTemplates ?? {});
174
+ const chosen = typeof value === 'string' ? value : value && typeof value === 'object' ? OWN : '';
175
+ if (typeof value === 'string' && value && !names.includes(value))
176
+ names.push(value);
177
+ const boardDefault = typeof board.statusTemplate === 'string' ? board.statusTemplate : undefined;
178
+ if (this.naming !== null)
179
+ return html `<div choose>
180
+ <input
181
+ aria-label=${i18next.t('figure.label.status-template-name')}
182
+ placeholder=${i18next.t('figure.label.status-template-name')}
183
+ .value=${this.naming}
184
+ @input=${(e) => (this.naming = e.target.value)}
185
+ @keydown=${(e) => e.key === 'Enter' && this.createTemplate(board)}
186
+ />
187
+ <button ?disabled=${!withNewTemplate(board, this.naming)} @click=${() => this.createTemplate(board)}>${i18next.t('figure.button.status-template-create')}</button>
188
+ <button @click=${() => (this.naming = null)}>${i18next.t('figure.button.status-template-cancel')}</button>
189
+ </div>`;
190
+ return html `<div choose>
191
+ <select data-template aria-label=${i18next.t('figure.label.status-template')}>
192
+ <option value="" ?selected=${chosen === ''}>
193
+ ${i18next.t('figure.label.status-template-board')}${boardDefault ? ` · ${boardDefault}` : place.at === 'none' ? ` · ${i18next.t('figure.label.status-template-none')}` : ''}
194
+ </option>
195
+ ${names.map(name => html `<option value=${name} ?selected=${chosen === name}>
196
+ ${name}${board.statusTemplates?.[name] ? '' : ` · ${i18next.t('figure.label.status-template-none')}`}
197
+ </option>`)}
198
+ ${chosen === OWN ? html `<option value=${OWN} selected>${i18next.t('figure.label.status-template-own')}</option>` : nothing}
199
+ </select>
200
+ <button @click=${() => (this.naming = '')}>${i18next.t('figure.button.status-template-new')}</button>
201
+ </div>`;
202
+ }
203
+ renderPort(port, code, found, issues) {
204
+ const own = issues.filter(i => i.port === port.id && i.source === 'resolver');
205
+ return html `<li>
206
+ <span>${port.label}</span>
207
+ <span meta>
208
+ ${code === undefined ? html `<span hint>${i18next.t('figure.text.status-no-code')}</span>` : html `<b>${code}</b>`}
209
+ ${found
210
+ ? html `${found.source === 'resolver' ? lookSummary(found.look) : nothing}<span source>${i18next.t('figure.label.status-source-' + found.source)}</span>`
211
+ : code !== undefined
212
+ ? html `<span source>${i18next.t('figure.label.status-source-none')}</span>`
213
+ : nothing}
214
+ </span>
215
+ ${found?.source === 'resolver' ? html `<p hint>${i18next.t('figure.text.status-resolver-note')}</p>` : nothing}
216
+ ${own.map(issue => html `<p warn>${issueSentence(issue)}</p>`)}
217
+ </li>`;
218
+ }
219
+ _valueChanged(e) {
220
+ e.stopPropagation();
221
+ const select = e.target;
222
+ if (!select.hasAttribute?.('data-template'))
223
+ return;
224
+ if (select.value === OWN)
225
+ return;
226
+ this.value = select.value || undefined;
227
+ this.dispatchEvent(new CustomEvent('change', { bubbles: true, composed: true }));
228
+ this.observe(this.value);
229
+ }
230
+ /** The looks written where the template lives: the placement's own value through the panel, a board's on the board. */
231
+ writeLooks(place, looks) {
232
+ this.withSelected(figure => {
233
+ const board = figure.rootModel?.state ?? {};
234
+ const write = writeLooksAt(place, looks, this.value, board);
235
+ if (write.board)
236
+ figure.rootModel?.set(write.board);
237
+ if (write.placement)
238
+ figure.set({ statusTemplate: write.placement });
239
+ });
240
+ this.requestUpdate();
241
+ }
242
+ /** A new named template on the board, chosen for this placement, in one undoable change. */
243
+ createTemplate(board) {
244
+ const name = (this.naming ?? '').trim();
245
+ const templates = withNewTemplate(board, name);
246
+ if (!templates)
247
+ return;
248
+ this.withSelected(figure => {
249
+ figure.rootModel?.set(templates);
250
+ figure.set({ statusTemplate: name });
251
+ });
252
+ this.naming = null;
253
+ }
254
+ selectedFigure() {
255
+ let figure;
256
+ this.withSelected(f => (figure = f), false);
257
+ return figure;
258
+ }
259
+ /** The one selected figure, given to `use` inside the panel's undoable change; none for a selection of several. */
260
+ withSelected(use, write = true) {
261
+ let selected;
262
+ this.dispatchEvent(new CustomEvent('i-need-selected', { bubbles: true, composed: true, detail: { callback: (s) => ((selected = s), write && s?.length === 1 && use(s[0])) } }));
263
+ if (!write && selected?.length === 1)
264
+ use(selected[0]);
265
+ }
266
+ /* The data's codes and the board's templates change outside this section (live data, undo): it reads them again. */
267
+ watch(figure) {
268
+ if (this.watched?.figure === figure)
269
+ return;
270
+ this.watched?.figure.off?.('change', this.refresh);
271
+ this.watched?.board?.off?.('change', this.refresh);
272
+ this.watched = figure ? { figure, board: figure.rootModel } : undefined;
273
+ figure?.on?.('change', this.refresh);
274
+ figure?.rootModel?.on?.('change', this.refresh);
275
+ }
276
+ };
277
+ __decorate([
278
+ state(),
279
+ __metadata("design:type", Object)
280
+ ], OxPropertyEditorFigureStatus.prototype, "naming", void 0);
281
+ OxPropertyEditorFigureStatus = __decorate([
282
+ customElement('ox-property-editor-figure-status')
283
+ ], OxPropertyEditorFigureStatus);
284
+ export { OxPropertyEditorFigureStatus };
285
+ /** A look the app's legend gave, read only: its colour and its values. */
286
+ function lookSummary(look) {
287
+ const values = look.values && typeof look.values === 'object' ? Object.entries(look.values).map(([k, v]) => `${k} ${v}`) : [];
288
+ return html `${isFigureColour(look.color) ? html `<span swatch style="background:${look.color}" title=${look.color}></span>` : nothing}${values.length ? html `<span>${values.join(' · ')}</span>` : nothing}`;
289
+ }
290
+ //# sourceMappingURL=ox-property-editor-figure-status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ox-property-editor-figure-status.js","sourceRoot":"","sources":["../../client/editors/ox-property-editor-figure-status.ts"],"names":[],"mappings":"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","sourcesContent":["import '../status-looks/ox-figure-status-looks.js'\n\nimport { css, html, nothing, type PropertyValues } from 'lit'\nimport { customElement, state } from 'lit/decorators.js'\n\nimport { resolveFigureStatus, resolveLegend } from '@hatiolab/things-scene'\nimport { i18next } from '@operato/i18n'\nimport { OxPropertyEditor, type PropertySpec } from '@operato/property-editor'\nimport { isFigureColour, type FigureAsset, type FigureStatusPort } from '@hatiolab/figure-model'\n\nimport { issueSentence } from '../status-looks/ox-figure-status-looks.js'\nimport {\n issuesByRow,\n looksAt,\n offeredGroupsOf,\n offeredInputsOf,\n templatePlaceOf,\n withNewTemplate,\n writeLooksAt,\n type BoardTemplates,\n type StatusIssue,\n type StatusLook,\n type StatusLooks,\n type TemplatePlace\n} from '../status-looks/status-looks.js'\n\n/** The parts of a placed figure the section reads and writes: things-scene's FigureInstance, as the property panel holds it. */\ninterface PlacedFigure {\n state?: { statusTemplate?: unknown }\n set(props: Record<string, unknown>): void\n on?(event: string, listener: (...args: unknown[]) => void): void\n off?(event: string, listener: (...args: unknown[]) => void): void\n rootModel?: PlacedFigure & { state?: BoardTemplates }\n figureInputs?: { asset: FigureAsset; data: { status: Record<string, string> } }\n /** The 3D object, when the board draws in 3D: what its status ports did not take (ADR-0051 2.3, 5). */\n _realObject?: { statusIssues?: StatusIssue[] }\n}\n\nconst OWN = '#own'\n\n/**\n * 「상태 표현」 on the board's property panel for a figure with status ports (ADR-0051 2.3, §8): the template this\n * placement shows its codes through -- the board's default, one of the board's named templates, or its own -- and,\n * per port, the code the data gives now and which source answered it (the app's legend, the placement's template, the\n * board's). Below, the template's looks to read and change: colour, effect, a value for each state input the ports\n * offer with its unit and range, the clip of a port's motion group. What the figure did not take is said by the field\n * that gave it.\n *\n * The property is the placement's `statusTemplate`; a look of a board template is written on the board, in the same\n * undoable change. The figure checks each look when it shows it (things-scene); this section reads what it said.\n */\n@customElement('ox-property-editor-figure-status')\nexport class OxPropertyEditorFigureStatus extends OxPropertyEditor {\n static styles = [\n ...OxPropertyEditor.styles,\n css`\n [body] {\n grid-column: 1 / -1;\n display: grid;\n gap: 6px;\n font-size: var(--ui-t-small, 11.5px);\n }\n [choose] {\n display: flex;\n gap: 4px;\n align-items: center;\n }\n [choose] select,\n [choose] input {\n flex: 1;\n min-width: 0;\n }\n [choose] button,\n [ports] 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 [choose] button:hover {\n background: var(--md-sys-color-surface-container-high);\n }\n ul {\n margin: 0;\n padding: 0;\n list-style: none;\n display: grid;\n gap: 2px;\n }\n li {\n display: flex;\n flex-wrap: wrap;\n gap: 0 6px;\n align-items: baseline;\n }\n li [meta] {\n margin-left: auto;\n display: flex;\n gap: 4px;\n align-items: baseline;\n }\n [source] {\n padding: 0 4px;\n border-radius: 4px;\n background: var(--md-sys-color-surface-container-high);\n color: var(--md-sys-color-on-surface-variant);\n }\n [swatch] {\n display: inline-block;\n width: 10px;\n height: 10px;\n border-radius: 2px;\n border: 1px solid var(--md-sys-color-outline-variant);\n vertical-align: middle;\n }\n [hint] {\n width: 100%;\n margin: 0;\n color: var(--md-sys-color-on-surface-variant);\n }\n [warn] {\n width: 100%;\n margin: 0;\n color: var(--md-sys-color-error);\n }\n ox-figure-status-looks {\n --status-looks-card-min: 100%;\n }\n `\n ]\n\n @state() private naming: string | null = null\n\n private watched?: { figure: PlacedFigure; board?: PlacedFigure }\n private readonly refresh = () => this.requestUpdate()\n /*\n Whether the selected figure was asked for since the value last came. The panel answers inside an undoable change,\n and each answer leaves a snapshot to undo to even when nothing changed: the figure is asked for when the panel gives\n a value (a new selection makes a new section), not again for each code or template the figure says changed.\n */\n private asked = false\n\n disconnectedCallback() {\n super.disconnectedCallback()\n this.watch(undefined)\n }\n\n willUpdate(changed: PropertyValues<this>) {\n if (changed.has('value')) this.asked = false\n }\n\n editorTemplate(value: unknown, spec: PropertySpec) {\n const figure = this.asked ? this.watched?.figure : this.selectedFigure()\n this.asked = true\n const inputs = figure?.figureInputs\n this.watch(figure)\n if (!figure || !inputs) return html`<div body><p hint>${i18next.t('figure.text.status-select-one')}</p></div>`\n\n const asset = inputs.asset\n const board: BoardTemplates = figure.rootModel?.state ?? {}\n const place = templatePlaceOf(value, board)\n const looks = looksAt(place, value, board)\n const source = place.at === 'placement' || (place.at === 'named' && place.chosenBy === 'placement') ? 'placement' : place.at === 'none' ? undefined : 'board'\n const ports = asset.dataInterface?.ports ?? []\n const issues = figure._realObject?.statusIssues ?? []\n const rowOf = (code: string) => {\n const found = resolveLegend(code, looks)\n return found === undefined ? undefined : Object.keys(looks).find(row => looks[row] === found)\n }\n\n const now: Record<string, string[]> = {}\n const answers = ports.map(port => {\n const code = inputs.data.status[port.id]\n const found = code === undefined ? undefined : resolveFigureStatus(figure, port, code)\n const row = found && found.source === source ? rowOf(code!) : undefined\n if (row !== undefined) now[row] = [...(now[row] ?? []), port.label]\n return { port, code, found }\n })\n const groups = offeredGroupsOf(asset)\n\n return html`<div body>\n ${this.renderChooser(value, board, place)}\n <ul ports>\n ${answers.map(a => this.renderPort(a.port, a.code, a.found, issues))}\n </ul>\n ${answers.some(a => a.found) && !figure._realObject ? html`<p hint>${i18next.t('figure.text.status-checked-in-3d')}</p>` : nothing}\n <ox-figure-status-looks\n .looks=${looks}\n .inputs=${offeredInputsOf(asset)}\n .clips=${[...new Set(groups.flatMap(g => g.clips))]}\n effects\n color-optional\n .now=${now}\n .issues=${issuesByRow(issues, source, rowOf)}\n @looks-change=${(e: CustomEvent<{ looks: StatusLooks }>) => this.writeLooks(place, e.detail.looks)}\n ></ox-figure-status-looks>\n </div>`\n }\n\n /** Which template: the board's default, one of the board's named ones, or the placement's own; a new named one. */\n private renderChooser(value: unknown, board: BoardTemplates, place: TemplatePlace) {\n const names = Object.keys(board.statusTemplates ?? {})\n const chosen = typeof value === 'string' ? value : value && typeof value === 'object' ? OWN : ''\n if (typeof value === 'string' && value && !names.includes(value)) names.push(value)\n const boardDefault = typeof board.statusTemplate === 'string' ? board.statusTemplate : undefined\n if (this.naming !== null)\n return html`<div choose>\n <input\n aria-label=${i18next.t('figure.label.status-template-name')}\n placeholder=${i18next.t('figure.label.status-template-name')}\n .value=${this.naming}\n @input=${(e: Event) => (this.naming = (e.target as HTMLInputElement).value)}\n @keydown=${(e: KeyboardEvent) => e.key === 'Enter' && this.createTemplate(board)}\n />\n <button ?disabled=${!withNewTemplate(board, this.naming)} @click=${() => this.createTemplate(board)}>${i18next.t('figure.button.status-template-create')}</button>\n <button @click=${() => (this.naming = null)}>${i18next.t('figure.button.status-template-cancel')}</button>\n </div>`\n return html`<div choose>\n <select data-template aria-label=${i18next.t('figure.label.status-template')}>\n <option value=\"\" ?selected=${chosen === ''}>\n ${i18next.t('figure.label.status-template-board')}${boardDefault ? ` · ${boardDefault}` : place.at === 'none' ? ` · ${i18next.t('figure.label.status-template-none')}` : ''}\n </option>\n ${names.map(\n name =>\n html`<option value=${name} ?selected=${chosen === name}>\n ${name}${board.statusTemplates?.[name] ? '' : ` · ${i18next.t('figure.label.status-template-none')}`}\n </option>`\n )}\n ${chosen === OWN ? html`<option value=${OWN} selected>${i18next.t('figure.label.status-template-own')}</option>` : nothing}\n </select>\n <button @click=${() => (this.naming = '')}>${i18next.t('figure.button.status-template-new')}</button>\n </div>`\n }\n\n private renderPort(port: FigureStatusPort, code: string | undefined, found: { look: StatusLook; source: string } | undefined, issues: readonly StatusIssue[]) {\n const own = issues.filter(i => i.port === port.id && i.source === 'resolver')\n return html`<li>\n <span>${port.label}</span>\n <span meta>\n ${code === undefined ? html`<span hint>${i18next.t('figure.text.status-no-code')}</span>` : html`<b>${code}</b>`}\n ${found\n ? html`${found.source === 'resolver' ? lookSummary(found.look) : nothing}<span source>${i18next.t('figure.label.status-source-' + found.source)}</span>`\n : code !== undefined\n ? html`<span source>${i18next.t('figure.label.status-source-none')}</span>`\n : nothing}\n </span>\n ${found?.source === 'resolver' ? html`<p hint>${i18next.t('figure.text.status-resolver-note')}</p>` : nothing}\n ${own.map(issue => html`<p warn>${issueSentence(issue)}</p>`)}\n </li>`\n }\n\n override _valueChanged(e: Event) {\n e.stopPropagation()\n const select = e.target as HTMLSelectElement\n if (!select.hasAttribute?.('data-template')) return\n if (select.value === OWN) return\n this.value = select.value || undefined\n this.dispatchEvent(new CustomEvent('change', { bubbles: true, composed: true }))\n this.observe(this.value)\n }\n\n /** The looks written where the template lives: the placement's own value through the panel, a board's on the board. */\n private writeLooks(place: TemplatePlace, looks: StatusLooks) {\n this.withSelected(figure => {\n const board: BoardTemplates = figure.rootModel?.state ?? {}\n const write = writeLooksAt(place, looks, this.value, board)\n if (write.board) figure.rootModel?.set(write.board as Record<string, unknown>)\n if (write.placement) figure.set({ statusTemplate: write.placement })\n })\n this.requestUpdate()\n }\n\n /** A new named template on the board, chosen for this placement, in one undoable change. */\n private createTemplate(board: BoardTemplates) {\n const name = (this.naming ?? '').trim()\n const templates = withNewTemplate(board, name)\n if (!templates) return\n this.withSelected(figure => {\n figure.rootModel?.set(templates as Record<string, unknown>)\n figure.set({ statusTemplate: name })\n })\n this.naming = null\n }\n\n private selectedFigure(): PlacedFigure | undefined {\n let figure: PlacedFigure | undefined\n this.withSelected(f => (figure = f), false)\n return figure\n }\n\n /** The one selected figure, given to `use` inside the panel's undoable change; none for a selection of several. */\n private withSelected(use: (figure: PlacedFigure) => void, write = true) {\n let selected: unknown[] | undefined\n this.dispatchEvent(new CustomEvent('i-need-selected', { bubbles: true, composed: true, detail: { callback: (s: unknown[]) => ((selected = s), write && s?.length === 1 && use(s[0] as PlacedFigure)) } }))\n if (!write && selected?.length === 1) use(selected[0] as PlacedFigure)\n }\n\n /* The data's codes and the board's templates change outside this section (live data, undo): it reads them again. */\n private watch(figure: PlacedFigure | undefined) {\n if (this.watched?.figure === figure) return\n this.watched?.figure.off?.('change', this.refresh)\n this.watched?.board?.off?.('change', this.refresh)\n this.watched = figure ? { figure, board: figure.rootModel } : undefined\n figure?.on?.('change', this.refresh)\n figure?.rootModel?.on?.('change', this.refresh)\n }\n}\n\n/** A look the app's legend gave, read only: its colour and its values. */\nfunction lookSummary(look: StatusLook) {\n const values = look.values && typeof look.values === 'object' ? Object.entries(look.values).map(([k, v]) => `${k} ${v}`) : []\n return html`${isFigureColour(look.color) ? html`<span swatch style=\"background:${look.color}\" title=${look.color}></span>` : nothing}${values.length ? html`<span>${values.join(' · ')}</span>` : nothing}`\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ox-property-editor-figure-status': OxPropertyEditorFigureStatus\n }\n}\n"]}
@@ -1,12 +1,14 @@
1
1
  /** One line of the domain's type map, as the tray reads it. */
2
2
  export interface FigureTypeMapLine {
3
3
  name: string;
4
- /** Whether the domain draws the name as an item a holder holds (ADR-0155 개정 1 E). */
5
- item?: boolean;
6
4
  release?: {
7
5
  ref: string;
8
6
  name: string;
9
7
  formatSupported: boolean;
8
+ /** Whether the release is tagged as the look of an item a holder holds (ADR-0155 amendment 2). */
9
+ item?: boolean | null;
10
+ /** Whether the figure holds things itself. */
11
+ holder?: boolean | null;
10
12
  assetFormat?: string;
11
13
  dependencies?: Array<{
12
14
  role: string;
@@ -28,10 +30,13 @@ export interface FigurePaletteTemplate {
28
30
  unavailableLabel?: string;
29
31
  unavailableReason?: string;
30
32
  /**
31
- * The domain draws it as an item a holder holds (ADR-0155 개정 1 E). The platform tray offers it all the same
32
- * (ADR-0123 결정 11); a modeller whose boards place items only by data leaves it out (fmsim's, where items are carriers).
33
+ * The release is tagged as the look of an item a holder holds (ADR-0155 amendment 2). The platform tray offers it all
34
+ * the same (ADR-0123 결정 11); a modeller whose boards place items only by data leaves out an item that holds nothing
35
+ * (fmsim's, where items are carriers). An item that holds -- a reel cart an AGV carries -- is still placed by hand.
33
36
  */
34
37
  item: boolean;
38
+ /** The figure holds things itself. */
39
+ holder: boolean;
35
40
  }
36
41
  export interface FigurePaletteGroup {
37
42
  name: 'figure';
@@ -29,7 +29,8 @@ export function figurePaletteGroupOf(lines, { contextPath, t }) {
29
29
  icon: thumbnail ? `${contextPath}/figure-library-file/${thumbnail}` : undefined,
30
30
  /* No box: placed, the figure takes the size it is made at through the drawing's scale (ADR-0144 2.3). */
31
31
  model: { type: line.name, left: 0, top: 0 },
32
- item: !!line.item,
32
+ item: !!release.item,
33
+ holder: !!release.holder,
33
34
  ...(!release.formatSupported && {
34
35
  unavailableLabel: t('figure-library.text.format-unsupported'),
35
36
  unavailableReason: t('figure-library.text.cannot-use-format', { format: release.assetFormat })
@@ -1 +1 @@
1
- {"version":3,"file":"figure-palette-group.js","sourceRoot":"","sources":["../client/figure-palette-group.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAwCH,2FAA2F;AAC3F,MAAM,UAAU,oBAAoB,CAAC,KAAmC;IACtE,OAAO,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACnF,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAClC,KAAmC,EACnC,EAAE,WAAW,EAAE,CAAC,EAA0F;IAE1G,OAAO;QACL,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,CAAC,CAAC,oCAAoC,CAAC;QACpD,IAAI,EAAE,EAAE;QACR,MAAM,EAAE,eAAe;QACvB,SAAS,EAAE,KAAK;aACb,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC;aAC5B,GAAG,CAAC,IAAI,CAAC,EAAE;YACV,MAAM,OAAO,GAAG,IAAI,CAAC,OAAQ,CAAA;YAC7B,MAAM,SAAS,GAAG,CAAC,OAAO,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,EAAE,IAAI,CAAA;YACtF,OAAO;gBACL,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,WAAW,EAAE,OAAO,CAAC,IAAI;gBACzB,KAAK,EAAE,QAAiB;gBACxB,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,WAAW,wBAAwB,SAAS,EAAE,CAAC,CAAC,CAAC,SAAS;gBAC/E,yGAAyG;gBACzG,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE;gBAC3C,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI;gBACjB,GAAG,CAAC,CAAC,OAAO,CAAC,eAAe,IAAI;oBAC9B,gBAAgB,EAAE,CAAC,CAAC,wCAAwC,CAAC;oBAC7D,iBAAiB,EAAE,CAAC,CAAC,uCAAuC,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC;iBAC/F,CAAC;aACH,CAAA;QACH,CAAC,CAAC;KACL,CAAA;AACH,CAAC","sourcesContent":["/*\n * The modeller tray's \"Figure\" group, from the domain's figure type map (ADR-0114): one template per line, with the\n * release it draws with. A line whose format this server cannot read is shown dimmed with its reason and cannot be\n * placed. Pure: the lines and the words come in, the group goes out -- `figure-palette.ts` asks the server.\n */\n\n/** One line of the domain's type map, as the tray reads it. */\nexport interface FigureTypeMapLine {\n name: string\n /** Whether the domain draws the name as an item a holder holds (ADR-0155 개정 1 E). */\n item?: boolean\n release?: {\n ref: string\n name: string\n formatSupported: boolean\n assetFormat?: string\n dependencies?: Array<{ role: string; hash: string }>\n } | null\n}\n\nexport interface FigurePaletteTemplate {\n type: string\n description: string\n group: 'figure'\n /** The release's thumbnail; a modeller's tray template always has the field, undefined when there is none. */\n icon: string | undefined\n model: { type: string; left: number; top: number }\n unavailableLabel?: string\n unavailableReason?: string\n /**\n * The domain draws it as an item a holder holds (ADR-0155 개정 1 E). The platform tray offers it all the same\n * (ADR-0123 결정 11); a modeller whose boards place items only by data leaves it out (fmsim's, where items are carriers).\n */\n item: boolean\n}\n\nexport interface FigurePaletteGroup {\n name: 'figure'\n description: string\n icon: string\n symbol: string\n templates: FigurePaletteTemplate[]\n}\n\n/** The lines a board can place now: those with a release in a format this server reads. */\nexport function placeableFigureTypes(lines: readonly FigureTypeMapLine[]): string[] {\n return lines.filter(line => line.release?.formatSupported).map(line => line.name)\n}\n\n/**\n * The tray group. `contextPath` is where this server's figure files are served from; `t` the app's translator.\n * A line with no release has nothing to draw and is left out.\n */\nexport function figurePaletteGroupOf(\n lines: readonly FigureTypeMapLine[],\n { contextPath, t }: { contextPath: string; t: (key: string, options?: Record<string, unknown>) => string }\n): FigurePaletteGroup {\n return {\n name: 'figure',\n description: t('figure-library.palette.description'),\n icon: '',\n symbol: 'deployed_code',\n templates: lines\n .filter(line => line.release)\n .map(line => {\n const release = line.release!\n const thumbnail = (release.dependencies ?? []).find(d => d.role === 'thumbnail')?.hash\n return {\n type: line.name,\n description: release.name,\n group: 'figure' as const,\n icon: thumbnail ? `${contextPath}/figure-library-file/${thumbnail}` : undefined,\n /* No box: placed, the figure takes the size it is made at through the drawing's scale (ADR-0144 2.3). */\n model: { type: line.name, left: 0, top: 0 },\n item: !!line.item,\n ...(!release.formatSupported && {\n unavailableLabel: t('figure-library.text.format-unsupported'),\n unavailableReason: t('figure-library.text.cannot-use-format', { format: release.assetFormat })\n })\n }\n })\n }\n}\n"]}
1
+ {"version":3,"file":"figure-palette-group.js","sourceRoot":"","sources":["../client/figure-palette-group.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA6CH,2FAA2F;AAC3F,MAAM,UAAU,oBAAoB,CAAC,KAAmC;IACtE,OAAO,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACnF,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAClC,KAAmC,EACnC,EAAE,WAAW,EAAE,CAAC,EAA0F;IAE1G,OAAO;QACL,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,CAAC,CAAC,oCAAoC,CAAC;QACpD,IAAI,EAAE,EAAE;QACR,MAAM,EAAE,eAAe;QACvB,SAAS,EAAE,KAAK;aACb,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC;aAC5B,GAAG,CAAC,IAAI,CAAC,EAAE;YACV,MAAM,OAAO,GAAG,IAAI,CAAC,OAAQ,CAAA;YAC7B,MAAM,SAAS,GAAG,CAAC,OAAO,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,EAAE,IAAI,CAAA;YACtF,OAAO;gBACL,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,WAAW,EAAE,OAAO,CAAC,IAAI;gBACzB,KAAK,EAAE,QAAiB;gBACxB,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,WAAW,wBAAwB,SAAS,EAAE,CAAC,CAAC,CAAC,SAAS;gBAC/E,yGAAyG;gBACzG,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE;gBAC3C,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI;gBACpB,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM;gBACxB,GAAG,CAAC,CAAC,OAAO,CAAC,eAAe,IAAI;oBAC9B,gBAAgB,EAAE,CAAC,CAAC,wCAAwC,CAAC;oBAC7D,iBAAiB,EAAE,CAAC,CAAC,uCAAuC,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC;iBAC/F,CAAC;aACH,CAAA;QACH,CAAC,CAAC;KACL,CAAA;AACH,CAAC","sourcesContent":["/*\n * The modeller tray's \"Figure\" group, from the domain's figure type map (ADR-0114): one template per line, with the\n * release it draws with. A line whose format this server cannot read is shown dimmed with its reason and cannot be\n * placed. Pure: the lines and the words come in, the group goes out -- `figure-palette.ts` asks the server.\n */\n\n/** One line of the domain's type map, as the tray reads it. */\nexport interface FigureTypeMapLine {\n name: string\n release?: {\n ref: string\n name: string\n formatSupported: boolean\n /** Whether the release is tagged as the look of an item a holder holds (ADR-0155 amendment 2). */\n item?: boolean | null\n /** Whether the figure holds things itself. */\n holder?: boolean | null\n assetFormat?: string\n dependencies?: Array<{ role: string; hash: string }>\n } | null\n}\n\nexport interface FigurePaletteTemplate {\n type: string\n description: string\n group: 'figure'\n /** The release's thumbnail; a modeller's tray template always has the field, undefined when there is none. */\n icon: string | undefined\n model: { type: string; left: number; top: number }\n unavailableLabel?: string\n unavailableReason?: string\n /**\n * The release is tagged as the look of an item a holder holds (ADR-0155 amendment 2). The platform tray offers it all\n * the same (ADR-0123 결정 11); a modeller whose boards place items only by data leaves out an item that holds nothing\n * (fmsim's, where items are carriers). An item that holds -- a reel cart an AGV carries -- is still placed by hand.\n */\n item: boolean\n /** The figure holds things itself. */\n holder: boolean\n}\n\nexport interface FigurePaletteGroup {\n name: 'figure'\n description: string\n icon: string\n symbol: string\n templates: FigurePaletteTemplate[]\n}\n\n/** The lines a board can place now: those with a release in a format this server reads. */\nexport function placeableFigureTypes(lines: readonly FigureTypeMapLine[]): string[] {\n return lines.filter(line => line.release?.formatSupported).map(line => line.name)\n}\n\n/**\n * The tray group. `contextPath` is where this server's figure files are served from; `t` the app's translator.\n * A line with no release has nothing to draw and is left out.\n */\nexport function figurePaletteGroupOf(\n lines: readonly FigureTypeMapLine[],\n { contextPath, t }: { contextPath: string; t: (key: string, options?: Record<string, unknown>) => string }\n): FigurePaletteGroup {\n return {\n name: 'figure',\n description: t('figure-library.palette.description'),\n icon: '',\n symbol: 'deployed_code',\n templates: lines\n .filter(line => line.release)\n .map(line => {\n const release = line.release!\n const thumbnail = (release.dependencies ?? []).find(d => d.role === 'thumbnail')?.hash\n return {\n type: line.name,\n description: release.name,\n group: 'figure' as const,\n icon: thumbnail ? `${contextPath}/figure-library-file/${thumbnail}` : undefined,\n /* No box: placed, the figure takes the size it is made at through the drawing's scale (ADR-0144 2.3). */\n model: { type: line.name, left: 0, top: 0 },\n item: !!release.item,\n holder: !!release.holder,\n ...(!release.formatSupported && {\n unavailableLabel: t('figure-library.text.format-unsupported'),\n unavailableReason: t('figure-library.text.cannot-use-format', { format: release.assetFormat })\n })\n }\n })\n }\n}\n"]}
@@ -14,11 +14,12 @@ const TYPE_MAP = gql `
14
14
  query {
15
15
  figureTypeMap {
16
16
  name
17
- item
18
17
  release {
19
18
  ref
20
19
  name
21
20
  formatSupported
21
+ item
22
+ holder
22
23
  assetFormat
23
24
  dependencies
24
25
  }
@@ -1 +1 @@
1
- {"version":3,"file":"figure-palette.js","sourceRoot":"","sources":["../client/figure-palette.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,GAAG,MAAM,aAAa,CAAA;AAE7B,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAE5C,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAmD,MAAM,2BAA2B,CAAA;AAEvI,cAAc,2BAA2B,CAAA;AAEzC,MAAM,QAAQ,GAAG,GAAG,CAAA;;;;;;;;;;;;;;CAcnB,CAAA;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,aAAkD;IAC5F,IAAI,CAAC;QACH,MAAM,KAAK,GAAwB,CAAC,MAAM,MAAM,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,aAAa,IAAI,EAAE,CAAA;QACnI;;;UAGE;QACF,MAAM,SAAS,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAA;QAC7C,IAAI,SAAS,CAAC,MAAM;YAAE,MAAM,mBAAmB,CAAC,EAAE,UAAU,EAAE,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAA;QAElG,MAAM,EAAE,WAAW,EAAE,GAAG,WAAW,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;QACtD,aAAa,CAAC,oBAAoB,CAAC,KAAK,EAAE,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAA;IAC3G,CAAC;IAAC,MAAM,CAAC;QACP,4FAA4F;IAC9F,CAAC;AACH,CAAC","sourcesContent":["/*\n * The figures this board server imported (ADR-0114), in a board modeller's tray. Every app whose boards place library\n * figures calls this once from its bootstrap and hands it its modeller's `registerGroup` -- the tray belongs to the\n * modeller the app uses, and an app may carry its own (fmsim).\n */\nimport gql from 'graphql-tag'\n\nimport { resolveUnknownTypes } from '@hatiolab/things-scene'\nimport { client } from '@operato/graphql'\nimport { i18next } from '@operato/i18n'\nimport { getPathInfo } from '@operato/utils'\n\nimport { figurePaletteGroupOf, placeableFigureTypes, type FigurePaletteGroup, type FigureTypeMapLine } from './figure-palette-group.js'\n\nexport * from './figure-palette-group.js'\n\nconst TYPE_MAP = gql`\n query {\n figureTypeMap {\n name\n item\n release {\n ref\n name\n formatSupported\n assetFormat\n dependencies\n }\n }\n }\n`\n\n/**\n * Asks the type map, registers the figures that can be placed, and gives the tray its \"Figure\" group. A server with no\n * figure library, or a user with no right to read it, gets no group and no error: the tray simply has none.\n */\nexport async function registerFigurePalette(registerGroup: (group: FigurePaletteGroup) => void): Promise<void> {\n try {\n const lines: FigureTypeMapLine[] = (await client.query({ query: TYPE_MAP, fetchPolicy: 'network-only' })).data?.figureTypeMap ?? []\n /*\n A figure placed from the tray must already be registered: the scene resolves types only when a board opens, and\n a type nobody registered is placed as the stand-in that cannot move. The figure provider registers them now.\n */\n const placeable = placeableFigureTypes(lines)\n if (placeable.length) await resolveUnknownTypes({ components: placeable.map(type => ({ type })) })\n\n const { contextPath } = getPathInfo(location.pathname)\n registerGroup(figurePaletteGroupOf(lines, { contextPath, t: (key, options) => i18next.t(key, options) }))\n } catch {\n /* No figure library on this server or no right to read it: the tray has no Figure group. */\n }\n}\n"]}
1
+ {"version":3,"file":"figure-palette.js","sourceRoot":"","sources":["../client/figure-palette.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,GAAG,MAAM,aAAa,CAAA;AAE7B,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAE5C,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAmD,MAAM,2BAA2B,CAAA;AAEvI,cAAc,2BAA2B,CAAA;AAEzC,MAAM,QAAQ,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;CAenB,CAAA;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,aAAkD;IAC5F,IAAI,CAAC;QACH,MAAM,KAAK,GAAwB,CAAC,MAAM,MAAM,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,aAAa,IAAI,EAAE,CAAA;QACnI;;;UAGE;QACF,MAAM,SAAS,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAA;QAC7C,IAAI,SAAS,CAAC,MAAM;YAAE,MAAM,mBAAmB,CAAC,EAAE,UAAU,EAAE,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAA;QAElG,MAAM,EAAE,WAAW,EAAE,GAAG,WAAW,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;QACtD,aAAa,CAAC,oBAAoB,CAAC,KAAK,EAAE,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAA;IAC3G,CAAC;IAAC,MAAM,CAAC;QACP,4FAA4F;IAC9F,CAAC;AACH,CAAC","sourcesContent":["/*\n * The figures this board server imported (ADR-0114), in a board modeller's tray. Every app whose boards place library\n * figures calls this once from its bootstrap and hands it its modeller's `registerGroup` -- the tray belongs to the\n * modeller the app uses, and an app may carry its own (fmsim).\n */\nimport gql from 'graphql-tag'\n\nimport { resolveUnknownTypes } from '@hatiolab/things-scene'\nimport { client } from '@operato/graphql'\nimport { i18next } from '@operato/i18n'\nimport { getPathInfo } from '@operato/utils'\n\nimport { figurePaletteGroupOf, placeableFigureTypes, type FigurePaletteGroup, type FigureTypeMapLine } from './figure-palette-group.js'\n\nexport * from './figure-palette-group.js'\n\nconst TYPE_MAP = gql`\n query {\n figureTypeMap {\n name\n release {\n ref\n name\n formatSupported\n item\n holder\n assetFormat\n dependencies\n }\n }\n }\n`\n\n/**\n * Asks the type map, registers the figures that can be placed, and gives the tray its \"Figure\" group. A server with no\n * figure library, or a user with no right to read it, gets no group and no error: the tray simply has none.\n */\nexport async function registerFigurePalette(registerGroup: (group: FigurePaletteGroup) => void): Promise<void> {\n try {\n const lines: FigureTypeMapLine[] = (await client.query({ query: TYPE_MAP, fetchPolicy: 'network-only' })).data?.figureTypeMap ?? []\n /*\n A figure placed from the tray must already be registered: the scene resolves types only when a board opens, and\n a type nobody registered is placed as the stand-in that cannot move. The figure provider registers them now.\n */\n const placeable = placeableFigureTypes(lines)\n if (placeable.length) await resolveUnknownTypes({ components: placeable.map(type => ({ type })) })\n\n const { contextPath } = getPathInfo(location.pathname)\n registerGroup(figurePaletteGroupOf(lines, { contextPath, t: (key, options) => i18next.t(key, options) }))\n } catch {\n /* No figure library on this server or no right to read it: the tray has no Figure group. */\n }\n}\n"]}
@@ -14,3 +14,11 @@ export declare function valueOf(rows: ReadonlyArray<ItemTypeRow>): {
14
14
  };
15
15
  /** What does not hold, by row: the issues of things-scene's rule, each on the rows (of those written) it names. */
16
16
  export declare function rowIssues(rows: ReadonlyArray<ItemTypeRow>): Map<number, ItemTypeIssue[]>;
17
+ /**
18
+ * What the figure picker shows for each figure: its display name alone, or with its full name when another figure shows
19
+ * the same display name, and the full name when it has none. The full name stays in the picker's tooltip.
20
+ */
21
+ export declare function figureChoiceLabels(figures: ReadonlyArray<{
22
+ name: string;
23
+ display?: string | null;
24
+ }>): Map<string, string>;
@@ -55,4 +55,15 @@ export function rowIssues(rows) {
55
55
  }
56
56
  return byRow;
57
57
  }
58
+ /**
59
+ * What the figure picker shows for each figure: its display name alone, or with its full name when another figure shows
60
+ * the same display name, and the full name when it has none. The full name stays in the picker's tooltip.
61
+ */
62
+ export function figureChoiceLabels(figures) {
63
+ const shown = (f) => (f.display && f.display.trim() ? f.display : f.name);
64
+ const count = new Map();
65
+ for (const f of figures)
66
+ count.set(shown(f), (count.get(shown(f)) ?? 0) + 1);
67
+ return new Map(figures.map(f => [f.name, count.get(shown(f)) > 1 && shown(f) !== f.name ? `${shown(f)} (${f.name})` : shown(f)]));
68
+ }
58
69
  //# sourceMappingURL=item-types-rows.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"item-types-rows.js","sourceRoot":"","sources":["../../client/item-types/item-types-rows.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,aAAa,EAAsB,MAAM,wBAAwB,CAAA;AAS1E,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAgB,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAA;AAE/E,MAAM,IAAI,GAAG,CAAC,CAAU,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;AAE7E,yHAAyH;AACzH,MAAM,UAAU,MAAM,CAAC,KAAc;IACnC,IAAI,CAAC,GAAG,KAAK,CAAA;IACb,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;QAC1B,IAAI,CAAC;YACH,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;QACnB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,CAAA;QACX,CAAC;IACH,CAAC;IACD,MAAM,KAAK,GAAG,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAE,CAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAE,CAAS,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAA;IACnG,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAA;AACvG,CAAC;AAED,qEAAqE;AACrE,MAAM,UAAU,OAAO,CAAC,IAAgC;IACtD,OAAO;QACL,KAAK,EAAE,IAAI;aACR,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;aACxD,GAAG,CAAC,CAAC,CAAC,EAAE;YACP,MAAM,IAAI,GAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;YAClC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE;gBAAE,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAA;YACrC,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE;gBAAE,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAA;YAClD,OAAO,IAAI,CAAA;QACb,CAAC,CAAC;KACL,CAAA;AACH,CAAC;AAED,mHAAmH;AACnH,MAAM,UAAU,SAAS,CAAC,IAAgC;IACxD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAA;IAChH,MAAM,EAAE,MAAM,EAAE,GAAG,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAA;IAC/C,MAAM,KAAK,GAAG,IAAI,GAAG,EAA2B,CAAA;IAChD,MAAM,GAAG,GAAG,CAAC,EAAU,EAAE,KAAoB,EAAE,EAAE;QAC/C,MAAM,GAAG,GAAG,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;QAC5B,IAAI,GAAG,KAAK,SAAS;YAAE,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,CAAA;IAC3E,CAAC,CAAA;IACD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,IAAI,IAAI,KAAK,IAAI,OAAO,KAAK,CAAC,EAAE,KAAK,QAAQ;YAAE,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAA;aAClE,IAAI,IAAI,IAAI,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAAE,KAAK,MAAM,EAAE,IAAI,KAAK,CAAC,EAAE;gBAAE,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,CAAA;IAC9F,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC","sourcesContent":["/*\n * The item type table as the editor shows it (ADR-0155): one row per type, each cell as typed. The value a theme of\n * type item-types (fmsim: carrier-types) keeps is `{ types: [{ code, name, figure }] }` -- a type has no size\n * (amendment 1); what holds is judged by things-scene's one rule (readItemTypes), so the editor and every scene read a\n * table the same way.\n */\nimport { readItemTypes, type ItemTypeIssue } from '@hatiolab/things-scene'\n\n/** One row as typed. */\nexport interface ItemTypeRow {\n code: string\n name: string\n figure: string\n}\n\nexport const emptyRow = (): ItemTypeRow => ({ code: '', name: '', figure: '' })\n\nconst text = (v: unknown) => (v === undefined || v === null ? '' : String(v))\n\n/** The rows of a theme's value; a value given as text (a store that keeps text) is read as JSON. Anything else: none. */\nexport function rowsOf(value: unknown): ItemTypeRow[] {\n let v = value\n if (typeof v === 'string') {\n try {\n v = JSON.parse(v)\n } catch {\n return []\n }\n }\n const types = v && typeof v === 'object' && Array.isArray((v as any).types) ? (v as any).types : []\n return types.map((t: any) => ({ code: text(t?.code), name: text(t?.name), figure: text(t?.figure) }))\n}\n\n/** The value the rows make. Rows with nothing typed are left out. */\nexport function valueOf(rows: ReadonlyArray<ItemTypeRow>): { types: any[] } {\n return {\n types: rows\n .filter(r => Object.values(r).some(c => c.trim() !== ''))\n .map(r => {\n const type: any = { code: r.code }\n if (r.name.trim()) type.name = r.name\n if (r.figure.trim()) type.figure = r.figure.trim()\n return type\n })\n }\n}\n\n/** What does not hold, by row: the issues of things-scene's rule, each on the rows (of those written) it names. */\nexport function rowIssues(rows: ReadonlyArray<ItemTypeRow>): Map<number, ItemTypeIssue[]> {\n const written = rows.map((r, i) => [r, i] as const).filter(([r]) => Object.values(r).some(c => c.trim() !== ''))\n const { issues } = readItemTypes(valueOf(rows))\n const byRow = new Map<number, ItemTypeIssue[]>()\n const add = (at: number, issue: ItemTypeIssue) => {\n const row = written[at]?.[1]\n if (row !== undefined) byRow.set(row, [...(byRow.get(row) ?? []), issue])\n }\n for (const issue of issues) {\n if ('at' in issue && typeof issue.at === 'number') add(issue.at, issue)\n else if ('at' in issue && Array.isArray(issue.at)) for (const at of issue.at) add(at, issue)\n }\n return byRow\n}\n"]}
1
+ {"version":3,"file":"item-types-rows.js","sourceRoot":"","sources":["../../client/item-types/item-types-rows.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * The item type table as the editor shows it (ADR-0155): one row per type, each cell as typed. The value a theme of\n * type item-types (fmsim: carrier-types) keeps is `{ types: [{ code, name, figure }] }` -- a type has no size\n * (amendment 1); what holds is judged by things-scene's one rule (readItemTypes), so the editor and every scene read a\n * table the same way.\n */\nimport { readItemTypes, type ItemTypeIssue } from '@hatiolab/things-scene'\n\n/** One row as typed. */\nexport interface ItemTypeRow {\n code: string\n name: string\n figure: string\n}\n\nexport const emptyRow = (): ItemTypeRow => ({ code: '', name: '', figure: '' })\n\nconst text = (v: unknown) => (v === undefined || v === null ? '' : String(v))\n\n/** The rows of a theme's value; a value given as text (a store that keeps text) is read as JSON. Anything else: none. */\nexport function rowsOf(value: unknown): ItemTypeRow[] {\n let v = value\n if (typeof v === 'string') {\n try {\n v = JSON.parse(v)\n } catch {\n return []\n }\n }\n const types = v && typeof v === 'object' && Array.isArray((v as any).types) ? (v as any).types : []\n return types.map((t: any) => ({ code: text(t?.code), name: text(t?.name), figure: text(t?.figure) }))\n}\n\n/** The value the rows make. Rows with nothing typed are left out. */\nexport function valueOf(rows: ReadonlyArray<ItemTypeRow>): { types: any[] } {\n return {\n types: rows\n .filter(r => Object.values(r).some(c => c.trim() !== ''))\n .map(r => {\n const type: any = { code: r.code }\n if (r.name.trim()) type.name = r.name\n if (r.figure.trim()) type.figure = r.figure.trim()\n return type\n })\n }\n}\n\n/** What does not hold, by row: the issues of things-scene's rule, each on the rows (of those written) it names. */\nexport function rowIssues(rows: ReadonlyArray<ItemTypeRow>): Map<number, ItemTypeIssue[]> {\n const written = rows.map((r, i) => [r, i] as const).filter(([r]) => Object.values(r).some(c => c.trim() !== ''))\n const { issues } = readItemTypes(valueOf(rows))\n const byRow = new Map<number, ItemTypeIssue[]>()\n const add = (at: number, issue: ItemTypeIssue) => {\n const row = written[at]?.[1]\n if (row !== undefined) byRow.set(row, [...(byRow.get(row) ?? []), issue])\n }\n for (const issue of issues) {\n if ('at' in issue && typeof issue.at === 'number') add(issue.at, issue)\n else if ('at' in issue && Array.isArray(issue.at)) for (const at of issue.at) add(at, issue)\n }\n return byRow\n}\n\n/**\n * What the figure picker shows for each figure: its display name alone, or with its full name when another figure shows\n * the same display name, and the full name when it has none. The full name stays in the picker's tooltip.\n */\nexport function figureChoiceLabels(figures: ReadonlyArray<{ name: string; display?: string | null }>): Map<string, string> {\n const shown = (f: { name: string; display?: string | null }) => (f.display && f.display.trim() ? f.display : f.name)\n const count = new Map<string, number>()\n for (const f of figures) count.set(shown(f), (count.get(shown(f)) ?? 0) + 1)\n return new Map(figures.map(f => [f.name, count.get(shown(f))! > 1 && shown(f) !== f.name ? `${shown(f)} (${f.name})` : shown(f)]))\n}\n"]}
@@ -1,4 +1,7 @@
1
+ import '@material/web/button/filled-button.js';
2
+ import '@material/web/button/text-button.js';
1
3
  import '@material/web/icon/icon.js';
4
+ import '@operato/popup/ox-popup-actions.js';
2
5
  import { LitElement } from 'lit';
3
6
  import { type ItemTypeRow } from './item-types-rows.js';
4
7
  export declare class OxItemTypesInput extends LitElement {
@@ -8,11 +11,12 @@ export declare class OxItemTypesInput extends LitElement {
8
11
  confirmCallback?: (rows: ItemTypeRow[]) => void;
9
12
  /** The domain's item figures; null until they are read, empty when the library cannot be read or marks none. */
10
13
  private figures;
11
- /** Thumbnails that could not be drawn: an empty box in their place, not a broken image. */
14
+ /** Thumbnails that could not be drawn: the empty mark in their place, not a broken image. */
12
15
  private unreadThumbnails;
13
16
  connectedCallback(): void;
14
17
  render(): import("lit-html").TemplateResult<1>;
15
18
  private renderRow;
19
+ updated(): void;
16
20
  private issueText;
17
21
  private onInput;
18
22
  private onAdd;