@things-factory/figure-ui 10.1.129 → 10.1.141
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/align.ts +24 -18
- package/client/modeller/editor.ts +165 -253
- package/client/modeller/fasten-geometry.ts +12 -9
- package/client/modeller/figure-facts.ts +12 -14
- package/client/modeller/figure-links.ts +16 -12
- package/client/modeller/figure-preview.ts +13 -4
- package/client/modeller/figure-properties.ts +6 -5
- package/client/modeller/figure-verdict.ts +14 -8
- package/client/modeller/joint-fan.ts +15 -17
- package/client/modeller/links.ts +17 -23
- package/client/modeller/live.ts +6 -3
- package/client/modeller/motion-ends.ts +6 -7
- package/client/modeller/occupancy.ts +2 -3
- package/client/modeller/product-session.ts +15 -0
- package/client/modeller/revision.ts +66 -0
- package/client/pages/figure-modeller-page.ts +5 -18
- package/dist-client/modeller/align.d.ts +12 -7
- package/dist-client/modeller/align.js +21 -17
- package/dist-client/modeller/align.js.map +1 -1
- package/dist-client/modeller/editor.d.ts +8 -34
- package/dist-client/modeller/editor.js +175 -250
- package/dist-client/modeller/editor.js.map +1 -1
- package/dist-client/modeller/fasten-geometry.d.ts +3 -2
- package/dist-client/modeller/fasten-geometry.js +11 -9
- package/dist-client/modeller/fasten-geometry.js.map +1 -1
- package/dist-client/modeller/figure-facts.d.ts +9 -1
- package/dist-client/modeller/figure-facts.js +11 -15
- package/dist-client/modeller/figure-facts.js.map +1 -1
- package/dist-client/modeller/figure-links.d.ts +4 -5
- package/dist-client/modeller/figure-links.js +14 -13
- package/dist-client/modeller/figure-links.js.map +1 -1
- package/dist-client/modeller/figure-preview.d.ts +5 -2
- package/dist-client/modeller/figure-preview.js +13 -4
- package/dist-client/modeller/figure-preview.js.map +1 -1
- package/dist-client/modeller/figure-properties.d.ts +3 -2
- package/dist-client/modeller/figure-properties.js +6 -6
- package/dist-client/modeller/figure-properties.js.map +1 -1
- package/dist-client/modeller/figure-verdict.d.ts +4 -2
- package/dist-client/modeller/figure-verdict.js +12 -9
- package/dist-client/modeller/figure-verdict.js.map +1 -1
- package/dist-client/modeller/joint-fan.d.ts +8 -4
- package/dist-client/modeller/joint-fan.js +15 -16
- package/dist-client/modeller/joint-fan.js.map +1 -1
- package/dist-client/modeller/links.d.ts +6 -5
- package/dist-client/modeller/links.js +17 -24
- package/dist-client/modeller/links.js.map +1 -1
- package/dist-client/modeller/live.d.ts +3 -2
- package/dist-client/modeller/live.js +7 -3
- package/dist-client/modeller/live.js.map +1 -1
- package/dist-client/modeller/motion-ends.d.ts +2 -2
- package/dist-client/modeller/motion-ends.js +5 -6
- package/dist-client/modeller/motion-ends.js.map +1 -1
- package/dist-client/modeller/occupancy.d.ts +2 -2
- package/dist-client/modeller/occupancy.js +2 -3
- package/dist-client/modeller/occupancy.js.map +1 -1
- package/dist-client/modeller/product-session.d.ts +44 -39
- package/dist-client/modeller/product-session.js +17 -0
- package/dist-client/modeller/product-session.js.map +1 -1
- package/dist-client/modeller/revision.d.ts +37 -0
- package/dist-client/modeller/revision.js +39 -0
- package/dist-client/modeller/revision.js.map +1 -0
- package/dist-client/pages/figure-modeller-page.d.ts +0 -6
- package/dist-client/pages/figure-modeller-page.js +6 -14
- package/dist-client/pages/figure-modeller-page.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/package.json +7 -7
- package/test/align.test.ts +14 -12
- package/test/browser/modeller-page.js +52 -4
- package/test/browser/modeller-revision.check.mjs +144 -0
- package/test/command-preview.test.ts +9 -8
- package/test/fasten-drawing.test.ts +1 -1
- package/test/fasten-geometry.test.ts +10 -9
- package/test/fields.test.ts +1 -1
- package/test/first-minute.test.ts +1 -1
- package/test/gizmo.test.ts +1 -1
- package/test/joint-fan.test.ts +30 -14
- package/test/joint-frames.test.ts +9 -8
- package/test/links.test.ts +13 -12
- package/test/live.test.ts +3 -3
- package/test/parts-wiring.test.ts +1 -1
- package/test/properties.test.ts +6 -5
- package/test/release-panel.test.ts +3 -3
- package/test/resize-with-placement.test.ts +8 -6
- package/test/revision-of.ts +22 -0
- package/test/revision.test.ts +172 -0
- package/test/section-editor.test.ts +4 -3
- package/test/section-panel.test.ts +5 -4
- package/test/verdict.test.ts +1 -1
- package/client/modeller/evaluated.ts +0 -47
- package/dist-client/modeller/evaluated.d.ts +0 -12
- package/dist-client/modeller/evaluated.js +0 -42
- package/dist-client/modeller/evaluated.js.map +0 -1
- package/dist-client/tsconfig.scratch.tsbuildinfo +0 -1
- package/test/evaluated.test.ts +0 -40
- package/test/mode-switch.test.ts +0 -43
|
@@ -6,6 +6,7 @@ import { compileFigureAsset } from '@hatiolab/figure-model';
|
|
|
6
6
|
import { create, registerFigure, unregisterFigure } from '@hatiolab/things-scene';
|
|
7
7
|
import { DEFAULT_VIEW, previewBoardDepth, sceneLook, WORKBENCH } from './figure-view.js';
|
|
8
8
|
import { dialShape } from './angle-dial.js';
|
|
9
|
+
import { derivedOf } from './revision.js';
|
|
9
10
|
import { authoredSizeOf, PREVIEW_FACTOR, PREVIEW_WAYS, previewClampsOf, previewInstances, setupPartOf } from './preview-model.js';
|
|
10
11
|
let FigurePreview = class FigurePreview extends localize(i18next)(LitElement) {
|
|
11
12
|
constructor() {
|
|
@@ -158,6 +159,14 @@ let FigurePreview = class FigurePreview extends localize(i18next)(LitElement) {
|
|
|
158
159
|
background-color: ${unsafeCSS(WORKBENCH)};
|
|
159
160
|
}
|
|
160
161
|
`; }
|
|
162
|
+
get asset() {
|
|
163
|
+
return this.revision?.asset;
|
|
164
|
+
}
|
|
165
|
+
/** The size the figure was made at, once per version: without a declared size it is measured by evaluating the figure. */
|
|
166
|
+
authoredSize() {
|
|
167
|
+
const shown = this.revision;
|
|
168
|
+
return derivedOf(shown, 'authored-size', () => authoredSizeOf(shown.asset));
|
|
169
|
+
}
|
|
161
170
|
/** What is being tried here now -- clip speeds and control values -- for the AI dock to hear with a request; none when nothing is. */
|
|
162
171
|
tried() {
|
|
163
172
|
const clips = Object.keys(this.driving).length ? { ...this.driving } : undefined;
|
|
@@ -170,7 +179,7 @@ let FigurePreview = class FigurePreview extends localize(i18next)(LitElement) {
|
|
|
170
179
|
const clips = asset ? [...new Set((asset.drivers ?? []).map(d => d.clip))] : [];
|
|
171
180
|
let clampsByWay = {};
|
|
172
181
|
try {
|
|
173
|
-
clampsByWay = asset ? previewClampsOf(asset,
|
|
182
|
+
clampsByWay = asset ? previewClampsOf(asset, this.authoredSize()) : {};
|
|
174
183
|
}
|
|
175
184
|
catch {
|
|
176
185
|
clampsByWay = {};
|
|
@@ -280,7 +289,7 @@ let FigurePreview = class FigurePreview extends localize(i18next)(LitElement) {
|
|
|
280
289
|
this.standUp();
|
|
281
290
|
return;
|
|
282
291
|
}
|
|
283
|
-
if (changed.has('
|
|
292
|
+
if (changed.has('revision') || changed.has('context')) {
|
|
284
293
|
this.standUp();
|
|
285
294
|
return;
|
|
286
295
|
}
|
|
@@ -329,7 +338,7 @@ let FigurePreview = class FigurePreview extends localize(i18next)(LitElement) {
|
|
|
329
338
|
try {
|
|
330
339
|
/* Registered as a board registers it, under a type of this preview's own: a real type's drawings stay as they are. */
|
|
331
340
|
const type = `figure-preview-${this.context || 'new'}`;
|
|
332
|
-
const size =
|
|
341
|
+
const size = this.authoredSize();
|
|
333
342
|
/*
|
|
334
343
|
The figure changed under a scene that is standing: the same type is registered again and the content made again
|
|
335
344
|
inside the same 3D scene. Making a scene anew costs about a third of a second and its first drawing compiles the
|
|
@@ -396,7 +405,7 @@ let FigurePreview = class FigurePreview extends localize(i18next)(LitElement) {
|
|
|
396
405
|
__decorate([
|
|
397
406
|
property({ attribute: false }),
|
|
398
407
|
__metadata("design:type", Object)
|
|
399
|
-
], FigurePreview.prototype, "
|
|
408
|
+
], FigurePreview.prototype, "revision", void 0);
|
|
400
409
|
__decorate([
|
|
401
410
|
property(),
|
|
402
411
|
__metadata("design:type", Object)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"figure-preview.js","sourceRoot":"","sources":["../../client/modeller/figure-preview.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement, nothing, unsafeCSS } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { compileFigureAsset } from '@hatiolab/figure-model'\nimport type { FigureAsset } from '@hatiolab/figure-model'\nimport { create, registerFigure, unregisterFigure } from '@hatiolab/things-scene'\n\nimport { DEFAULT_VIEW, previewBoardDepth, sceneLook, WORKBENCH, type ViewSettings } from './figure-view.js'\nimport { dialShape } from './angle-dial.js'\nimport { authoredSizeOf, PREVIEW_FACTOR, PREVIEW_WAYS, previewClampsOf, previewInstances, setupPartOf } from './preview-model.js'\n\n/**\n * The figure placed on a board.\n *\n * The editing canvas shows the figure at the size it was made. Half of what a figure is lies in how it answers a\n * different size, so here the figure being authored is registered as a board registers it and placed as\n * `FigureInstance`s: the size it was made, and each of the seven ways of growing one, two or three axes twice as\n * large, side by side at one scale, four to a row. The board draws them as it will on a real board --\n * placement, lights, environment, the same renderer.\n *\n * The controls: each value that poses the figure with a slider (and a dial for an angle), each clip's\n * speed, and 「이 자세를 기본으로」 to keep the pose as the one it stands in. Nothing here is edited; the canvas edits.\n */\n\ninterface SceneHandle {\n dispose?: () => void\n resize?: () => void\n fit?: (type?: string) => void\n /** The scene's container: it can make the content again while keeping the 3D renderer and the camera (undo and redo use it). */\n rootContainer?: { rebuildContentModel?: (model: unknown, options?: { preserveThreeD?: boolean }) => void }\n root?: {\n set?: (patch: Record<string, unknown>) => void\n fitCameraToModel?: () => void\n components?: { set?: (property: string, value: unknown) => void }[]\n }\n}\n\n@customElement('figure-preview')\nexport class FigurePreview extends localize(i18next)(LitElement) {\n static styles = css`\n :host {\n position: relative;\n display: flex;\n min-width: 0;\n min-height: 0;\n overflow: hidden;\n background-color: ${unsafeCSS(WORKBENCH)};\n font-size: 0.76rem;\n }\n div[stage] {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n }\n /*\n The size help and the posing controls share the stage's bottom edge. Each stood in its own corner, so on a narrow\n stage (the 1024 width, both side panels open) the controls lay over the help's button. One row that wraps keeps both\n whole: side by side when there is room, the controls above the help when there is not.\n */\n div[foot] {\n position: absolute;\n left: 8px;\n right: 8px;\n bottom: 8px;\n display: flex;\n flex-wrap: wrap-reverse;\n justify-content: space-between;\n align-items: flex-end;\n gap: 8px;\n pointer-events: none;\n }\n div[foot] > * { pointer-events: auto; }\n div[setup] { max-width: min(320px, 100%); padding: 12px; border-radius: 8px; background: rgba(28,28,30,.9); color: #fff; display: grid; gap: 8px; }\n div[setup] p { margin: 0; line-height: 1.5; }\n div[setup] select, div[setup] button { font: inherit; padding: 8px; min-width: 0; }\n /* Which is which: side by side means nothing without a legend. */\n div[legend] {\n position: absolute;\n top: 8px;\n left: 8px;\n display: flex;\n gap: 6px;\n padding: 4px 8px;\n color: rgba(255, 255, 255, 0.9);\n background-color: rgba(28, 28, 30, 0.6);\n border-radius: 6px;\n font-size: 0.72rem;\n flex-wrap: wrap;\n max-width: calc(100% - 16px);\n }\n /* A variant drawn at another size than it asks: the figure does not declare that size. */\n div[legend] small[clamp] {\n margin-left: 4px;\n color: #ffcc80;\n }\n div[clips] {\n margin-left: auto;\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 8px 10px;\n color: rgba(255, 255, 255, 0.92);\n background-color: rgba(28, 28, 30, 0.72);\n border-radius: 8px;\n font-size: 0.72rem;\n }\n div[clips] label {\n display: grid;\n grid-template-columns: auto 20px 96px 34px;\n align-items: center;\n gap: 8px;\n }\n div[clips] svg[dial] {\n width: 20px;\n height: 20px;\n }\n div[clips] svg[dial] path {\n fill: rgba(255, 255, 255, 0.22);\n }\n div[clips] svg[dial] line {\n stroke: var(--md-sys-color-primary, #7cc6ff);\n stroke-width: 2;\n stroke-linecap: round;\n }\n div[clips] svg[dial] circle {\n fill: none;\n stroke: rgba(255, 255, 255, 0.35);\n }\n div[clips] button[pose] {\n align-self: stretch;\n padding: 4px 8px;\n font: inherit;\n font-size: 0.7rem;\n color: rgba(255, 255, 255, 0.92);\n background-color: rgba(255, 255, 255, 0.14);\n border: 1px solid rgba(255, 255, 255, 0.22);\n border-radius: 5px;\n cursor: pointer;\n }\n div[clips] button[pose]:hover {\n background-color: rgba(255, 255, 255, 0.24);\n }\n div[clips] span[drive] {\n opacity: 0.6;\n font-size: 0.66rem;\n }\n div[clips] input {\n width: 96px;\n accent-color: var(--md-sys-color-primary);\n }\n div[clips] output {\n font-variant-numeric: tabular-nums;\n text-align: right;\n opacity: 0.85;\n }\n div[cannot] {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 12px;\n text-align: center;\n line-height: 1.6;\n color: #f4f4f4;\n background-color: ${unsafeCSS(WORKBENCH)};\n }\n `\n\n /** The figure being authored, as the editor holds it now. */\n @property({ attribute: false }) asset?: FigureAsset\n /** Which figure: the type it is registered under here is this one's own, never a real type a board uses. */\n @property() context = ''\n /**\n * In front. Once made, the preview stays standing behind the edit canvas, so coming back to it is not a new 3D scene\n * (about 300 ms): out of sight it does not follow the figure, and when it is shown again it makes its content again\n * inside the scene that stands if the figure changed meanwhile.\n */\n @property({ type: Boolean }) active = true\n private stale = false\n @property({ attribute: false }) view: ViewSettings = DEFAULT_VIEW\n\n @query('div[stage]') private stage!: HTMLDivElement\n @state() private cannot = ''\n /** Clip speeds and control values given here -- the preview's, not the figure's. */\n @state() private driving: Record<string, number> = {}\n @state() private giving: Record<string, number> = {}\n /** The part chosen in the editor. The size help starts on it, so the help speaks of the part the author was working on. */\n @property() selected = ''\n @state() private setupPart = ''\n\n /** What is being tried here now -- clip speeds and control values -- for the AI dock to hear with a request; none when nothing is. */\n tried(): { clips?: Record<string, number>; controls?: Record<string, number> } | undefined {\n const clips = Object.keys(this.driving).length ? { ...this.driving } : undefined\n const controls = Object.keys(this.giving).length ? { ...this.giving } : undefined\n return clips || controls ? { ...(clips ? { clips } : {}), ...(controls ? { controls } : {}) } : undefined\n }\n\n private scene?: SceneHandle\n private standing?: string\n private registered?: string\n private watcher?: ResizeObserver\n\n render() {\n const asset = this.asset\n const controls = asset ? asset.document.model.inputs.filter(i => i.role === 'state') : []\n const clips = asset ? [...new Set((asset.drivers ?? []).map(d => d.clip))] : []\n let clampsByWay: ReturnType<typeof previewClampsOf> = {}\n try {\n clampsByWay = asset ? previewClampsOf(asset, authoredSizeOf(asset)) : {}\n } catch {\n clampsByWay = {}\n }\n /* The part the help speaks of: the one picked in it, else the one chosen in the editor, else the first. */\n const setupPart = setupPartOf(this.setupPart, this.selected, asset?.appearance.map(p => p.target) ?? [])\n return html`<div stage></div>\n ${this.cannot\n ? html`<div cannot>${this.cannot}</div>`\n : html`<div legend>\n ${PREVIEW_WAYS.map(way => {\n const clamps = clampsByWay[way.name] ?? []\n return html`<span>\n ${way.axes.length ? way.name : i18next.t('figure.label.preview-base')}\n ${clamps.length\n ? html`<small clamp>${clamps.map(c => i18next.t('figure.text.preview-clamped', { axis: c.axis.toUpperCase(), asked: c.asked.toLocaleString(), used: c.used.toLocaleString() })).join(' · ')}</small>`\n : nothing}\n </span>`\n })}\n </div>\n <div foot>${asset?.appearance.length ? html`<div setup>\n <p>${i18next.t('figure.text.preview-setup')}</p>\n <select aria-label=${i18next.t('figure.label.resize-part')} @change=${(e: Event) => this.setupPart = (e.target as HTMLSelectElement).value}>\n ${asset.appearance.map(p => html`<option value=${p.target} ?selected=${p.target === setupPart}>${p.target}</option>`)}\n </select>\n <button @click=${() => this.dispatchEvent(new CustomEvent('configure-size', { detail: { part: setupPart }, bubbles: true, composed: true }))}>${i18next.t('figure.button.configure-size')}</button>\n </div>` : nothing}\n ${controls.length + clips.length ? this.renderDrivers(asset!, controls, clips) : nothing}</div>`}`\n }\n\n private renderDrivers(asset: FigureAsset, controls: FigureAsset['document']['model']['inputs'], clips: string[]) {\n const changed = controls.filter(c => this.giving[c.id] !== undefined && this.giving[c.id] !== asset.stateDefaults[c.id])\n return html`<div clips>\n ${changed.length\n ? html`<button pose title=${i18next.t('figure.text.pose-as-default-explained')} @click=${() => this.poseAsDefault()}>\n ${i18next.t('figure.button.pose-as-default')}\n </button>`\n : nothing}\n ${controls.map(control => {\n const value = this.giving[control.id] ?? asset.stateDefaults[control.id] ?? control.min\n const step = Math.max((control.max - control.min) / 100, 0.01)\n const label = asset.stateInputs?.[control.id]?.label ?? control.id\n return html`<label>\n <span>${label} <span drive>${control.unit}</span></span>\n ${this.renderDial(control, value)}\n <input\n type=\"range\"\n min=${control.min}\n max=${control.max}\n step=${step}\n .value=${String(value)}\n @input=${(e: Event) => this.give(control.id, Number((e.target as HTMLInputElement).value))}\n />\n <output>${Math.round(value)}</output>\n </label>`\n })}\n ${clips.map(clip => {\n /*\n A clip nothing has driven stands still, here as on a board: the instances get a speed only from `drive`. The\n slider showed 1.00 over rollers that did not turn (2026-10-03). It shows what plays -- 0 until moved.\n */\n const value = this.driving[clip] ?? 0\n return html`<label>\n <span>${clip} <span drive>${i18next.t('figure.label.playback-speed')}</span></span>\n <span></span>\n <input type=\"range\" min=\"0\" max=\"3\" step=\"0.05\" .value=${String(value)} @input=${(e: Event) => this.drive(clip, Number((e.target as HTMLInputElement).value))} />\n <output>${value.toFixed(2)}</output>\n </label>`\n })}\n </div>`\n }\n\n private renderDial(control: { unit: string; min: number; max: number }, value: number) {\n if (control.unit !== 'deg') return html`<span></span>`\n const dial = dialShape(control.min, control.max, value)\n const span = dial.radius * 2 + 2\n return html`<svg dial viewBox=\"0 0 ${span} ${span}\" aria-hidden=\"true\">\n <path d=${dial.sector}></path>\n <circle cx=${dial.centre.x} cy=${dial.centre.y} r=${dial.radius}></circle>\n <line x1=${dial.centre.x} y1=${dial.centre.y} x2=${dial.needle.x} y2=${dial.needle.y}></line>\n </svg>`\n }\n\n private drive(clip: string, value: number) {\n this.driving = { ...this.driving, [clip]: value }\n this.tellInstances('clips', this.driving)\n }\n\n private give(id: string, value: number) {\n this.giving = { ...this.giving, [id]: value }\n this.tellInstances('parameters', this.giving)\n }\n\n private poseAsDefault() {\n this.dispatchEvent(new CustomEvent('part-edit', { detail: { edit: { kind: 'set-state-defaults', values: { ...this.giving } } }, bubbles: true, composed: true }))\n this.giving = {}\n }\n\n private tellInstances(key: 'clips' | 'parameters', values: Record<string, number>) {\n for (const component of this.scene?.root?.components ?? []) component.set?.(key, { ...values })\n }\n\n willUpdate(changed: Map<string, unknown>) {\n if (!this.hasUpdated) return\n if (!this.active) {\n this.stale = true\n return\n }\n if (this.stale || changed.has('active')) {\n this.stale = false\n this.standUp()\n return\n }\n if (changed.has('asset') || changed.has('context')) {\n this.standUp()\n return\n }\n if (!changed.has('view')) return\n const before = changed.get('view') as ViewSettings | undefined\n const now = this.view ?? DEFAULT_VIEW\n if (before?.placement !== now.placement || before?.ceilingHeight !== now.ceilingHeight) this.standUp()\n else this.scene?.root?.set?.(sceneLook(now))\n }\n\n firstUpdated() {\n this.standUp()\n this.watcher = new ResizeObserver(() => {\n if (this.active) this.scene?.resize?.()\n })\n this.watcher.observe(this)\n }\n\n disconnectedCallback() {\n super.disconnectedCallback()\n this.watcher?.disconnect()\n this.watcher = undefined\n this.teardown()\n }\n\n private standUp() {\n const asset = this.asset\n const view = this.view ?? DEFAULT_VIEW\n if (!asset || !asset.appearance.length) {\n this.cannot = i18next.t('figure.text.preview-needs-a-part')\n this.teardown()\n return\n }\n const signature = JSON.stringify([asset, view.placement, view.ceilingHeight])\n if (this.scene && this.standing === signature) return\n try {\n compileFigureAsset(asset)\n } catch {\n this.cannot = i18next.t('figure.text.preview-blocked-by-errors')\n this.teardown()\n return\n }\n try {\n /* Registered as a board registers it, under a type of this preview's own: a real type's drawings stay as they are. */\n const type = `figure-preview-${this.context || 'new'}`\n const size = authoredSizeOf(asset)\n /*\n The figure changed under a scene that is standing: the same type is registered again and the content made again\n inside the same 3D scene. Making a scene anew costs about a third of a second and its first drawing compiles the\n shaders again -- a value typed beside the preview held the screen for seconds. The scene is made anew only when\n there is none, for another figure, or when the content cannot be made again in place.\n */\n const again = this.scene?.rootContainer?.rebuildContentModel && this.registered === type\n if (!again) this.teardown()\n this.driving = {}\n registerFigure(type, asset)\n this.registered = type\n const { components, board } = previewInstances(type, size)\n const model = {\n type: 'model-layer',\n width: board.width,\n height: board.height,\n depth: previewBoardDepth({ placement: asset.placement, base: { y: size.y } }, view.ceilingHeight, PREVIEW_FACTOR),\n threed: true,\n sky: 'color',\n ...sceneLook(view),\n placement: view.placement,\n heights: { floor: 0, ceiling: view.ceilingHeight },\n pixelRatio: Math.min(3, (window.devicePixelRatio || 1) * 2),\n components\n }\n if (again) {\n try {\n this.scene!.rootContainer!.rebuildContentModel!(model, { preserveThreeD: true })\n this.standing = signature\n this.cannot = ''\n return\n } catch {\n this.teardown()\n registerFigure(type, asset)\n this.registered = type\n }\n }\n this.scene = create({\n target: this.stage,\n model,\n mode: 0\n }) as SceneHandle\n this.standing = signature\n this.scene.resize?.()\n this.scene.fit?.('ratio')\n this.scene.root?.fitCameraToModel?.()\n this.cannot = ''\n } catch (error) {\n this.cannot = (error as Error).message\n }\n }\n\n private teardown() {\n this.scene?.dispose?.()\n this.scene = undefined\n this.standing = undefined\n if (this.registered) unregisterFigure(this.registered)\n this.registered = undefined\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"figure-preview.js","sourceRoot":"","sources":["../../client/modeller/figure-preview.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement, nothing, unsafeCSS } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { compileFigureAsset } from '@hatiolab/figure-model'\nimport type { FigureAsset } from '@hatiolab/figure-model'\nimport { create, registerFigure, unregisterFigure } from '@hatiolab/things-scene'\n\nimport { DEFAULT_VIEW, previewBoardDepth, sceneLook, WORKBENCH, type ViewSettings } from './figure-view.js'\nimport { dialShape } from './angle-dial.js'\nimport { derivedOf, type FigureRevision } from './revision.js'\nimport { authoredSizeOf, PREVIEW_FACTOR, PREVIEW_WAYS, previewClampsOf, previewInstances, setupPartOf } from './preview-model.js'\n\n/**\n * The figure placed on a board.\n *\n * The editing canvas shows the figure at the size it was made. Half of what a figure is lies in how it answers a\n * different size, so here the figure being authored is registered as a board registers it and placed as\n * `FigureInstance`s: the size it was made, and each of the seven ways of growing one, two or three axes twice as\n * large, side by side at one scale, four to a row. The board draws them as it will on a real board --\n * placement, lights, environment, the same renderer.\n *\n * The controls: each value that poses the figure with a slider (and a dial for an angle), each clip's\n * speed, and 「이 자세를 기본으로」 to keep the pose as the one it stands in. Nothing here is edited; the canvas edits.\n */\n\ninterface SceneHandle {\n dispose?: () => void\n resize?: () => void\n fit?: (type?: string) => void\n /** The scene's container: it can make the content again while keeping the 3D renderer and the camera (undo and redo use it). */\n rootContainer?: { rebuildContentModel?: (model: unknown, options?: { preserveThreeD?: boolean }) => void }\n root?: {\n set?: (patch: Record<string, unknown>) => void\n fitCameraToModel?: () => void\n components?: { set?: (property: string, value: unknown) => void }[]\n }\n}\n\n@customElement('figure-preview')\nexport class FigurePreview extends localize(i18next)(LitElement) {\n static styles = css`\n :host {\n position: relative;\n display: flex;\n min-width: 0;\n min-height: 0;\n overflow: hidden;\n background-color: ${unsafeCSS(WORKBENCH)};\n font-size: 0.76rem;\n }\n div[stage] {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n }\n /*\n The size help and the posing controls share the stage's bottom edge. Each stood in its own corner, so on a narrow\n stage (the 1024 width, both side panels open) the controls lay over the help's button. One row that wraps keeps both\n whole: side by side when there is room, the controls above the help when there is not.\n */\n div[foot] {\n position: absolute;\n left: 8px;\n right: 8px;\n bottom: 8px;\n display: flex;\n flex-wrap: wrap-reverse;\n justify-content: space-between;\n align-items: flex-end;\n gap: 8px;\n pointer-events: none;\n }\n div[foot] > * { pointer-events: auto; }\n div[setup] { max-width: min(320px, 100%); padding: 12px; border-radius: 8px; background: rgba(28,28,30,.9); color: #fff; display: grid; gap: 8px; }\n div[setup] p { margin: 0; line-height: 1.5; }\n div[setup] select, div[setup] button { font: inherit; padding: 8px; min-width: 0; }\n /* Which is which: side by side means nothing without a legend. */\n div[legend] {\n position: absolute;\n top: 8px;\n left: 8px;\n display: flex;\n gap: 6px;\n padding: 4px 8px;\n color: rgba(255, 255, 255, 0.9);\n background-color: rgba(28, 28, 30, 0.6);\n border-radius: 6px;\n font-size: 0.72rem;\n flex-wrap: wrap;\n max-width: calc(100% - 16px);\n }\n /* A variant drawn at another size than it asks: the figure does not declare that size. */\n div[legend] small[clamp] {\n margin-left: 4px;\n color: #ffcc80;\n }\n div[clips] {\n margin-left: auto;\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 8px 10px;\n color: rgba(255, 255, 255, 0.92);\n background-color: rgba(28, 28, 30, 0.72);\n border-radius: 8px;\n font-size: 0.72rem;\n }\n div[clips] label {\n display: grid;\n grid-template-columns: auto 20px 96px 34px;\n align-items: center;\n gap: 8px;\n }\n div[clips] svg[dial] {\n width: 20px;\n height: 20px;\n }\n div[clips] svg[dial] path {\n fill: rgba(255, 255, 255, 0.22);\n }\n div[clips] svg[dial] line {\n stroke: var(--md-sys-color-primary, #7cc6ff);\n stroke-width: 2;\n stroke-linecap: round;\n }\n div[clips] svg[dial] circle {\n fill: none;\n stroke: rgba(255, 255, 255, 0.35);\n }\n div[clips] button[pose] {\n align-self: stretch;\n padding: 4px 8px;\n font: inherit;\n font-size: 0.7rem;\n color: rgba(255, 255, 255, 0.92);\n background-color: rgba(255, 255, 255, 0.14);\n border: 1px solid rgba(255, 255, 255, 0.22);\n border-radius: 5px;\n cursor: pointer;\n }\n div[clips] button[pose]:hover {\n background-color: rgba(255, 255, 255, 0.24);\n }\n div[clips] span[drive] {\n opacity: 0.6;\n font-size: 0.66rem;\n }\n div[clips] input {\n width: 96px;\n accent-color: var(--md-sys-color-primary);\n }\n div[clips] output {\n font-variant-numeric: tabular-nums;\n text-align: right;\n opacity: 0.85;\n }\n div[cannot] {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 12px;\n text-align: center;\n line-height: 1.6;\n color: #f4f4f4;\n background-color: ${unsafeCSS(WORKBENCH)};\n }\n `\n\n /** The figure being authored, as the editor holds it now. */\n @property({ attribute: false }) revision?: FigureRevision\n private get asset(): FigureAsset | undefined {\n return this.revision?.asset\n }\n /** The size the figure was made at, once per version: without a declared size it is measured by evaluating the figure. */\n private authoredSize(): { x: number; y: number; z: number } {\n const shown = this.revision!\n return derivedOf(shown, 'authored-size', () => authoredSizeOf(shown.asset))\n }\n /** Which figure: the type it is registered under here is this one's own, never a real type a board uses. */\n @property() context = ''\n /**\n * In front. Once made, the preview stays standing behind the edit canvas, so coming back to it is not a new 3D scene\n * (about 300 ms): out of sight it does not follow the figure, and when it is shown again it makes its content again\n * inside the scene that stands if the figure changed meanwhile.\n */\n @property({ type: Boolean }) active = true\n private stale = false\n @property({ attribute: false }) view: ViewSettings = DEFAULT_VIEW\n\n @query('div[stage]') private stage!: HTMLDivElement\n @state() private cannot = ''\n /** Clip speeds and control values given here -- the preview's, not the figure's. */\n @state() private driving: Record<string, number> = {}\n @state() private giving: Record<string, number> = {}\n /** The part chosen in the editor. The size help starts on it, so the help speaks of the part the author was working on. */\n @property() selected = ''\n @state() private setupPart = ''\n\n /** What is being tried here now -- clip speeds and control values -- for the AI dock to hear with a request; none when nothing is. */\n tried(): { clips?: Record<string, number>; controls?: Record<string, number> } | undefined {\n const clips = Object.keys(this.driving).length ? { ...this.driving } : undefined\n const controls = Object.keys(this.giving).length ? { ...this.giving } : undefined\n return clips || controls ? { ...(clips ? { clips } : {}), ...(controls ? { controls } : {}) } : undefined\n }\n\n private scene?: SceneHandle\n private standing?: string\n private registered?: string\n private watcher?: ResizeObserver\n\n render() {\n const asset = this.asset\n const controls = asset ? asset.document.model.inputs.filter(i => i.role === 'state') : []\n const clips = asset ? [...new Set((asset.drivers ?? []).map(d => d.clip))] : []\n let clampsByWay: ReturnType<typeof previewClampsOf> = {}\n try {\n clampsByWay = asset ? previewClampsOf(asset, this.authoredSize()) : {}\n } catch {\n clampsByWay = {}\n }\n /* The part the help speaks of: the one picked in it, else the one chosen in the editor, else the first. */\n const setupPart = setupPartOf(this.setupPart, this.selected, asset?.appearance.map(p => p.target) ?? [])\n return html`<div stage></div>\n ${this.cannot\n ? html`<div cannot>${this.cannot}</div>`\n : html`<div legend>\n ${PREVIEW_WAYS.map(way => {\n const clamps = clampsByWay[way.name] ?? []\n return html`<span>\n ${way.axes.length ? way.name : i18next.t('figure.label.preview-base')}\n ${clamps.length\n ? html`<small clamp>${clamps.map(c => i18next.t('figure.text.preview-clamped', { axis: c.axis.toUpperCase(), asked: c.asked.toLocaleString(), used: c.used.toLocaleString() })).join(' · ')}</small>`\n : nothing}\n </span>`\n })}\n </div>\n <div foot>${asset?.appearance.length ? html`<div setup>\n <p>${i18next.t('figure.text.preview-setup')}</p>\n <select aria-label=${i18next.t('figure.label.resize-part')} @change=${(e: Event) => this.setupPart = (e.target as HTMLSelectElement).value}>\n ${asset.appearance.map(p => html`<option value=${p.target} ?selected=${p.target === setupPart}>${p.target}</option>`)}\n </select>\n <button @click=${() => this.dispatchEvent(new CustomEvent('configure-size', { detail: { part: setupPart }, bubbles: true, composed: true }))}>${i18next.t('figure.button.configure-size')}</button>\n </div>` : nothing}\n ${controls.length + clips.length ? this.renderDrivers(asset!, controls, clips) : nothing}</div>`}`\n }\n\n private renderDrivers(asset: FigureAsset, controls: FigureAsset['document']['model']['inputs'], clips: string[]) {\n const changed = controls.filter(c => this.giving[c.id] !== undefined && this.giving[c.id] !== asset.stateDefaults[c.id])\n return html`<div clips>\n ${changed.length\n ? html`<button pose title=${i18next.t('figure.text.pose-as-default-explained')} @click=${() => this.poseAsDefault()}>\n ${i18next.t('figure.button.pose-as-default')}\n </button>`\n : nothing}\n ${controls.map(control => {\n const value = this.giving[control.id] ?? asset.stateDefaults[control.id] ?? control.min\n const step = Math.max((control.max - control.min) / 100, 0.01)\n const label = asset.stateInputs?.[control.id]?.label ?? control.id\n return html`<label>\n <span>${label} <span drive>${control.unit}</span></span>\n ${this.renderDial(control, value)}\n <input\n type=\"range\"\n min=${control.min}\n max=${control.max}\n step=${step}\n .value=${String(value)}\n @input=${(e: Event) => this.give(control.id, Number((e.target as HTMLInputElement).value))}\n />\n <output>${Math.round(value)}</output>\n </label>`\n })}\n ${clips.map(clip => {\n /*\n A clip nothing has driven stands still, here as on a board: the instances get a speed only from `drive`. The\n slider showed 1.00 over rollers that did not turn (2026-10-03). It shows what plays -- 0 until moved.\n */\n const value = this.driving[clip] ?? 0\n return html`<label>\n <span>${clip} <span drive>${i18next.t('figure.label.playback-speed')}</span></span>\n <span></span>\n <input type=\"range\" min=\"0\" max=\"3\" step=\"0.05\" .value=${String(value)} @input=${(e: Event) => this.drive(clip, Number((e.target as HTMLInputElement).value))} />\n <output>${value.toFixed(2)}</output>\n </label>`\n })}\n </div>`\n }\n\n private renderDial(control: { unit: string; min: number; max: number }, value: number) {\n if (control.unit !== 'deg') return html`<span></span>`\n const dial = dialShape(control.min, control.max, value)\n const span = dial.radius * 2 + 2\n return html`<svg dial viewBox=\"0 0 ${span} ${span}\" aria-hidden=\"true\">\n <path d=${dial.sector}></path>\n <circle cx=${dial.centre.x} cy=${dial.centre.y} r=${dial.radius}></circle>\n <line x1=${dial.centre.x} y1=${dial.centre.y} x2=${dial.needle.x} y2=${dial.needle.y}></line>\n </svg>`\n }\n\n private drive(clip: string, value: number) {\n this.driving = { ...this.driving, [clip]: value }\n this.tellInstances('clips', this.driving)\n }\n\n private give(id: string, value: number) {\n this.giving = { ...this.giving, [id]: value }\n this.tellInstances('parameters', this.giving)\n }\n\n private poseAsDefault() {\n this.dispatchEvent(new CustomEvent('part-edit', { detail: { edit: { kind: 'set-state-defaults', values: { ...this.giving } } }, bubbles: true, composed: true }))\n this.giving = {}\n }\n\n private tellInstances(key: 'clips' | 'parameters', values: Record<string, number>) {\n for (const component of this.scene?.root?.components ?? []) component.set?.(key, { ...values })\n }\n\n willUpdate(changed: Map<string, unknown>) {\n if (!this.hasUpdated) return\n if (!this.active) {\n this.stale = true\n return\n }\n if (this.stale || changed.has('active')) {\n this.stale = false\n this.standUp()\n return\n }\n if (changed.has('revision') || changed.has('context')) {\n this.standUp()\n return\n }\n if (!changed.has('view')) return\n const before = changed.get('view') as ViewSettings | undefined\n const now = this.view ?? DEFAULT_VIEW\n if (before?.placement !== now.placement || before?.ceilingHeight !== now.ceilingHeight) this.standUp()\n else this.scene?.root?.set?.(sceneLook(now))\n }\n\n firstUpdated() {\n this.standUp()\n this.watcher = new ResizeObserver(() => {\n if (this.active) this.scene?.resize?.()\n })\n this.watcher.observe(this)\n }\n\n disconnectedCallback() {\n super.disconnectedCallback()\n this.watcher?.disconnect()\n this.watcher = undefined\n this.teardown()\n }\n\n private standUp() {\n const asset = this.asset\n const view = this.view ?? DEFAULT_VIEW\n if (!asset || !asset.appearance.length) {\n this.cannot = i18next.t('figure.text.preview-needs-a-part')\n this.teardown()\n return\n }\n const signature = JSON.stringify([asset, view.placement, view.ceilingHeight])\n if (this.scene && this.standing === signature) return\n try {\n compileFigureAsset(asset)\n } catch {\n this.cannot = i18next.t('figure.text.preview-blocked-by-errors')\n this.teardown()\n return\n }\n try {\n /* Registered as a board registers it, under a type of this preview's own: a real type's drawings stay as they are. */\n const type = `figure-preview-${this.context || 'new'}`\n const size = this.authoredSize()\n /*\n The figure changed under a scene that is standing: the same type is registered again and the content made again\n inside the same 3D scene. Making a scene anew costs about a third of a second and its first drawing compiles the\n shaders again -- a value typed beside the preview held the screen for seconds. The scene is made anew only when\n there is none, for another figure, or when the content cannot be made again in place.\n */\n const again = this.scene?.rootContainer?.rebuildContentModel && this.registered === type\n if (!again) this.teardown()\n this.driving = {}\n registerFigure(type, asset)\n this.registered = type\n const { components, board } = previewInstances(type, size)\n const model = {\n type: 'model-layer',\n width: board.width,\n height: board.height,\n depth: previewBoardDepth({ placement: asset.placement, base: { y: size.y } }, view.ceilingHeight, PREVIEW_FACTOR),\n threed: true,\n sky: 'color',\n ...sceneLook(view),\n placement: view.placement,\n heights: { floor: 0, ceiling: view.ceilingHeight },\n pixelRatio: Math.min(3, (window.devicePixelRatio || 1) * 2),\n components\n }\n if (again) {\n try {\n this.scene!.rootContainer!.rebuildContentModel!(model, { preserveThreeD: true })\n this.standing = signature\n this.cannot = ''\n return\n } catch {\n this.teardown()\n registerFigure(type, asset)\n this.registered = type\n }\n }\n this.scene = create({\n target: this.stage,\n model,\n mode: 0\n }) as SceneHandle\n this.standing = signature\n this.scene.resize?.()\n this.scene.fit?.('ratio')\n this.scene.root?.fitCameraToModel?.()\n this.cannot = ''\n } catch (error) {\n this.cannot = (error as Error).message\n }\n }\n\n private teardown() {\n this.scene?.dispose?.()\n this.scene = undefined\n this.standing = undefined\n if (this.registered) unregisterFigure(this.registered)\n this.registered = undefined\n }\n}\n"]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import '@material/web/icon/icon.js';
|
|
2
2
|
import { LitElement } from 'lit';
|
|
3
|
+
import type { FigureRevision } from './revision.js';
|
|
3
4
|
declare const FigureProperties_base: (new (...args: any[]) => LitElement) & typeof LitElement;
|
|
4
5
|
/**
|
|
5
6
|
* 속성 — the modeller's figure properties.
|
|
@@ -18,8 +19,8 @@ declare const FigureProperties_base: (new (...args: any[]) => LitElement) & type
|
|
|
18
19
|
*/
|
|
19
20
|
export declare class FigureProperties extends FigureProperties_base {
|
|
20
21
|
static styles: import("lit").CSSResult[];
|
|
21
|
-
/** The
|
|
22
|
-
|
|
22
|
+
/** The figure at the version on screen. */
|
|
23
|
+
revision?: FigureRevision;
|
|
23
24
|
/** The saved row, if any. Category and tags live on it. */
|
|
24
25
|
figureId?: string;
|
|
25
26
|
figureCategory?: string;
|
|
@@ -57,7 +57,7 @@ let FigureProperties = class FigureProperties extends localize(i18next)(LitEleme
|
|
|
57
57
|
`]; }
|
|
58
58
|
facts() {
|
|
59
59
|
try {
|
|
60
|
-
return this.
|
|
60
|
+
return this.revision ? figureFigureFacts(this.revision) : undefined;
|
|
61
61
|
}
|
|
62
62
|
catch {
|
|
63
63
|
/* A source the format refuses has no facts to show; the verdict tab says why. */
|
|
@@ -223,9 +223,9 @@ let FigureProperties = class FigureProperties extends localize(i18next)(LitEleme
|
|
|
223
223
|
`;
|
|
224
224
|
}
|
|
225
225
|
declare(placement) {
|
|
226
|
-
if (!this.
|
|
226
|
+
if (!this.revision)
|
|
227
227
|
return;
|
|
228
|
-
this.command(occupancyFromParts(this.
|
|
228
|
+
this.command(occupancyFromParts(this.revision.asset, placement));
|
|
229
229
|
}
|
|
230
230
|
command(action) {
|
|
231
231
|
this.dispatchEvent(new CustomEvent('command', { detail: { action }, bubbles: true, composed: true }));
|
|
@@ -235,9 +235,9 @@ let FigureProperties = class FigureProperties extends localize(i18next)(LitEleme
|
|
|
235
235
|
}
|
|
236
236
|
};
|
|
237
237
|
__decorate([
|
|
238
|
-
property({
|
|
239
|
-
__metadata("design:type",
|
|
240
|
-
], FigureProperties.prototype, "
|
|
238
|
+
property({ attribute: false }),
|
|
239
|
+
__metadata("design:type", Object)
|
|
240
|
+
], FigureProperties.prototype, "revision", void 0);
|
|
241
241
|
__decorate([
|
|
242
242
|
property({ type: String }),
|
|
243
243
|
__metadata("design:type", String)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"figure-properties.js","sourceRoot":"","sources":["../../client/modeller/figure-properties.ts"],"names":[],"mappings":";AAAA,OAAO,4BAA4B,CAAA;AAEnC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,KAAK,CAAA;AACpD,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAA;AAE7C,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAGrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AACnD,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAA0C,MAAM,mBAAmB,CAAA;AACrG,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEjD,MAAM,UAAU,GAAgB,CAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAA;AACtE,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,YAAY,CAAiB,CAAA;AAEvD;;;;;;;;;;;;;;GAcG;AAEI,IAAM,gBAAgB,GAAtB,MAAM,gBAAiB,SAAQ,QAAQ,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC;IAA5D;;QAmDG,eAAU,GAAG,KAAK,CAAA;IAoL5B,CAAC;aAtOQ,WAAM,GAAG,CAAC,eAAe,EAAE,eAAe,EAAE,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBrD,CAAC,AAvBW,CAuBX;IAYM,KAAK;QACX,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;QACjE,CAAC;QAAC,MAAM,CAAC;YACP,iFAAiF;YACjF,OAAO,SAAS,CAAA;QAClB,CAAC;IACH,CAAC;IAUD,iBAAiB;QACf,KAAK,CAAC,iBAAiB,EAAE,CAAA;QACzB,IAAI,CAAC,KAAK,GAAG,IAAI,cAAc,CAAC,GAAG,EAAE;YACnC,IAAI,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,eAAe,EAAE,EAAE,KAAK,KAAK,EAAE,CAAC;gBAC1D,IAAI,CAAC,UAAU,GAAG,KAAK,CAAA;gBACvB,IAAI,CAAC,aAAa,EAAE,CAAA;YACtB,CAAC;QACH,CAAC,CAAC,CAAA;QACF,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1B,CAAC;IACD,oBAAoB;QAClB,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,CAAA;QACxB,KAAK,CAAC,oBAAoB,EAAE,CAAA;IAC9B,CAAC;IAED,MAAM;QACJ,IAAI,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,eAAe,EAAE,EAAE,KAAK,KAAK,EAAE,CAAC;YAC1D,IAAI,CAAC,UAAU,GAAG,IAAI,CAAA;YACtB,OAAO,IAAI,CAAC,SAAS,IAAI,OAAO,CAAA;QAClC,CAAC;QACD,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;QAC5B,OAAO,IAAI,CAAC,SAAS,CAAA;IACvB,CAAC;IAEO,IAAI;QACV,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,EAAE,CAAA;QAC1B,IAAI,CAAC,KAAK;YAAE,OAAO,OAAO,CAAA;QAC1B,kGAAkG;QAClG,OAAO,IAAI,CAAA;cACD,OAAO,CAAC,CAAC,CAAC,2BAA2B,CAAC;;UAE1C,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC;;;cAGjD,OAAO,CAAC,CAAC,CAAC,6BAA6B,CAAC;UAC5C,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC;;;cAGjD,OAAO,CAAC,CAAC,CAAC,4BAA4B,CAAC;UAC3C,IAAI,CAAC,aAAa,EAAE;iBACb,CAAA;IACf,CAAC;IAEO,UAAU,CAAC,KAAwB;QACzC,OAAO,IAAI,CAAA;;iBAEE,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC;;mBAE5B,KAAK,CAAC,IAAI;wBACL,OAAO,CAAC,CAAC,CAAC,iCAAiC,CAAC;oBAChD,CAAC,KAAY,EAAE,EAAE;YACzB,MAAM,KAAK,GAAG,KAAK,CAAC,MAA0B,CAAA;YAC9C,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;gBACxB,kGAAkG;gBAClG,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,IAAI,CAAA;gBACxB,OAAM;YACR,CAAC;YACD,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,KAAK,CAAC,IAAI;gBAAE,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,CAAA;QAC5F,CAAC;;;KAGN,CAAA;IACH,CAAC;IAED;;;OAGG;IACK,eAAe,CAAC,KAAwB;QAC9C,MAAM,OAAO,GAAG,KAAK,CAAC,SAAS,IAAI,OAAO,CAAA;QAC1C,OAAO,IAAI,CAAA;;iBAEE,OAAO,CAAC,CAAC,CAAC,+BAA+B,CAAC;;mBAExC,IAAI,CAAC,OAAO,CAAC;oBACZ,CAAC,KAAY,EAAE,EAAE;YACzB,MAAM,MAAM,GAAG,KAAK,CAAC,MAA2B,CAAA;YAChD,2GAA2G;YAC3G,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,CAAC,KAAkB,EAAE,CAAC,CAAA;YAC7E,oHAAoH;YACpH,MAAM,CAAC,KAAK,GAAG,OAAO,CAAA;QACxB,CAAC;;YAEC,UAAU,CAAC,GAAG,CACd,GAAG,CAAC,EAAE,CAAC,IAAI,CAAA,iBAAiB,GAAG,cAAc,GAAG,KAAK,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,yBAAyB,GAAG,GAAG,CAAC,WAAW,CACtH;;iBAEM,OAAO,CAAC,CAAC,CAAC,iCAAiC,CAAC;;KAExD,CAAA;IACH,CAAC;IAEO,WAAW,CAAC,KAAwB;QAC1C,OAAO,IAAI,CAAA;;iBAEE,OAAO,CAAC,CAAC,CAAC,6BAA6B,CAAC;;kBAEvC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,qCAAqC,CAAC,CAAC,CAAC,iCAAiC,CAAC;kCACrF,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,WAAW,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,IAAI,OAAO,CAAC;2CACnE,OAAO,CAAC,CAAC,CAAC,iCAAiC,CAAC;;;;KAIlF,CAAA;IACH,CAAC;IAEO,cAAc,CAAC,KAAwB;QAC7C,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAA;QAC/B,wGAAwG;QACxG,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,SAAS,EAAE,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAA;QACnI,MAAM,IAAI,GAAe,IAAI,CAAC,UAAU,IAAI,QAAQ,EAAE,IAAI,IAAI,KAAK,CAAC,SAAS,EAAE,IAAI,IAAI,QAAQ,CAAA;QAC/F,OAAO,IAAI,CAAA;;iBAEE,OAAO,CAAC,CAAC,CAAC,4BAA4B,CAAC;;8BAE1B,CAAC,KAAK,CAAC,QAAQ,YAAY,CAAC,CAAQ,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,GAAI,CAAC,CAAC,MAA4B,CAAC,KAAK,CAAC;cAClH,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAA,iBAAiB,GAAG,cAAc,GAAG,KAAK,IAAI,IAAI,GAAG,WAAW,CAAC;;8BAE5E,CAAC,KAAK,CAAC,QAAQ,YAAY,CAAC,CAAQ,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,GAAI,CAAC,CAAC,MAA4B,CAAC,KAAmB,CAAC;cAChI,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAA,iBAAiB,GAAG,cAAc,GAAG,KAAK,IAAI,IAAI,OAAO,CAAC,CAAC,CAAC,oBAAoB,GAAG,GAAG,CAAC,WAAW,CAAC;;;;kCAIpG,CAAC,KAAK,CAAC,QAAQ,IAAI,CAAC,IAAI,WAAW,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAE,IAAK,EAAE,IAAI,EAAE,CAAC;sCACnG,OAAO,CAAC,CAAC,CAAC,iCAAiC,CAAC;;kCAEhD,CAAC,QAAQ,WAAW,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,qBAAqB,EAAE,CAAC;sCACnE,OAAO,CAAC,CAAC,CAAC,mCAAmC,CAAC;;;;YAIxE,KAAK,CAAC,QAAQ;YACd,CAAC,CAAC,QAAQ;gBACR,CAAC,CAAC,GAAG,QAAQ,CAAC,IAAI,MAAM,OAAO,CAAC,CAAC,CAAC,oBAAoB,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE;gBACzE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,iCAAiC,CAAC;YAChD,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,uCAAuC,CAAC;;;KAG3D,CAAA;IACH,CAAC;IAEO,aAAa;QACnB,MAAM,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAA;QAC7B,OAAO,IAAI,CAAA;;iBAEE,OAAO,CAAC,CAAC,CAAC,uBAAuB,CAAC;;mBAEhC,IAAI,CAAC,cAAc,IAAI,EAAE;sBACtB,CAAC,KAAK;wBACJ,OAAO,CAAC,CAAC,CAAC,kCAAkC,CAAC;oBACjD,CAAC,CAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAG,CAAC,CAAC,MAA2B,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;;;;iBAIxF,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC;;mBAE5B,CAAC,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;sBAC/B,CAAC,KAAK;wBACJ,OAAO,CAAC,CAAC,CAAC,8BAA8B,CAAC;oBAC7C,CAAC,CAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,CAAE,CAAC,CAAC,MAA2B,CAAC,KAAK,CAAC,EAAE,CAAC;;UAE5F,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAA,UAAU,OAAO,CAAC,CAAC,CAAC,kCAAkC,CAAC,UAAU;;KAE5F,CAAA;IACH,CAAC;IAEO,OAAO,CAAC,SAAoB;QAClC,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAM;QACxB,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAA;IAC1D,CAAC;IAEO,OAAO,CAAC,MAA6B;QAC3C,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,SAAS,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;IACvG,CAAC;IAEO,OAAO,CAAC,KAA6C;QAC3D,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,SAAS,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;IAClG,CAAC;;AA3M2B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;gDAAgB;AAEf;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;kDAAkB;AACjB;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;wDAAwB;AACxB;IAA1B,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;;oDAAsB;AAE/B;IAAhB,KAAK,EAAE;;oDAA4B;AACnB;IAAhB,KAAK,EAAE;;oDAAgC;AAlC7B,gBAAgB;IAD5B,aAAa,CAAC,mBAAmB,CAAC;GACtB,gBAAgB,CAuO5B","sourcesContent":["import '@material/web/icon/icon.js'\n\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { live } from 'lit/directives/live.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { FIGURE_FACES } from '@hatiolab/figure-model'\nimport type { FigureAuthoringAction, FigureFace } from '@hatiolab/figure-model'\n\nimport { occupancyFromParts } from './occupancy.js'\nimport { tagsOf, figureFigureFacts, type Placement, type FigureFigureFacts } from './figure-facts.js'\nimport { SidePanelStyles } from './side-panel-styles.js'\nimport { ScrollbarStyles } from '@operato/styles'\n\nconst PLACEMENTS: Placement[] = ['floor', 'ceiling', 'center', 'wall']\nconst FACES = Object.keys(FIGURE_FACES) as FigureFace[]\n\n/**\n * 속성 — the modeller's figure properties.\n *\n * The tab opens with what the figure is: its name, the face it is placed by, the room it takes up, where the\n * catalogue files it.\n *\n * Two kinds of change leave this tab, and it does neither itself:\n * - `command` carries an authoring command (rename, declare the room, the mounting face). The page runs it\n * through the session, so it is one step of the same undo history as every other edit, and is saved with it.\n * - `catalog` carries a change to the row (category, tags). Those are not in the asset; the page writes them\n * to the saved row at once, so they need a saved figure.\n *\n * Not here yet, because has no place for them: editing the declared room by hand (declares it from the\n * parts, as graph expressions), and the detail level. Both wait on a ruling.\n */\n@customElement('figure-properties')\nexport class FigureProperties extends localize(i18next)(LitElement) {\n static styles = [ScrollbarStyles, SidePanelStyles, css`\n :host {\n display: block;\n /* It stands inside the properties tab's panel, which gives the margin; a second one indented it past the type. */\n padding: 0;\n overflow: auto;\n }\n div[row] {\n display: flex;\n gap: 6px;\n align-items: center;\n }\n div[row] > select {\n flex: 1;\n }\n div[row] > button[act] {\n flex: 1;\n width: auto;\n margin-top: 0;\n }\n div[row] > span {\n flex: 1;\n }\n `]\n\n /** The source being edited. */\n @property({ type: String }) source?: string\n /** The saved row, if any. Category and tags live on it. */\n @property({ type: String }) figureId?: string\n @property({ type: String }) figureCategory?: string\n @property({ type: Array }) figureTags?: string[]\n /** The part and face picked for the mounting face, before 「이 면으로」 is pressed. */\n @state() private pickedPart?: string\n @state() private pickedFace?: FigureFace\n\n private facts(): FigureFigureFacts | undefined {\n try {\n return this.source ? figureFigureFacts(this.source) : undefined\n } catch {\n /* A source the format refuses has no facts to show; the verdict tab says why. */\n return undefined\n }\n }\n\n /*\n The figure's own settings are shown while no part is picked; with one picked this is out of sight, and working out its\n facts (the figure parsed and compiled) on every edit is for nobody. Out of sight it keeps what it last drew, and it\n draws again when it comes back into view.\n */\n private lastDrawn?: unknown\n private outOfSight = false\n private watch?: ResizeObserver\n connectedCallback() {\n super.connectedCallback()\n this.watch = new ResizeObserver(() => {\n if (this.outOfSight && this.checkVisibility?.() !== false) {\n this.outOfSight = false\n this.requestUpdate()\n }\n })\n this.watch.observe(this)\n }\n disconnectedCallback() {\n this.watch?.disconnect()\n super.disconnectedCallback()\n }\n\n render() {\n if (this.hasUpdated && this.checkVisibility?.() === false) {\n this.outOfSight = true\n return this.lastDrawn ?? nothing\n }\n this.lastDrawn = this.draw()\n return this.lastDrawn\n }\n\n private draw() {\n const facts = this.facts()\n if (!facts) return nothing\n /* The figure's type is the page's (it lives on the row); it is slotted into the first section. */\n return html`<section>\n <h3>${i18next.t('figure.label.group-figure')}</h3>\n <slot name=\"type\"></slot>\n ${this.renderName(facts)} ${this.renderPlacement(facts)}\n </section>\n <section>\n <h3>${i18next.t('figure.label.group-standing')}</h3>\n ${this.renderSpace(facts)} ${this.renderMounting(facts)}\n </section>\n <section>\n <h3>${i18next.t('figure.label.group-catalog')}</h3>\n ${this.renderCatalog()}\n </section>`\n }\n\n private renderName(facts: FigureFigureFacts) {\n return html`\n <div field>\n <label>${i18next.t('figure.label.name')}</label>\n <input\n .value=${facts.name}\n placeholder=${i18next.t('figure.text.figure-display-name')}\n @change=${(event: Event) => {\n const input = event.target as HTMLInputElement\n if (!input.value.trim()) {\n /* The format refuses a blank name; put the old one back rather than send a command that fails. */\n input.value = facts.name\n return\n }\n if (input.value.trim() !== facts.name) this.command({ kind: 'rename', name: input.value })\n }}\n />\n </div>\n `\n }\n\n /**\n * The face the figure is placed by. In it is part of the room declaration, so choosing one declares the room\n * again from the parts — the only way declares it — with the new face. The hint says so.\n */\n private renderPlacement(facts: FigureFigureFacts) {\n const current = facts.placement ?? 'floor'\n return html`\n <div field>\n <label>${i18next.t('figure.label.figure-placement')}</label>\n <select\n .value=${live(current)}\n @change=${(event: Event) => {\n const select = event.target as HTMLSelectElement\n /* The figure's own setting (ADR-0097): chosen with no part too, and the room is left as it is declared. */\n this.command({ kind: 'set-placement', placement: select.value as Placement })\n /* Refused, the figure is placed as it was, and the list says so; taken, the figure drawn again says the new one. */\n select.value = current\n }}\n >\n ${PLACEMENTS.map(\n one => html`<option value=${one} ?selected=${one === current}>${i18next.t('figure.label.placement-' + one)}</option>`\n )}\n </select>\n <small>${i18next.t('figure.text.placement-is-intent')}</small>\n </div>\n `\n }\n\n private renderSpace(facts: FigureFigureFacts) {\n return html`\n <div field>\n <label>${i18next.t('figure.label.declared-space')}</label>\n <div row>\n <span>${i18next.t(facts.declared ? 'figure.text.declared-space-declared' : 'figure.text.declared-space-none')}</span>\n <button act ?disabled=${!facts.parts.length} @click=${() => this.declare(facts.placement ?? 'floor')}>\n <md-icon>fit_screen</md-icon>${i18next.t('figure.button.fit-base-to-parts')}\n </button>\n </div>\n </div>\n `\n }\n\n private renderMounting(facts: FigureFigureFacts) {\n const mounting = facts.mounting\n /* Chosen, or what is set, or where the figure meets its plane -- not the first part listed (walk 1). */\n const part = [this.pickedPart, mounting?.part, facts.suggested?.part, facts.parts[0]].find(one => one && facts.parts.includes(one))\n const face: FigureFace = this.pickedFace ?? mounting?.face ?? facts.suggested?.face ?? 'bottom'\n return html`\n <div field>\n <label>${i18next.t('figure.label.mounting-face')}</label>\n <div row>\n <select ?disabled=${!facts.declared} @change=${(e: Event) => (this.pickedPart = (e.target as HTMLSelectElement).value)}>\n ${facts.parts.map(one => html`<option value=${one} ?selected=${one === part}>${one}</option>`)}\n </select>\n <select ?disabled=${!facts.declared} @change=${(e: Event) => (this.pickedFace = (e.target as HTMLSelectElement).value as FigureFace)}>\n ${FACES.map(one => html`<option value=${one} ?selected=${one === face}>${i18next.t('figure.label.face-' + one)}</option>`)}\n </select>\n </div>\n <div row>\n <button act ?disabled=${!facts.declared || !part} @click=${() => this.command({ kind: 'set-mounting-face', part: part!, face })}>\n <md-icon>check</md-icon>${i18next.t('figure.button.set-mounting-face')}\n </button>\n <button act ?disabled=${!mounting} @click=${() => this.command({ kind: 'clear-mounting-face' })}>\n <md-icon>close</md-icon>${i18next.t('figure.button.clear-mounting-face')}\n </button>\n </div>\n <small>\n ${facts.declared\n ? mounting\n ? `${mounting.part} · ${i18next.t('figure.label.face-' + mounting.face)}`\n : i18next.t('figure.label.mounting-face-none')\n : i18next.t('figure.text.mounting-face-needs-space')}\n </small>\n </div>\n `\n }\n\n private renderCatalog() {\n const saved = !!this.figureId\n return html`\n <div field>\n <label>${i18next.t('figure.label.category')}</label>\n <input\n .value=${this.figureCategory ?? ''}\n ?disabled=${!saved}\n placeholder=${i18next.t('figure.text.category-placeholder')}\n @change=${(e: Event) => this.catalog({ category: (e.target as HTMLInputElement).value.trim() })}\n />\n </div>\n <div field>\n <label>${i18next.t('figure.label.tags')}</label>\n <input\n .value=${(this.figureTags ?? []).join(', ')}\n ?disabled=${!saved}\n placeholder=${i18next.t('figure.text.tags-placeholder')}\n @change=${(e: Event) => this.catalog({ tags: tagsOf((e.target as HTMLInputElement).value) })}\n />\n ${saved ? nothing : html`<small>${i18next.t('figure.text.catalog-needs-a-save')}</small>`}\n </div>\n `\n }\n\n private declare(placement: Placement) {\n if (!this.source) return\n this.command(occupancyFromParts(this.source, placement))\n }\n\n private command(action: FigureAuthoringAction) {\n this.dispatchEvent(new CustomEvent('command', { detail: { action }, bubbles: true, composed: true }))\n }\n\n private catalog(patch: { category?: string; tags?: string[] }) {\n this.dispatchEvent(new CustomEvent('catalog', { detail: patch, bubbles: true, composed: true }))\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"figure-properties.js","sourceRoot":"","sources":["../../client/modeller/figure-properties.ts"],"names":[],"mappings":";AAAA,OAAO,4BAA4B,CAAA;AAEnC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,KAAK,CAAA;AACpD,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAA;AAE7C,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAGrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AACnD,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAA0C,MAAM,mBAAmB,CAAA;AAErG,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEjD,MAAM,UAAU,GAAgB,CAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAA;AACtE,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,YAAY,CAAiB,CAAA;AAEvD;;;;;;;;;;;;;;GAcG;AAEI,IAAM,gBAAgB,GAAtB,MAAM,gBAAiB,SAAQ,QAAQ,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC;IAA5D;;QAmDG,eAAU,GAAG,KAAK,CAAA;IAoL5B,CAAC;aAtOQ,WAAM,GAAG,CAAC,eAAe,EAAE,eAAe,EAAE,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBrD,CAAC,AAvBW,CAuBX;IAYM,KAAK;QACX,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;QACrE,CAAC;QAAC,MAAM,CAAC;YACP,iFAAiF;YACjF,OAAO,SAAS,CAAA;QAClB,CAAC;IACH,CAAC;IAUD,iBAAiB;QACf,KAAK,CAAC,iBAAiB,EAAE,CAAA;QACzB,IAAI,CAAC,KAAK,GAAG,IAAI,cAAc,CAAC,GAAG,EAAE;YACnC,IAAI,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,eAAe,EAAE,EAAE,KAAK,KAAK,EAAE,CAAC;gBAC1D,IAAI,CAAC,UAAU,GAAG,KAAK,CAAA;gBACvB,IAAI,CAAC,aAAa,EAAE,CAAA;YACtB,CAAC;QACH,CAAC,CAAC,CAAA;QACF,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1B,CAAC;IACD,oBAAoB;QAClB,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,CAAA;QACxB,KAAK,CAAC,oBAAoB,EAAE,CAAA;IAC9B,CAAC;IAED,MAAM;QACJ,IAAI,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,eAAe,EAAE,EAAE,KAAK,KAAK,EAAE,CAAC;YAC1D,IAAI,CAAC,UAAU,GAAG,IAAI,CAAA;YACtB,OAAO,IAAI,CAAC,SAAS,IAAI,OAAO,CAAA;QAClC,CAAC;QACD,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;QAC5B,OAAO,IAAI,CAAC,SAAS,CAAA;IACvB,CAAC;IAEO,IAAI;QACV,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,EAAE,CAAA;QAC1B,IAAI,CAAC,KAAK;YAAE,OAAO,OAAO,CAAA;QAC1B,kGAAkG;QAClG,OAAO,IAAI,CAAA;cACD,OAAO,CAAC,CAAC,CAAC,2BAA2B,CAAC;;UAE1C,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC;;;cAGjD,OAAO,CAAC,CAAC,CAAC,6BAA6B,CAAC;UAC5C,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC;;;cAGjD,OAAO,CAAC,CAAC,CAAC,4BAA4B,CAAC;UAC3C,IAAI,CAAC,aAAa,EAAE;iBACb,CAAA;IACf,CAAC;IAEO,UAAU,CAAC,KAAwB;QACzC,OAAO,IAAI,CAAA;;iBAEE,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC;;mBAE5B,KAAK,CAAC,IAAI;wBACL,OAAO,CAAC,CAAC,CAAC,iCAAiC,CAAC;oBAChD,CAAC,KAAY,EAAE,EAAE;YACzB,MAAM,KAAK,GAAG,KAAK,CAAC,MAA0B,CAAA;YAC9C,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;gBACxB,kGAAkG;gBAClG,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,IAAI,CAAA;gBACxB,OAAM;YACR,CAAC;YACD,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,KAAK,CAAC,IAAI;gBAAE,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,CAAA;QAC5F,CAAC;;;KAGN,CAAA;IACH,CAAC;IAED;;;OAGG;IACK,eAAe,CAAC,KAAwB;QAC9C,MAAM,OAAO,GAAG,KAAK,CAAC,SAAS,IAAI,OAAO,CAAA;QAC1C,OAAO,IAAI,CAAA;;iBAEE,OAAO,CAAC,CAAC,CAAC,+BAA+B,CAAC;;mBAExC,IAAI,CAAC,OAAO,CAAC;oBACZ,CAAC,KAAY,EAAE,EAAE;YACzB,MAAM,MAAM,GAAG,KAAK,CAAC,MAA2B,CAAA;YAChD,2GAA2G;YAC3G,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,CAAC,KAAkB,EAAE,CAAC,CAAA;YAC7E,oHAAoH;YACpH,MAAM,CAAC,KAAK,GAAG,OAAO,CAAA;QACxB,CAAC;;YAEC,UAAU,CAAC,GAAG,CACd,GAAG,CAAC,EAAE,CAAC,IAAI,CAAA,iBAAiB,GAAG,cAAc,GAAG,KAAK,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,yBAAyB,GAAG,GAAG,CAAC,WAAW,CACtH;;iBAEM,OAAO,CAAC,CAAC,CAAC,iCAAiC,CAAC;;KAExD,CAAA;IACH,CAAC;IAEO,WAAW,CAAC,KAAwB;QAC1C,OAAO,IAAI,CAAA;;iBAEE,OAAO,CAAC,CAAC,CAAC,6BAA6B,CAAC;;kBAEvC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,qCAAqC,CAAC,CAAC,CAAC,iCAAiC,CAAC;kCACrF,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,WAAW,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,IAAI,OAAO,CAAC;2CACnE,OAAO,CAAC,CAAC,CAAC,iCAAiC,CAAC;;;;KAIlF,CAAA;IACH,CAAC;IAEO,cAAc,CAAC,KAAwB;QAC7C,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAA;QAC/B,wGAAwG;QACxG,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,SAAS,EAAE,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAA;QACnI,MAAM,IAAI,GAAe,IAAI,CAAC,UAAU,IAAI,QAAQ,EAAE,IAAI,IAAI,KAAK,CAAC,SAAS,EAAE,IAAI,IAAI,QAAQ,CAAA;QAC/F,OAAO,IAAI,CAAA;;iBAEE,OAAO,CAAC,CAAC,CAAC,4BAA4B,CAAC;;8BAE1B,CAAC,KAAK,CAAC,QAAQ,YAAY,CAAC,CAAQ,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,GAAI,CAAC,CAAC,MAA4B,CAAC,KAAK,CAAC;cAClH,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAA,iBAAiB,GAAG,cAAc,GAAG,KAAK,IAAI,IAAI,GAAG,WAAW,CAAC;;8BAE5E,CAAC,KAAK,CAAC,QAAQ,YAAY,CAAC,CAAQ,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,GAAI,CAAC,CAAC,MAA4B,CAAC,KAAmB,CAAC;cAChI,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAA,iBAAiB,GAAG,cAAc,GAAG,KAAK,IAAI,IAAI,OAAO,CAAC,CAAC,CAAC,oBAAoB,GAAG,GAAG,CAAC,WAAW,CAAC;;;;kCAIpG,CAAC,KAAK,CAAC,QAAQ,IAAI,CAAC,IAAI,WAAW,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAE,IAAK,EAAE,IAAI,EAAE,CAAC;sCACnG,OAAO,CAAC,CAAC,CAAC,iCAAiC,CAAC;;kCAEhD,CAAC,QAAQ,WAAW,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,qBAAqB,EAAE,CAAC;sCACnE,OAAO,CAAC,CAAC,CAAC,mCAAmC,CAAC;;;;YAIxE,KAAK,CAAC,QAAQ;YACd,CAAC,CAAC,QAAQ;gBACR,CAAC,CAAC,GAAG,QAAQ,CAAC,IAAI,MAAM,OAAO,CAAC,CAAC,CAAC,oBAAoB,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE;gBACzE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,iCAAiC,CAAC;YAChD,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,uCAAuC,CAAC;;;KAG3D,CAAA;IACH,CAAC;IAEO,aAAa;QACnB,MAAM,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAA;QAC7B,OAAO,IAAI,CAAA;;iBAEE,OAAO,CAAC,CAAC,CAAC,uBAAuB,CAAC;;mBAEhC,IAAI,CAAC,cAAc,IAAI,EAAE;sBACtB,CAAC,KAAK;wBACJ,OAAO,CAAC,CAAC,CAAC,kCAAkC,CAAC;oBACjD,CAAC,CAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAG,CAAC,CAAC,MAA2B,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;;;;iBAIxF,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC;;mBAE5B,CAAC,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;sBAC/B,CAAC,KAAK;wBACJ,OAAO,CAAC,CAAC,CAAC,8BAA8B,CAAC;oBAC7C,CAAC,CAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,CAAE,CAAC,CAAC,MAA2B,CAAC,KAAK,CAAC,EAAE,CAAC;;UAE5F,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAA,UAAU,OAAO,CAAC,CAAC,CAAC,kCAAkC,CAAC,UAAU;;KAE5F,CAAA;IACH,CAAC;IAEO,OAAO,CAAC,SAAoB;QAClC,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,OAAM;QAC1B,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,CAAA;IAClE,CAAC;IAEO,OAAO,CAAC,MAA6B;QAC3C,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,SAAS,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;IACvG,CAAC;IAEO,OAAO,CAAC,KAA6C;QAC3D,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,SAAS,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;IAClG,CAAC;;AA3M+B;IAA/B,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;;kDAA0B;AAE7B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;kDAAkB;AACjB;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;wDAAwB;AACxB;IAA1B,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;;oDAAsB;AAE/B;IAAhB,KAAK,EAAE;;oDAA4B;AACnB;IAAhB,KAAK,EAAE;;oDAAgC;AAlC7B,gBAAgB;IAD5B,aAAa,CAAC,mBAAmB,CAAC;GACtB,gBAAgB,CAuO5B","sourcesContent":["import '@material/web/icon/icon.js'\n\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { live } from 'lit/directives/live.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { FIGURE_FACES } from '@hatiolab/figure-model'\nimport type { FigureAuthoringAction, FigureFace } from '@hatiolab/figure-model'\n\nimport { occupancyFromParts } from './occupancy.js'\nimport { tagsOf, figureFigureFacts, type Placement, type FigureFigureFacts } from './figure-facts.js'\nimport type { FigureRevision } from './revision.js'\nimport { SidePanelStyles } from './side-panel-styles.js'\nimport { ScrollbarStyles } from '@operato/styles'\n\nconst PLACEMENTS: Placement[] = ['floor', 'ceiling', 'center', 'wall']\nconst FACES = Object.keys(FIGURE_FACES) as FigureFace[]\n\n/**\n * 속성 — the modeller's figure properties.\n *\n * The tab opens with what the figure is: its name, the face it is placed by, the room it takes up, where the\n * catalogue files it.\n *\n * Two kinds of change leave this tab, and it does neither itself:\n * - `command` carries an authoring command (rename, declare the room, the mounting face). The page runs it\n * through the session, so it is one step of the same undo history as every other edit, and is saved with it.\n * - `catalog` carries a change to the row (category, tags). Those are not in the asset; the page writes them\n * to the saved row at once, so they need a saved figure.\n *\n * Not here yet, because has no place for them: editing the declared room by hand (declares it from the\n * parts, as graph expressions), and the detail level. Both wait on a ruling.\n */\n@customElement('figure-properties')\nexport class FigureProperties extends localize(i18next)(LitElement) {\n static styles = [ScrollbarStyles, SidePanelStyles, css`\n :host {\n display: block;\n /* It stands inside the properties tab's panel, which gives the margin; a second one indented it past the type. */\n padding: 0;\n overflow: auto;\n }\n div[row] {\n display: flex;\n gap: 6px;\n align-items: center;\n }\n div[row] > select {\n flex: 1;\n }\n div[row] > button[act] {\n flex: 1;\n width: auto;\n margin-top: 0;\n }\n div[row] > span {\n flex: 1;\n }\n `]\n\n /** The figure at the version on screen. */\n @property({ attribute: false }) revision?: FigureRevision\n /** The saved row, if any. Category and tags live on it. */\n @property({ type: String }) figureId?: string\n @property({ type: String }) figureCategory?: string\n @property({ type: Array }) figureTags?: string[]\n /** The part and face picked for the mounting face, before 「이 면으로」 is pressed. */\n @state() private pickedPart?: string\n @state() private pickedFace?: FigureFace\n\n private facts(): FigureFigureFacts | undefined {\n try {\n return this.revision ? figureFigureFacts(this.revision) : undefined\n } catch {\n /* A source the format refuses has no facts to show; the verdict tab says why. */\n return undefined\n }\n }\n\n /*\n The figure's own settings are shown while no part is picked; with one picked this is out of sight, and working out its\n facts (the figure parsed and compiled) on every edit is for nobody. Out of sight it keeps what it last drew, and it\n draws again when it comes back into view.\n */\n private lastDrawn?: unknown\n private outOfSight = false\n private watch?: ResizeObserver\n connectedCallback() {\n super.connectedCallback()\n this.watch = new ResizeObserver(() => {\n if (this.outOfSight && this.checkVisibility?.() !== false) {\n this.outOfSight = false\n this.requestUpdate()\n }\n })\n this.watch.observe(this)\n }\n disconnectedCallback() {\n this.watch?.disconnect()\n super.disconnectedCallback()\n }\n\n render() {\n if (this.hasUpdated && this.checkVisibility?.() === false) {\n this.outOfSight = true\n return this.lastDrawn ?? nothing\n }\n this.lastDrawn = this.draw()\n return this.lastDrawn\n }\n\n private draw() {\n const facts = this.facts()\n if (!facts) return nothing\n /* The figure's type is the page's (it lives on the row); it is slotted into the first section. */\n return html`<section>\n <h3>${i18next.t('figure.label.group-figure')}</h3>\n <slot name=\"type\"></slot>\n ${this.renderName(facts)} ${this.renderPlacement(facts)}\n </section>\n <section>\n <h3>${i18next.t('figure.label.group-standing')}</h3>\n ${this.renderSpace(facts)} ${this.renderMounting(facts)}\n </section>\n <section>\n <h3>${i18next.t('figure.label.group-catalog')}</h3>\n ${this.renderCatalog()}\n </section>`\n }\n\n private renderName(facts: FigureFigureFacts) {\n return html`\n <div field>\n <label>${i18next.t('figure.label.name')}</label>\n <input\n .value=${facts.name}\n placeholder=${i18next.t('figure.text.figure-display-name')}\n @change=${(event: Event) => {\n const input = event.target as HTMLInputElement\n if (!input.value.trim()) {\n /* The format refuses a blank name; put the old one back rather than send a command that fails. */\n input.value = facts.name\n return\n }\n if (input.value.trim() !== facts.name) this.command({ kind: 'rename', name: input.value })\n }}\n />\n </div>\n `\n }\n\n /**\n * The face the figure is placed by. In it is part of the room declaration, so choosing one declares the room\n * again from the parts — the only way declares it — with the new face. The hint says so.\n */\n private renderPlacement(facts: FigureFigureFacts) {\n const current = facts.placement ?? 'floor'\n return html`\n <div field>\n <label>${i18next.t('figure.label.figure-placement')}</label>\n <select\n .value=${live(current)}\n @change=${(event: Event) => {\n const select = event.target as HTMLSelectElement\n /* The figure's own setting (ADR-0097): chosen with no part too, and the room is left as it is declared. */\n this.command({ kind: 'set-placement', placement: select.value as Placement })\n /* Refused, the figure is placed as it was, and the list says so; taken, the figure drawn again says the new one. */\n select.value = current\n }}\n >\n ${PLACEMENTS.map(\n one => html`<option value=${one} ?selected=${one === current}>${i18next.t('figure.label.placement-' + one)}</option>`\n )}\n </select>\n <small>${i18next.t('figure.text.placement-is-intent')}</small>\n </div>\n `\n }\n\n private renderSpace(facts: FigureFigureFacts) {\n return html`\n <div field>\n <label>${i18next.t('figure.label.declared-space')}</label>\n <div row>\n <span>${i18next.t(facts.declared ? 'figure.text.declared-space-declared' : 'figure.text.declared-space-none')}</span>\n <button act ?disabled=${!facts.parts.length} @click=${() => this.declare(facts.placement ?? 'floor')}>\n <md-icon>fit_screen</md-icon>${i18next.t('figure.button.fit-base-to-parts')}\n </button>\n </div>\n </div>\n `\n }\n\n private renderMounting(facts: FigureFigureFacts) {\n const mounting = facts.mounting\n /* Chosen, or what is set, or where the figure meets its plane -- not the first part listed (walk 1). */\n const part = [this.pickedPart, mounting?.part, facts.suggested?.part, facts.parts[0]].find(one => one && facts.parts.includes(one))\n const face: FigureFace = this.pickedFace ?? mounting?.face ?? facts.suggested?.face ?? 'bottom'\n return html`\n <div field>\n <label>${i18next.t('figure.label.mounting-face')}</label>\n <div row>\n <select ?disabled=${!facts.declared} @change=${(e: Event) => (this.pickedPart = (e.target as HTMLSelectElement).value)}>\n ${facts.parts.map(one => html`<option value=${one} ?selected=${one === part}>${one}</option>`)}\n </select>\n <select ?disabled=${!facts.declared} @change=${(e: Event) => (this.pickedFace = (e.target as HTMLSelectElement).value as FigureFace)}>\n ${FACES.map(one => html`<option value=${one} ?selected=${one === face}>${i18next.t('figure.label.face-' + one)}</option>`)}\n </select>\n </div>\n <div row>\n <button act ?disabled=${!facts.declared || !part} @click=${() => this.command({ kind: 'set-mounting-face', part: part!, face })}>\n <md-icon>check</md-icon>${i18next.t('figure.button.set-mounting-face')}\n </button>\n <button act ?disabled=${!mounting} @click=${() => this.command({ kind: 'clear-mounting-face' })}>\n <md-icon>close</md-icon>${i18next.t('figure.button.clear-mounting-face')}\n </button>\n </div>\n <small>\n ${facts.declared\n ? mounting\n ? `${mounting.part} · ${i18next.t('figure.label.face-' + mounting.face)}`\n : i18next.t('figure.label.mounting-face-none')\n : i18next.t('figure.text.mounting-face-needs-space')}\n </small>\n </div>\n `\n }\n\n private renderCatalog() {\n const saved = !!this.figureId\n return html`\n <div field>\n <label>${i18next.t('figure.label.category')}</label>\n <input\n .value=${this.figureCategory ?? ''}\n ?disabled=${!saved}\n placeholder=${i18next.t('figure.text.category-placeholder')}\n @change=${(e: Event) => this.catalog({ category: (e.target as HTMLInputElement).value.trim() })}\n />\n </div>\n <div field>\n <label>${i18next.t('figure.label.tags')}</label>\n <input\n .value=${(this.figureTags ?? []).join(', ')}\n ?disabled=${!saved}\n placeholder=${i18next.t('figure.text.tags-placeholder')}\n @change=${(e: Event) => this.catalog({ tags: tagsOf((e.target as HTMLInputElement).value) })}\n />\n ${saved ? nothing : html`<small>${i18next.t('figure.text.catalog-needs-a-save')}</small>`}\n </div>\n `\n }\n\n private declare(placement: Placement) {\n if (!this.revision) return\n this.command(occupancyFromParts(this.revision.asset, placement))\n }\n\n private command(action: FigureAuthoringAction) {\n this.dispatchEvent(new CustomEvent('command', { detail: { action }, bubbles: true, composed: true }))\n }\n\n private catalog(patch: { category?: string; tags?: string[] }) {\n this.dispatchEvent(new CustomEvent('catalog', { detail: patch, bubbles: true, composed: true }))\n }\n}\n"]}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import '@material/web/icon/icon.js';
|
|
2
2
|
import { LitElement } from 'lit';
|
|
3
|
+
import type { FigureRevision } from './revision.js';
|
|
3
4
|
/** How long an edit settles before the server is asked again. One question per pause, not one per keystroke. */
|
|
4
5
|
export declare const VERDICT_SETTLE_MS = 400;
|
|
5
6
|
declare const FigureVerdict_base: (new (...args: any[]) => LitElement) & typeof LitElement;
|
|
6
7
|
export declare class FigureVerdict extends FigureVerdict_base {
|
|
7
8
|
static styles: import("lit").CSSResult[];
|
|
8
|
-
/** The
|
|
9
|
-
|
|
9
|
+
/** The figure at the version on screen. A version whose text is another is a new question. */
|
|
10
|
+
revision?: FigureRevision;
|
|
11
|
+
private judged?;
|
|
10
12
|
/** The saved row, if any — the server reads its type and last release from it. */
|
|
11
13
|
figureId?: string;
|
|
12
14
|
/** Changing the type changes the verdict (a temporary type is refused), so it is a reason to ask again. */
|
|
@@ -4,7 +4,7 @@ import { css, html, LitElement, nothing, svg } from 'lit';
|
|
|
4
4
|
import { customElement, property, state } from 'lit/decorators.js';
|
|
5
5
|
import { i18next, localize } from '@operato/i18n';
|
|
6
6
|
import { ScrollbarStyles } from '@operato/styles';
|
|
7
|
-
import { LIMITS,
|
|
7
|
+
import { LIMITS, FIGURE_PER_INSTANCE, figureCostOf } from '@hatiolab/figure-model';
|
|
8
8
|
import { inspectFigureDraft } from '../graphql/index.js';
|
|
9
9
|
import { gateFindingStyles, renderGateFinding } from './gate-findings.js';
|
|
10
10
|
import { MEASURED } from './scene-budget.js';
|
|
@@ -389,21 +389,24 @@ let FigureVerdict = class FigureVerdict extends localize(i18next)(LitElement) {
|
|
|
389
389
|
super.disconnectedCallback();
|
|
390
390
|
}
|
|
391
391
|
updated(changes) {
|
|
392
|
-
|
|
392
|
+
const text = changes.has('revision') ? this.revision?.text : this.judged;
|
|
393
|
+
const changed = text !== this.judged;
|
|
394
|
+
if (changed) {
|
|
395
|
+
this.judged = text;
|
|
393
396
|
clearTimeout(this.measureTimer);
|
|
394
397
|
if (this.report === undefined && !this.measureTimer)
|
|
395
398
|
this.measure();
|
|
396
399
|
else
|
|
397
400
|
this.measureTimer = setTimeout(() => this.measure(), MEASURE_SETTLE_MS);
|
|
398
401
|
}
|
|
399
|
-
if (
|
|
402
|
+
if (changed || changes.has('figureId') || changes.has('figureType'))
|
|
400
403
|
this.schedule();
|
|
401
404
|
}
|
|
402
405
|
measure() {
|
|
403
406
|
let report;
|
|
404
407
|
let bodies = 0;
|
|
405
408
|
try {
|
|
406
|
-
const asset = this.
|
|
409
|
+
const asset = this.revision?.asset;
|
|
407
410
|
const cost = asset ? figureCostOf(asset) : undefined;
|
|
408
411
|
bodies = cost ? cost.groups + cost.hidden : 0;
|
|
409
412
|
report = asset ? figureReportOf(asset) : undefined;
|
|
@@ -420,7 +423,7 @@ let FigureVerdict = class FigureVerdict extends localize(i18next)(LitElement) {
|
|
|
420
423
|
}
|
|
421
424
|
schedule() {
|
|
422
425
|
clearTimeout(this.timer);
|
|
423
|
-
if (!this.
|
|
426
|
+
if (!this.revision) {
|
|
424
427
|
this.inspection = undefined;
|
|
425
428
|
return;
|
|
426
429
|
}
|
|
@@ -428,7 +431,7 @@ let FigureVerdict = class FigureVerdict extends localize(i18next)(LitElement) {
|
|
|
428
431
|
}
|
|
429
432
|
async ask() {
|
|
430
433
|
const question = ++this.asked;
|
|
431
|
-
const source = this.
|
|
434
|
+
const source = this.revision.text;
|
|
432
435
|
this.asking = true;
|
|
433
436
|
try {
|
|
434
437
|
const inspection = await inspectFigureDraft(source, this.figureId);
|
|
@@ -753,9 +756,9 @@ let FigureVerdict = class FigureVerdict extends localize(i18next)(LitElement) {
|
|
|
753
756
|
}
|
|
754
757
|
};
|
|
755
758
|
__decorate([
|
|
756
|
-
property({
|
|
757
|
-
__metadata("design:type",
|
|
758
|
-
], FigureVerdict.prototype, "
|
|
759
|
+
property({ attribute: false }),
|
|
760
|
+
__metadata("design:type", Object)
|
|
761
|
+
], FigureVerdict.prototype, "revision", void 0);
|
|
759
762
|
__decorate([
|
|
760
763
|
property({ type: String }),
|
|
761
764
|
__metadata("design:type", String)
|