@fmsim/layout-view 2.0.2 → 3.0.0-beta.10
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/board-provider.js +3 -2
- package/dist-client/board-provider.js.map +1 -1
- package/dist-client/bootstrap.d.ts +1 -1
- package/dist-client/bootstrap.js +12 -1
- package/dist-client/bootstrap.js.map +1 -1
- package/dist-client/data-grist/animation-map-editor.d.ts +15 -0
- package/dist-client/data-grist/animation-map-editor.js +81 -17
- package/dist-client/data-grist/animation-map-editor.js.map +1 -1
- package/dist-client/data-grist/color-map-editor.d.ts +6 -0
- package/dist-client/data-grist/color-map-editor.js +41 -0
- package/dist-client/data-grist/color-map-editor.js.map +1 -1
- package/dist-client/data-grist/ox-input-animation-map.d.ts +3 -13
- package/dist-client/data-grist/ox-input-animation-map.js +12 -61
- package/dist-client/data-grist/ox-input-animation-map.js.map +1 -1
- package/dist-client/pages/board-modeller-page.d.ts +2 -0
- package/dist-client/pages/board-modeller-page.js +11 -4
- package/dist-client/pages/board-modeller-page.js.map +1 -1
- package/dist-client/pages/board-viewer-page.js +6 -4
- package/dist-client/pages/board-viewer-page.js.map +1 -1
- package/dist-client/pages/theme/theme-list-page.js +2 -2
- package/dist-client/pages/theme/theme-list-page.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/helps/board-modeller/accessor.ko.md +1 -1
- package/helps/board-modeller/data-binding.ko.md +21 -21
- package/helps/board-modeller/data-spread.ko.md +13 -13
- package/helps/board-modeller/effects/hover-event.ko.md +8 -8
- package/helps/board-modeller/effects/tap-event.ko.md +8 -8
- package/helps/board-modeller/initial-data.ko.md +5 -5
- package/helps/scene/component/popup.ko.md +6 -6
- package/package.json +5 -4
- package/translations/en.json +33 -1
- package/translations/ja.json +34 -2
- package/translations/ko.json +111 -79
- package/translations/ms.json +33 -1
- package/translations/zh.json +35 -3
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import JSON5 from 'json5';
|
|
2
|
-
import { create, error, ReferenceMap } from '@hatiolab/things-scene';
|
|
2
|
+
import { create, error, itemTypesFromThemes, ReferenceMap } from '@hatiolab/things-scene';
|
|
3
3
|
import { DataStorage } from '@fmsim/board';
|
|
4
|
-
import { fetchBoardById } from '@fmsim/api';
|
|
4
|
+
import { fetchBoardById, CARRIER_TYPES_THEME } from '@fmsim/api';
|
|
5
5
|
export function createBoardProvider() {
|
|
6
6
|
var _provider = new ReferenceMap(async (boardId, resolve, reject) => {
|
|
7
7
|
try {
|
|
@@ -30,6 +30,7 @@ export function createBoardProvider() {
|
|
|
30
30
|
scene = create({
|
|
31
31
|
model,
|
|
32
32
|
style,
|
|
33
|
+
itemTypes: itemTypesFromThemes(themes === null || themes === void 0 ? void 0 : themes.items, CARRIER_TYPES_THEME),
|
|
33
34
|
mode: 0,
|
|
34
35
|
refProvider: provider,
|
|
35
36
|
dataStorage: new DataStorage(boardId),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"board-provider.js","sourceRoot":"","sources":["../client/board-provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAS,MAAM,wBAAwB,CAAA;
|
|
1
|
+
{"version":3,"file":"board-provider.js","sourceRoot":"","sources":["../client/board-provider.ts"],"names":[],"mappings":"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","sourcesContent":["import JSON5 from 'json5'\nimport { create, error, itemTypesFromThemes, ReferenceMap, Scene } from '@hatiolab/things-scene'\nimport { DataStorage } from '@fmsim/board'\nimport { fetchBoardById, CARRIER_TYPES_THEME } from '@fmsim/api'\n\nexport function createBoardProvider() {\n var _provider = new ReferenceMap(\n async (boardId, resolve, reject): Promise<any> => {\n try {\n const fetched = await fetchBoardById(boardId)\n const { board, themes } = 'data' in fetched ? fetched.data : fetched || {}\n const style = themes?.items.reduce((style, theme) => {\n try {\n style[theme.name] = typeof theme.value == 'string' ? JSON5.parse(theme.value) : theme.value\n } catch (err) {\n console.error('themes parse error', err)\n }\n return style\n }, {})\n\n if (!board) {\n reject(new Error('Failed to get the requested board.'))\n return\n }\n\n var model = JSON.parse(board.model)\n\n var scene: Scene\n\n try {\n scene = await provider.get(boardId)\n console.warn('Board fetched more than twice.', boardId)\n } catch (e) {\n scene = create({\n model,\n style,\n itemTypes: itemTypesFromThemes(themes?.items, CARRIER_TYPES_THEME),\n mode: 0,\n refProvider: provider as any,\n dataStorage: new DataStorage(boardId),\n handlers: ['mcs-event-handler', 'zoom-handler', 'shift-handler'],\n layers: [{ type: 'scroll-layer' }, { type: 'movement-layer', id: 'movement-layer' }]\n })\n\n // s.app.baseUrl = undefined;\n }\n\n resolve(scene)\n } catch (e) {\n error(e)\n reject(e)\n }\n },\n async (id, ref) => {\n ref.dispose()\n }\n )\n\n return _provider\n}\n\nexport const provider = createBoardProvider()\n"]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import '@fmsim/board/ox-property-editor-board-selector.js';
|
|
2
|
-
export default function bootstrap(): void
|
|
2
|
+
export default function bootstrap(): Promise<void>;
|
package/dist-client/bootstrap.js
CHANGED
|
@@ -4,20 +4,31 @@ import { OxPropertyEditor } from '@operato/property-editor';
|
|
|
4
4
|
import { BoardModeller } from '@fmsim/board/ox-board-modeller.js';
|
|
5
5
|
import { registerDefaultGroups } from '@fmsim/board';
|
|
6
6
|
import { MachineGroups } from '@fmsim/machine';
|
|
7
|
+
import { CARRIER_TYPES_THEME } from '@fmsim/api';
|
|
8
|
+
import { registerFigurePalette } from '@things-factory/figure-library/dist-client/figure-palette.js';
|
|
9
|
+
import { registerItemTypesEditor } from '@things-factory/figure-library/dist-client/item-types/index.js';
|
|
7
10
|
import { ColorMapEditor } from './data-grist/color-map-editor.js';
|
|
8
11
|
import { ColorRangesEditor } from './data-grist/color-ranges-editor.js';
|
|
9
12
|
import { AnimationMapEditor } from './data-grist/animation-map-editor.js';
|
|
10
|
-
export default function bootstrap() {
|
|
13
|
+
export default async function bootstrap() {
|
|
11
14
|
registerRenderer('color-map', OxGristRendererJson5);
|
|
12
15
|
registerRenderer('color-ranges', OxGristRendererJson5);
|
|
13
16
|
registerRenderer('animation-map', OxGristRendererJson5);
|
|
14
17
|
registerEditor('color-map', ColorMapEditor);
|
|
15
18
|
registerEditor('color-ranges', ColorRangesEditor);
|
|
16
19
|
registerEditor('animation-map', AnimationMapEditor);
|
|
20
|
+
/* Carrier types are the domain's table, a theme of type carrier-types (ADR-0155 amendment 1 D) */
|
|
21
|
+
registerItemTypesEditor(CARRIER_TYPES_THEME);
|
|
17
22
|
OxPropertyEditor.register({
|
|
18
23
|
'board-selector': 'ox-property-editor-board-selector'
|
|
19
24
|
});
|
|
20
25
|
MachineGroups.map(group => BoardModeller.registerGroup(group));
|
|
21
26
|
registerDefaultGroups();
|
|
27
|
+
/*
|
|
28
|
+
The figures this server imported (ADR-0114), in the modeller tray; the same group operato-board shows. A figure
|
|
29
|
+
whose release is tagged as an item -- a carrier here -- is not placed on its own: carriers come by data (ADR-0123
|
|
30
|
+
decision 11, ADR-0155 amendment 2 K). An item that holds things itself is placed all the same.
|
|
31
|
+
*/
|
|
32
|
+
await registerFigurePalette(group => BoardModeller.registerGroup(Object.assign(Object.assign({}, group), { templates: group.templates.filter(t => !t.item || t.holder) })));
|
|
22
33
|
}
|
|
23
34
|
//# sourceMappingURL=bootstrap.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../client/bootstrap.ts"],"names":[],"mappings":"AAAA,OAAO,mDAAmD,CAAA;AAE1D,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAC5F,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAA;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../client/bootstrap.ts"],"names":[],"mappings":"AAAA,OAAO,mDAAmD,CAAA;AAE1D,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAC5F,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAA;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAC9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAChD,OAAO,EAAE,qBAAqB,EAAE,MAAM,8DAA8D,CAAA;AACpG,OAAO,EAAE,uBAAuB,EAAE,MAAM,gEAAgE,CAAA;AAExG,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAA;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAA;AACvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAA;AAEzE,MAAM,CAAC,OAAO,CAAC,KAAK,UAAU,SAAS;IACrC,gBAAgB,CAAC,WAAW,EAAE,oBAAoB,CAAC,CAAA;IACnD,gBAAgB,CAAC,cAAc,EAAE,oBAAoB,CAAC,CAAA;IACtD,gBAAgB,CAAC,eAAe,EAAE,oBAAoB,CAAC,CAAA;IAEvD,cAAc,CAAC,WAAW,EAAE,cAAc,CAAC,CAAA;IAC3C,cAAc,CAAC,cAAc,EAAE,iBAAiB,CAAC,CAAA;IACjD,cAAc,CAAC,eAAe,EAAE,kBAAkB,CAAC,CAAA;IACnD,kGAAkG;IAClG,uBAAuB,CAAC,mBAAmB,CAAC,CAAA;IAE5C,gBAAgB,CAAC,QAAQ,CAAC;QACxB,gBAAgB,EAAE,mCAAmC;KACtD,CAAC,CAAA;IAEF,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,aAAa,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAA;IAE9D,qBAAqB,EAAE,CAAA;IAEvB;;;;MAIE;IACF,MAAM,qBAAqB,CAAC,KAAK,CAAC,EAAE,CAAC,aAAa,CAAC,aAAa,iCAAM,KAAK,KAAE,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,MAAM,CAAC,IAAG,CAAC,CAAA;AAC9I,CAAC","sourcesContent":["import '@fmsim/board/ox-property-editor-board-selector.js'\n\nimport { OxGristRendererJson5, registerEditor, registerRenderer } from '@operato/data-grist'\nimport { OxPropertyEditor } from '@operato/property-editor'\nimport { BoardModeller } from '@fmsim/board/ox-board-modeller.js'\nimport { registerDefaultGroups } from '@fmsim/board'\nimport { MachineGroups } from '@fmsim/machine'\nimport { CARRIER_TYPES_THEME } from '@fmsim/api'\nimport { registerFigurePalette } from '@things-factory/figure-library/dist-client/figure-palette.js'\nimport { registerItemTypesEditor } from '@things-factory/figure-library/dist-client/item-types/index.js'\n\nimport { ColorMapEditor } from './data-grist/color-map-editor.js'\nimport { ColorRangesEditor } from './data-grist/color-ranges-editor.js'\nimport { AnimationMapEditor } from './data-grist/animation-map-editor.js'\n\nexport default async function bootstrap() {\n registerRenderer('color-map', OxGristRendererJson5)\n registerRenderer('color-ranges', OxGristRendererJson5)\n registerRenderer('animation-map', OxGristRendererJson5)\n\n registerEditor('color-map', ColorMapEditor)\n registerEditor('color-ranges', ColorRangesEditor)\n registerEditor('animation-map', AnimationMapEditor)\n /* Carrier types are the domain's table, a theme of type carrier-types (ADR-0155 amendment 1 D) */\n registerItemTypesEditor(CARRIER_TYPES_THEME)\n\n OxPropertyEditor.register({\n 'board-selector': 'ox-property-editor-board-selector'\n })\n\n MachineGroups.map(group => BoardModeller.registerGroup(group))\n\n registerDefaultGroups()\n\n /*\n The figures this server imported (ADR-0114), in the modeller tray; the same group operato-board shows. A figure\n whose release is tagged as an item -- a carrier here -- is not placed on its own: carriers come by data (ADR-0123\n decision 11, ADR-0155 amendment 2 K). An item that holds things itself is placed all the same.\n */\n await registerFigurePalette(group => BoardModeller.registerGroup({ ...group, templates: group.templates.filter(t => !t.item || t.holder) }))\n}\n"]}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import './ox-input-animation-map.js';
|
|
2
|
+
import '@things-factory/figure-library/dist-client/legend-looks/ox-legend-looks.js';
|
|
3
|
+
import { LitElement } from 'lit';
|
|
2
4
|
import { OxGristEditor } from '@operato/data-grist';
|
|
3
5
|
export declare class AnimationMapEditor extends OxGristEditor {
|
|
4
6
|
private popup?;
|
|
@@ -8,3 +10,16 @@ export declare class AnimationMapEditor extends OxGristEditor {
|
|
|
8
10
|
_onkeydown(e: KeyboardEvent): void;
|
|
9
11
|
openSelector(): Promise<void>;
|
|
10
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* An animation map edited whole: each code's 2D motion (ox-input-animation-map) and its 3D colour and blink, which a
|
|
15
|
+
* carrier figure's body parts show (ADR-0167 decision 12), with the one legend editor (ox-legend-looks) that board legend
|
|
16
|
+
* themes use. Both edit one value, entry by entry, each keeping what the other wrote.
|
|
17
|
+
*/
|
|
18
|
+
export declare class AnimationMapPopup extends LitElement {
|
|
19
|
+
static styles: import("lit").CSSResult;
|
|
20
|
+
/** code → entry: the 2D motion under `animation`, colour and effect beside it (animationEntriesOf) */
|
|
21
|
+
value: Record<string, Record<string, unknown>>;
|
|
22
|
+
render(): import("lit-html").TemplateResult<1>;
|
|
23
|
+
/** Whether a 2D motion row has no code: the map cannot be kept so (each code is the map's key) */
|
|
24
|
+
hasEmptyKey(): boolean;
|
|
25
|
+
}
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import { __decorate } from "tslib";
|
|
1
|
+
import { __decorate, __metadata } from "tslib";
|
|
2
2
|
import './ox-input-animation-map.js';
|
|
3
|
+
import '@things-factory/figure-library/dist-client/legend-looks/ox-legend-looks.js';
|
|
3
4
|
import JSON5 from 'json5';
|
|
4
|
-
import { html } from 'lit';
|
|
5
|
-
import { customElement } from 'lit/decorators.js';
|
|
5
|
+
import { css, html, LitElement } from 'lit';
|
|
6
|
+
import { customElement, property } from 'lit/decorators.js';
|
|
6
7
|
import { createRef, ref } from 'lit/directives/ref.js';
|
|
7
8
|
import { cloneDeep } from 'lodash-es';
|
|
8
9
|
import { OxGristEditor } from '@operato/data-grist';
|
|
9
10
|
import { i18next } from '@operato/i18n';
|
|
10
11
|
import { openPopup } from '@operato/popup';
|
|
12
|
+
import { animationEntriesOf } from '@fmsim/machine';
|
|
11
13
|
let AnimationMapEditor = class AnimationMapEditor extends OxGristEditor {
|
|
12
14
|
get options() {
|
|
13
15
|
var _a;
|
|
@@ -48,17 +50,16 @@ let AnimationMapEditor = class AnimationMapEditor extends OxGristEditor {
|
|
|
48
50
|
};
|
|
49
51
|
let value;
|
|
50
52
|
try {
|
|
51
|
-
value = !objectified && typeof this.value === 'string' ? JSON5.parse(this.value) : cloneDeep(this.value || {});
|
|
53
|
+
value = animationEntriesOf(!objectified && typeof this.value === 'string' ? JSON5.parse(this.value) : cloneDeep(this.value || {}));
|
|
52
54
|
}
|
|
53
55
|
catch (e) {
|
|
54
56
|
value = {};
|
|
55
57
|
}
|
|
56
|
-
|
|
57
|
-
const editorRef = createRef();
|
|
58
|
+
const popupRef = createRef();
|
|
58
59
|
const onConfirm = () => {
|
|
59
|
-
var _a, _b, _c;
|
|
60
|
+
var _a, _b, _c, _d;
|
|
60
61
|
// key 없이 정의된 애니메이션이 있으면 확인(저장) 불가 — key 는 맵의 식별자.
|
|
61
|
-
if ((
|
|
62
|
+
if ((_a = popupRef.value) === null || _a === void 0 ? void 0 : _a.hasEmptyKey()) {
|
|
62
63
|
document.dispatchEvent(new CustomEvent('notify', {
|
|
63
64
|
detail: {
|
|
64
65
|
level: 'warn',
|
|
@@ -69,8 +70,8 @@ let AnimationMapEditor = class AnimationMapEditor extends OxGristEditor {
|
|
|
69
70
|
}));
|
|
70
71
|
return;
|
|
71
72
|
}
|
|
72
|
-
confirmCallback(
|
|
73
|
-
(
|
|
73
|
+
confirmCallback((_c = (_b = popupRef.value) === null || _b === void 0 ? void 0 : _b.value) !== null && _c !== void 0 ? _c : value);
|
|
74
|
+
(_d = this.popup) === null || _d === void 0 ? void 0 : _d.close();
|
|
74
75
|
};
|
|
75
76
|
const template = html `
|
|
76
77
|
<style>
|
|
@@ -81,12 +82,7 @@ let AnimationMapEditor = class AnimationMapEditor extends OxGristEditor {
|
|
|
81
82
|
</style>
|
|
82
83
|
<div class="animation-map-popup" style="display:flex;flex-direction:row;height:100%;box-sizing:border-box;gap:0;">
|
|
83
84
|
<div style="display:flex;flex-direction:column;flex:2;overflow:hidden;">
|
|
84
|
-
<
|
|
85
|
-
${ref(editorRef)}
|
|
86
|
-
.value=${value}
|
|
87
|
-
@change=${(e) => { latestValue = e.detail; }}
|
|
88
|
-
style="flex:1;overflow:auto;padding:12px 12px 0;"
|
|
89
|
-
></ox-input-animation-map>
|
|
85
|
+
<animation-map-popup ${ref(popupRef)} .value=${value} style="flex:1;overflow:auto;"></animation-map-popup>
|
|
90
86
|
<div style="display:flex;justify-content:flex-end;gap:8px;padding:12px;">
|
|
91
87
|
<button @click=${onConfirm}
|
|
92
88
|
style="padding:6px 16px;background:var(--md-sys-color-primary,#1976d2);color:#fff;border:none;border-radius:4px;cursor:pointer;">
|
|
@@ -98,7 +94,6 @@ let AnimationMapEditor = class AnimationMapEditor extends OxGristEditor {
|
|
|
98
94
|
</button>
|
|
99
95
|
</div>
|
|
100
96
|
</div>
|
|
101
|
-
|
|
102
97
|
<div style="flex:1;padding:12px 16px;overflow:auto;border-left:1px solid var(--md-sys-color-outline-variant,#ddd);
|
|
103
98
|
font-size:12px;line-height:1.6;color:var(--md-sys-color-on-surface-variant,#555);background:var(--md-sys-color-surface-container-low,#f4f4f4);">
|
|
104
99
|
<h3 style="margin:0 0 10px;font-size:15px;font-weight:700;color:var(--md-sys-color-primary,#1976d2);">Animation Types</h3>
|
|
@@ -147,4 +142,73 @@ AnimationMapEditor = __decorate([
|
|
|
147
142
|
customElement('animation-map-editor')
|
|
148
143
|
], AnimationMapEditor);
|
|
149
144
|
export { AnimationMapEditor };
|
|
145
|
+
/**
|
|
146
|
+
* An animation map edited whole: each code's 2D motion (ox-input-animation-map) and its 3D colour and blink, which a
|
|
147
|
+
* carrier figure's body parts show (ADR-0167 decision 12), with the one legend editor (ox-legend-looks) that board legend
|
|
148
|
+
* themes use. Both edit one value, entry by entry, each keeping what the other wrote.
|
|
149
|
+
*/
|
|
150
|
+
let AnimationMapPopup = class AnimationMapPopup extends LitElement {
|
|
151
|
+
constructor() {
|
|
152
|
+
super(...arguments);
|
|
153
|
+
/** code → entry: the 2D motion under `animation`, colour and effect beside it (animationEntriesOf) */
|
|
154
|
+
this.value = {};
|
|
155
|
+
}
|
|
156
|
+
render() {
|
|
157
|
+
return html `
|
|
158
|
+
<h3>${i18next.t('label.animation-2d', { defaultValue: '2D animation' })}</h3>
|
|
159
|
+
<ox-input-animation-map
|
|
160
|
+
.value=${this.value}
|
|
161
|
+
@change=${(e) => {
|
|
162
|
+
e.stopPropagation();
|
|
163
|
+
this.value = animationEntriesOf(e.detail);
|
|
164
|
+
}}
|
|
165
|
+
></ox-input-animation-map>
|
|
166
|
+
<h3>${i18next.t('label.animation-3d-looks', { defaultValue: '3D colour and blink' })}</h3>
|
|
167
|
+
<p>${i18next.t('text.animation-3d-looks', { defaultValue: "Shown on a carrier figure's body parts." })}</p>
|
|
168
|
+
<ox-legend-looks
|
|
169
|
+
.looks=${this.value}
|
|
170
|
+
effects
|
|
171
|
+
color-optional
|
|
172
|
+
no-values
|
|
173
|
+
@looks-change=${(e) => {
|
|
174
|
+
e.stopPropagation();
|
|
175
|
+
this.value = animationEntriesOf(e.detail.looks);
|
|
176
|
+
}}
|
|
177
|
+
></ox-legend-looks>
|
|
178
|
+
`;
|
|
179
|
+
}
|
|
180
|
+
/** Whether a 2D motion row has no code: the map cannot be kept so (each code is the map's key) */
|
|
181
|
+
hasEmptyKey() {
|
|
182
|
+
var _a, _b;
|
|
183
|
+
return !!((_b = (_a = this.renderRoot.querySelector('ox-input-animation-map')) === null || _a === void 0 ? void 0 : _a.hasEmptyKey) === null || _b === void 0 ? void 0 : _b.call(_a));
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
AnimationMapPopup.styles = css `
|
|
187
|
+
:host {
|
|
188
|
+
display: block;
|
|
189
|
+
padding: 12px 12px 0;
|
|
190
|
+
}
|
|
191
|
+
h3 {
|
|
192
|
+
margin: 12px 0 6px;
|
|
193
|
+
font-size: 13px;
|
|
194
|
+
font-weight: 700;
|
|
195
|
+
color: var(--md-sys-color-primary, #1976d2);
|
|
196
|
+
}
|
|
197
|
+
h3:first-child {
|
|
198
|
+
margin-top: 0;
|
|
199
|
+
}
|
|
200
|
+
p {
|
|
201
|
+
margin: 0 0 6px;
|
|
202
|
+
font-size: 12px;
|
|
203
|
+
color: var(--md-sys-color-on-surface-variant, #555);
|
|
204
|
+
}
|
|
205
|
+
`;
|
|
206
|
+
__decorate([
|
|
207
|
+
property({ type: Object }),
|
|
208
|
+
__metadata("design:type", Object)
|
|
209
|
+
], AnimationMapPopup.prototype, "value", void 0);
|
|
210
|
+
AnimationMapPopup = __decorate([
|
|
211
|
+
customElement('animation-map-popup')
|
|
212
|
+
], AnimationMapPopup);
|
|
213
|
+
export { AnimationMapPopup };
|
|
150
214
|
//# sourceMappingURL=animation-map-editor.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"animation-map-editor.js","sourceRoot":"","sources":["../../client/data-grist/animation-map-editor.ts"],"names":[],"mappings":"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","sourcesContent":["import './ox-input-animation-map.js'\n\nimport JSON5 from 'json5'\nimport { html } from 'lit'\nimport { customElement } from 'lit/decorators.js'\nimport { createRef, ref } from 'lit/directives/ref.js'\n\nimport { cloneDeep } from 'lodash-es'\n\nimport { OxGristEditor } from '@operato/data-grist'\nimport { i18next } from '@operato/i18n'\nimport { openPopup, PopupHandle } from '@operato/popup'\n\n@customElement('animation-map-editor')\nexport class AnimationMapEditor extends OxGristEditor {\n private popup?: PopupHandle\n\n get options() {\n const overidable = this.column.record?.options || {}\n\n return {\n name: `Animation : ${this.record.name}`,\n objectified: false,\n ...overidable\n }\n }\n\n get editorTemplate() {\n const value = typeof this.value === 'object' ? JSON5.stringify(this.value) : this.value\n return html`<div tabindex=\"0\">${value || ''}</div>`\n }\n\n _onclick(e: Event): void {\n e.stopPropagation()\n this.openSelector()\n }\n\n _onkeydown(e: KeyboardEvent): void {\n if (e.key === 'Enter') {\n e.stopPropagation()\n this.openSelector()\n }\n }\n\n async openSelector() {\n if (this.popup) {\n delete this.popup\n }\n\n const { name, objectified = false } = this.options || {}\n\n const confirmCallback = (newval: any) => {\n this.dispatchEvent(\n new CustomEvent('field-change', {\n bubbles: true,\n composed: true,\n detail: {\n before: this.value,\n after: !objectified ? JSON5.stringify(newval, null, 2) : newval,\n record: this.record,\n column: this.column,\n row: this.row\n }\n })\n )\n }\n\n let value: any\n try {\n value = !objectified && typeof this.value === 'string' ? JSON5.parse(this.value) : cloneDeep(this.value || {})\n } catch (e) {\n value = {}\n }\n\n let latestValue = value\n\n const editorRef = createRef<any>()\n\n const onConfirm = () => {\n // key 없이 정의된 애니메이션이 있으면 확인(저장) 불가 — key 는 맵의 식별자.\n if (editorRef.value?.hasEmptyKey?.()) {\n document.dispatchEvent(\n new CustomEvent('notify', {\n detail: {\n level: 'warn',\n message: i18next.t('text.animation_key_required', {\n defaultValue: 'Enter a key for each animation definition.'\n })\n }\n })\n )\n return\n }\n confirmCallback(latestValue)\n this.popup?.close()\n }\n\n const template = html`\n <style>\n .animation-map-popup ::-webkit-scrollbar { width: 5px; height: 5px; }\n .animation-map-popup ::-webkit-scrollbar-track { background-color: transparent; }\n .animation-map-popup ::-webkit-scrollbar-thumb { background-color: var(--md-sys-color-outline, #888); border-radius: 0; }\n .animation-map-popup ::-webkit-scrollbar-thumb:hover { background-color: var(--md-sys-color-outline-variant, #aaa); }\n </style>\n <div class=\"animation-map-popup\" style=\"display:flex;flex-direction:row;height:100%;box-sizing:border-box;gap:0;\">\n <div style=\"display:flex;flex-direction:column;flex:2;overflow:hidden;\">\n <ox-input-animation-map\n ${ref(editorRef)}\n .value=${value}\n @change=${(e: CustomEvent) => { latestValue = e.detail }}\n style=\"flex:1;overflow:auto;padding:12px 12px 0;\"\n ></ox-input-animation-map>\n <div style=\"display:flex;justify-content:flex-end;gap:8px;padding:12px;\">\n <button @click=${onConfirm}\n style=\"padding:6px 16px;background:var(--md-sys-color-primary,#1976d2);color:#fff;border:none;border-radius:4px;cursor:pointer;\">\n ${i18next.t('button.confirm') || 'Confirm'}\n </button>\n <button @click=${() => this.popup?.close()}\n style=\"padding:6px 16px;background:var(--md-sys-color-surface-variant,#e0e0e0);color:#333;border:none;border-radius:4px;cursor:pointer;\">\n ${i18next.t('button.cancel') || 'Cancel'}\n </button>\n </div>\n </div>\n\n <div style=\"flex:1;padding:12px 16px;overflow:auto;border-left:1px solid var(--md-sys-color-outline-variant,#ddd);\n font-size:12px;line-height:1.6;color:var(--md-sys-color-on-surface-variant,#555);background:var(--md-sys-color-surface-container-low,#f4f4f4);\">\n <h3 style=\"margin:0 0 10px;font-size:15px;font-weight:700;color:var(--md-sys-color-primary,#1976d2);\">Animation Types</h3>\n <dl style=\"margin:0;padding:0;\">\n <dt style=\"font-weight:600;margin-top:6px;\">Rotation</dt>\n <dd style=\"margin:0 0 4px 8px;\">Theta(°) 각도만큼 회전. 360°이면 1회전.</dd>\n <dt style=\"font-weight:600;margin-top:6px;\">Vibration</dt>\n <dd style=\"margin:0 0 4px 8px;\">Theta(°) 범위 내에서 좌우 진동.</dd>\n <dt style=\"font-weight:600;margin-top:6px;\">Heartbeat</dt>\n <dd style=\"margin:0 0 4px 8px;\">Scale 비율로 확대/축소 반복. 1.2 = 20% 확대.</dd>\n <dt style=\"font-weight:600;margin-top:6px;\">Moving</dt>\n <dd style=\"margin:0 0 4px 8px;\">X, Y 픽셀만큼 이동 후 복귀.</dd>\n <dt style=\"font-weight:600;margin-top:6px;\">Fade</dt>\n <dd style=\"margin:0 0 4px 8px;\">Start/End Alpha(0~1) 사이에서 투명도 변화.</dd>\n </dl>\n\n <h3 style=\"margin:18px 0 10px;font-size:15px;font-weight:700;color:var(--md-sys-color-primary,#1976d2);\">Common Properties</h3>\n <dl style=\"margin:0;padding:0;\">\n <dt style=\"font-weight:600;margin-top:6px;\">Delay</dt>\n <dd style=\"margin:0 0 4px 8px;\">애니메이션 시작 전 대기 시간 (ms).</dd>\n <dt style=\"font-weight:600;margin-top:6px;\">Duration</dt>\n <dd style=\"margin:0 0 4px 8px;\">한 사이클 소요 시간 (ms). 1000 = 1초.</dd>\n <dt style=\"font-weight:600;margin-top:6px;\">Interval</dt>\n <dd style=\"margin:0 0 4px 8px;\">반복 사이 대기 시간 (ms).</dd>\n <dt style=\"font-weight:600;margin-top:6px;\">Delta</dt>\n <dd style=\"margin:0 0 4px 8px;\">보간 함수. linear(균일), quad(가속), circ(원형), back(오버슈트), bounce(바운스), elastic(탄성).</dd>\n <dt style=\"font-weight:600;margin-top:6px;\">Ease</dt>\n <dd style=\"margin:0 0 4px 8px;\">이징 방향. in(시작 느림), out(끝 느림), inout(양쪽 느림).</dd>\n <dt style=\"font-weight:600;margin-top:6px;\">Repeat</dt>\n <dd style=\"margin:0 0 4px 8px;\">체크 시 무한 반복.</dd>\n <dt style=\"font-weight:600;margin-top:6px;\">Autoplay</dt>\n <dd style=\"margin:0 0 4px 8px;\">체크 시 로드 즉시 자동 재생.</dd>\n </dl>\n\n </div>\n </div>\n `\n\n this.popup = openPopup(template, {\n backdrop: true,\n size: 'large',\n title: `${name?.toUpperCase() || 'ANIMATION MAP'}`\n })\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"animation-map-editor.js","sourceRoot":"","sources":["../../client/data-grist/animation-map-editor.ts"],"names":[],"mappings":"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","sourcesContent":["import './ox-input-animation-map.js'\nimport '@things-factory/figure-library/dist-client/legend-looks/ox-legend-looks.js'\n\nimport JSON5 from 'json5'\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\nimport { createRef, ref } from 'lit/directives/ref.js'\n\nimport { cloneDeep } from 'lodash-es'\n\nimport { OxGristEditor } from '@operato/data-grist'\nimport { i18next } from '@operato/i18n'\nimport { openPopup, PopupHandle } from '@operato/popup'\nimport { animationEntriesOf } from '@fmsim/machine'\n\n@customElement('animation-map-editor')\nexport class AnimationMapEditor extends OxGristEditor {\n private popup?: PopupHandle\n\n get options() {\n const overidable = this.column.record?.options || {}\n\n return {\n name: `Animation : ${this.record.name}`,\n objectified: false,\n ...overidable\n }\n }\n\n get editorTemplate() {\n const value = typeof this.value === 'object' ? JSON5.stringify(this.value) : this.value\n return html`<div tabindex=\"0\">${value || ''}</div>`\n }\n\n _onclick(e: Event): void {\n e.stopPropagation()\n this.openSelector()\n }\n\n _onkeydown(e: KeyboardEvent): void {\n if (e.key === 'Enter') {\n e.stopPropagation()\n this.openSelector()\n }\n }\n\n async openSelector() {\n if (this.popup) {\n delete this.popup\n }\n\n const { name, objectified = false } = this.options || {}\n\n const confirmCallback = (newval: any) => {\n this.dispatchEvent(\n new CustomEvent('field-change', {\n bubbles: true,\n composed: true,\n detail: {\n before: this.value,\n after: !objectified ? JSON5.stringify(newval, null, 2) : newval,\n record: this.record,\n column: this.column,\n row: this.row\n }\n })\n )\n }\n\n let value: any\n try {\n value = animationEntriesOf(!objectified && typeof this.value === 'string' ? JSON5.parse(this.value) : cloneDeep(this.value || {}))\n } catch (e) {\n value = {}\n }\n\n const popupRef = createRef<AnimationMapPopup>()\n\n const onConfirm = () => {\n // key 없이 정의된 애니메이션이 있으면 확인(저장) 불가 — key 는 맵의 식별자.\n if (popupRef.value?.hasEmptyKey()) {\n document.dispatchEvent(\n new CustomEvent('notify', {\n detail: {\n level: 'warn',\n message: i18next.t('text.animation_key_required', {\n defaultValue: 'Enter a key for each animation definition.'\n })\n }\n })\n )\n return\n }\n confirmCallback(popupRef.value?.value ?? value)\n this.popup?.close()\n }\n\n const template = html`\n <style>\n .animation-map-popup ::-webkit-scrollbar { width: 5px; height: 5px; }\n .animation-map-popup ::-webkit-scrollbar-track { background-color: transparent; }\n .animation-map-popup ::-webkit-scrollbar-thumb { background-color: var(--md-sys-color-outline, #888); border-radius: 0; }\n .animation-map-popup ::-webkit-scrollbar-thumb:hover { background-color: var(--md-sys-color-outline-variant, #aaa); }\n </style>\n <div class=\"animation-map-popup\" style=\"display:flex;flex-direction:row;height:100%;box-sizing:border-box;gap:0;\">\n <div style=\"display:flex;flex-direction:column;flex:2;overflow:hidden;\">\n <animation-map-popup ${ref(popupRef)} .value=${value} style=\"flex:1;overflow:auto;\"></animation-map-popup>\n <div style=\"display:flex;justify-content:flex-end;gap:8px;padding:12px;\">\n <button @click=${onConfirm}\n style=\"padding:6px 16px;background:var(--md-sys-color-primary,#1976d2);color:#fff;border:none;border-radius:4px;cursor:pointer;\">\n ${i18next.t('button.confirm') || 'Confirm'}\n </button>\n <button @click=${() => this.popup?.close()}\n style=\"padding:6px 16px;background:var(--md-sys-color-surface-variant,#e0e0e0);color:#333;border:none;border-radius:4px;cursor:pointer;\">\n ${i18next.t('button.cancel') || 'Cancel'}\n </button>\n </div>\n </div>\n <div style=\"flex:1;padding:12px 16px;overflow:auto;border-left:1px solid var(--md-sys-color-outline-variant,#ddd);\n font-size:12px;line-height:1.6;color:var(--md-sys-color-on-surface-variant,#555);background:var(--md-sys-color-surface-container-low,#f4f4f4);\">\n <h3 style=\"margin:0 0 10px;font-size:15px;font-weight:700;color:var(--md-sys-color-primary,#1976d2);\">Animation Types</h3>\n <dl style=\"margin:0;padding:0;\">\n <dt style=\"font-weight:600;margin-top:6px;\">Rotation</dt>\n <dd style=\"margin:0 0 4px 8px;\">Theta(°) 각도만큼 회전. 360°이면 1회전.</dd>\n <dt style=\"font-weight:600;margin-top:6px;\">Vibration</dt>\n <dd style=\"margin:0 0 4px 8px;\">Theta(°) 범위 내에서 좌우 진동.</dd>\n <dt style=\"font-weight:600;margin-top:6px;\">Heartbeat</dt>\n <dd style=\"margin:0 0 4px 8px;\">Scale 비율로 확대/축소 반복. 1.2 = 20% 확대.</dd>\n <dt style=\"font-weight:600;margin-top:6px;\">Moving</dt>\n <dd style=\"margin:0 0 4px 8px;\">X, Y 픽셀만큼 이동 후 복귀.</dd>\n <dt style=\"font-weight:600;margin-top:6px;\">Fade</dt>\n <dd style=\"margin:0 0 4px 8px;\">Start/End Alpha(0~1) 사이에서 투명도 변화.</dd>\n </dl>\n\n <h3 style=\"margin:18px 0 10px;font-size:15px;font-weight:700;color:var(--md-sys-color-primary,#1976d2);\">Common Properties</h3>\n <dl style=\"margin:0;padding:0;\">\n <dt style=\"font-weight:600;margin-top:6px;\">Delay</dt>\n <dd style=\"margin:0 0 4px 8px;\">애니메이션 시작 전 대기 시간 (ms).</dd>\n <dt style=\"font-weight:600;margin-top:6px;\">Duration</dt>\n <dd style=\"margin:0 0 4px 8px;\">한 사이클 소요 시간 (ms). 1000 = 1초.</dd>\n <dt style=\"font-weight:600;margin-top:6px;\">Interval</dt>\n <dd style=\"margin:0 0 4px 8px;\">반복 사이 대기 시간 (ms).</dd>\n <dt style=\"font-weight:600;margin-top:6px;\">Delta</dt>\n <dd style=\"margin:0 0 4px 8px;\">보간 함수. linear(균일), quad(가속), circ(원형), back(오버슈트), bounce(바운스), elastic(탄성).</dd>\n <dt style=\"font-weight:600;margin-top:6px;\">Ease</dt>\n <dd style=\"margin:0 0 4px 8px;\">이징 방향. in(시작 느림), out(끝 느림), inout(양쪽 느림).</dd>\n <dt style=\"font-weight:600;margin-top:6px;\">Repeat</dt>\n <dd style=\"margin:0 0 4px 8px;\">체크 시 무한 반복.</dd>\n <dt style=\"font-weight:600;margin-top:6px;\">Autoplay</dt>\n <dd style=\"margin:0 0 4px 8px;\">체크 시 로드 즉시 자동 재생.</dd>\n </dl>\n\n </div>\n </div>\n `\n\n this.popup = openPopup(template, {\n backdrop: true,\n size: 'large',\n title: `${name?.toUpperCase() || 'ANIMATION MAP'}`\n })\n }\n}\n\n/**\n * An animation map edited whole: each code's 2D motion (ox-input-animation-map) and its 3D colour and blink, which a\n * carrier figure's body parts show (ADR-0167 decision 12), with the one legend editor (ox-legend-looks) that board legend\n * themes use. Both edit one value, entry by entry, each keeping what the other wrote.\n */\n@customElement('animation-map-popup')\nexport class AnimationMapPopup extends LitElement {\n static styles = css`\n :host {\n display: block;\n padding: 12px 12px 0;\n }\n h3 {\n margin: 12px 0 6px;\n font-size: 13px;\n font-weight: 700;\n color: var(--md-sys-color-primary, #1976d2);\n }\n h3:first-child {\n margin-top: 0;\n }\n p {\n margin: 0 0 6px;\n font-size: 12px;\n color: var(--md-sys-color-on-surface-variant, #555);\n }\n `\n\n /** code → entry: the 2D motion under `animation`, colour and effect beside it (animationEntriesOf) */\n @property({ type: Object }) value: Record<string, Record<string, unknown>> = {}\n\n render() {\n return html`\n <h3>${i18next.t('label.animation-2d', { defaultValue: '2D animation' })}</h3>\n <ox-input-animation-map\n .value=${this.value}\n @change=${(e: CustomEvent) => {\n e.stopPropagation()\n this.value = animationEntriesOf(e.detail)\n }}\n ></ox-input-animation-map>\n <h3>${i18next.t('label.animation-3d-looks', { defaultValue: '3D colour and blink' })}</h3>\n <p>${i18next.t('text.animation-3d-looks', { defaultValue: \"Shown on a carrier figure's body parts.\" })}</p>\n <ox-legend-looks\n .looks=${this.value}\n effects\n color-optional\n no-values\n @looks-change=${(e: CustomEvent) => {\n e.stopPropagation()\n this.value = animationEntriesOf(e.detail.looks)\n }}\n ></ox-legend-looks>\n `\n }\n\n /** Whether a 2D motion row has no code: the map cannot be kept so (each code is the map's key) */\n hasEmptyKey(): boolean {\n return !!(this.renderRoot.querySelector('ox-input-animation-map') as any)?.hasEmptyKey?.()\n }\n}\n"]}
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
+
import '@things-factory/figure-library/dist-client/legend-looks/legend-looks-editor.js';
|
|
1
2
|
import { OxGristEditorValueMap } from '@operato/grist-editor/ox-grist-editor-value-map.js';
|
|
3
|
+
/**
|
|
4
|
+
* 범례(color-map) 테마의 편집기: 코드마다 색 하나 — 피규어 라이브러리의 범례 편집기(legend-looks-popup)를 색만으로 연다. 캐리어 모양
|
|
5
|
+
* 피규어의 두께는 피규어의 고정 표가 정하므로 범례는 값을 주지 않는다(ADR-0167 결정 12). 항목이 이미 가진 다른 칸은 그대로 남는다.
|
|
6
|
+
*/
|
|
2
7
|
export declare class ColorMapEditor extends OxGristEditorValueMap {
|
|
3
8
|
get options(): any;
|
|
9
|
+
openSelector(): Promise<void>;
|
|
4
10
|
}
|
|
@@ -1,12 +1,53 @@
|
|
|
1
1
|
import { __decorate } from "tslib";
|
|
2
|
+
import '@things-factory/figure-library/dist-client/legend-looks/legend-looks-editor.js';
|
|
3
|
+
import { html } from 'lit';
|
|
2
4
|
import { customElement } from 'lit/decorators.js';
|
|
3
5
|
import { OxGristEditorValueMap } from '@operato/grist-editor/ox-grist-editor-value-map.js';
|
|
6
|
+
import { i18next } from '@operato/i18n';
|
|
7
|
+
import { openPopup } from '@operato/popup';
|
|
8
|
+
import { legendLooksOf, legendOf } from '@things-factory/figure-library/dist-client/legend-looks/legend-looks.js';
|
|
9
|
+
/**
|
|
10
|
+
* 범례(color-map) 테마의 편집기: 코드마다 색 하나 — 피규어 라이브러리의 범례 편집기(legend-looks-popup)를 색만으로 연다. 캐리어 모양
|
|
11
|
+
* 피규어의 두께는 피규어의 고정 표가 정하므로 범례는 값을 주지 않는다(ADR-0167 결정 12). 항목이 이미 가진 다른 칸은 그대로 남는다.
|
|
12
|
+
*/
|
|
4
13
|
let ColorMapEditor = class ColorMapEditor extends OxGristEditorValueMap {
|
|
5
14
|
get options() {
|
|
6
15
|
var _a;
|
|
7
16
|
const overidable = ((_a = this.column.record) === null || _a === void 0 ? void 0 : _a.options) || {};
|
|
8
17
|
return Object.assign({ name: `Color Map : ${this.record.name}`, valuetype: 'color', objectified: false, defaultValue: '#F0F0F0' }, overidable);
|
|
9
18
|
}
|
|
19
|
+
async openSelector() {
|
|
20
|
+
const { name, help, defaultValue, objectified } = this.options;
|
|
21
|
+
let before;
|
|
22
|
+
try {
|
|
23
|
+
before = !objectified && typeof this.value === 'string' ? JSON.parse(this.value) : Object.assign({}, (this.value || {}));
|
|
24
|
+
}
|
|
25
|
+
catch (e) {
|
|
26
|
+
before = {};
|
|
27
|
+
}
|
|
28
|
+
/* 팝업이 다시 그려져도 같은 값·콜백을 쓰도록 참조를 한 번만 만든다 (OxGristEditorValueMap 주석) */
|
|
29
|
+
const draft = { looks: legendLooksOf(before) };
|
|
30
|
+
const confirmCallback = (looks) => {
|
|
31
|
+
const after = legendOf(looks);
|
|
32
|
+
this.dispatchEvent(new CustomEvent('field-change', {
|
|
33
|
+
bubbles: true,
|
|
34
|
+
composed: true,
|
|
35
|
+
detail: {
|
|
36
|
+
before: this.value,
|
|
37
|
+
after: !objectified ? JSON.stringify(after) : after,
|
|
38
|
+
record: this.record,
|
|
39
|
+
column: this.column,
|
|
40
|
+
row: this.row
|
|
41
|
+
}
|
|
42
|
+
}));
|
|
43
|
+
};
|
|
44
|
+
openPopup(html ` <legend-looks-popup .draft=${draft} colour-only default-color=${defaultValue} .confirmCallback=${confirmCallback}></legend-looks-popup> `, {
|
|
45
|
+
backdrop: true,
|
|
46
|
+
size: 'large',
|
|
47
|
+
title: `${(name === null || name === void 0 ? void 0 : name.toUpperCase()) || i18next.t('title.value-map')} `,
|
|
48
|
+
help
|
|
49
|
+
});
|
|
50
|
+
}
|
|
10
51
|
};
|
|
11
52
|
ColorMapEditor = __decorate([
|
|
12
53
|
customElement('color-map-editor')
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"color-map-editor.js","sourceRoot":"","sources":["../../client/data-grist/color-map-editor.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAEjD,OAAO,EAAE,qBAAqB,EAAE,MAAM,oDAAoD,CAAA;
|
|
1
|
+
{"version":3,"file":"color-map-editor.js","sourceRoot":"","sources":["../../client/data-grist/color-map-editor.ts"],"names":[],"mappings":";AAAA,OAAO,gFAAgF,CAAA;AAEvF,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAA;AAC1B,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAEjD,OAAO,EAAE,qBAAqB,EAAE,MAAM,oDAAoD,CAAA;AAC1F,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAoB,MAAM,yEAAyE,CAAA;AAEnI;;;GAGG;AAEI,IAAM,cAAc,GAApB,MAAM,cAAe,SAAQ,qBAAqB;IACvD,IAAI,OAAO;;QACT,MAAM,UAAU,GAAG,CAAA,MAAA,IAAI,CAAC,MAAM,CAAC,MAAM,0CAAE,OAAO,KAAI,EAAE,CAAA;QAEpD,uBACE,IAAI,EAAE,eAAe,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,EACvC,SAAS,EAAE,OAAO,EAClB,WAAW,EAAE,KAAK,EAClB,YAAY,EAAE,SAAS,IACpB,UAAU,EACd;IACH,CAAC;IAED,KAAK,CAAC,YAAY;QAChB,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC,OAAO,CAAA;QAC9D,IAAI,MAAe,CAAA;QACnB,IAAI,CAAC;YACH,MAAM,GAAG,CAAC,WAAW,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,mBAAM,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CAAE,CAAA;QAC9G,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,GAAG,EAAE,CAAA;QACb,CAAC;QACD,sEAAsE;QACtE,MAAM,KAAK,GAAG,EAAE,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,EAAE,CAAA;QAC9C,MAAM,eAAe,GAAG,CAAC,KAAkB,EAAE,EAAE;YAC7C,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;YAC7B,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,cAAc,EAAE;gBAC9B,OAAO,EAAE,IAAI;gBACb,QAAQ,EAAE,IAAI;gBACd,MAAM,EAAE;oBACN,MAAM,EAAE,IAAI,CAAC,KAAK;oBAClB,KAAK,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK;oBACnD,MAAM,EAAE,IAAI,CAAC,MAAM;oBACnB,MAAM,EAAE,IAAI,CAAC,MAAM;oBACnB,GAAG,EAAE,IAAI,CAAC,GAAG;iBACd;aACF,CAAC,CACH,CAAA;QACH,CAAC,CAAA;QAED,SAAS,CACP,IAAI,CAAA,+BAA+B,KAAK,8BAA8B,YAAY,qBAAqB,eAAe,yBAAyB,EAC/I;YACE,QAAQ,EAAE,IAAI;YACd,IAAI,EAAE,OAAO;YACb,KAAK,EAAE,GAAG,CAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,WAAW,EAAE,KAAI,OAAO,CAAC,CAAC,CAAC,iBAAiB,CAAC,GAAG;YAChE,IAAI;SACL,CACF,CAAA;IACH,CAAC;CACF,CAAA;AAlDY,cAAc;IAD1B,aAAa,CAAC,kBAAkB,CAAC;GACrB,cAAc,CAkD1B","sourcesContent":["import '@things-factory/figure-library/dist-client/legend-looks/legend-looks-editor.js'\n\nimport { html } from 'lit'\nimport { customElement } from 'lit/decorators.js'\n\nimport { OxGristEditorValueMap } from '@operato/grist-editor/ox-grist-editor-value-map.js'\nimport { i18next } from '@operato/i18n'\nimport { openPopup } from '@operato/popup'\nimport { legendLooksOf, legendOf, type LegendLooks } from '@things-factory/figure-library/dist-client/legend-looks/legend-looks.js'\n\n/**\n * 범례(color-map) 테마의 편집기: 코드마다 색 하나 — 피규어 라이브러리의 범례 편집기(legend-looks-popup)를 색만으로 연다. 캐리어 모양\n * 피규어의 두께는 피규어의 고정 표가 정하므로 범례는 값을 주지 않는다(ADR-0167 결정 12). 항목이 이미 가진 다른 칸은 그대로 남는다.\n */\n@customElement('color-map-editor')\nexport class ColorMapEditor extends OxGristEditorValueMap {\n get options() {\n const overidable = this.column.record?.options || {}\n\n return {\n name: `Color Map : ${this.record.name}`,\n valuetype: 'color',\n objectified: false,\n defaultValue: '#F0F0F0',\n ...overidable\n }\n }\n\n async openSelector() {\n const { name, help, defaultValue, objectified } = this.options\n let before: unknown\n try {\n before = !objectified && typeof this.value === 'string' ? JSON.parse(this.value) : { ...(this.value || {}) }\n } catch (e) {\n before = {}\n }\n /* 팝업이 다시 그려져도 같은 값·콜백을 쓰도록 참조를 한 번만 만든다 (OxGristEditorValueMap 주석) */\n const draft = { looks: legendLooksOf(before) }\n const confirmCallback = (looks: LegendLooks) => {\n const after = legendOf(looks)\n this.dispatchEvent(\n new CustomEvent('field-change', {\n bubbles: true,\n composed: true,\n detail: {\n before: this.value,\n after: !objectified ? JSON.stringify(after) : after,\n record: this.record,\n column: this.column,\n row: this.row\n }\n })\n )\n }\n\n openPopup(\n html` <legend-looks-popup .draft=${draft} colour-only default-color=${defaultValue} .confirmCallback=${confirmCallback}></legend-looks-popup> `,\n {\n backdrop: true,\n size: 'large',\n title: `${name?.toUpperCase() || i18next.t('title.value-map')} `,\n help\n }\n )\n }\n}\n"]}
|
|
@@ -1,18 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* An animation map's 2D motions, one row per code: the code and its motion (ox-input-animation-config).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* value 구조 (실제 데이터):
|
|
8
|
-
* {
|
|
9
|
-
* "CRITICAL": "{ animation: { type: 'vibration', duration: 1000, ... }, icon: { ... } }",
|
|
10
|
-
* "WARN": "{ animation: { type: 'vibration', ... } }",
|
|
11
|
-
* "default": ""
|
|
12
|
-
* }
|
|
13
|
-
*
|
|
14
|
-
* 각 entry value는 JSON5 string이며, 내부에 animation 키가 있으면 그 속성만 폼에 표시.
|
|
15
|
-
* 저장 시 animation 외 다른 키(icon 등)는 보존됨.
|
|
4
|
+
* The value is read by animationEntriesOf: each entry a record, its 2D motion under `animation` and what else it holds
|
|
5
|
+
* beside it -- the 3D colour and effect (ADR-0167 decision 12), an icon -- kept as it is when the motion changes.
|
|
16
6
|
*/
|
|
17
7
|
import '@material/web/icon/icon.js';
|
|
18
8
|
import './ox-input-animation-config.js';
|
|
@@ -1,25 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* An animation map's 2D motions, one row per code: the code and its motion (ox-input-animation-config).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* value 구조 (실제 데이터):
|
|
8
|
-
* {
|
|
9
|
-
* "CRITICAL": "{ animation: { type: 'vibration', duration: 1000, ... }, icon: { ... } }",
|
|
10
|
-
* "WARN": "{ animation: { type: 'vibration', ... } }",
|
|
11
|
-
* "default": ""
|
|
12
|
-
* }
|
|
13
|
-
*
|
|
14
|
-
* 각 entry value는 JSON5 string이며, 내부에 animation 키가 있으면 그 속성만 폼에 표시.
|
|
15
|
-
* 저장 시 animation 외 다른 키(icon 등)는 보존됨.
|
|
4
|
+
* The value is read by animationEntriesOf: each entry a record, its 2D motion under `animation` and what else it holds
|
|
5
|
+
* beside it -- the 3D colour and effect (ADR-0167 decision 12), an icon -- kept as it is when the motion changes.
|
|
16
6
|
*/
|
|
17
7
|
import { __decorate, __metadata } from "tslib";
|
|
18
8
|
import '@material/web/icon/icon.js';
|
|
19
9
|
import './ox-input-animation-config.js';
|
|
20
|
-
import JSON5 from 'json5';
|
|
21
10
|
import { css, html, LitElement } from 'lit';
|
|
22
11
|
import { customElement, property } from 'lit/decorators.js';
|
|
12
|
+
import { animationEntriesOf } from '@fmsim/machine';
|
|
23
13
|
import { keyed } from 'lit/directives/keyed.js';
|
|
24
14
|
let OxInputAnimationMap = class OxInputAnimationMap extends LitElement {
|
|
25
15
|
constructor() {
|
|
@@ -109,8 +99,7 @@ let OxInputAnimationMap = class OxInputAnimationMap extends LitElement {
|
|
|
109
99
|
if (!entry)
|
|
110
100
|
return;
|
|
111
101
|
// 항상 { animation: config } 구조로 저장 (원본에 다른 키가 있으면 보존)
|
|
112
|
-
const newEntryValue = entry.
|
|
113
|
-
? Object.assign(Object.assign({}, entry.full), { animation: e.detail }) : { animation: e.detail };
|
|
102
|
+
const newEntryValue = Object.assign(Object.assign({}, entry.full), { animation: e.detail });
|
|
114
103
|
this.value = Object.assign(Object.assign({}, this.value), { [entry.key]: newEntryValue });
|
|
115
104
|
this.dispatchEvent(new CustomEvent('change', { bubbles: true, composed: true, detail: this.value }));
|
|
116
105
|
}
|
|
@@ -132,15 +121,14 @@ let OxInputAnimationMap = class OxInputAnimationMap extends LitElement {
|
|
|
132
121
|
const records = this.renderRoot.querySelectorAll('[data-record]');
|
|
133
122
|
const newMap = {};
|
|
134
123
|
records.forEach((record, idx) => {
|
|
135
|
-
var _a;
|
|
124
|
+
var _a, _b;
|
|
136
125
|
const key = (_a = record.querySelector('[data-key]')) === null || _a === void 0 ? void 0 : _a.value;
|
|
137
126
|
if (!key)
|
|
138
127
|
return;
|
|
139
128
|
const configEl = record.querySelector('ox-input-animation-config');
|
|
140
129
|
const animConfig = (configEl === null || configEl === void 0 ? void 0 : configEl.value) || {};
|
|
141
130
|
const entry = this._parsed[idx];
|
|
142
|
-
newMap[key] = (entry === null || entry === void 0 ? void 0 : entry.
|
|
143
|
-
? Object.assign(Object.assign({}, entry.full), { animation: animConfig }) : { animation: animConfig };
|
|
131
|
+
newMap[key] = Object.assign(Object.assign({}, ((_b = entry === null || entry === void 0 ? void 0 : entry.full) !== null && _b !== void 0 ? _b : {})), { animation: animConfig });
|
|
144
132
|
});
|
|
145
133
|
if (((_a = this.value) === null || _a === void 0 ? void 0 : _a.default) !== undefined) {
|
|
146
134
|
newMap.default = this.value.default;
|
|
@@ -170,51 +158,14 @@ let OxInputAnimationMap = class OxInputAnimationMap extends LitElement {
|
|
|
170
158
|
this.value = newMap;
|
|
171
159
|
this.dispatchEvent(new CustomEvent('change', { bubbles: true, composed: true, detail: this.value }));
|
|
172
160
|
}
|
|
161
|
+
/* Entries are records, read by the one rule (animationEntriesOf): the 2D motion under `animation`, the rest kept */
|
|
173
162
|
_parseEntries(map) {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
continue;
|
|
178
|
-
let val = map[key];
|
|
179
|
-
// JSON5 string → object 파싱
|
|
180
|
-
if (typeof val === 'string') {
|
|
181
|
-
try {
|
|
182
|
-
val = JSON5.parse(val);
|
|
183
|
-
}
|
|
184
|
-
catch (e) {
|
|
185
|
-
val = {};
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
if (typeof val !== 'object' || val === null) {
|
|
189
|
-
val = {};
|
|
190
|
-
}
|
|
191
|
-
// 중첩 구조 { animation: {...}, icon: {...} } 처리
|
|
192
|
-
const isNested = 'animation' in val;
|
|
193
|
-
const animation = isNested ? (val.animation || {}) : val;
|
|
194
|
-
arr.push({ key, animation, full: val, isNested });
|
|
195
|
-
}
|
|
196
|
-
return arr;
|
|
163
|
+
return Object.entries(map)
|
|
164
|
+
.filter(([key]) => key !== 'default')
|
|
165
|
+
.map(([key, full]) => ({ key, animation: (full === null || full === void 0 ? void 0 : full.animation) || {}, full }));
|
|
197
166
|
}
|
|
198
|
-
// 입력 value의 모든 string entry를 object로 정규화 (JSON/JSON5 호환)
|
|
199
167
|
_normalize(map) {
|
|
200
|
-
|
|
201
|
-
return {};
|
|
202
|
-
const result = {};
|
|
203
|
-
for (const key in map) {
|
|
204
|
-
const val = map[key];
|
|
205
|
-
if (typeof val === 'string' && val.trim()) {
|
|
206
|
-
try {
|
|
207
|
-
result[key] = JSON5.parse(val);
|
|
208
|
-
}
|
|
209
|
-
catch (_a) {
|
|
210
|
-
result[key] = val;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
else {
|
|
214
|
-
result[key] = val;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
return result;
|
|
168
|
+
return animationEntriesOf(map);
|
|
218
169
|
}
|
|
219
170
|
};
|
|
220
171
|
OxInputAnimationMap.styles = css `
|