@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.
- package/dist-client/bootstrap.d.ts +5 -3
- package/dist-client/bootstrap.js +6 -3
- package/dist-client/bootstrap.js.map +1 -1
- package/dist-client/editors/ox-property-editor-figure-status.d.ts +41 -0
- package/dist-client/editors/ox-property-editor-figure-status.js +290 -0
- package/dist-client/editors/ox-property-editor-figure-status.js.map +1 -0
- package/dist-client/figure-palette-group.d.ts +9 -4
- package/dist-client/figure-palette-group.js +2 -1
- package/dist-client/figure-palette-group.js.map +1 -1
- package/dist-client/figure-palette.js +2 -1
- package/dist-client/figure-palette.js.map +1 -1
- package/dist-client/item-types/item-types-rows.d.ts +8 -0
- package/dist-client/item-types/item-types-rows.js +11 -0
- package/dist-client/item-types/item-types-rows.js.map +1 -1
- package/dist-client/item-types/ox-item-types-input.d.ts +5 -1
- package/dist-client/item-types/ox-item-types-input.js +144 -112
- package/dist-client/item-types/ox-item-types-input.js.map +1 -1
- package/dist-client/pages/figure-library-page.js +0 -1
- package/dist-client/pages/figure-library-page.js.map +1 -1
- package/dist-client/status-looks/ox-figure-status-looks.d.ts +58 -0
- package/dist-client/status-looks/ox-figure-status-looks.js +489 -0
- package/dist-client/status-looks/ox-figure-status-looks.js.map +1 -0
- package/dist-client/status-looks/status-looks.d.ts +99 -0
- package/dist-client/status-looks/status-looks.js +134 -0
- package/dist-client/status-looks/status-looks.js.map +1 -0
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-client/viewparts/figure-releases-popup.d.ts +1 -4
- package/dist-client/viewparts/figure-releases-popup.js +3 -21
- package/dist-client/viewparts/figure-releases-popup.js.map +1 -1
- package/dist-server/service/figure-library-release/figure-library-release.d.ts +3 -1
- package/dist-server/service/figure-library-release/figure-library-release.js +11 -1
- package/dist-server/service/figure-library-release/figure-library-release.js.map +1 -1
- package/dist-server/service/figure-library-resolver.d.ts +0 -1
- package/dist-server/service/figure-library-resolver.js +0 -15
- package/dist-server/service/figure-library-resolver.js.map +1 -1
- package/dist-server/service/figure-library-types.js +1 -1
- package/dist-server/service/figure-library-types.js.map +1 -1
- package/dist-server/service/figure-type-map/figure-type-map-entry.d.ts +0 -1
- package/dist-server/service/figure-type-map/figure-type-map-entry.js +1 -12
- package/dist-server/service/figure-type-map/figure-type-map-entry.js.map +1 -1
- package/dist-server/service/library/derived.d.ts +6 -2
- package/dist-server/service/library/derived.js +4 -2
- package/dist-server/service/library/derived.js.map +1 -1
- package/dist-server/service/library/figures.d.ts +2 -2
- package/dist-server/service/library/figures.js +2 -2
- package/dist-server/service/library/figures.js.map +1 -1
- package/dist-server/service/library/type-map.d.ts +0 -5
- package/dist-server/service/library/type-map.js +0 -14
- package/dist-server/service/library/type-map.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -5
- package/translations/en.json +49 -5
- package/translations/es.json +49 -5
- package/translations/ja.json +49 -5
- package/translations/ko.json +49 -5
- package/translations/ms.json +49 -5
- package/translations/zh.json +49 -5
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
const isRecord = (v) => !!v && typeof v === 'object' && !Array.isArray(v);
|
|
2
|
+
/** The state inputs the figure's status ports offer a template, in port order, with the input's unit and range. */
|
|
3
|
+
export function offeredInputsOf(asset) {
|
|
4
|
+
const inputs = new Map(asset.document.model.inputs.map(i => [i.id, i]));
|
|
5
|
+
return (asset.dataInterface?.ports ?? []).flatMap(port => (port.states ?? []).map(({ input, sourceMode }) => {
|
|
6
|
+
const declared = inputs.get(input);
|
|
7
|
+
return {
|
|
8
|
+
input,
|
|
9
|
+
label: asset.stateInputs?.[input]?.label ?? input,
|
|
10
|
+
...(declared?.unit !== undefined ? { unit: declared.unit } : {}),
|
|
11
|
+
...(declared?.min !== undefined ? { min: declared.min } : {}),
|
|
12
|
+
...(declared?.max !== undefined ? { max: declared.max } : {}),
|
|
13
|
+
sourceMode,
|
|
14
|
+
port: port.id,
|
|
15
|
+
portLabel: port.label
|
|
16
|
+
};
|
|
17
|
+
}));
|
|
18
|
+
}
|
|
19
|
+
/** The motion groups the figure's status ports let a template choose a clip of. */
|
|
20
|
+
export function offeredGroupsOf(asset) {
|
|
21
|
+
const groups = new Map((asset.motionGroups ?? []).map(g => [g.id, g]));
|
|
22
|
+
return (asset.dataInterface?.ports ?? []).flatMap(port => {
|
|
23
|
+
const group = port.group !== undefined ? groups.get(port.group) : undefined;
|
|
24
|
+
return group ? [{ id: group.id, label: group.label, clips: [...group.clips], port: port.id }] : [];
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
/** A template's looks as they are stored; anything not a record of records reads as no looks. */
|
|
28
|
+
export function looksOf(states) {
|
|
29
|
+
if (!isRecord(states))
|
|
30
|
+
return {};
|
|
31
|
+
return Object.fromEntries(Object.entries(states).filter(([, look]) => isRecord(look)));
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* One code's look with some parts changed: a part given as undefined is taken away, so the template no longer gives it
|
|
35
|
+
* and the next source does (ADR-0051 2.3, 4). A look left with nothing stays, as a code the template names.
|
|
36
|
+
*/
|
|
37
|
+
export function withLook(looks, code, patch) {
|
|
38
|
+
const look = { ...(looks[code] ?? {}) };
|
|
39
|
+
for (const [part, value] of Object.entries(patch)) {
|
|
40
|
+
if (value === undefined)
|
|
41
|
+
delete look[part];
|
|
42
|
+
else
|
|
43
|
+
look[part] = value;
|
|
44
|
+
}
|
|
45
|
+
return { ...looks, [code]: look };
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* One value of one code's look: a number sets it, undefined takes it away. The values of inputs this figure does not
|
|
49
|
+
* offer -- another figure's, in a table shared by many (ADR-0051 2.3, 9) -- stay as they were.
|
|
50
|
+
*/
|
|
51
|
+
export function withLookValue(looks, code, input, value) {
|
|
52
|
+
const held = looks[code]?.values;
|
|
53
|
+
const values = isRecord(held) ? { ...held } : {};
|
|
54
|
+
if (value === undefined)
|
|
55
|
+
delete values[input];
|
|
56
|
+
else
|
|
57
|
+
values[input] = value;
|
|
58
|
+
return withLook(looks, code, { values: Object.keys(values).length ? values : undefined });
|
|
59
|
+
}
|
|
60
|
+
export function withCode(looks, code) {
|
|
61
|
+
return code in looks ? looks : { ...looks, [code]: {} };
|
|
62
|
+
}
|
|
63
|
+
export function withoutCode(looks, code) {
|
|
64
|
+
const { [code]: _gone, ...rest } = looks;
|
|
65
|
+
return rest;
|
|
66
|
+
}
|
|
67
|
+
/** The inputs some look gives a value to, in the order first met. */
|
|
68
|
+
export function inputsGivenIn(looks) {
|
|
69
|
+
const seen = new Set();
|
|
70
|
+
for (const look of Object.values(looks))
|
|
71
|
+
if (isRecord(look.values))
|
|
72
|
+
for (const input of Object.keys(look.values))
|
|
73
|
+
seen.add(input);
|
|
74
|
+
return [...seen];
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* The template a placement's 「상태 표현」 edits: the one its own `statusTemplate` names or holds, else the board's
|
|
78
|
+
* default. A name with no template behind it is still that name: writing to it makes the template.
|
|
79
|
+
*/
|
|
80
|
+
export function templatePlaceOf(placement, board) {
|
|
81
|
+
if (typeof placement === 'string' && placement)
|
|
82
|
+
return { at: 'named', name: placement, chosenBy: 'placement' };
|
|
83
|
+
if (isRecord(placement))
|
|
84
|
+
return { at: 'placement' };
|
|
85
|
+
const chosen = board.statusTemplate;
|
|
86
|
+
if (typeof chosen === 'string' && chosen)
|
|
87
|
+
return { at: 'named', name: chosen, chosenBy: 'board' };
|
|
88
|
+
if (isRecord(chosen))
|
|
89
|
+
return { at: 'board' };
|
|
90
|
+
return { at: 'none' };
|
|
91
|
+
}
|
|
92
|
+
/** The looks of the template at a place; none yet is no looks. */
|
|
93
|
+
export function looksAt(place, placement, board) {
|
|
94
|
+
const template = place.at === 'placement' ? placement : place.at === 'board' ? board.statusTemplate : place.at === 'named' ? board.statusTemplates?.[place.name] : undefined;
|
|
95
|
+
return looksOf(isRecord(template) ? template.states : undefined);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* What to write so the template at a place holds these looks: the placement's own value, or the board's. A board with
|
|
99
|
+
* no template yet gets its default, held whole. The rest of a template (anything beside `states`) is kept.
|
|
100
|
+
*/
|
|
101
|
+
export function writeLooksAt(place, looks, placement, board) {
|
|
102
|
+
const kept = (t) => ({ ...(isRecord(t) ? t : {}), states: looks });
|
|
103
|
+
if (place.at === 'placement')
|
|
104
|
+
return { placement: kept(placement) };
|
|
105
|
+
if (place.at === 'named')
|
|
106
|
+
return { board: { statusTemplates: { ...(board.statusTemplates ?? {}), [place.name]: kept(board.statusTemplates?.[place.name]) } } };
|
|
107
|
+
return { board: { statusTemplate: kept(place.at === 'board' ? board.statusTemplate : undefined) } };
|
|
108
|
+
}
|
|
109
|
+
/** The board's templates with a new, empty one by this name; undefined when the name is empty or taken. */
|
|
110
|
+
export function withNewTemplate(board, name) {
|
|
111
|
+
const trimmed = name.trim();
|
|
112
|
+
if (!trimmed || (board.statusTemplates && trimmed in board.statusTemplates))
|
|
113
|
+
return undefined;
|
|
114
|
+
return { statusTemplates: { ...(board.statusTemplates ?? {}), [trimmed]: { states: {} } } };
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* 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
|
|
118
|
+
* up (`lookedUp`, the code's own or `default`). Issues of another source than the table shown are not the table's.
|
|
119
|
+
*/
|
|
120
|
+
export function issuesByRow(issues, source, rowOf) {
|
|
121
|
+
const rows = new Map();
|
|
122
|
+
if (!source)
|
|
123
|
+
return rows;
|
|
124
|
+
for (const issue of issues) {
|
|
125
|
+
if (issue.source !== source)
|
|
126
|
+
continue;
|
|
127
|
+
const row = rowOf(issue.code);
|
|
128
|
+
if (row === undefined)
|
|
129
|
+
continue;
|
|
130
|
+
rows.set(row, [...(rows.get(row) ?? []), issue]);
|
|
131
|
+
}
|
|
132
|
+
return rows;
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=status-looks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status-looks.js","sourceRoot":"","sources":["../../client/status-looks/status-looks.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * A status template as a person reads and writes it (ADR-0051 2.3): each code's look -- a colour, an effect, a value for\n * each state input a figure's status port offers, the clip of its motion group -- and where the template lives. The\n * board's 「상태 표현」 section and fmsim's legend editor both write looks through these.\n *\n * Nothing here decides how a look is taken: things-scene looks a code up (`resolveFigureStatus`, `resolveLegend`) and\n * checks each part, and says what it did not take on the placed figure's `statusIssues`. This only reads the asset for\n * what a template may give, and writes a look the way the template holds it. Kept apart from the elements so it is\n * tested without a board.\n */\nimport type { FigureAsset } from '@hatiolab/figure-model'\n\nexport interface StatusLookEffect {\n kind: 'blink' | 'glow'\n hz?: number\n}\n\n/** One code's look, as a template holds it. Any part may be missing; a value is in its input's own unit. */\nexport interface StatusLook {\n color?: string\n effect?: StatusLookEffect | null\n values?: Record<string, number>\n clip?: string\n}\n\n/** A template's states: code → look, `default` for a code the template does not name. */\nexport type StatusLooks = Record<string, StatusLook>\n\n/** A state input a template may give a value to: the input, its name, unit and range, and the port that offers it. */\nexport interface LookInput {\n input: string\n label: string\n unit?: string\n min?: number\n max?: number\n sourceMode?: 'observed' | 'commanded'\n port?: string\n portLabel?: string\n}\n\n/** A motion group a template may choose a clip of, through the port that holds it. */\nexport interface LookGroup {\n id: string\n label: string\n clips: string[]\n port: string\n}\n\n/** What one status port of a placed figure said of the last look it was given, as things-scene's `statusIssues` holds it. */\nexport interface StatusIssue {\n port: string\n code: string\n source: 'resolver' | 'placement' | 'board'\n target: 'state' | 'motion-clip' | 'color' | 'effect' | 'values' | 'resolver'\n id?: string\n reason: string\n value: unknown\n}\n\nconst isRecord = (v: unknown): v is Record<string, unknown> => !!v && typeof v === 'object' && !Array.isArray(v)\n\n/** The state inputs the figure's status ports offer a template, in port order, with the input's unit and range. */\nexport function offeredInputsOf(asset: FigureAsset): LookInput[] {\n const inputs = new Map(asset.document.model.inputs.map(i => [i.id, i] as const))\n return (asset.dataInterface?.ports ?? []).flatMap(port =>\n (port.states ?? []).map(({ input, sourceMode }) => {\n const declared = inputs.get(input)\n return {\n input,\n label: asset.stateInputs?.[input]?.label ?? input,\n ...(declared?.unit !== undefined ? { unit: declared.unit } : {}),\n ...(declared?.min !== undefined ? { min: declared.min } : {}),\n ...(declared?.max !== undefined ? { max: declared.max } : {}),\n sourceMode,\n port: port.id,\n portLabel: port.label\n }\n })\n )\n}\n\n/** The motion groups the figure's status ports let a template choose a clip of. */\nexport function offeredGroupsOf(asset: FigureAsset): LookGroup[] {\n const groups = new Map((asset.motionGroups ?? []).map(g => [g.id, g] as const))\n return (asset.dataInterface?.ports ?? []).flatMap(port => {\n const group = port.group !== undefined ? groups.get(port.group) : undefined\n return group ? [{ id: group.id, label: group.label, clips: [...group.clips], port: port.id }] : []\n })\n}\n\n/** A template's looks as they are stored; anything not a record of records reads as no looks. */\nexport function looksOf(states: unknown): StatusLooks {\n if (!isRecord(states)) return {}\n return Object.fromEntries(Object.entries(states).filter(([, look]) => isRecord(look))) as StatusLooks\n}\n\n/**\n * One code's look with some parts changed: a part given as undefined is taken away, so the template no longer gives it\n * and the next source does (ADR-0051 2.3, 4). A look left with nothing stays, as a code the template names.\n */\nexport function withLook(looks: StatusLooks, code: string, patch: Partial<StatusLook>): StatusLooks {\n const look: StatusLook = { ...(looks[code] ?? {}) }\n for (const [part, value] of Object.entries(patch) as [keyof StatusLook, unknown][]) {\n if (value === undefined) delete look[part]\n else (look as Record<string, unknown>)[part] = value\n }\n return { ...looks, [code]: look }\n}\n\n/**\n * One value of one code's look: a number sets it, undefined takes it away. The values of inputs this figure does not\n * offer -- another figure's, in a table shared by many (ADR-0051 2.3, 9) -- stay as they were.\n */\nexport function withLookValue(looks: StatusLooks, code: string, input: string, value: number | undefined): StatusLooks {\n const held = looks[code]?.values\n const values: Record<string, unknown> = isRecord(held) ? { ...held } : {}\n if (value === undefined) delete values[input]\n else values[input] = value\n return withLook(looks, code, { values: Object.keys(values).length ? (values as Record<string, number>) : undefined })\n}\n\nexport function withCode(looks: StatusLooks, code: string): StatusLooks {\n return code in looks ? looks : { ...looks, [code]: {} }\n}\n\nexport function withoutCode(looks: StatusLooks, code: string): StatusLooks {\n const { [code]: _gone, ...rest } = looks\n return rest\n}\n\n/** The inputs some look gives a value to, in the order first met. */\nexport function inputsGivenIn(looks: StatusLooks): string[] {\n const seen = new Set<string>()\n for (const look of Object.values(looks)) if (isRecord(look.values)) for (const input of Object.keys(look.values)) seen.add(input)\n return [...seen]\n}\n\n/*\n Where a placement's template is: the board's default (the placement chose none), one of the board's named templates,\n or a template the placement holds whole. A board's default is itself a name or a template.\n*/\nexport interface BoardTemplates {\n statusTemplate?: unknown\n statusTemplates?: Record<string, unknown>\n}\n\nexport type TemplatePlace =\n | { at: 'placement' }\n | { at: 'named'; name: string; chosenBy: 'placement' | 'board' }\n | { at: 'board' }\n | { at: 'none' }\n\n/**\n * The template a placement's 「상태 표현」 edits: the one its own `statusTemplate` names or holds, else the board's\n * default. A name with no template behind it is still that name: writing to it makes the template.\n */\nexport function templatePlaceOf(placement: unknown, board: BoardTemplates): TemplatePlace {\n if (typeof placement === 'string' && placement) return { at: 'named', name: placement, chosenBy: 'placement' }\n if (isRecord(placement)) return { at: 'placement' }\n const chosen = board.statusTemplate\n if (typeof chosen === 'string' && chosen) return { at: 'named', name: chosen, chosenBy: 'board' }\n if (isRecord(chosen)) return { at: 'board' }\n return { at: 'none' }\n}\n\n/** The looks of the template at a place; none yet is no looks. */\nexport function looksAt(place: TemplatePlace, placement: unknown, board: BoardTemplates): StatusLooks {\n const template = place.at === 'placement' ? placement : place.at === 'board' ? board.statusTemplate : place.at === 'named' ? board.statusTemplates?.[place.name] : undefined\n return looksOf(isRecord(template) ? template.states : undefined)\n}\n\n/**\n * What to write so the template at a place holds these looks: the placement's own value, or the board's. A board with\n * no template yet gets its default, held whole. The rest of a template (anything beside `states`) is kept.\n */\nexport function writeLooksAt(\n place: TemplatePlace,\n looks: StatusLooks,\n placement: unknown,\n board: BoardTemplates\n): { placement?: Record<string, unknown>; board?: BoardTemplates } {\n const kept = (t: unknown) => ({ ...(isRecord(t) ? t : {}), states: looks })\n if (place.at === 'placement') return { placement: kept(placement) }\n if (place.at === 'named') return { board: { statusTemplates: { ...(board.statusTemplates ?? {}), [place.name]: kept(board.statusTemplates?.[place.name]) } } }\n return { board: { statusTemplate: kept(place.at === 'board' ? board.statusTemplate : undefined) } }\n}\n\n/** The board's templates with a new, empty one by this name; undefined when the name is empty or taken. */\nexport function withNewTemplate(board: BoardTemplates, name: string): BoardTemplates | undefined {\n const trimmed = name.trim()\n if (!trimmed || (board.statusTemplates && trimmed in board.statusTemplates)) return undefined\n return { statusTemplates: { ...(board.statusTemplates ?? {}), [trimmed]: { states: {} } } }\n}\n\n/**\n * 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\n * up (`lookedUp`, the code's own or `default`). Issues of another source than the table shown are not the table's.\n */\nexport function issuesByRow(issues: readonly StatusIssue[], source: StatusIssue['source'] | undefined, rowOf: (code: string) => string | undefined): Map<string, StatusIssue[]> {\n const rows = new Map<string, StatusIssue[]>()\n if (!source) return rows\n for (const issue of issues) {\n if (issue.source !== source) continue\n const row = rowOf(issue.code)\n if (row === undefined) continue\n rows.set(row, [...(rows.get(row) ?? []), issue])\n }\n return rows\n}\n"]}
|