@things-factory/figure-ui 10.1.104 → 10.1.105
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/modeller/editor.ts +2 -2
- package/client/modeller/fields.ts +7 -1
- package/client/modeller/figure-cavity-drawing.ts +65 -9
- package/client/modeller/figure-material-panel.ts +0 -1
- package/client/modeller/figure-section-panel.ts +15 -103
- package/dist-client/modeller/clips.d.ts +1 -1
- package/dist-client/modeller/editor.js +2 -2
- package/dist-client/modeller/editor.js.map +1 -1
- package/dist-client/modeller/fields.js +7 -1
- package/dist-client/modeller/fields.js.map +1 -1
- package/dist-client/modeller/figure-cavity-drawing.d.ts +6 -0
- package/dist-client/modeller/figure-cavity-drawing.js +68 -9
- package/dist-client/modeller/figure-cavity-drawing.js.map +1 -1
- package/dist-client/modeller/figure-material-panel.js +0 -1
- package/dist-client/modeller/figure-material-panel.js.map +1 -1
- package/dist-client/modeller/figure-section-panel.d.ts +0 -1
- package/dist-client/modeller/figure-section-panel.js +14 -73
- package/dist-client/modeller/figure-section-panel.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/test/cavity-drawing.test.ts +5 -1
- package/test/section-editor.test.ts +3 -1
- package/test/section-panel.test.ts +5 -3
- package/translations/en.json +0 -1
- package/translations/ja.json +0 -1
- package/translations/ko.json +0 -1
- package/translations/ms.json +0 -1
- package/translations/zh.json +0 -1
|
@@ -31,7 +31,13 @@ export function groupFields(fields, part) {
|
|
|
31
31
|
A drawn section's points and a pyramid's apex are edited in the section editor, where a move is checked as it is made
|
|
32
32
|
and the points stand in the outline's order (user 2026-10-01): not here, one field each, in the order they were made.
|
|
33
33
|
*/
|
|
34
|
-
|
|
34
|
+
/*
|
|
35
|
+
The section's own numbers -- its corners, its inside's walls and closed ends -- are edited in the 단면 group, where
|
|
36
|
+
they are drawn (user 2026-10-01: 「wall (mm)」, 「closed · start (mm)」 stood in the shape's list under their
|
|
37
|
+
inner names).
|
|
38
|
+
*/
|
|
39
|
+
const ofSection = (id) => /^(dimension\.)?(round|roundX|roundZ|wall|wallX|wallZ|floor|closed|corner)(\.|$)/.test(id.slice(prefix.length));
|
|
40
|
+
const drawn = (id) => /^(point\.[^.]+|apex)\.[xyz]$/.test(id.slice(prefix.length)) || ofSection(id);
|
|
35
41
|
const singles = own
|
|
36
42
|
.filter(f => !used.has(f.id) && !drawn(f.id))
|
|
37
43
|
.map(field => ({ kind: 'single', name: nameOf(field.id.slice(prefix.length)), field }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fields.js","sourceRoot":"","sources":["../../client/modeller/fields.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * The values a part or the figure is edited by, grouped: position, rotation and size\n * as one row of three cells each (X · Y · Z read together), and the shape's own measures one to a line under their\n * own title. Kept apart from the editor so the grouping is tested without a browser.\n */\nexport interface FieldLike {\n id: string\n unit: string\n role?: string\n value: number\n}\n\nexport type Axis3 = 'x' | 'y' | 'z'\nconst AXES: readonly Axis3[] = ['x', 'y', 'z']\n\nexport type FieldGroup =\n /* A cell is missing where a rule sets that axis instead of a number: a floor part's height position (ADR-0097). */\n | { kind: 'vector'; name: 'position' | 'rotation' | 'size'; cells: Partial<Record<Axis3, FieldLike>> }\n | { kind: 'single'; name: string; field: FieldLike }\n\n/** The name a single value goes by: its id without the part, `dimension.` and corner numbers read as words. */\nfunction nameOf(rest: string): string {\n return rest.replace(/^dimension\\./, '')\n}\n\n/**\n * The part's own values (`<part>.…`), or with no part the figure's (`size.x` …). Position, rotation and size come\n * first, each as one row when any of its axes is there -- an axis a rule sets shows as held, not as a stray single\n * further down; the rest follow in the order they are declared.\n */\nexport function groupFields(fields: readonly FieldLike[], part?: string): { vectors: FieldGroup[]; singles: FieldGroup[] } {\n /*\n A part is always placed and turned, so its position and turn rows stand even when a rule sets every axis (a\n fastened part): the screen shows the numbers the rule gives. Its size row stands only when it has a field of its own.\n */\n const prefix = part ? `${part}.` : ''\n const own = fields.filter(f => (part ? f.id.startsWith(prefix) : !f.id.includes('.') || /^size\\.[xyz]$/.test(f.id)))\n const byId = new Map(own.map(f => [f.id, f]))\n const used = new Set<string>()\n const vectors: FieldGroup[] = []\n for (const name of ['position', 'rotation', 'size'] as const) {\n const ids = AXES.map(axis => `${prefix}${name}.${axis}`)\n if (!ids.some(id => byId.has(id)) && !(part && name !== 'size')) continue\n ids.forEach(id => used.add(id))\n const cells: Partial<Record<Axis3, FieldLike>> = {}\n AXES.forEach((axis, i) => byId.has(ids[i]!) && (cells[axis] = byId.get(ids[i]!)!))\n vectors.push({ kind: 'vector', name, cells })\n }\n /*\n A drawn section's points and a pyramid's apex are edited in the section editor, where a move is checked as it is made\n and the points stand in the outline's order (user 2026-10-01): not here, one field each, in the order they were made.\n */\n const drawn = (id: string) => /^(point\\.[^.]+|apex)\\.[xyz]$/.test(id.slice(prefix.length))\n const singles: FieldGroup[] = own\n .filter(f => !used.has(f.id) && !drawn(f.id))\n .map(field => ({ kind: 'single', name: nameOf(field.id.slice(prefix.length)), field }))\n return { vectors, singles }\n}\n\n/**\n * The part a copy copies: the member at the end of its path. A row repeats its part and what is fastened to it\n * (ADR-0093, 2026-09-26), so the copies of one row are of several parts -- a roller's and the mark on it.\n */\nconst memberOf = (path: unknown[]): string => {\n const last = [...path].reverse().find((step): step is string => typeof step === 'string')!\n return last.replace(/\\.(placed|value)$/, '').replace(/\\.repeat$/, '')\n}\n\n/**\n * The name a person reads for a body. A repeated body's id is its path through the repeats (`[\"roller.repeat\",0,\n * \"roller.placed\"]`), which the list showed as it was; it reads as the part it copies and its place counted from 1 --\n * `roller 1`, and `mark 1` for the mark the first roller carries. Any other id is its own name.\n */\nexport function partLabelOf(id: string): string {\n const path = pathOf(id)\n if (!path) return id\n const places = path.filter((step): step is number => typeof step === 'number').map(n => n + 1)\n return places.length ? `${memberOf(path)} ${places.join('·')}` : id\n}\n\n/**\n * The repeat a body is a copy of: its name, how many copies it makes, and which copy this is (counted from 1). Nothing\n * for a body that is not a copy.\n */\nexport function repeatOf(id: string, geometry: readonly unknown[] | undefined): { name: string; count: number; index: number } | null {\n const path = pathOf(id)\n const paths = (geometry ?? []).map(g => pathOf((g as { id?: string }).id ?? '')).filter((p): p is unknown[] => !!p)\n if (!path) {\n /* The part itself, by its name: how many copies of it the row makes now. */\n const copies = paths.filter(p => memberOf(p) === id).length\n return copies ? { name: id, count: copies, index: 0 } : null\n }\n const name = memberOf(path)\n const count = paths.filter(p => p[0] === path[0] && memberOf(p) === name).length\n const index = path.find((step): step is number => typeof step === 'number')\n return { name, count, index: (index ?? 0) + 1 }\n}\n\nfunction pathOf(id: string): unknown[] | null {\n if (!id.startsWith('[')) return null\n try {\n const path = JSON.parse(id)\n return Array.isArray(path) && typeof path[0] === 'string' ? path : null\n } catch {\n return null\n }\n}\n\n/**\n * The authored part a body belongs to: a repeat's copy belongs to its repeat (`roller`), any other body is its own. The\n * editor selects, lists, hides and names parts by this -- what the author made, not every body the kernel draws\n * (user, 2026-09-24: the conveyor's sixteen rollers were sixteen rows).\n */\nexport function ownerOf(id: string): string {\n const path = pathOf(id)\n return path ? memberOf(path) : id\n}\n\n"]}
|
|
1
|
+
{"version":3,"file":"fields.js","sourceRoot":"","sources":["../../client/modeller/fields.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * The values a part or the figure is edited by, grouped: position, rotation and size\n * as one row of three cells each (X · Y · Z read together), and the shape's own measures one to a line under their\n * own title. Kept apart from the editor so the grouping is tested without a browser.\n */\nexport interface FieldLike {\n id: string\n unit: string\n role?: string\n value: number\n}\n\nexport type Axis3 = 'x' | 'y' | 'z'\nconst AXES: readonly Axis3[] = ['x', 'y', 'z']\n\nexport type FieldGroup =\n /* A cell is missing where a rule sets that axis instead of a number: a floor part's height position (ADR-0097). */\n | { kind: 'vector'; name: 'position' | 'rotation' | 'size'; cells: Partial<Record<Axis3, FieldLike>> }\n | { kind: 'single'; name: string; field: FieldLike }\n\n/** The name a single value goes by: its id without the part, `dimension.` and corner numbers read as words. */\nfunction nameOf(rest: string): string {\n return rest.replace(/^dimension\\./, '')\n}\n\n/**\n * The part's own values (`<part>.…`), or with no part the figure's (`size.x` …). Position, rotation and size come\n * first, each as one row when any of its axes is there -- an axis a rule sets shows as held, not as a stray single\n * further down; the rest follow in the order they are declared.\n */\nexport function groupFields(fields: readonly FieldLike[], part?: string): { vectors: FieldGroup[]; singles: FieldGroup[] } {\n /*\n A part is always placed and turned, so its position and turn rows stand even when a rule sets every axis (a\n fastened part): the screen shows the numbers the rule gives. Its size row stands only when it has a field of its own.\n */\n const prefix = part ? `${part}.` : ''\n const own = fields.filter(f => (part ? f.id.startsWith(prefix) : !f.id.includes('.') || /^size\\.[xyz]$/.test(f.id)))\n const byId = new Map(own.map(f => [f.id, f]))\n const used = new Set<string>()\n const vectors: FieldGroup[] = []\n for (const name of ['position', 'rotation', 'size'] as const) {\n const ids = AXES.map(axis => `${prefix}${name}.${axis}`)\n if (!ids.some(id => byId.has(id)) && !(part && name !== 'size')) continue\n ids.forEach(id => used.add(id))\n const cells: Partial<Record<Axis3, FieldLike>> = {}\n AXES.forEach((axis, i) => byId.has(ids[i]!) && (cells[axis] = byId.get(ids[i]!)!))\n vectors.push({ kind: 'vector', name, cells })\n }\n /*\n A drawn section's points and a pyramid's apex are edited in the section editor, where a move is checked as it is made\n and the points stand in the outline's order (user 2026-10-01): not here, one field each, in the order they were made.\n */\n /*\n The section's own numbers -- its corners, its inside's walls and closed ends -- are edited in the 단면 group, where\n they are drawn (user 2026-10-01: 「wall (mm)」, 「closed · start (mm)」 stood in the shape's list under their\n inner names).\n */\n const ofSection = (id: string) => /^(dimension\\.)?(round|roundX|roundZ|wall|wallX|wallZ|floor|closed|corner)(\\.|$)/.test(id.slice(prefix.length))\n const drawn = (id: string) => /^(point\\.[^.]+|apex)\\.[xyz]$/.test(id.slice(prefix.length)) || ofSection(id)\n const singles: FieldGroup[] = own\n .filter(f => !used.has(f.id) && !drawn(f.id))\n .map(field => ({ kind: 'single', name: nameOf(field.id.slice(prefix.length)), field }))\n return { vectors, singles }\n}\n\n/**\n * The part a copy copies: the member at the end of its path. A row repeats its part and what is fastened to it\n * (ADR-0093, 2026-09-26), so the copies of one row are of several parts -- a roller's and the mark on it.\n */\nconst memberOf = (path: unknown[]): string => {\n const last = [...path].reverse().find((step): step is string => typeof step === 'string')!\n return last.replace(/\\.(placed|value)$/, '').replace(/\\.repeat$/, '')\n}\n\n/**\n * The name a person reads for a body. A repeated body's id is its path through the repeats (`[\"roller.repeat\",0,\n * \"roller.placed\"]`), which the list showed as it was; it reads as the part it copies and its place counted from 1 --\n * `roller 1`, and `mark 1` for the mark the first roller carries. Any other id is its own name.\n */\nexport function partLabelOf(id: string): string {\n const path = pathOf(id)\n if (!path) return id\n const places = path.filter((step): step is number => typeof step === 'number').map(n => n + 1)\n return places.length ? `${memberOf(path)} ${places.join('·')}` : id\n}\n\n/**\n * The repeat a body is a copy of: its name, how many copies it makes, and which copy this is (counted from 1). Nothing\n * for a body that is not a copy.\n */\nexport function repeatOf(id: string, geometry: readonly unknown[] | undefined): { name: string; count: number; index: number } | null {\n const path = pathOf(id)\n const paths = (geometry ?? []).map(g => pathOf((g as { id?: string }).id ?? '')).filter((p): p is unknown[] => !!p)\n if (!path) {\n /* The part itself, by its name: how many copies of it the row makes now. */\n const copies = paths.filter(p => memberOf(p) === id).length\n return copies ? { name: id, count: copies, index: 0 } : null\n }\n const name = memberOf(path)\n const count = paths.filter(p => p[0] === path[0] && memberOf(p) === name).length\n const index = path.find((step): step is number => typeof step === 'number')\n return { name, count, index: (index ?? 0) + 1 }\n}\n\nfunction pathOf(id: string): unknown[] | null {\n if (!id.startsWith('[')) return null\n try {\n const path = JSON.parse(id)\n return Array.isArray(path) && typeof path[0] === 'string' ? path : null\n } catch {\n return null\n }\n}\n\n/**\n * The authored part a body belongs to: a repeat's copy belongs to its repeat (`roller`), any other body is its own. The\n * editor selects, lists, hides and names parts by this -- what the author made, not every body the kernel draws\n * (user, 2026-09-24: the conveyor's sixteen rollers were sixteen rows).\n */\nexport function ownerOf(id: string): string {\n const path = pathOf(id)\n return path ? memberOf(path) : id\n}\n\n"]}
|
|
@@ -24,10 +24,13 @@ export declare class FigureCavityDrawing extends FigureCavityDrawing_base {
|
|
|
24
24
|
private working?;
|
|
25
25
|
private refusal;
|
|
26
26
|
private dragging;
|
|
27
|
+
/** A number pressed to be typed: which, and where on its picture (percent of the picture's box). */
|
|
28
|
+
private typing?;
|
|
27
29
|
private pressedAt;
|
|
28
30
|
private get now();
|
|
29
31
|
private request;
|
|
30
32
|
private action;
|
|
33
|
+
/** What the kernel would refuse, in words; for one side's wall, the most that side can be with the opposite kept. */
|
|
31
34
|
private judge;
|
|
32
35
|
/** The working inside while dragging: drawn, judged, and previewed behind when the kernel would take it. */
|
|
33
36
|
private hold;
|
|
@@ -35,6 +38,9 @@ export declare class FigureCavityDrawing extends FigureCavityDrawing_base {
|
|
|
35
38
|
private emit;
|
|
36
39
|
private point;
|
|
37
40
|
render(): import("lit-html").TemplateResult<1> | typeof nothing;
|
|
41
|
+
/** Press a number, type it, Enter: the same one set-cavity a drag sends; Esc or leaving puts it back. */
|
|
42
|
+
private type;
|
|
43
|
+
private renderTyping;
|
|
38
44
|
/** Seen along the push: the section, its inside and a handle on each wall. */
|
|
39
45
|
private top;
|
|
40
46
|
/** Cut along the push: the walls across the first plane axis, and the two ends -- pressed to open or close. */
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { __decorate, __metadata } from "tslib";
|
|
2
2
|
import { css, html, LitElement, nothing, svg } from 'lit';
|
|
3
3
|
import { customElement, property, state } from 'lit/decorators.js';
|
|
4
|
+
import { ref } from 'lit/directives/ref.js';
|
|
4
5
|
import { i18next, localize } from '@operato/i18n';
|
|
5
6
|
import { figureCavitySectionOf } from '@hatiolab/figure-model';
|
|
6
|
-
import { cavityRefusalOf, cavityWorkingOf, END_FACE, endToggled, mm, SIDE_FACE, wallDragged } from './section-controls.js';
|
|
7
|
+
import { cavityRefusalOf, cavityWorkingOf, END_FACE, endToggled, mm, SIDE_FACE, sideWallLimitOf, wallDragged } from './section-controls.js';
|
|
8
|
+
/** A field opened by a press takes the keys at once. */
|
|
9
|
+
const focusOnRender = () => ref(el => el && requestAnimationFrame(() => el.select()));
|
|
7
10
|
/** How the section is laid on the screen, by the axis it is pushed along: across to the right, then down. */
|
|
8
11
|
const SCREEN = { y: ['x', 'z'], x: ['z', 'y'], z: ['x', 'y'] };
|
|
9
12
|
/**
|
|
@@ -42,6 +45,19 @@ let FigureCavityDrawing = class FigureCavityDrawing extends localize(i18next)(Li
|
|
|
42
45
|
small[refusal] {
|
|
43
46
|
color: var(--md-sys-color-error);
|
|
44
47
|
}
|
|
48
|
+
div[pane] {
|
|
49
|
+
position: relative;
|
|
50
|
+
}
|
|
51
|
+
div[pane] input {
|
|
52
|
+
position: absolute;
|
|
53
|
+
width: 64px;
|
|
54
|
+
transform: translate(-50%, -50%);
|
|
55
|
+
font: inherit;
|
|
56
|
+
}
|
|
57
|
+
text[typed] {
|
|
58
|
+
cursor: text;
|
|
59
|
+
text-decoration: underline dotted;
|
|
60
|
+
}
|
|
45
61
|
`; }
|
|
46
62
|
get now() {
|
|
47
63
|
return this.working ?? (this.body ? cavityWorkingOf(this.body.shape) : undefined);
|
|
@@ -52,20 +68,23 @@ let FigureCavityDrawing = class FigureCavityDrawing extends localize(i18next)(Li
|
|
|
52
68
|
action(w) {
|
|
53
69
|
return { kind: 'set-cavity', part: this.body.id, cavity: this.request(w) };
|
|
54
70
|
}
|
|
55
|
-
|
|
71
|
+
/** What the kernel would refuse, in words; for one side's wall, the most that side can be with the opposite kept. */
|
|
72
|
+
judge(w, side) {
|
|
56
73
|
const ask = cavityRefusalOf(this.body.shape, this.request(w));
|
|
57
74
|
if (!ask)
|
|
58
75
|
return '';
|
|
59
76
|
if (ask.code === 'wall-too-thick')
|
|
60
|
-
return i18next.t('figure.text.section-wall-over', {
|
|
77
|
+
return i18next.t('figure.text.section-wall-over', {
|
|
78
|
+
max: String(this.perSide && side ? mm(sideWallLimitOf(this.body.shape, w.wall, side)) : ask.max)
|
|
79
|
+
});
|
|
61
80
|
if (ask.code === 'ends-too-thick')
|
|
62
81
|
return i18next.t('figure.text.section-ends-over', { max: String(ask.max) });
|
|
63
82
|
return i18next.t('figure.text.section-not-positive');
|
|
64
83
|
}
|
|
65
84
|
/** The working inside while dragging: drawn, judged, and previewed behind when the kernel would take it. */
|
|
66
|
-
hold(w) {
|
|
85
|
+
hold(w, side) {
|
|
67
86
|
this.working = w;
|
|
68
|
-
this.refusal = this.judge(w);
|
|
87
|
+
this.refusal = this.judge(w, side);
|
|
69
88
|
this.emit('command-live', this.refusal ? null : this.action(w));
|
|
70
89
|
}
|
|
71
90
|
release() {
|
|
@@ -95,9 +114,43 @@ let FigureCavityDrawing = class FigureCavityDrawing extends localize(i18next)(Li
|
|
|
95
114
|
const w = this.now;
|
|
96
115
|
if (!e || !w || (e.section.kind !== 'rectangle' && e.section.kind !== 'ellipse'))
|
|
97
116
|
return nothing;
|
|
98
|
-
return html
|
|
117
|
+
return html `<div pane>${this.top(e, w)}${this.typing?.pane === 'top' ? this.renderTyping() : nothing}</div>
|
|
118
|
+
<div pane>${this.side(e, w)}${this.typing?.pane === 'side' ? this.renderTyping() : nothing}</div>
|
|
99
119
|
${this.refusal ? html `<small refusal role="alert">${this.refusal}</small>` : nothing}`;
|
|
100
120
|
}
|
|
121
|
+
/** Press a number, type it, Enter: the same one set-cavity a drag sends; Esc or leaving puts it back. */
|
|
122
|
+
type(ev, what, pane, value) {
|
|
123
|
+
if (this.locked)
|
|
124
|
+
return;
|
|
125
|
+
ev.stopPropagation();
|
|
126
|
+
const svgEl = ev.target.closest('svg');
|
|
127
|
+
const box = svgEl.getBoundingClientRect();
|
|
128
|
+
this.refusal = '';
|
|
129
|
+
this.typing = { ...what, pane, value, x: ((ev.clientX - box.left) / box.width) * 100, y: ((ev.clientY - box.top) / box.height) * 100 };
|
|
130
|
+
}
|
|
131
|
+
renderTyping() {
|
|
132
|
+
const t = this.typing;
|
|
133
|
+
return html `<input type="number" step="1" min="1" .value=${String(t.value)} style=${`left:${t.x}%;top:${t.y}%`}
|
|
134
|
+
aria-label=${t.kind === 'wall' ? i18next.t('figure.label.section-wall') : i18next.t('figure.label.face-' + END_FACE(this.body.shape.extrusion.axis, t.end))}
|
|
135
|
+
@keydown=${(ev) => {
|
|
136
|
+
ev.stopPropagation();
|
|
137
|
+
if (ev.key === 'Escape')
|
|
138
|
+
this.typing = undefined;
|
|
139
|
+
if (ev.key !== 'Enter')
|
|
140
|
+
return;
|
|
141
|
+
const value = Number(ev.target.value);
|
|
142
|
+
this.typing = undefined;
|
|
143
|
+
if (!(Number.isFinite(value) && value > 0))
|
|
144
|
+
return;
|
|
145
|
+
const now = this.now;
|
|
146
|
+
const next = t.kind === 'wall' ? { ...now, wall: wallDragged(now.wall, t.side, value, this.perSide) } : { ...now, [t.end]: { closed: Math.round(value) } };
|
|
147
|
+
this.refusal = this.judge(next, t.kind === 'wall' ? t.side : undefined);
|
|
148
|
+
if (!this.refusal)
|
|
149
|
+
this.emit('command', this.action(next));
|
|
150
|
+
}}
|
|
151
|
+
@blur=${() => (this.typing = undefined)}
|
|
152
|
+
${focusOnRender()} />`;
|
|
153
|
+
}
|
|
101
154
|
/** Seen along the push: the section, its inside and a handle on each wall. */
|
|
102
155
|
top(e, w) {
|
|
103
156
|
const [h, v] = SCREEN[e.axis];
|
|
@@ -129,7 +182,8 @@ let FigureCavityDrawing = class FigureCavityDrawing extends localize(i18next)(Li
|
|
|
129
182
|
return svg `<g wall=${side} style=${`cursor:${a === h ? 'ew-resize' : 'ns-resize'}`}
|
|
130
183
|
@pointerdown=${(ev) => this.grab(ev, { kind: 'wall', side })}>
|
|
131
184
|
<rect x=${x - 6} y=${y - 6} width="12" height="12" rx="2" style="fill:var(--md-sys-color-surface);stroke:var(--md-sys-color-primary);stroke-width:1.5" />
|
|
132
|
-
<text x=${tx} y=${ty} font-size="11" text-anchor=${a === h ? 'middle' : 'start'} style="fill:var(--md-sys-color-on-surface)"
|
|
185
|
+
<text typed x=${tx} y=${ty} font-size="11" text-anchor=${a === h ? 'middle' : 'start'} style="fill:var(--md-sys-color-on-surface)"
|
|
186
|
+
@pointerdown=${(ev) => this.type(ev, { kind: 'wall', side }, 'top', w.wall[side])}>${mm(w.wall[side])}</text>
|
|
133
187
|
<title>${i18next.t('figure.label.face-' + SIDE_FACE[side])} ${i18next.t('figure.label.section-wall')}</title>
|
|
134
188
|
</g>`;
|
|
135
189
|
});
|
|
@@ -168,7 +222,8 @@ let FigureCavityDrawing = class FigureCavityDrawing extends localize(i18next)(Li
|
|
|
168
222
|
@pointerdown=${(ev) => this.grab(ev, { kind: 'end', end })}>
|
|
169
223
|
<rect x=${x0 + wl} y=${Math.min(y, inner) - 8} width=${x1 - x0 - wl - wr} height=${Math.abs(t) + 16} style="fill:transparent" />
|
|
170
224
|
${open ? svg `<line x1=${x0 + wl} y1=${y} x2=${x1 - wr} y2=${y} style="stroke:var(--md-sys-color-outline);stroke-dasharray:3 3" />` : nothing}
|
|
171
|
-
<text x=${W / 2} y=${end === 'start' ? yBot + 16 : yTop - 8} font-size="11" text-anchor="middle" style="fill:var(--md-sys-color-primary)"
|
|
225
|
+
<text ?typed=${!open} x=${W / 2} y=${end === 'start' ? yBot + 16 : yTop - 8} font-size="11" text-anchor="middle" style="fill:var(--md-sys-color-primary)"
|
|
226
|
+
@pointerdown=${(ev) => !open && this.type(ev, { kind: 'end', end }, 'side', w[end].closed)}>${label}</text>
|
|
172
227
|
<title>${label}</title>
|
|
173
228
|
</g>`;
|
|
174
229
|
};
|
|
@@ -200,7 +255,7 @@ let FigureCavityDrawing = class FigureCavityDrawing extends localize(i18next)(Li
|
|
|
200
255
|
const a = d.side[0], low = d.side[1] === '-';
|
|
201
256
|
const at = a === h ? p.x - ox : p.y - oy;
|
|
202
257
|
const value = (half[a] - (low ? -at : at)) / k;
|
|
203
|
-
this.hold({ ...this.now, wall: wallDragged(this.now.wall, d.side, value, this.perSide) });
|
|
258
|
+
this.hold({ ...this.now, wall: wallDragged(this.now.wall, d.side, value, this.perSide) }, d.side);
|
|
204
259
|
}
|
|
205
260
|
dragEnd(ev, k, yTop, yBot) {
|
|
206
261
|
const d = this.dragging;
|
|
@@ -246,6 +301,10 @@ __decorate([
|
|
|
246
301
|
state(),
|
|
247
302
|
__metadata("design:type", Object)
|
|
248
303
|
], FigureCavityDrawing.prototype, "refusal", void 0);
|
|
304
|
+
__decorate([
|
|
305
|
+
state(),
|
|
306
|
+
__metadata("design:type", Object)
|
|
307
|
+
], FigureCavityDrawing.prototype, "typing", void 0);
|
|
249
308
|
FigureCavityDrawing = __decorate([
|
|
250
309
|
customElement('figure-cavity-drawing')
|
|
251
310
|
], FigureCavityDrawing);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"figure-cavity-drawing.js","sourceRoot":"","sources":["../../client/modeller/figure-cavity-drawing.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement, nothing, svg } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { figureCavitySectionOf } from '@hatiolab/figure-model'\nimport type { FigureAuthoringAction, FigureCavityRequest, FigureEvaluatedShape, FigureSection } from '@hatiolab/figure-model'\nimport { cavityRefusalOf, cavityWorkingOf, END_FACE, endToggled, mm, SIDE_FACE, wallDragged } from './section-controls.js'\n\ntype Axis = 'x' | 'y' | 'z'\ntype End = 'start' | 'end'\ntype Body = { id: string; shape: FigureEvaluatedShape }\n\n/** How the section is laid on the screen, by the axis it is pushed along: across to the right, then down. */\nconst SCREEN: Record<Axis, [Axis, Axis]> = { y: ['x', 'z'], x: ['z', 'y'], z: ['x', 'y'] }\n\n/**\n * 속 공간 그림 — the inside of a pushed part drawn, and edited by drawing (user 2026-10-01: 「이해와 편집이 직관적이지 않다」).\n *\n * Seen along the push, the section and its inside: a handle in the middle of each wall is dragged to its thickness,\n * every wall together unless 면마다 벽 is on. Cut along the push, the walls and the two ends: an end pressed opens or\n * closes it, a closed end's inner line is dragged to its thickness. While dragging, the figure behind shows what the\n * inside makes (`command-live`); letting go sends one `set-cavity`. What the kernel would refuse is drawn in the error\n * colour and said, by the kernel's own check, and is not sent.\n */\n@customElement('figure-cavity-drawing')\nexport class FigureCavityDrawing extends localize(i18next)(LitElement) {\n static styles = css`\n :host {\n display: grid;\n gap: 6px;\n }\n svg {\n width: 100%;\n display: block;\n touch-action: none;\n user-select: none;\n }\n svg text {\n font: inherit;\n }\n small[refusal] {\n color: var(--md-sys-color-error);\n }\n `\n\n @property({ attribute: false }) body?: Body\n @property({ type: Boolean }) locked = false\n /** Walls one per side: a handle moves its own wall only. */\n @property({ type: Boolean }) perSide = false\n\n /** What is being dragged, and the inside it makes; undefined when nothing is. */\n @state() private working?: ReturnType<typeof cavityWorkingOf>\n @state() private refusal = ''\n private dragging: { kind: 'wall'; side: string } | { kind: 'end'; end: End } | null = null\n private pressedAt = 0\n\n private get now() {\n return this.working ?? (this.body ? cavityWorkingOf(this.body.shape) : undefined)\n }\n\n private request(w: NonNullable<ReturnType<typeof cavityWorkingOf>>): FigureCavityRequest {\n return { wall: { ...w.wall }, start: w.start, end: w.end }\n }\n\n private action(w: NonNullable<ReturnType<typeof cavityWorkingOf>>): FigureAuthoringAction {\n return { kind: 'set-cavity', part: this.body!.id, cavity: this.request(w) }\n }\n\n private judge(w: NonNullable<ReturnType<typeof cavityWorkingOf>>): string {\n const ask = cavityRefusalOf(this.body!.shape, this.request(w))\n if (!ask) return ''\n if (ask.code === 'wall-too-thick') return i18next.t('figure.text.section-wall-over', { max: String(ask.max) })\n if (ask.code === 'ends-too-thick') return i18next.t('figure.text.section-ends-over', { max: String(ask.max) })\n return i18next.t('figure.text.section-not-positive')\n }\n\n /** The working inside while dragging: drawn, judged, and previewed behind when the kernel would take it. */\n private hold(w: NonNullable<ReturnType<typeof cavityWorkingOf>>) {\n this.working = w\n this.refusal = this.judge(w)\n this.emit('command-live', this.refusal ? null : this.action(w))\n }\n\n private release() {\n const w = this.working\n this.dragging = null\n this.working = undefined\n if (!w) return\n /* Refused: nothing is sent, and the reason stays said until the next drag -- letting go must not look like taking it. */\n if (this.refusal) {\n this.emit('command-live', null)\n return\n }\n this.emit('command', this.action(w))\n }\n\n private emit(name: 'command' | 'command-live', action: FigureAuthoringAction | null) {\n this.dispatchEvent(new CustomEvent(name, { detail: { action }, bubbles: true, composed: true }))\n }\n\n private point(ev: PointerEvent, el: SVGSVGElement) {\n const pt = el.createSVGPoint()\n pt.x = ev.clientX\n pt.y = ev.clientY\n return pt.matrixTransform(el.getScreenCTM()!.inverse())\n }\n\n render() {\n const e = this.body?.shape.extrusion\n const w = this.now\n if (!e || !w || (e.section.kind !== 'rectangle' && e.section.kind !== 'ellipse')) return nothing\n return html`${this.top(e, w)}${this.side(e, w)}\n ${this.refusal ? html`<small refusal role=\"alert\">${this.refusal}</small>` : nothing}`\n }\n\n /** Seen along the push: the section, its inside and a handle on each wall. */\n private top(e: NonNullable<FigureEvaluatedShape['extrusion']>, w: NonNullable<ReturnType<typeof cavityWorkingOf>>) {\n const [h, v] = SCREEN[e.axis]\n const s = e.section\n const across = (a: Axis) => (s.kind === 'rectangle' ? s.size[a]! : 2 * (s as { radius: Record<string, number> }).radius[a]!)\n const W = 300,\n H = 170,\n pad = 26\n const k = Math.min((W - 2 * pad) / across(h), (H - 2 * pad) / across(v))\n const ox = W / 2,\n oy = H / 2\n const inside = figureCavitySectionOf(s as FigureSection, e.axis, w.wall)\n const bad = !!this.refusal || !('section' in inside)\n const shape = (sec: FigureSection, c: Partial<Record<Axis, number>>, attrs: string) => {\n const cx = ox + (c[h] ?? 0) * k,\n cy = oy + (c[v] ?? 0) * k\n if (sec.kind === 'ellipse') return svg`<ellipse cx=${cx} cy=${cy} rx=${sec.radius[h]! * k} ry=${sec.radius[v]! * k} style=${attrs} />`\n const r = sec as { size: Record<string, number>; corner?: Record<string, number> }\n return svg`<rect x=${cx - (r.size[h]! * k) / 2} y=${cy - (r.size[v]! * k) / 2} width=${r.size[h]! * k} height=${r.size[v]! * k}\n rx=${(r.corner?.[h] ?? 0) * k} ry=${(r.corner?.[v] ?? 0) * k} style=${attrs} />`\n }\n const half = { [h]: (across(h) * k) / 2, [v]: (across(v) * k) / 2 } as Record<Axis, number>\n /* Each wall's handle sits on the inside's edge, half way along it; the value is the wall's own. */\n const handles = [`${h}-`, `${h}+`, `${v}-`, `${v}+`].map(side => {\n const a = side[0] as Axis,\n low = side[1] === '-'\n const edge = (low ? -1 : 1) * (half[a] - w.wall[side]! * k)\n const x = a === h ? ox + edge : ox,\n y = a === v ? oy + edge : oy\n /* The number stands in the wall itself, half way through it; a wall too thin for it has it just outside. */\n const band = w.wall[side]! * k\n const mid = (low ? -1 : 1) * (half[a] - (band < 16 ? -9 : band / 2))\n const tx = a === h ? ox + mid : x + 14,\n ty = a === v ? oy + mid + 4 : y - 10\n return svg`<g wall=${side} style=${`cursor:${a === h ? 'ew-resize' : 'ns-resize'}`}\n @pointerdown=${(ev: PointerEvent) => this.grab(ev, { kind: 'wall', side })}>\n <rect x=${x - 6} y=${y - 6} width=\"12\" height=\"12\" rx=\"2\" style=\"fill:var(--md-sys-color-surface);stroke:var(--md-sys-color-primary);stroke-width:1.5\" />\n <text x=${tx} y=${ty} font-size=\"11\" text-anchor=${a === h ? 'middle' : 'start'} style=\"fill:var(--md-sys-color-on-surface)\">${mm(w.wall[side]!)}</text>\n <title>${i18next.t('figure.label.face-' + SIDE_FACE[side])} ${i18next.t('figure.label.section-wall')}</title>\n </g>`\n })\n return svg`<svg viewBox=${`0 0 ${W} ${H}`} role=\"img\" aria-label=${i18next.t('figure.label.section-cavity-top')}\n @pointermove=${(ev: PointerEvent) => this.drag(ev, e, k, ox, oy, half)}\n @pointerup=${() => this.release()} @pointercancel=${() => this.release()}>\n ${shape(s as FigureSection, {}, 'fill:var(--md-sys-color-primary-container);stroke:var(--md-sys-color-primary);stroke-width:1.5')}\n ${'section' in inside\n ? shape(inside.section, inside.centre, `fill:var(--md-sys-color-surface);stroke:${bad ? 'var(--md-sys-color-error)' : 'var(--md-sys-color-primary)'};stroke-width:1.2;stroke-dasharray:4 3`)\n : nothing}\n ${this.locked ? nothing : handles}\n </svg>`\n }\n\n /** Cut along the push: the walls across the first plane axis, and the two ends -- pressed to open or close. */\n private side(e: NonNullable<FigureEvaluatedShape['extrusion']>, w: NonNullable<ReturnType<typeof cavityWorkingOf>>) {\n const [h] = SCREEN[e.axis]\n const s = e.section\n const width = s.kind === 'rectangle' ? s.size[h]! : 2 * (s as { radius: Record<string, number> }).radius[h]!\n const length = e.end - e.start\n const W = 300,\n H = 170,\n padX = 40,\n padY = 26\n const k = Math.min((W - 2 * padX) / width, (H - 2 * padY) / length)\n const x0 = W / 2 - (width * k) / 2,\n x1 = W / 2 + (width * k) / 2,\n yTop = H / 2 - (length * k) / 2,\n yBot = H / 2 + (length * k) / 2\n const wl = w.wall[`${h}-`]! * k,\n wr = w.wall[`${h}+`]! * k\n const thick = (end: End) => (w[end] === 'open' ? 0 : (w[end] as { closed: number }).closed * k)\n /* The push's start is drawn at the bottom: a tote stands on its floor. */\n const floor = thick('start'),\n lid = thick('end')\n const fill = 'fill:var(--md-sys-color-primary-container);stroke:var(--md-sys-color-primary);stroke-width:1.2'\n const endZone = (end: End, y: number, t: number) => {\n const open = w[end] === 'open'\n const words = open\n ? i18next.t('figure.label.section-end-open')\n : `${i18next.t('figure.label.section-end-closed')} ${mm((w[end] as { closed: number }).closed)}`\n const label = `${i18next.t('figure.label.face-' + END_FACE(e.axis, end))}: ${words}`\n const inner = end === 'start' ? y - t : y + t\n return svg`<g end=${end} style=${`cursor:${open ? 'pointer' : 'ns-resize'}`}\n @pointerdown=${(ev: PointerEvent) => this.grab(ev, { kind: 'end', end })}>\n <rect x=${x0 + wl} y=${Math.min(y, inner) - 8} width=${x1 - x0 - wl - wr} height=${Math.abs(t) + 16} style=\"fill:transparent\" />\n ${open ? svg`<line x1=${x0 + wl} y1=${y} x2=${x1 - wr} y2=${y} style=\"stroke:var(--md-sys-color-outline);stroke-dasharray:3 3\" />` : nothing}\n <text x=${W / 2} y=${end === 'start' ? yBot + 16 : yTop - 8} font-size=\"11\" text-anchor=\"middle\" style=\"fill:var(--md-sys-color-primary)\">${label}</text>\n <title>${label}</title>\n </g>`\n }\n return svg`<svg viewBox=${`0 0 ${W} ${H + 8}`} role=\"img\" aria-label=${i18next.t('figure.label.section-cavity-side')}\n @pointermove=${(ev: PointerEvent) => this.dragEnd(ev, k, yTop, yBot)}\n @pointerup=${(ev: PointerEvent) => this.releaseEnd(ev)} @pointercancel=${() => this.release()}>\n <rect x=${x0} y=${yTop} width=${wl} height=${yBot - yTop} style=${fill} />\n <rect x=${x1 - wr} y=${yTop} width=${wr} height=${yBot - yTop} style=${fill} />\n ${floor ? svg`<rect x=${x0 + wl} y=${yBot - floor} width=${x1 - x0 - wl - wr} height=${floor} style=${fill} />` : nothing}\n ${lid ? svg`<rect x=${x0 + wl} y=${yTop} width=${x1 - x0 - wl - wr} height=${lid} style=${fill} />` : nothing}\n ${this.locked ? nothing : [endZone('start', yBot, floor), endZone('end', yTop, lid)]}\n </svg>`\n }\n\n private grab(ev: PointerEvent, what: NonNullable<FigureCavityDrawing['dragging']>) {\n if (this.locked) return\n ev.stopPropagation()\n ;(ev.currentTarget as Element).closest('svg')!.setPointerCapture(ev.pointerId)\n this.dragging = what\n this.pressedAt = ev.clientY\n this.refusal = ''\n }\n\n private drag(ev: PointerEvent, e: NonNullable<FigureEvaluatedShape['extrusion']>, k: number, ox: number, oy: number, half: Record<Axis, number>) {\n const d = this.dragging\n if (d?.kind !== 'wall') return\n const [h] = SCREEN[e.axis]\n const p = this.point(ev, ev.currentTarget as SVGSVGElement)\n const a = d.side[0] as Axis,\n low = d.side[1] === '-'\n const at = a === h ? p.x - ox : p.y - oy\n const value = (half[a] - (low ? -at : at)) / k\n this.hold({ ...this.now!, wall: wallDragged(this.now!.wall, d.side, value, this.perSide) })\n }\n\n private dragEnd(ev: PointerEvent, k: number, yTop: number, yBot: number) {\n const d = this.dragging\n if (d?.kind !== 'end' || this.now![d.end] === 'open') return\n if (Math.abs(ev.clientY - this.pressedAt) < 3 && !this.working) return\n const p = this.point(ev, ev.currentTarget as SVGSVGElement)\n const t = d.end === 'start' ? (yBot - p.y) / k : (p.y - yTop) / k\n this.hold({ ...this.now!, [d.end]: { closed: Math.max(1, Math.round(t)) } })\n }\n\n /** A press on an end that did not move is a toggle; a drag was a thickness. */\n private releaseEnd(ev: PointerEvent) {\n const d = this.dragging\n if (d?.kind === 'end' && !this.working && Math.abs(ev.clientY - this.pressedAt) < 3) {\n this.dragging = null\n const next = { ...this.now!, [d.end]: endToggled(this.body!.shape, this.now![d.end]) }\n this.refusal = this.judge(next)\n if (!this.refusal) this.emit('command', this.action(next))\n return\n }\n this.release()\n }\n}\n\n"]}
|
|
1
|
+
{"version":3,"file":"figure-cavity-drawing.js","sourceRoot":"","sources":["../../client/modeller/figure-cavity-drawing.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAA;AACzD,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAClE,OAAO,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAA;AAE3C,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAA;AAE9D,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE,SAAS,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAI3I,wDAAwD;AACxD,MAAM,aAAa,GAAG,GAAG,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,qBAAqB,CAAC,GAAG,EAAE,CAAE,EAAuB,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;AAI3G,6GAA6G;AAC7G,MAAM,MAAM,GAA+B,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAA;AAE1F;;;;;;;;GAQG;AAEI,IAAM,mBAAmB,GAAzB,MAAM,mBAAoB,SAAQ,QAAQ,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC;IAA/D;;QAkCwB,WAAM,GAAG,KAAK,CAAA;QAC3C,4DAA4D;QAC/B,YAAO,GAAG,KAAK,CAAA;QAI3B,YAAO,GAAG,EAAE,CAAA;QACrB,aAAQ,GAAsE,IAAI,CAAA;QAGlF,cAAS,GAAG,CAAC,CAAA;IAgPvB,CAAC;aA3RQ,WAAM,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BlB,AA9BY,CA8BZ;IAeD,IAAY,GAAG;QACb,OAAO,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;IACnF,CAAC;IAEO,OAAO,CAAC,CAAkD;QAChE,OAAO,EAAE,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAA;IAC5D,CAAC;IAEO,MAAM,CAAC,CAAkD;QAC/D,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,IAAI,CAAC,IAAK,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAA;IAC7E,CAAC;IAED,qHAAqH;IAC7G,KAAK,CAAC,CAAkD,EAAE,IAAa;QAC7E,MAAM,GAAG,GAAG,eAAe,CAAC,IAAI,CAAC,IAAK,CAAC,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAA;QAC9D,IAAI,CAAC,GAAG;YAAE,OAAO,EAAE,CAAA;QACnB,IAAI,GAAG,CAAC,IAAI,KAAK,gBAAgB;YAC/B,OAAO,OAAO,CAAC,CAAC,CAAC,+BAA+B,EAAE;gBAChD,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,IAAK,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;aAClG,CAAC,CAAA;QACJ,IAAI,GAAG,CAAC,IAAI,KAAK,gBAAgB;YAAE,OAAO,OAAO,CAAC,CAAC,CAAC,+BAA+B,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QAC9G,OAAO,OAAO,CAAC,CAAC,CAAC,kCAAkC,CAAC,CAAA;IACtD,CAAC;IAED,4GAA4G;IACpG,IAAI,CAAC,CAAkD,EAAE,IAAa;QAC5E,IAAI,CAAC,OAAO,GAAG,CAAC,CAAA;QAChB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAA;QAClC,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;IACjE,CAAC;IAEO,OAAO;QACb,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAA;QACtB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAA;QACpB,IAAI,CAAC,OAAO,GAAG,SAAS,CAAA;QACxB,IAAI,CAAC,CAAC;YAAE,OAAM;QACd,yHAAyH;QACzH,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,CAAA;YAC/B,OAAM;QACR,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;IACtC,CAAC;IAEO,IAAI,CAAC,IAAgC,EAAE,MAAoC;QACjF,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;IAClG,CAAC;IAEO,KAAK,CAAC,EAAgB,EAAE,EAAiB;QAC/C,MAAM,EAAE,GAAG,EAAE,CAAC,cAAc,EAAE,CAAA;QAC9B,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,OAAO,CAAA;QACjB,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,OAAO,CAAA;QACjB,OAAO,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC,YAAY,EAAG,CAAC,OAAO,EAAE,CAAC,CAAA;IACzD,CAAC;IAED,MAAM;QACJ,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,SAAS,CAAA;QACpC,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAA;QAClB,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,KAAK,WAAW,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,KAAK,SAAS,CAAC;YAAE,OAAO,OAAO,CAAA;QAChG,OAAO,IAAI,CAAA,aAAa,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,OAAO;kBACtF,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,OAAO;QACxF,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAA,+BAA+B,IAAI,CAAC,OAAO,UAAU,CAAC,CAAC,CAAC,OAAO,EAAE,CAAA;IAC1F,CAAC;IAED,yGAAyG;IACjG,IAAI,CAAC,EAAgB,EAAE,IAAgE,EAAE,IAAoB,EAAE,KAAa;QAClI,IAAI,IAAI,CAAC,MAAM;YAAE,OAAM;QACvB,EAAE,CAAC,eAAe,EAAE,CAAA;QACpB,MAAM,KAAK,GAAI,EAAE,CAAC,MAAkB,CAAC,OAAO,CAAC,KAAK,CAAE,CAAA;QACpD,MAAM,GAAG,GAAG,KAAK,CAAC,qBAAqB,EAAE,CAAA;QACzC,IAAI,CAAC,OAAO,GAAG,EAAE,CAAA;QACjB,IAAI,CAAC,MAAM,GAAG,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,OAAO,GAAG,GAAG,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,OAAO,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,GAAG,EAAE,CAAA;IACxI,CAAC;IAEO,YAAY;QAClB,MAAM,CAAC,GAAG,IAAI,CAAC,MAAO,CAAA;QACtB,OAAO,IAAI,CAAA,gDAAgD,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG;mBAC/F,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,2BAA2B,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,oBAAoB,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAK,CAAC,KAAK,CAAC,SAAU,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;iBAClJ,CAAC,EAAiB,EAAE,EAAE;YAC/B,EAAE,CAAC,eAAe,EAAE,CAAA;YACpB,IAAI,EAAE,CAAC,GAAG,KAAK,QAAQ;gBAAE,IAAI,CAAC,MAAM,GAAG,SAAS,CAAA;YAChD,IAAI,EAAE,CAAC,GAAG,KAAK,OAAO;gBAAE,OAAM;YAC9B,MAAM,KAAK,GAAG,MAAM,CAAE,EAAE,CAAC,MAA2B,CAAC,KAAK,CAAC,CAAA;YAC3D,IAAI,CAAC,MAAM,GAAG,SAAS,CAAA;YACvB,IAAI,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC;gBAAE,OAAM;YAClD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAI,CAAA;YACrB,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,IAAI,EAAE,WAAW,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,EAAE,CAAA;YAC1J,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;YACvE,IAAI,CAAC,IAAI,CAAC,OAAO;gBAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAA;QAC5D,CAAC;cACO,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;QACrC,aAAa,EAAE,KAAK,CAAA;IAC1B,CAAC;IAED,8EAA8E;IACtE,GAAG,CAAC,CAAiD,EAAE,CAAkD;QAC/G,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;QAC7B,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAA;QACnB,MAAM,MAAM,GAAG,CAAC,CAAO,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC,GAAI,CAAwC,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,CAAA;QAC5H,MAAM,CAAC,GAAG,GAAG,EACX,CAAC,GAAG,GAAG,EACP,GAAG,GAAG,EAAE,CAAA;QACV,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;QACxE,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,EACd,EAAE,GAAG,CAAC,GAAG,CAAC,CAAA;QACZ,MAAM,MAAM,GAAG,qBAAqB,CAAC,CAAkB,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAA;QACxE,MAAM,GAAG,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC,SAAS,IAAI,MAAM,CAAC,CAAA;QACpD,MAAM,KAAK,GAAG,CAAC,GAAkB,EAAE,CAAgC,EAAE,KAAa,EAAE,EAAE;YACpF,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAC7B,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAA;YAC3B,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS;gBAAE,OAAO,GAAG,CAAA,eAAe,EAAE,OAAO,EAAE,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,CAAE,GAAG,CAAC,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,CAAE,GAAG,CAAC,UAAU,KAAK,KAAK,CAAA;YACtI,MAAM,CAAC,GAAG,GAAwE,CAAA;YAClF,OAAO,GAAG,CAAA,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAE,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAE,GAAG,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAE,GAAG,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAE,GAAG,CAAC;aACvH,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,UAAU,KAAK,KAAK,CAAA;QACpF,CAAC,CAAA;QACD,MAAM,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,EAA0B,CAAA;QAC3F,mGAAmG;QACnG,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;YAC9D,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAS,EACvB,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,CAAA;YACvB,MAAM,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAE,GAAG,CAAC,CAAC,CAAA;YAC3D,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,EAChC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,CAAA;YAC9B,4GAA4G;YAC5G,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAE,GAAG,CAAC,CAAA;YAC9B,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAA;YACpE,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,EACpC,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAA;YACtC,OAAO,GAAG,CAAA,WAAW,IAAI,UAAU,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,EAAE;yBAC/D,CAAC,EAAgB,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;kBAClE,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC;wBACV,EAAE,MAAM,EAAE,+BAA+B,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO;yBACpE,CAAC,EAAgB,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAE,CAAC;iBAC9G,OAAO,CAAC,CAAC,CAAC,oBAAoB,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,2BAA2B,CAAC;WACjG,CAAA;QACP,CAAC,CAAC,CAAA;QACF,OAAO,GAAG,CAAA,gBAAgB,OAAO,CAAC,IAAI,CAAC,EAAE,0BAA0B,OAAO,CAAC,CAAC,CAAC,iCAAiC,CAAC;uBAC5F,CAAC,EAAgB,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC;qBACzD,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,mBAAmB,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE;QACxE,KAAK,CAAC,CAAkB,EAAE,EAAE,EAAE,gGAAgG,CAAC;QAC/H,SAAS,IAAI,MAAM;YACnB,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,2CAA2C,GAAG,CAAC,CAAC,CAAC,2BAA2B,CAAC,CAAC,CAAC,6BAA6B,wCAAwC,CAAC;YAC5L,CAAC,CAAC,OAAO;QACT,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO;WAC5B,CAAA;IACT,CAAC;IAED,+GAA+G;IACvG,IAAI,CAAC,CAAiD,EAAE,CAAkD;QAChH,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;QAC1B,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAA;QACnB,MAAM,KAAK,GAAG,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC,GAAI,CAAwC,CAAC,MAAM,CAAC,CAAC,CAAE,CAAA;QAC5G,MAAM,MAAM,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,KAAK,CAAA;QAC9B,MAAM,CAAC,GAAG,GAAG,EACX,CAAC,GAAG,GAAG,EACP,IAAI,GAAG,EAAE,EACT,IAAI,GAAG,EAAE,CAAA;QACX,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,MAAM,CAAC,CAAA;QACnE,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,EAChC,EAAE,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,EAC5B,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,EAC/B,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,CAAA;QACjC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAE,GAAG,CAAC,EAC7B,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAE,GAAG,CAAC,CAAA;QAC3B,MAAM,KAAK,GAAG,CAAC,GAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC,GAAG,CAAwB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;QAC/F,0EAA0E;QAC1E,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,EAC1B,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,CAAA;QACpB,MAAM,IAAI,GAAG,gGAAgG,CAAA;QAC7G,MAAM,OAAO,GAAG,CAAC,GAAQ,EAAE,CAAS,EAAE,CAAS,EAAE,EAAE;YACjD,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,MAAM,CAAA;YAC9B,MAAM,KAAK,GAAG,IAAI;gBAChB,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,+BAA+B,CAAC;gBAC5C,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,iCAAiC,CAAC,IAAI,EAAE,CAAE,CAAC,CAAC,GAAG,CAAwB,CAAC,MAAM,CAAC,EAAE,CAAA;YAClG,MAAM,KAAK,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,oBAAoB,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,KAAK,KAAK,EAAE,CAAA;YACpF,MAAM,KAAK,GAAG,GAAG,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;YAC7C,OAAO,GAAG,CAAA,UAAU,GAAG,UAAU,UAAU,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,EAAE;yBACxD,CAAC,EAAgB,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;kBAChE,EAAE,GAAG,EAAE,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,WAAW,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE;UACjG,IAAI,CAAC,CAAC,CAAC,GAAG,CAAA,YAAY,EAAE,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,qEAAqE,CAAC,CAAC,CAAC,OAAO;uBAC7H,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,MAAM,GAAG,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC;yBAC1D,CAAC,EAAgB,EAAE,EAAE,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,MAAM,EAAG,CAAC,CAAC,GAAG,CAAwB,CAAC,MAAM,CAAC,IAAI,KAAK;iBAClI,KAAK;WACX,CAAA;QACP,CAAC,CAAA;QACD,OAAO,GAAG,CAAA,gBAAgB,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,0BAA0B,OAAO,CAAC,CAAC,CAAC,kCAAkC,CAAC;uBACjG,CAAC,EAAgB,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC;qBACvD,CAAC,EAAgB,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,mBAAmB,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE;gBACrF,EAAE,MAAM,IAAI,UAAU,EAAE,WAAW,IAAI,GAAG,IAAI,UAAU,IAAI;gBAC5D,EAAE,GAAG,EAAE,MAAM,IAAI,UAAU,EAAE,WAAW,IAAI,GAAG,IAAI,UAAU,IAAI;QACzE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAA,WAAW,EAAE,GAAG,EAAE,MAAM,IAAI,GAAG,KAAK,UAAU,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,WAAW,KAAK,UAAU,IAAI,KAAK,CAAC,CAAC,CAAC,OAAO;QACvH,GAAG,CAAC,CAAC,CAAC,GAAG,CAAA,WAAW,EAAE,GAAG,EAAE,MAAM,IAAI,UAAU,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,WAAW,GAAG,UAAU,IAAI,KAAK,CAAC,CAAC,CAAC,OAAO;QAC3G,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,EAAE,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;WAC/E,CAAA;IACT,CAAC;IAEO,IAAI,CAAC,EAAgB,EAAE,IAAkD;QAC/E,IAAI,IAAI,CAAC,MAAM;YAAE,OAAM;QACvB,EAAE,CAAC,eAAe,EAAE,CACnB;QAAC,EAAE,CAAC,aAAyB,CAAC,OAAO,CAAC,KAAK,CAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC,SAAS,CAAC,CAAA;QAC9E,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAA;QACpB,IAAI,CAAC,SAAS,GAAG,EAAE,CAAC,OAAO,CAAA;QAC3B,IAAI,CAAC,OAAO,GAAG,EAAE,CAAA;IACnB,CAAC;IAEO,IAAI,CAAC,EAAgB,EAAE,CAAiD,EAAE,CAAS,EAAE,EAAU,EAAE,EAAU,EAAE,IAA0B;QAC7I,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAA;QACvB,IAAI,CAAC,EAAE,IAAI,KAAK,MAAM;YAAE,OAAM;QAC9B,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;QAC1B,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,aAA8B,CAAC,CAAA;QAC3D,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAS,EACzB,GAAG,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,CAAA;QACzB,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAA;QACxC,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAA;QAC9C,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,GAAI,EAAE,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,GAAI,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAA;IACrG,CAAC;IAEO,OAAO,CAAC,EAAgB,EAAE,CAAS,EAAE,IAAY,EAAE,IAAY;QACrE,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAA;QACvB,IAAI,CAAC,EAAE,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,GAAI,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,MAAM;YAAE,OAAM;QAC5D,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAM;QACtE,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,aAA8B,CAAC,CAAA;QAC3D,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAA;QACjE,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,GAAI,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IAC9E,CAAC;IAED,+EAA+E;IACvE,UAAU,CAAC,EAAgB;QACjC,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAA;QACvB,IAAI,CAAC,EAAE,IAAI,KAAK,KAAK,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;YACpF,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAA;YACpB,MAAM,IAAI,GAAG,EAAE,GAAG,IAAI,CAAC,GAAI,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,UAAU,CAAC,IAAI,CAAC,IAAK,CAAC,KAAK,EAAE,IAAI,CAAC,GAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAA;YACtF,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;YAC/B,IAAI,CAAC,IAAI,CAAC,OAAO;gBAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAA;YAC1D,OAAM;QACR,CAAC;QACD,IAAI,CAAC,OAAO,EAAE,CAAA;IAChB,CAAC;;AA1P+B;IAA/B,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;;iDAAY;AACd;IAA5B,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;;mDAAe;AAEd;IAA5B,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;;oDAAgB;AAG3B;IAAhB,KAAK,EAAE;;oDAAqD;AAC5C;IAAhB,KAAK,EAAE;;oDAAqB;AAGZ;IAAhB,KAAK,EAAE;;mDAA8I;AA3C3I,mBAAmB;IAD/B,aAAa,CAAC,uBAAuB,CAAC;GAC1B,mBAAmB,CA4R/B","sourcesContent":["import { css, html, LitElement, nothing, svg } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { ref } from 'lit/directives/ref.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { figureCavitySectionOf } from '@hatiolab/figure-model'\nimport type { FigureAuthoringAction, FigureCavityRequest, FigureEvaluatedShape, FigureSection } from '@hatiolab/figure-model'\nimport { cavityRefusalOf, cavityWorkingOf, END_FACE, endToggled, mm, SIDE_FACE, sideWallLimitOf, wallDragged } from './section-controls.js'\n\ntype Axis = 'x' | 'y' | 'z'\n\n/** A field opened by a press takes the keys at once. */\nconst focusOnRender = () => ref(el => el && requestAnimationFrame(() => (el as HTMLInputElement).select()))\ntype End = 'start' | 'end'\ntype Body = { id: string; shape: FigureEvaluatedShape }\n\n/** How the section is laid on the screen, by the axis it is pushed along: across to the right, then down. */\nconst SCREEN: Record<Axis, [Axis, Axis]> = { y: ['x', 'z'], x: ['z', 'y'], z: ['x', 'y'] }\n\n/**\n * 속 공간 그림 — the inside of a pushed part drawn, and edited by drawing (user 2026-10-01: 「이해와 편집이 직관적이지 않다」).\n *\n * Seen along the push, the section and its inside: a handle in the middle of each wall is dragged to its thickness,\n * every wall together unless 면마다 벽 is on. Cut along the push, the walls and the two ends: an end pressed opens or\n * closes it, a closed end's inner line is dragged to its thickness. While dragging, the figure behind shows what the\n * inside makes (`command-live`); letting go sends one `set-cavity`. What the kernel would refuse is drawn in the error\n * colour and said, by the kernel's own check, and is not sent.\n */\n@customElement('figure-cavity-drawing')\nexport class FigureCavityDrawing extends localize(i18next)(LitElement) {\n static styles = css`\n :host {\n display: grid;\n gap: 6px;\n }\n svg {\n width: 100%;\n display: block;\n touch-action: none;\n user-select: none;\n }\n svg text {\n font: inherit;\n }\n small[refusal] {\n color: var(--md-sys-color-error);\n }\n div[pane] {\n position: relative;\n }\n div[pane] input {\n position: absolute;\n width: 64px;\n transform: translate(-50%, -50%);\n font: inherit;\n }\n text[typed] {\n cursor: text;\n text-decoration: underline dotted;\n }\n `\n\n @property({ attribute: false }) body?: Body\n @property({ type: Boolean }) locked = false\n /** Walls one per side: a handle moves its own wall only. */\n @property({ type: Boolean }) perSide = false\n\n /** What is being dragged, and the inside it makes; undefined when nothing is. */\n @state() private working?: ReturnType<typeof cavityWorkingOf>\n @state() private refusal = ''\n private dragging: { kind: 'wall'; side: string } | { kind: 'end'; end: End } | null = null\n /** A number pressed to be typed: which, and where on its picture (percent of the picture's box). */\n @state() private typing?: ({ kind: 'wall'; side: string } | { kind: 'end'; end: End }) & { x: number; y: number; pane: 'top' | 'side'; value: number }\n private pressedAt = 0\n\n private get now() {\n return this.working ?? (this.body ? cavityWorkingOf(this.body.shape) : undefined)\n }\n\n private request(w: NonNullable<ReturnType<typeof cavityWorkingOf>>): FigureCavityRequest {\n return { wall: { ...w.wall }, start: w.start, end: w.end }\n }\n\n private action(w: NonNullable<ReturnType<typeof cavityWorkingOf>>): FigureAuthoringAction {\n return { kind: 'set-cavity', part: this.body!.id, cavity: this.request(w) }\n }\n\n /** What the kernel would refuse, in words; for one side's wall, the most that side can be with the opposite kept. */\n private judge(w: NonNullable<ReturnType<typeof cavityWorkingOf>>, side?: string): string {\n const ask = cavityRefusalOf(this.body!.shape, this.request(w))\n if (!ask) return ''\n if (ask.code === 'wall-too-thick')\n return i18next.t('figure.text.section-wall-over', {\n max: String(this.perSide && side ? mm(sideWallLimitOf(this.body!.shape, w.wall, side)) : ask.max)\n })\n if (ask.code === 'ends-too-thick') return i18next.t('figure.text.section-ends-over', { max: String(ask.max) })\n return i18next.t('figure.text.section-not-positive')\n }\n\n /** The working inside while dragging: drawn, judged, and previewed behind when the kernel would take it. */\n private hold(w: NonNullable<ReturnType<typeof cavityWorkingOf>>, side?: string) {\n this.working = w\n this.refusal = this.judge(w, side)\n this.emit('command-live', this.refusal ? null : this.action(w))\n }\n\n private release() {\n const w = this.working\n this.dragging = null\n this.working = undefined\n if (!w) return\n /* Refused: nothing is sent, and the reason stays said until the next drag -- letting go must not look like taking it. */\n if (this.refusal) {\n this.emit('command-live', null)\n return\n }\n this.emit('command', this.action(w))\n }\n\n private emit(name: 'command' | 'command-live', action: FigureAuthoringAction | null) {\n this.dispatchEvent(new CustomEvent(name, { detail: { action }, bubbles: true, composed: true }))\n }\n\n private point(ev: PointerEvent, el: SVGSVGElement) {\n const pt = el.createSVGPoint()\n pt.x = ev.clientX\n pt.y = ev.clientY\n return pt.matrixTransform(el.getScreenCTM()!.inverse())\n }\n\n render() {\n const e = this.body?.shape.extrusion\n const w = this.now\n if (!e || !w || (e.section.kind !== 'rectangle' && e.section.kind !== 'ellipse')) return nothing\n return html`<div pane>${this.top(e, w)}${this.typing?.pane === 'top' ? this.renderTyping() : nothing}</div>\n <div pane>${this.side(e, w)}${this.typing?.pane === 'side' ? this.renderTyping() : nothing}</div>\n ${this.refusal ? html`<small refusal role=\"alert\">${this.refusal}</small>` : nothing}`\n }\n\n /** Press a number, type it, Enter: the same one set-cavity a drag sends; Esc or leaving puts it back. */\n private type(ev: PointerEvent, what: { kind: 'wall'; side: string } | { kind: 'end'; end: End }, pane: 'top' | 'side', value: number) {\n if (this.locked) return\n ev.stopPropagation()\n const svgEl = (ev.target as Element).closest('svg')!\n const box = svgEl.getBoundingClientRect()\n this.refusal = ''\n this.typing = { ...what, pane, value, x: ((ev.clientX - box.left) / box.width) * 100, y: ((ev.clientY - box.top) / box.height) * 100 }\n }\n\n private renderTyping() {\n const t = this.typing!\n return html`<input type=\"number\" step=\"1\" min=\"1\" .value=${String(t.value)} style=${`left:${t.x}%;top:${t.y}%`}\n aria-label=${t.kind === 'wall' ? i18next.t('figure.label.section-wall') : i18next.t('figure.label.face-' + END_FACE(this.body!.shape.extrusion!.axis, t.end))}\n @keydown=${(ev: KeyboardEvent) => {\n ev.stopPropagation()\n if (ev.key === 'Escape') this.typing = undefined\n if (ev.key !== 'Enter') return\n const value = Number((ev.target as HTMLInputElement).value)\n this.typing = undefined\n if (!(Number.isFinite(value) && value > 0)) return\n const now = this.now!\n const next = t.kind === 'wall' ? { ...now, wall: wallDragged(now.wall, t.side, value, this.perSide) } : { ...now, [t.end]: { closed: Math.round(value) } }\n this.refusal = this.judge(next, t.kind === 'wall' ? t.side : undefined)\n if (!this.refusal) this.emit('command', this.action(next))\n }}\n @blur=${() => (this.typing = undefined)}\n ${focusOnRender()} />`\n }\n\n /** Seen along the push: the section, its inside and a handle on each wall. */\n private top(e: NonNullable<FigureEvaluatedShape['extrusion']>, w: NonNullable<ReturnType<typeof cavityWorkingOf>>) {\n const [h, v] = SCREEN[e.axis]\n const s = e.section\n const across = (a: Axis) => (s.kind === 'rectangle' ? s.size[a]! : 2 * (s as { radius: Record<string, number> }).radius[a]!)\n const W = 300,\n H = 170,\n pad = 26\n const k = Math.min((W - 2 * pad) / across(h), (H - 2 * pad) / across(v))\n const ox = W / 2,\n oy = H / 2\n const inside = figureCavitySectionOf(s as FigureSection, e.axis, w.wall)\n const bad = !!this.refusal || !('section' in inside)\n const shape = (sec: FigureSection, c: Partial<Record<Axis, number>>, attrs: string) => {\n const cx = ox + (c[h] ?? 0) * k,\n cy = oy + (c[v] ?? 0) * k\n if (sec.kind === 'ellipse') return svg`<ellipse cx=${cx} cy=${cy} rx=${sec.radius[h]! * k} ry=${sec.radius[v]! * k} style=${attrs} />`\n const r = sec as { size: Record<string, number>; corner?: Record<string, number> }\n return svg`<rect x=${cx - (r.size[h]! * k) / 2} y=${cy - (r.size[v]! * k) / 2} width=${r.size[h]! * k} height=${r.size[v]! * k}\n rx=${(r.corner?.[h] ?? 0) * k} ry=${(r.corner?.[v] ?? 0) * k} style=${attrs} />`\n }\n const half = { [h]: (across(h) * k) / 2, [v]: (across(v) * k) / 2 } as Record<Axis, number>\n /* Each wall's handle sits on the inside's edge, half way along it; the value is the wall's own. */\n const handles = [`${h}-`, `${h}+`, `${v}-`, `${v}+`].map(side => {\n const a = side[0] as Axis,\n low = side[1] === '-'\n const edge = (low ? -1 : 1) * (half[a] - w.wall[side]! * k)\n const x = a === h ? ox + edge : ox,\n y = a === v ? oy + edge : oy\n /* The number stands in the wall itself, half way through it; a wall too thin for it has it just outside. */\n const band = w.wall[side]! * k\n const mid = (low ? -1 : 1) * (half[a] - (band < 16 ? -9 : band / 2))\n const tx = a === h ? ox + mid : x + 14,\n ty = a === v ? oy + mid + 4 : y - 10\n return svg`<g wall=${side} style=${`cursor:${a === h ? 'ew-resize' : 'ns-resize'}`}\n @pointerdown=${(ev: PointerEvent) => this.grab(ev, { kind: 'wall', side })}>\n <rect x=${x - 6} y=${y - 6} width=\"12\" height=\"12\" rx=\"2\" style=\"fill:var(--md-sys-color-surface);stroke:var(--md-sys-color-primary);stroke-width:1.5\" />\n <text typed x=${tx} y=${ty} font-size=\"11\" text-anchor=${a === h ? 'middle' : 'start'} style=\"fill:var(--md-sys-color-on-surface)\"\n @pointerdown=${(ev: PointerEvent) => this.type(ev, { kind: 'wall', side }, 'top', w.wall[side]!)}>${mm(w.wall[side]!)}</text>\n <title>${i18next.t('figure.label.face-' + SIDE_FACE[side])} ${i18next.t('figure.label.section-wall')}</title>\n </g>`\n })\n return svg`<svg viewBox=${`0 0 ${W} ${H}`} role=\"img\" aria-label=${i18next.t('figure.label.section-cavity-top')}\n @pointermove=${(ev: PointerEvent) => this.drag(ev, e, k, ox, oy, half)}\n @pointerup=${() => this.release()} @pointercancel=${() => this.release()}>\n ${shape(s as FigureSection, {}, 'fill:var(--md-sys-color-primary-container);stroke:var(--md-sys-color-primary);stroke-width:1.5')}\n ${'section' in inside\n ? shape(inside.section, inside.centre, `fill:var(--md-sys-color-surface);stroke:${bad ? 'var(--md-sys-color-error)' : 'var(--md-sys-color-primary)'};stroke-width:1.2;stroke-dasharray:4 3`)\n : nothing}\n ${this.locked ? nothing : handles}\n </svg>`\n }\n\n /** Cut along the push: the walls across the first plane axis, and the two ends -- pressed to open or close. */\n private side(e: NonNullable<FigureEvaluatedShape['extrusion']>, w: NonNullable<ReturnType<typeof cavityWorkingOf>>) {\n const [h] = SCREEN[e.axis]\n const s = e.section\n const width = s.kind === 'rectangle' ? s.size[h]! : 2 * (s as { radius: Record<string, number> }).radius[h]!\n const length = e.end - e.start\n const W = 300,\n H = 170,\n padX = 40,\n padY = 26\n const k = Math.min((W - 2 * padX) / width, (H - 2 * padY) / length)\n const x0 = W / 2 - (width * k) / 2,\n x1 = W / 2 + (width * k) / 2,\n yTop = H / 2 - (length * k) / 2,\n yBot = H / 2 + (length * k) / 2\n const wl = w.wall[`${h}-`]! * k,\n wr = w.wall[`${h}+`]! * k\n const thick = (end: End) => (w[end] === 'open' ? 0 : (w[end] as { closed: number }).closed * k)\n /* The push's start is drawn at the bottom: a tote stands on its floor. */\n const floor = thick('start'),\n lid = thick('end')\n const fill = 'fill:var(--md-sys-color-primary-container);stroke:var(--md-sys-color-primary);stroke-width:1.2'\n const endZone = (end: End, y: number, t: number) => {\n const open = w[end] === 'open'\n const words = open\n ? i18next.t('figure.label.section-end-open')\n : `${i18next.t('figure.label.section-end-closed')} ${mm((w[end] as { closed: number }).closed)}`\n const label = `${i18next.t('figure.label.face-' + END_FACE(e.axis, end))}: ${words}`\n const inner = end === 'start' ? y - t : y + t\n return svg`<g end=${end} style=${`cursor:${open ? 'pointer' : 'ns-resize'}`}\n @pointerdown=${(ev: PointerEvent) => this.grab(ev, { kind: 'end', end })}>\n <rect x=${x0 + wl} y=${Math.min(y, inner) - 8} width=${x1 - x0 - wl - wr} height=${Math.abs(t) + 16} style=\"fill:transparent\" />\n ${open ? svg`<line x1=${x0 + wl} y1=${y} x2=${x1 - wr} y2=${y} style=\"stroke:var(--md-sys-color-outline);stroke-dasharray:3 3\" />` : nothing}\n <text ?typed=${!open} x=${W / 2} y=${end === 'start' ? yBot + 16 : yTop - 8} font-size=\"11\" text-anchor=\"middle\" style=\"fill:var(--md-sys-color-primary)\"\n @pointerdown=${(ev: PointerEvent) => !open && this.type(ev, { kind: 'end', end }, 'side', (w[end] as { closed: number }).closed)}>${label}</text>\n <title>${label}</title>\n </g>`\n }\n return svg`<svg viewBox=${`0 0 ${W} ${H + 8}`} role=\"img\" aria-label=${i18next.t('figure.label.section-cavity-side')}\n @pointermove=${(ev: PointerEvent) => this.dragEnd(ev, k, yTop, yBot)}\n @pointerup=${(ev: PointerEvent) => this.releaseEnd(ev)} @pointercancel=${() => this.release()}>\n <rect x=${x0} y=${yTop} width=${wl} height=${yBot - yTop} style=${fill} />\n <rect x=${x1 - wr} y=${yTop} width=${wr} height=${yBot - yTop} style=${fill} />\n ${floor ? svg`<rect x=${x0 + wl} y=${yBot - floor} width=${x1 - x0 - wl - wr} height=${floor} style=${fill} />` : nothing}\n ${lid ? svg`<rect x=${x0 + wl} y=${yTop} width=${x1 - x0 - wl - wr} height=${lid} style=${fill} />` : nothing}\n ${this.locked ? nothing : [endZone('start', yBot, floor), endZone('end', yTop, lid)]}\n </svg>`\n }\n\n private grab(ev: PointerEvent, what: NonNullable<FigureCavityDrawing['dragging']>) {\n if (this.locked) return\n ev.stopPropagation()\n ;(ev.currentTarget as Element).closest('svg')!.setPointerCapture(ev.pointerId)\n this.dragging = what\n this.pressedAt = ev.clientY\n this.refusal = ''\n }\n\n private drag(ev: PointerEvent, e: NonNullable<FigureEvaluatedShape['extrusion']>, k: number, ox: number, oy: number, half: Record<Axis, number>) {\n const d = this.dragging\n if (d?.kind !== 'wall') return\n const [h] = SCREEN[e.axis]\n const p = this.point(ev, ev.currentTarget as SVGSVGElement)\n const a = d.side[0] as Axis,\n low = d.side[1] === '-'\n const at = a === h ? p.x - ox : p.y - oy\n const value = (half[a] - (low ? -at : at)) / k\n this.hold({ ...this.now!, wall: wallDragged(this.now!.wall, d.side, value, this.perSide) }, d.side)\n }\n\n private dragEnd(ev: PointerEvent, k: number, yTop: number, yBot: number) {\n const d = this.dragging\n if (d?.kind !== 'end' || this.now![d.end] === 'open') return\n if (Math.abs(ev.clientY - this.pressedAt) < 3 && !this.working) return\n const p = this.point(ev, ev.currentTarget as SVGSVGElement)\n const t = d.end === 'start' ? (yBot - p.y) / k : (p.y - yTop) / k\n this.hold({ ...this.now!, [d.end]: { closed: Math.max(1, Math.round(t)) } })\n }\n\n /** A press on an end that did not move is a toggle; a drag was a thickness. */\n private releaseEnd(ev: PointerEvent) {\n const d = this.dragging\n if (d?.kind === 'end' && !this.working && Math.abs(ev.clientY - this.pressedAt) < 3) {\n this.dragging = null\n const next = { ...this.now!, [d.end]: endToggled(this.body!.shape, this.now![d.end]) }\n this.refusal = this.judge(next)\n if (!this.refusal) this.emit('command', this.action(next))\n return\n }\n this.release()\n }\n}\n\n"]}
|
|
@@ -180,7 +180,6 @@ let FigureMaterialPanel = class FigureMaterialPanel extends localize(i18next)(Li
|
|
|
180
180
|
? html `<small>${i18next.t('figure.label.status-colors')}</small>
|
|
181
181
|
<div swatches>${this.swatches(lit, material.token, token => this.put({ token }))}</div>`
|
|
182
182
|
: nothing}
|
|
183
|
-
<small><b>${purposeOf(material.token)}</b> — ${i18next.t('figure.text.palette-purpose-explained')}</small>
|
|
184
183
|
</div>
|
|
185
184
|
<div form>
|
|
186
185
|
<span>${i18next.t('figure.label.preset')}</span>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"figure-material-panel.js","sourceRoot":"","sources":["../../client/modeller/figure-material-panel.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAA;AACzD,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAElE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC7F,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAEtD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAEjD,0DAA0D;AAC1D,MAAM,OAAO,GAA2B;IACtC,iBAAiB,EAAE,SAAS;IAC5B,gBAAgB,EAAE,QAAQ;IAC1B,iBAAiB,EAAE,SAAS;IAC5B,cAAc,EAAE,MAAM;IACtB,eAAe,EAAE,OAAO;IACxB,iBAAiB,EAAE,SAAS;IAC5B,uBAAuB,EAAE,QAAQ;IACjC,wBAAwB,EAAE,SAAS;IACnC,qBAAqB,EAAE,MAAM;IAC7B,wBAAwB,EAAE,SAAS;CACpC,CAAA;AACD,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,KAAc,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,gCAAgC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,IAAI,YAAY,EAAE,CAAC,CAAA;AAE9H,2DAA2D;AAC3D,MAAM,gBAAgB,GAAG,EAAE,CAAA;AAE3B;;;;;;;;;;;;GAYG;AAEI,IAAM,mBAAmB,GAAzB,MAAM,mBAAoB,SAAQ,QAAQ,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC;IAA/D;;QAwHL,2CAA2C;QACX,YAAO,GAA2B,EAAE,CAAA;QACvC,WAAM,GAAG,KAAK,CAAA;IAwJ7C,CAAC;aAjRQ,WAAM,GAAG,CAAC,eAAe,EAAE,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmHpC,CAAC,AAnHW,CAmHX;IAUF,MAAM;QACJ,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAA;QACtB,IAAI,CAAC,IAAI;YAAE,OAAO,OAAO,CAAA;QACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAA;QAC9B;;;UAGE;QACF,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAA;QAC9C,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAA;QACjF,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAA;QAC5E,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAA;QAC9B,OAAO,IAAI,CAAA;YACH,OAAO,CAAC,CAAC,CAAC,4BAA4B,CAAC;;iBAElC,OAAO,CAAC,CAAC,CAAC,2BAA2B,CAAC;wBAC/B,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;UAClF,GAAG,CAAC,MAAM;YACV,CAAC,CAAC,IAAI,CAAA,UAAU,OAAO,CAAC,CAAC,CAAC,4BAA4B,CAAC;8BACnC,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,QAAQ;YAC5F,CAAC,CAAC,OAAO;oBACC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,UAAU,OAAO,CAAC,CAAC,CAAC,uCAAuC,CAAC;;;gBAGzF,OAAO,CAAC,CAAC,CAAC,qBAAqB,CAAC;;sBAE1B,IAAI,CAAC,MAAM;oBACb,CAAC,CAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,CAAE,CAAC,CAAC,MAA4B,CAAC,KAAK,IAAI,SAAS,CAA6B,EAAE,CAAC;;uCAEjG,CAAC,QAAQ,CAAC,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC;YAC7E,gBAAgB,CAAC,GAAG,CACpB,MAAM,CAAC,EAAE,CAAC,IAAI,CAAA,iBAAiB,MAAM,cAAc,MAAM,KAAK,QAAQ,CAAC,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,sBAAsB,GAAG,MAAM,CAAC,WAAW,CACvI;;;;;;sBAMW,IAAI,CAAC,MAAM;qBACZ,CAAC,CAAC,QAAQ,CAAC,WAAW;oBACvB,CAAC,CAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,WAAW,EAAG,CAAC,CAAC,MAA2B,CAAC,OAAO,IAAI,SAAS,EAAE,CAAC;;UAEtG,OAAO,CAAC,CAAC,CAAC,0BAA0B,CAAC;;;gBAG/B,OAAO,CAAC,CAAC,CAAC,uBAAuB,CAAC;;;;;;;sBAO5B,IAAI,CAAC,MAAM;mBACd,MAAM,CAAC,IAAI,EAAE,SAAS,IAAI,CAAC,CAAC;mBAC5B,CAAC,CAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAE,CAAC,CAAC,MAA2B,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC;oBAC1E,CAAC,CAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAE,CAAC,CAAC,MAA2B,CAAC,KAAK,CAAC,CAAC;;kBAEvE,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,EAAE,SAAS,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;;;QAG3D,IAAI;YACJ,CAAC,CAAC,IAAI,CAAA;qBACO,OAAO,CAAC,CAAC,CAAC,6BAA6B,CAAC;4BACjC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;iBACrH;YACT,CAAC,CAAC,OAAO;QACT,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC;eAClB,CAAA;IACb,CAAC;IAEO,cAAc,CAAC,IAA0C;QAC/D,IAAI,CAAC,WAAW,CAAE,IAA0B,CAAC,KAAK,CAAC;YAAE,OAAO,OAAO,CAAA;QACnE,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,IAAI,gBAAgB,CAAA;QACjD,OAAO,IAAI,CAAA;;iBAEE,OAAO,CAAC,CAAC,CAAC,uBAAuB,CAAC;;YAEvC,eAAe,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAC/B,MAAM,CAAC,EAAE,CAAC,IAAI,CAAA;;oBAEN,MAAM,KAAK,OAAO;0BACZ,IAAI,CAAC,MAAM;uBACd,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;;gBAEnF,UAAU,CAAC,MAAM,CAAC;mBACf,MAAM;uBACF,OAAO,CAAC,CAAC,CAAC,yBAAyB,EAAE,EAAE,KAAK,EAAE,iBAAiB,CAAC,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;sBAClG,CACX;;8BAEmB,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAgB,CAAC;qBAC5D,OAAO,CAAC,CAAC,CAAC,kCAAkC,CAAC;;cAEpD,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAC5B,MAAM,CAAC,EAAE,CAAC,IAAI,CAAA,eAAe,MAAM,KAAK,OAAO,cAAc,IAAI,CAAC,MAAM,WAAW,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;kBAC3J,MAAM;wBACA,CACX;;;;KAIR,CAAA;IACH,CAAC;IAEO,QAAQ,CAAC,OAA2B,EAAE,MAA0B,EAAE,IAA6B;QACrG,OAAO,OAAO,CAAC,GAAG,CAChB,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,IAAI,CAAA;;cAEjB,KAAK,KAAK,MAAM;oBACV,IAAI,CAAC,MAAM;gBACf,SAAS,CAAC,KAAK,CAAC;qBACX,SAAS,CAAC,KAAK,CAAC;0BACX,MAAM;iBACf,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC;iBACjB,CACZ,CAAA;IACH,CAAC;IAEO,OAAO;QACb,OAAO,EAAE,GAAI,aAAa,EAA6B,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAA;IAC5E,CAAC;IAED,qGAAqG;IAC7F,IAAI,CAAC,SAAiB,EAAE,IAAI,GAAG,KAAK;QAC1C,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAK,CAAC,QAAQ,CAAA;QACpC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAA;QAC3C,IAAI,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,CAAC,QAAQ,EAAE,KAAK,IAAI,QAAQ,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,EAAE,EAAE,IAAI,CAAC,CAAA;IACtI,CAAC;IAED,gGAAgG;IACxF,GAAG,CAAC,KAA8B,EAAE,IAAI,GAAG,KAAK;QACtD,MAAM,QAAQ,GAAmB,EAAE,GAAG,IAAI,CAAC,IAAK,CAAC,QAAQ,EAAE,GAAG,KAAK,EAAE,CAAA;QACrE,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAA6B;YAAE,IAAI,QAAQ,CAAC,GAAG,CAAC,KAAK,SAAS;gBAAE,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAA;QAC1H,wEAAwE;QACxE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,CAAA;QAC9B,MAAM,OAAO,GAAG,MAAM,CAAC,WAAW,CAChC,CAAC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC;aACvC,MAAM,CAAC,CAAC,KAAK,EAAmB,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,SAAS,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,SAAS,CAAC;aAChH,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,OAAO,CAAC,KAAK,CAAE,CAAC,CAAC,CAC1C,CAAA;QACD,MAAM,IAAI,GAAmB,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,IAAI,CAAC,IAAK,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAA;QAC3I,IAAI,IAAI;YAAE,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,WAAW,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;;YAC1G,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACtB,CAAC;IAEO,IAAI,CAAC,IAAoB;QAC/B,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,WAAW,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;IACvG,CAAC;;AA1J+B;IAA/B,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;;iDAA4C;AAE3C;IAA/B,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;;oDAAqC;AACvC;IAA5B,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;;mDAAe;AAE1B;IAAhB,KAAK,EAAE;;oDAAyB;AA5HtB,mBAAmB;IAD/B,aAAa,CAAC,uBAAuB,CAAC;GAC1B,mBAAmB,CAkR/B;;AAED,uGAAuG;AACvG,SAAS,UAAU,CAAC,QAAgB;IAClC,MAAM,MAAM,GAAa,EAAE,CAAA;IAC3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC;QAClC,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAA;QACzD,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;IACpG,CAAC;IACD,OAAO,GAAG,CAAA,+DAA+D,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,mBAAmB,CAAA;AAC9G,CAAC","sourcesContent":["import { css, html, LitElement, nothing, svg } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { MATERIAL_PRESETS, SEGMENT_PRESETS, figureTrianglesOf } from '@hatiolab/figure-model'\nimport { activePalette } from '@hatiolab/things-scene'\nimport type { FigureAssetGeometry, FigureMaterial, FigurePartEdit } from '@hatiolab/figure-model'\nimport { SidePanelStyles } from './side-panel-styles.js'\nimport { isRoundBody } from './starting-shape.js'\n\n/** The purpose each palette role is for, by its token. */\nconst PURPOSE: Record<string, string> = {\n 'palette.primary': 'primary',\n 'palette.accent': 'accent',\n 'palette.neutral': 'neutral',\n 'palette.dark': 'dark',\n 'palette.light': 'light',\n 'palette.surface': 'surface',\n 'palette.status-danger': 'danger',\n 'palette.status-warning': 'warning',\n 'palette.status-info': 'info',\n 'palette.status-success': 'success'\n}\nexport const purposeOf = (token?: string) => i18next.t(`figure.label.palette-purpose-${PURPOSE[token ?? ''] ?? 'registered'}`)\n\n/** Bodies with a rim — the ones `set-segments` accepts. */\nconst DEFAULT_SEGMENTS = 12\n\n/**\n * 재질 — a part's material.\n *\n * An earlier editor showed the colour role as a raw token (`palette.dark`) in a select and nothing else. The material\n * holds the colour role, a preset, transparency and a glow; a round body also has how finely its rim is drawn. This\n * shows those: painted colours and lit colours as two groups of swatches, each named for what it\n * is for.\n *\n * Not here, because a material has no place for them: flat shading and casting\n * shadows. The glow's colour comes from the lit colours.\n *\n * Every change leaves as one `part-edit`; the editor runs it through the session, one step of the undo history.\n */\n@customElement('figure-material-panel')\nexport class FigureMaterialPanel extends localize(i18next)(LitElement) {\n static styles = [SidePanelStyles, css`\n :host {\n display: block;\n }\n div[field] {\n display: grid;\n gap: 4px;\n }\n /* A slider and its value on one line, the value at the end where the eye finishes. */\n div[slider] {\n display: grid;\n grid-template-columns: minmax(0, 1fr) 3em;\n align-items: center;\n gap: 8px;\n }\n div[slider] output {\n text-align: right;\n font-variant-numeric: tabular-nums;\n }\n div[swatches] {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n }\n button[swatch] {\n width: 22px;\n height: 22px;\n padding: 0;\n border-radius: 50%;\n border: 1px solid var(--md-sys-color-outline-variant);\n background: var(--swatch);\n cursor: pointer;\n }\n button[swatch][on] {\n outline: 2px solid var(--md-sys-color-primary);\n outline-offset: 1px;\n }\n select,\n input[type='range'] {\n font: inherit;\n min-width: 0;\n }\n /* The segment picker: the four common counts as their silhouettes with their triangle cost, the rest folded. */\n div[segments] {\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n gap: 4px;\n }\n button[seg] {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 1px;\n padding: 6px 2px 4px;\n font: inherit;\n color: var(--md-sys-color-on-surface);\n background: none;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 6px;\n cursor: pointer;\n }\n button[seg]:hover:not([on]) {\n background-color: var(--md-sys-color-surface-container);\n }\n button[seg][on] {\n color: var(--md-sys-color-on-primary-container);\n background-color: var(--md-sys-color-primary-container);\n border-color: transparent;\n }\n /* Small, and 12 and 16 both read as circles: large enough for the corners to show. */\n button[seg] svg {\n display: block;\n width: 32px;\n height: 32px;\n }\n button[seg] svg polygon {\n fill: var(--md-sys-color-surface-container-highest);\n stroke: currentColor;\n stroke-width: 1.1;\n stroke-linejoin: miter;\n }\n button[seg][on] svg polygon {\n fill: var(--md-sys-color-surface-container-lowest);\n }\n button[seg] b {\n font-weight: 600;\n }\n button[seg] small {\n margin: 0;\n }\n details[free] summary {\n margin-top: 4px;\n cursor: pointer;\n color: var(--md-sys-color-on-surface-variant);\n }\n div[presets] {\n display: flex;\n gap: 4px;\n margin-top: 4px;\n }\n div[presets] button {\n flex: 1;\n padding: 3px 0;\n font: inherit;\n color: var(--md-sys-color-on-surface);\n background: none;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 6px;\n cursor: pointer;\n }\n div[presets] button[on] {\n color: var(--md-sys-color-on-primary-container);\n background-color: var(--md-sys-color-primary-container);\n border-color: transparent;\n }\n `]\n\n /** The selected body as evaluated — its material, its segments and its shape. */\n @property({ attribute: false }) body?: FigureAssetGeometry & { id: string }\n /** The asset's palette, token → colour. */\n @property({ attribute: false }) palette: Record<string, string> = {}\n @property({ type: Boolean }) locked = false\n /** The glow while its slider is dragged: shown beside it and drawn on the canvas, recorded on release. */\n @state() private glowing?: number\n\n render() {\n const part = this.body\n if (!part) return nothing\n const material = part.material\n /*\n The roles offered are the app's palette, with any the asset carries beyond it. A new asset carries\n only its primary colour; a role it lacks is sent with its colour and added in the same edit (`put`).\n */\n const entries = Object.entries(this.offered())\n const painted = entries.filter(([token]) => !token.startsWith('palette.status-'))\n const lit = entries.filter(([token]) => token.startsWith('palette.status-'))\n const glow = material.emissive\n return html`<section>\n <h3>${i18next.t('figure.label.part-material')}</h3>\n <div field>\n <label>${i18next.t('figure.label.palette-role')}</label>\n <div swatches>${this.swatches(painted, material.token, token => this.put({ token }))}</div>\n ${lit.length\n ? html`<small>${i18next.t('figure.label.status-colors')}</small>\n <div swatches>${this.swatches(lit, material.token, token => this.put({ token }))}</div>`\n : nothing}\n <small><b>${purposeOf(material.token)}</b> — ${i18next.t('figure.text.palette-purpose-explained')}</small>\n </div>\n <div form>\n <span>${i18next.t('figure.label.preset')}</span>\n <select\n ?disabled=${this.locked}\n @change=${(e: Event) => this.put({ preset: ((e.target as HTMLSelectElement).value || undefined) as FigureMaterial['preset'] })}\n >\n <option value=\"\" ?selected=${!material.preset}>${i18next.t('figure.label.none')}</option>\n ${MATERIAL_PRESETS.map(\n preset => html`<option value=${preset} ?selected=${preset === material.preset}>${i18next.t('figure.label.preset-' + preset)}</option>`\n )}\n </select>\n </div>\n <label toggle>\n <input\n type=\"checkbox\"\n ?disabled=${this.locked}\n .checked=${!!material.transparent}\n @change=${(e: Event) => this.put({ transparent: (e.target as HTMLInputElement).checked || undefined })}\n />\n ${i18next.t('figure.label.transparent')}\n </label>\n <div form>\n <span>${i18next.t('figure.label.emissive')}</span>\n <div slider>\n <input\n type=\"range\"\n min=\"0\"\n max=\"1\"\n step=\"0.05\"\n ?disabled=${this.locked}\n .value=${String(glow?.intensity ?? 0)}\n @input=${(e: Event) => this.glow(Number((e.target as HTMLInputElement).value), true)}\n @change=${(e: Event) => this.glow(Number((e.target as HTMLInputElement).value))}\n />\n <output>${(this.glowing ?? glow?.intensity ?? 0).toFixed(2)}</output>\n </div>\n </div>\n ${glow\n ? html`<div field>\n <label>${i18next.t('figure.label.emissive-color')}</label>\n <div swatches>${this.swatches(lit.length ? lit : painted, glow.token, token => this.put({ emissive: { ...glow, token } }))}</div>\n </div>`\n : nothing}\n ${this.renderSegments(part)}\n </section>`\n }\n\n private renderSegments(part: FigureAssetGeometry & { id: string }) {\n if (!isRoundBody((part as { shape?: never }).shape)) return nothing\n const current = part.segments ?? DEFAULT_SEGMENTS\n return html`\n <div field>\n <label>${i18next.t('figure.label.segments')}</label>\n <div segments>\n ${SEGMENT_PRESETS.slice(0, 4).map(\n preset => html`<button\n seg\n ?on=${preset === current}\n ?disabled=${this.locked}\n @click=${() => this.edit({ kind: 'set-segments', target: part.id, segments: preset })}\n >\n ${silhouette(preset)}\n <b>${preset}</b>\n <small>${i18next.t('figure.text.n-triangles', { count: figureTrianglesOf({ ...part, segments: preset }) })}</small>\n </button>`\n )}\n </div>\n <details free ?open=${SEGMENT_PRESETS.slice(4).includes(current as never)}>\n <summary>${i18next.t('figure.text.more-segment-options')}</summary>\n <div presets>\n ${SEGMENT_PRESETS.slice(4).map(\n preset => html`<button ?on=${preset === current} ?disabled=${this.locked} @click=${() => this.edit({ kind: 'set-segments', target: part.id, segments: preset })}>\n ${preset}\n </button>`\n )}\n </div>\n </details>\n </div>\n `\n }\n\n private swatches(entries: [string, string][], chosen: string | undefined, pick: (token: string) => void) {\n return entries.map(\n ([token, colour]) => html`<button\n swatch\n ?on=${token === chosen}\n ?disabled=${this.locked}\n title=${purposeOf(token)}\n aria-label=${purposeOf(token)}\n style=\"--swatch:${colour}\"\n @click=${() => pick(token)}\n ></button>`\n )\n }\n\n private offered(): Record<string, string> {\n return { ...(activePalette() as Record<string, string>), ...this.palette }\n }\n\n /** Intensity 0 is no glow at all; a new glow takes the part's own colour until another is picked. */\n private glow(intensity: number, live = false) {\n const material = this.body!.material\n this.glowing = live ? intensity : undefined\n this.put({ emissive: intensity > 0 ? { token: material.emissive?.token ?? material.token, intensity, on: true } : undefined }, live)\n }\n\n /** A material change: recorded, or -- while a slider is dragged -- only drawn (`part-live`). */\n private put(patch: Partial<FigureMaterial>, live = false) {\n const material: FigureMaterial = { ...this.body!.material, ...patch }\n for (const key of Object.keys(material) as (keyof FigureMaterial)[]) if (material[key] === undefined) delete material[key]\n /* The colours this material names that the asset does not carry yet. */\n const offered = this.offered()\n const palette = Object.fromEntries(\n [material.token, material.emissive?.token]\n .filter((token): token is string => !!token && this.palette[token] === undefined && offered[token] !== undefined)\n .map(token => [token, offered[token]!])\n )\n const edit: FigurePartEdit = { kind: 'set-material', target: this.body!.id, material, ...(Object.keys(palette).length ? { palette } : {}) }\n if (live) this.dispatchEvent(new CustomEvent('part-live', { detail: { edit }, bubbles: true, composed: true }))\n else this.edit(edit)\n }\n\n private edit(edit: FigurePartEdit) {\n this.dispatchEvent(new CustomEvent('part-edit', { detail: { edit }, bubbles: true, composed: true }))\n }\n}\n\n/** A regular polygon of this many sides -- how round a body with this rim count looks from its end. */\nfunction silhouette(segments: number) {\n const points: string[] = []\n for (let i = 0; i < segments; i++) {\n const angle = -Math.PI / 2 + (i * 2 * Math.PI) / segments\n points.push(`${(16 + 13 * Math.cos(angle)).toFixed(2)},${(16 + 13 * Math.sin(angle)).toFixed(2)}`)\n }\n return svg`<svg viewBox=\"0 0 32 32\" aria-hidden=\"true\"><polygon points=${points.join(' ')}></polygon></svg>`\n}\n"]}
|
|
1
|
+
{"version":3,"file":"figure-material-panel.js","sourceRoot":"","sources":["../../client/modeller/figure-material-panel.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement, nothing, svg } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { MATERIAL_PRESETS, SEGMENT_PRESETS, figureTrianglesOf } from '@hatiolab/figure-model'\nimport { activePalette } from '@hatiolab/things-scene'\nimport type { FigureAssetGeometry, FigureMaterial, FigurePartEdit } from '@hatiolab/figure-model'\nimport { SidePanelStyles } from './side-panel-styles.js'\nimport { isRoundBody } from './starting-shape.js'\n\n/** The purpose each palette role is for, by its token. */\nconst PURPOSE: Record<string, string> = {\n 'palette.primary': 'primary',\n 'palette.accent': 'accent',\n 'palette.neutral': 'neutral',\n 'palette.dark': 'dark',\n 'palette.light': 'light',\n 'palette.surface': 'surface',\n 'palette.status-danger': 'danger',\n 'palette.status-warning': 'warning',\n 'palette.status-info': 'info',\n 'palette.status-success': 'success'\n}\nexport const purposeOf = (token?: string) => i18next.t(`figure.label.palette-purpose-${PURPOSE[token ?? ''] ?? 'registered'}`)\n\n/** Bodies with a rim — the ones `set-segments` accepts. */\nconst DEFAULT_SEGMENTS = 12\n\n/**\n * 재질 — a part's material.\n *\n * An earlier editor showed the colour role as a raw token (`palette.dark`) in a select and nothing else. The material\n * holds the colour role, a preset, transparency and a glow; a round body also has how finely its rim is drawn. This\n * shows those: painted colours and lit colours as two groups of swatches, each named for what it\n * is for.\n *\n * Not here, because a material has no place for them: flat shading and casting\n * shadows. The glow's colour comes from the lit colours.\n *\n * Every change leaves as one `part-edit`; the editor runs it through the session, one step of the undo history.\n */\n@customElement('figure-material-panel')\nexport class FigureMaterialPanel extends localize(i18next)(LitElement) {\n static styles = [SidePanelStyles, css`\n :host {\n display: block;\n }\n div[field] {\n display: grid;\n gap: 4px;\n }\n /* A slider and its value on one line, the value at the end where the eye finishes. */\n div[slider] {\n display: grid;\n grid-template-columns: minmax(0, 1fr) 3em;\n align-items: center;\n gap: 8px;\n }\n div[slider] output {\n text-align: right;\n font-variant-numeric: tabular-nums;\n }\n div[swatches] {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n }\n button[swatch] {\n width: 22px;\n height: 22px;\n padding: 0;\n border-radius: 50%;\n border: 1px solid var(--md-sys-color-outline-variant);\n background: var(--swatch);\n cursor: pointer;\n }\n button[swatch][on] {\n outline: 2px solid var(--md-sys-color-primary);\n outline-offset: 1px;\n }\n select,\n input[type='range'] {\n font: inherit;\n min-width: 0;\n }\n /* The segment picker: the four common counts as their silhouettes with their triangle cost, the rest folded. */\n div[segments] {\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n gap: 4px;\n }\n button[seg] {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 1px;\n padding: 6px 2px 4px;\n font: inherit;\n color: var(--md-sys-color-on-surface);\n background: none;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 6px;\n cursor: pointer;\n }\n button[seg]:hover:not([on]) {\n background-color: var(--md-sys-color-surface-container);\n }\n button[seg][on] {\n color: var(--md-sys-color-on-primary-container);\n background-color: var(--md-sys-color-primary-container);\n border-color: transparent;\n }\n /* Small, and 12 and 16 both read as circles: large enough for the corners to show. */\n button[seg] svg {\n display: block;\n width: 32px;\n height: 32px;\n }\n button[seg] svg polygon {\n fill: var(--md-sys-color-surface-container-highest);\n stroke: currentColor;\n stroke-width: 1.1;\n stroke-linejoin: miter;\n }\n button[seg][on] svg polygon {\n fill: var(--md-sys-color-surface-container-lowest);\n }\n button[seg] b {\n font-weight: 600;\n }\n button[seg] small {\n margin: 0;\n }\n details[free] summary {\n margin-top: 4px;\n cursor: pointer;\n color: var(--md-sys-color-on-surface-variant);\n }\n div[presets] {\n display: flex;\n gap: 4px;\n margin-top: 4px;\n }\n div[presets] button {\n flex: 1;\n padding: 3px 0;\n font: inherit;\n color: var(--md-sys-color-on-surface);\n background: none;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 6px;\n cursor: pointer;\n }\n div[presets] button[on] {\n color: var(--md-sys-color-on-primary-container);\n background-color: var(--md-sys-color-primary-container);\n border-color: transparent;\n }\n `]\n\n /** The selected body as evaluated — its material, its segments and its shape. */\n @property({ attribute: false }) body?: FigureAssetGeometry & { id: string }\n /** The asset's palette, token → colour. */\n @property({ attribute: false }) palette: Record<string, string> = {}\n @property({ type: Boolean }) locked = false\n /** The glow while its slider is dragged: shown beside it and drawn on the canvas, recorded on release. */\n @state() private glowing?: number\n\n render() {\n const part = this.body\n if (!part) return nothing\n const material = part.material\n /*\n The roles offered are the app's palette, with any the asset carries beyond it. A new asset carries\n only its primary colour; a role it lacks is sent with its colour and added in the same edit (`put`).\n */\n const entries = Object.entries(this.offered())\n const painted = entries.filter(([token]) => !token.startsWith('palette.status-'))\n const lit = entries.filter(([token]) => token.startsWith('palette.status-'))\n const glow = material.emissive\n return html`<section>\n <h3>${i18next.t('figure.label.part-material')}</h3>\n <div field>\n <label>${i18next.t('figure.label.palette-role')}</label>\n <div swatches>${this.swatches(painted, material.token, token => this.put({ token }))}</div>\n ${lit.length\n ? html`<small>${i18next.t('figure.label.status-colors')}</small>\n <div swatches>${this.swatches(lit, material.token, token => this.put({ token }))}</div>`\n : nothing}\n </div>\n <div form>\n <span>${i18next.t('figure.label.preset')}</span>\n <select\n ?disabled=${this.locked}\n @change=${(e: Event) => this.put({ preset: ((e.target as HTMLSelectElement).value || undefined) as FigureMaterial['preset'] })}\n >\n <option value=\"\" ?selected=${!material.preset}>${i18next.t('figure.label.none')}</option>\n ${MATERIAL_PRESETS.map(\n preset => html`<option value=${preset} ?selected=${preset === material.preset}>${i18next.t('figure.label.preset-' + preset)}</option>`\n )}\n </select>\n </div>\n <label toggle>\n <input\n type=\"checkbox\"\n ?disabled=${this.locked}\n .checked=${!!material.transparent}\n @change=${(e: Event) => this.put({ transparent: (e.target as HTMLInputElement).checked || undefined })}\n />\n ${i18next.t('figure.label.transparent')}\n </label>\n <div form>\n <span>${i18next.t('figure.label.emissive')}</span>\n <div slider>\n <input\n type=\"range\"\n min=\"0\"\n max=\"1\"\n step=\"0.05\"\n ?disabled=${this.locked}\n .value=${String(glow?.intensity ?? 0)}\n @input=${(e: Event) => this.glow(Number((e.target as HTMLInputElement).value), true)}\n @change=${(e: Event) => this.glow(Number((e.target as HTMLInputElement).value))}\n />\n <output>${(this.glowing ?? glow?.intensity ?? 0).toFixed(2)}</output>\n </div>\n </div>\n ${glow\n ? html`<div field>\n <label>${i18next.t('figure.label.emissive-color')}</label>\n <div swatches>${this.swatches(lit.length ? lit : painted, glow.token, token => this.put({ emissive: { ...glow, token } }))}</div>\n </div>`\n : nothing}\n ${this.renderSegments(part)}\n </section>`\n }\n\n private renderSegments(part: FigureAssetGeometry & { id: string }) {\n if (!isRoundBody((part as { shape?: never }).shape)) return nothing\n const current = part.segments ?? DEFAULT_SEGMENTS\n return html`\n <div field>\n <label>${i18next.t('figure.label.segments')}</label>\n <div segments>\n ${SEGMENT_PRESETS.slice(0, 4).map(\n preset => html`<button\n seg\n ?on=${preset === current}\n ?disabled=${this.locked}\n @click=${() => this.edit({ kind: 'set-segments', target: part.id, segments: preset })}\n >\n ${silhouette(preset)}\n <b>${preset}</b>\n <small>${i18next.t('figure.text.n-triangles', { count: figureTrianglesOf({ ...part, segments: preset }) })}</small>\n </button>`\n )}\n </div>\n <details free ?open=${SEGMENT_PRESETS.slice(4).includes(current as never)}>\n <summary>${i18next.t('figure.text.more-segment-options')}</summary>\n <div presets>\n ${SEGMENT_PRESETS.slice(4).map(\n preset => html`<button ?on=${preset === current} ?disabled=${this.locked} @click=${() => this.edit({ kind: 'set-segments', target: part.id, segments: preset })}>\n ${preset}\n </button>`\n )}\n </div>\n </details>\n </div>\n `\n }\n\n private swatches(entries: [string, string][], chosen: string | undefined, pick: (token: string) => void) {\n return entries.map(\n ([token, colour]) => html`<button\n swatch\n ?on=${token === chosen}\n ?disabled=${this.locked}\n title=${purposeOf(token)}\n aria-label=${purposeOf(token)}\n style=\"--swatch:${colour}\"\n @click=${() => pick(token)}\n ></button>`\n )\n }\n\n private offered(): Record<string, string> {\n return { ...(activePalette() as Record<string, string>), ...this.palette }\n }\n\n /** Intensity 0 is no glow at all; a new glow takes the part's own colour until another is picked. */\n private glow(intensity: number, live = false) {\n const material = this.body!.material\n this.glowing = live ? intensity : undefined\n this.put({ emissive: intensity > 0 ? { token: material.emissive?.token ?? material.token, intensity, on: true } : undefined }, live)\n }\n\n /** A material change: recorded, or -- while a slider is dragged -- only drawn (`part-live`). */\n private put(patch: Partial<FigureMaterial>, live = false) {\n const material: FigureMaterial = { ...this.body!.material, ...patch }\n for (const key of Object.keys(material) as (keyof FigureMaterial)[]) if (material[key] === undefined) delete material[key]\n /* The colours this material names that the asset does not carry yet. */\n const offered = this.offered()\n const palette = Object.fromEntries(\n [material.token, material.emissive?.token]\n .filter((token): token is string => !!token && this.palette[token] === undefined && offered[token] !== undefined)\n .map(token => [token, offered[token]!])\n )\n const edit: FigurePartEdit = { kind: 'set-material', target: this.body!.id, material, ...(Object.keys(palette).length ? { palette } : {}) }\n if (live) this.dispatchEvent(new CustomEvent('part-live', { detail: { edit }, bubbles: true, composed: true }))\n else this.edit(edit)\n }\n\n private edit(edit: FigurePartEdit) {\n this.dispatchEvent(new CustomEvent('part-edit', { detail: { edit }, bubbles: true, composed: true }))\n }\n}\n\n/** A regular polygon of this many sides -- how round a body with this rim count looks from its end. */\nfunction silhouette(segments: number) {\n const points: string[] = []\n for (let i = 0; i < segments; i++) {\n const angle = -Math.PI / 2 + (i * 2 * Math.PI) / segments\n points.push(`${(16 + 13 * Math.cos(angle)).toFixed(2)},${(16 + 13 * Math.sin(angle)).toFixed(2)}`)\n }\n return svg`<svg viewBox=\"0 0 32 32\" aria-hidden=\"true\"><polygon points=${points.join(' ')}></polygon></svg>`\n}\n"]}
|
|
@@ -32,7 +32,6 @@ export declare class FigureSectionPanel extends FigureSectionPanel_base {
|
|
|
32
32
|
render(): import("lit-html").TemplateResult<1> | typeof nothing;
|
|
33
33
|
private renderCorner;
|
|
34
34
|
private renderCavity;
|
|
35
|
-
private renderEnd;
|
|
36
35
|
/**
|
|
37
36
|
* A millimetre field. Typing draws the value (or, if the kernel would refuse it, says why under the field and draws the
|
|
38
37
|
* figure as it stands); Enter or leaving sends it once; Esc puts the value back.
|