@things-factory/figure-ui 10.1.270 → 10.1.272
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/graphql/index.ts +2 -0
- package/client/modeller/canvas.ts +4 -2
- package/client/modeller/clips.ts +74 -4
- package/client/modeller/data-interface.ts +14 -0
- package/client/modeller/editor-styles.ts +11 -0
- package/client/modeller/editor.ts +39 -11
- package/client/modeller/fasten-form.ts +73 -3
- package/client/modeller/fasten-geometry.ts +11 -1
- package/client/modeller/figure-cavity-drawing.ts +1 -3
- package/client/modeller/figure-clips.ts +101 -8
- package/client/modeller/figure-fasten-dialog.ts +41 -30
- package/client/modeller/figure-fasten-drawing.ts +5 -4
- package/client/modeller/figure-first-save.ts +4 -3
- package/client/modeller/figure-links.ts +85 -28
- package/client/modeller/figure-preview.ts +50 -4
- package/client/modeller/figure-size-editor.ts +7 -2
- package/client/modeller/first-save.ts +8 -0
- package/client/modeller/focus-on-render.ts +4 -0
- package/client/modeller/palette.ts +27 -0
- package/client/modeller/pivot.ts +76 -0
- package/client/modeller/product-session.ts +5 -1
- package/client/modeller/size-response.ts +14 -0
- package/client/modeller/stage-model.ts +50 -6
- package/client/types.ts +2 -0
- package/dist-client/graphql/index.js +2 -0
- package/dist-client/graphql/index.js.map +1 -1
- package/dist-client/modeller/canvas.d.ts +1 -0
- package/dist-client/modeller/canvas.js +3 -2
- package/dist-client/modeller/canvas.js.map +1 -1
- package/dist-client/modeller/clips.d.ts +23 -6
- package/dist-client/modeller/clips.js +69 -4
- package/dist-client/modeller/clips.js.map +1 -1
- package/dist-client/modeller/data-interface.d.ts +5 -0
- package/dist-client/modeller/data-interface.js +15 -0
- package/dist-client/modeller/data-interface.js.map +1 -1
- package/dist-client/modeller/editor-styles.js +11 -0
- package/dist-client/modeller/editor-styles.js.map +1 -1
- package/dist-client/modeller/editor.d.ts +6 -0
- package/dist-client/modeller/editor.js +35 -11
- package/dist-client/modeller/editor.js.map +1 -1
- package/dist-client/modeller/fasten-form.d.ts +8 -0
- package/dist-client/modeller/fasten-form.js +68 -5
- package/dist-client/modeller/fasten-form.js.map +1 -1
- package/dist-client/modeller/fasten-geometry.d.ts +6 -0
- package/dist-client/modeller/fasten-geometry.js +10 -1
- package/dist-client/modeller/fasten-geometry.js.map +1 -1
- package/dist-client/modeller/figure-cavity-drawing.js +1 -3
- package/dist-client/modeller/figure-cavity-drawing.js.map +1 -1
- package/dist-client/modeller/figure-clips.d.ts +9 -0
- package/dist-client/modeller/figure-clips.js +104 -8
- package/dist-client/modeller/figure-clips.js.map +1 -1
- package/dist-client/modeller/figure-fasten-dialog.js +39 -24
- package/dist-client/modeller/figure-fasten-dialog.js.map +1 -1
- package/dist-client/modeller/figure-fasten-drawing.js +5 -4
- package/dist-client/modeller/figure-fasten-drawing.js.map +1 -1
- package/dist-client/modeller/figure-first-save.js +4 -3
- package/dist-client/modeller/figure-first-save.js.map +1 -1
- package/dist-client/modeller/figure-links.d.ts +9 -0
- package/dist-client/modeller/figure-links.js +89 -35
- package/dist-client/modeller/figure-links.js.map +1 -1
- package/dist-client/modeller/figure-preview.js +48 -4
- package/dist-client/modeller/figure-preview.js.map +1 -1
- package/dist-client/modeller/figure-size-editor.js +7 -3
- package/dist-client/modeller/figure-size-editor.js.map +1 -1
- package/dist-client/modeller/first-save.d.ts +5 -0
- package/dist-client/modeller/first-save.js +7 -0
- package/dist-client/modeller/first-save.js.map +1 -1
- package/dist-client/modeller/focus-on-render.d.ts +2 -0
- package/dist-client/modeller/focus-on-render.js +4 -0
- package/dist-client/modeller/focus-on-render.js.map +1 -0
- package/dist-client/modeller/links.d.ts +1 -1
- package/dist-client/modeller/palette.d.ts +14 -0
- package/dist-client/modeller/palette.js +23 -0
- package/dist-client/modeller/palette.js.map +1 -1
- package/dist-client/modeller/pivot.d.ts +12 -0
- package/dist-client/modeller/pivot.js +59 -0
- package/dist-client/modeller/pivot.js.map +1 -0
- package/dist-client/modeller/product-session.js +6 -2
- package/dist-client/modeller/product-session.js.map +1 -1
- package/dist-client/modeller/size-response.d.ts +6 -0
- package/dist-client/modeller/size-response.js +14 -0
- package/dist-client/modeller/size-response.js.map +1 -1
- package/dist-client/modeller/stage-model.d.ts +17 -3
- package/dist-client/modeller/stage-model.js +44 -6
- package/dist-client/modeller/stage-model.js.map +1 -1
- package/dist-client/route.d.ts +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-client/types.d.ts +2 -0
- package/dist-client/types.js.map +1 -1
- package/package.json +5 -5
- package/test/browser/editing.check.mjs +6 -5
- package/test/browser/section.check.mjs +21 -0
- package/test/clips.test.ts +49 -4
- package/test/data-motion.test.ts +8 -0
- package/test/fasten-form.test.ts +57 -0
- package/test/fasten-geometry.test.ts +25 -1
- package/test/first-part-on-plane.test.ts +52 -0
- package/test/first-save.test.ts +11 -1
- package/test/pivot.test.ts +57 -0
- package/test/save-landed.test.ts +20 -1
- package/test/size-response.test.ts +10 -2
- package/test/stage-model.test.ts +23 -1
- package/translations/en.json +9 -0
- package/translations/es.json +9 -0
- package/translations/ja.json +9 -0
- package/translations/ko.json +9 -0
- package/translations/ms.json +9 -0
- package/translations/zh.json +9 -0
- package/tutorial/humanoid/README.md +22 -0
- package/tutorial/humanoid/chapters.mjs +247 -0
- package/tutorial/humanoid/encode.mjs +26 -0
- package/tutorial/humanoid/lib.mjs +197 -0
- package/tutorial/humanoid/record.mjs +65 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"figure-first-save.js","sourceRoot":"","sources":["../../client/modeller/figure-first-save.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, html, css, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { i18next } from '@operato/i18n'\nimport { closePopup } from '@operato/popup'\nimport '@operato/popup/ox-popup-actions.js'\nimport { CommonPopupStyles, FormFieldStyles } from '@operato/styles'\nimport '@material/web/button/filled-button.js'\nimport '@material/web/button/text-button.js'\n\nimport { firstSaveRefusalOf, offeredTypeOf, releasableType, typeOf, type FirstSave } from './first-save.js'\n\n/**\n * The first save of a new figure: its type and its name, asked once, in the suite's popup look.\n * Closes with the answer, or with nothing when cancelled -- then nothing is saved.\n */\n@customElement('figure-first-save')\nexport class FigureFirstSave extends LitElement {\n static styles = [\n FormFieldStyles,\n CommonPopupStyles,\n css`\n /* The popup's height is a share of the window (small is 40%): on a low window the buttons must still be reached. */\n :host {\n overflow-y: auto;\n }\n div[field] {\n display: grid;\n gap: 4px;\n }\n div[field] label {\n font-size: var(--popup-font-size-small);\n color: var(--md-sys-color-on-surface-variant);\n }\n div[field] input,\n div[field] select {\n box-sizing: border-box;\n width: 100%;\n }\n [type-field] {\n font-family: var(--ui-mono, ui-monospace, monospace);\n }\n `\n ]\n\n /** The type the figure has so far -- empty for a temporary one, which is not offered. */\n @property() type = ''\n @property() name = ''\n /** Type names already used in this domain. */\n @property({ attribute: false }) taken: string[] = []\n /** The domain's active namespaces, its default first. Asked only when there are several (LV figure-server design G1). */\n @property({ attribute: false }) namespaces: { name: string; isDefault: boolean }[] = []\n @state() private namespace = ''\n @state() private refusal: { key: string; type?: string } | null = null\n /** The identifier offered, while the author has not changed it. */\n @state() private suggested = ''\n\n /*\n Asked for a name first, with a valid identifier already there to keep or change (Q-D3). The identifier is not the\n name: renaming does not change it, and a retried first save opens on the one answered before (the page keeps it).\n Only an offered one found taken -- told by the server, or in the list -- is offered again; one the author typed is\n kept as typed, and its refusal said.\n */\n willUpdate(changed: Map<string, unknown>) {\n if (!(changed.has('type') || changed.has('taken'))) return\n const offer = offeredTypeOf(this.type, this.name, this.taken)\n this.type = offer.type\n if (offer.suggested !== undefined) this.suggested = offer.suggested\n }\n\n /*\n The name is focused here, each time the question opens. The browser honours `autofocus` once per document: the\n question asked again opened with nothing focused, and any autofocus taken earlier on the page left even the first\n opening unfocused (2026-10-11, product-page check).\n */\n firstUpdated() {\n this.renderRoot.querySelector<HTMLInputElement>('#name')?.focus()\n }\n\n render() {\n return html`\n <div class=\"what\">${i18next.t('figure.text.save-new-figure-desc')}</div>\n <div field>\n <label for=\"name\">${i18next.t('figure.label.name')}</label>\n <input\n id=\"name\"\n .value=${this.name}\n placeholder=${i18next.t('figure.text.figure-name-example')}\n @input=${(e: Event) => (this.name = (e.target as HTMLInputElement).value)}\n @keydown=${this.onKey}\n />\n </div>\n <div field>\n <label for=\"type\">${i18next.t('figure.label.figure-identifier')}</label>\n <input\n id=\"type\"\n type-field\n .value=${this.type}\n placeholder=${i18next.t('figure.text.figure-type-example')}\n @input=${(e: Event) => {\n this.type = typeOf((e.target as HTMLInputElement).value)\n ;(e.target as HTMLInputElement).value = this.type\n this.refusal = null\n }}\n @keydown=${this.onKey}\n />\n ${this.type && !releasableType(this.type)\n ? html`<div class=\"note\">${i18next.t('figure.text.type-name-will-not-release')}</div>`\n : this.suggested && this.type === this.suggested\n ? html`<div class=\"note\">${i18next.t('figure.text.identifier-suggested')}</div>`\n : nothing}\n </div>\n ${this.namespaces.length > 1\n ? html`<div field>\n <label for=\"namespace\">${i18next.t('figure.label.namespace')}</label>\n <select id=\"namespace\" type-field @change=${(e: Event) => (this.namespace = (e.target as HTMLSelectElement).value)}>\n ${this.namespaces.map(\n namespace => html`<option value=${namespace.name} ?selected=${namespace.name === this.chosenNamespace}>${namespace.name}</option>`\n )}\n </select>\n </div>`\n : nothing}\n ${this.refusal ? html`<div class=\"failure\" role=\"alert\">${i18next.t(this.refusal.key, { type: this.refusal.type })}</div>` : nothing}\n <ox-popup-actions>\n <md-text-button slot=\"cancel\" @click=${() => closePopup(this)}>${i18next.t('figure.button.cancel')}</md-text-button>\n <md-filled-button slot=\"confirm\" ?disabled=${!this.type} @click=${this.confirm}>${i18next.t('figure.button.save')}</md-filled-button>\n </ox-popup-actions>\n `\n }\n\n private onKey = (e: KeyboardEvent) => {\n if (e.key === 'Enter' && !e.isComposing) this.confirm()\n }\n\n private confirm = () => {\n this.refusal = firstSaveRefusalOf(this.type, this.taken)\n if (this.refusal) return\n const namespace = this.namespaces.length > 1 ? this.chosenNamespace : undefined\n closePopup(this, { type: this.type, name: this.name.trim() || this.type, ...(namespace ? { namespace } : {}) } satisfies FirstSave)\n }\n\n /** The namespace chosen, or the domain's default until one is. */\n private get chosenNamespace(): string {\n return this.namespace || this.namespaces.find(namespace => namespace.isDefault)?.name || this.namespaces[0]?.name || ''\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"figure-first-save.js","sourceRoot":"","sources":["../../client/modeller/figure-first-save.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, html, css, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { i18next } from '@operato/i18n'\nimport { closePopup } from '@operato/popup'\nimport '@operato/popup/ox-popup-actions.js'\nimport { CommonPopupStyles, FormFieldStyles } from '@operato/styles'\nimport '@material/web/button/filled-button.js'\nimport '@material/web/button/text-button.js'\n\nimport { firstSaveRefusalOf, offeredTypeOf, releasableType, typeOf, typingTypeOf, type FirstSave } from './first-save.js'\n\n/**\n * The first save of a new figure: its type and its name, asked once, in the suite's popup look.\n * Closes with the answer, or with nothing when cancelled -- then nothing is saved.\n */\n@customElement('figure-first-save')\nexport class FigureFirstSave extends LitElement {\n static styles = [\n FormFieldStyles,\n CommonPopupStyles,\n css`\n /* The popup's height is a share of the window (small is 40%): on a low window the buttons must still be reached. */\n :host {\n overflow-y: auto;\n }\n div[field] {\n display: grid;\n gap: 4px;\n }\n div[field] label {\n font-size: var(--popup-font-size-small);\n color: var(--md-sys-color-on-surface-variant);\n }\n div[field] input,\n div[field] select {\n box-sizing: border-box;\n width: 100%;\n }\n [type-field] {\n font-family: var(--ui-mono, ui-monospace, monospace);\n }\n `\n ]\n\n /** The type the figure has so far -- empty for a temporary one, which is not offered. */\n @property() type = ''\n @property() name = ''\n /** Type names already used in this domain. */\n @property({ attribute: false }) taken: string[] = []\n /** The domain's active namespaces, its default first. Asked only when there are several (LV figure-server design G1). */\n @property({ attribute: false }) namespaces: { name: string; isDefault: boolean }[] = []\n @state() private namespace = ''\n @state() private refusal: { key: string; type?: string } | null = null\n /** The identifier offered, while the author has not changed it. */\n @state() private suggested = ''\n\n /*\n Asked for a name first, with a valid identifier already there to keep or change (Q-D3). The identifier is not the\n name: renaming does not change it, and a retried first save opens on the one answered before (the page keeps it).\n Only an offered one found taken -- told by the server, or in the list -- is offered again; one the author typed is\n kept as typed, and its refusal said.\n */\n willUpdate(changed: Map<string, unknown>) {\n if (!(changed.has('type') || changed.has('taken'))) return\n const offer = offeredTypeOf(this.type, this.name, this.taken)\n this.type = offer.type\n if (offer.suggested !== undefined) this.suggested = offer.suggested\n }\n\n /*\n The name is focused here, each time the question opens. The browser honours `autofocus` once per document: the\n question asked again opened with nothing focused, and any autofocus taken earlier on the page left even the first\n opening unfocused (2026-10-11, product-page check).\n */\n firstUpdated() {\n this.renderRoot.querySelector<HTMLInputElement>('#name')?.focus()\n }\n\n render() {\n return html`\n <div class=\"what\">${i18next.t('figure.text.save-new-figure-desc')}</div>\n <div field>\n <label for=\"name\">${i18next.t('figure.label.name')}</label>\n <input\n id=\"name\"\n .value=${this.name}\n placeholder=${i18next.t('figure.text.figure-name-example')}\n @input=${(e: Event) => (this.name = (e.target as HTMLInputElement).value)}\n @keydown=${this.onKey}\n />\n </div>\n <div field>\n <label for=\"type\">${i18next.t('figure.label.figure-identifier')}</label>\n <input\n id=\"type\"\n type-field\n .value=${this.type}\n placeholder=${i18next.t('figure.text.figure-type-example')}\n @input=${(e: Event) => {\n this.type = typingTypeOf((e.target as HTMLInputElement).value)\n ;(e.target as HTMLInputElement).value = this.type\n this.refusal = null\n }}\n @keydown=${this.onKey}\n />\n ${typeOf(this.type) && !releasableType(typeOf(this.type))\n ? html`<div class=\"note\">${i18next.t('figure.text.type-name-will-not-release')}</div>`\n : this.suggested && this.type === this.suggested\n ? html`<div class=\"note\">${i18next.t('figure.text.identifier-suggested')}</div>`\n : nothing}\n </div>\n ${this.namespaces.length > 1\n ? html`<div field>\n <label for=\"namespace\">${i18next.t('figure.label.namespace')}</label>\n <select id=\"namespace\" type-field @change=${(e: Event) => (this.namespace = (e.target as HTMLSelectElement).value)}>\n ${this.namespaces.map(\n namespace => html`<option value=${namespace.name} ?selected=${namespace.name === this.chosenNamespace}>${namespace.name}</option>`\n )}\n </select>\n </div>`\n : nothing}\n ${this.refusal ? html`<div class=\"failure\" role=\"alert\">${i18next.t(this.refusal.key, { type: this.refusal.type })}</div>` : nothing}\n <ox-popup-actions>\n <md-text-button slot=\"cancel\" @click=${() => closePopup(this)}>${i18next.t('figure.button.cancel')}</md-text-button>\n <md-filled-button slot=\"confirm\" ?disabled=${!this.type} @click=${this.confirm}>${i18next.t('figure.button.save')}</md-filled-button>\n </ox-popup-actions>\n `\n }\n\n private onKey = (e: KeyboardEvent) => {\n if (e.key === 'Enter' && !e.isComposing) this.confirm()\n }\n\n private confirm = () => {\n this.type = typeOf(this.type)\n this.refusal = firstSaveRefusalOf(this.type, this.taken)\n if (this.refusal) return\n const namespace = this.namespaces.length > 1 ? this.chosenNamespace : undefined\n closePopup(this, { type: this.type, name: this.name.trim() || this.type, ...(namespace ? { namespace } : {}) } satisfies FirstSave)\n }\n\n /** The namespace chosen, or the domain's default until one is. */\n private get chosenNamespace(): string {\n return this.namespace || this.namespaces.find(namespace => namespace.isDefault)?.name || this.namespaces[0]?.name || ''\n }\n}\n"]}
|
|
@@ -3,7 +3,14 @@ import { LitElement, nothing } from 'lit';
|
|
|
3
3
|
import '@operato/input/ox-input-select-buttons.js';
|
|
4
4
|
import './figure-slot-layout-panel.js';
|
|
5
5
|
import './figure-size-editor.js';
|
|
6
|
+
import { type MotionForm } from './links.js';
|
|
6
7
|
import type { FigureRevision } from './revision.js';
|
|
8
|
+
/**
|
|
9
|
+
* The motion a part's form starts from: a part hung on another part most often turns there -- a thigh at the hip, a door
|
|
10
|
+
* at its frame -- so it starts as a turn; a part on the plane, or on nothing, as a slide (review 2026-11-11: eight
|
|
11
|
+
* joints of a humanoid, each changed from slide to turn by hand).
|
|
12
|
+
*/
|
|
13
|
+
export declare function motionStartOf(revision: FigureRevision | undefined, part: string): MotionForm;
|
|
7
14
|
declare const FigureLinks_base: (new (...args: any[]) => LitElement) & typeof LitElement;
|
|
8
15
|
/**
|
|
9
16
|
* What a part is tied to — its size response, what it is fastened to, how it moves.
|
|
@@ -135,6 +142,8 @@ export declare class FigureLinks extends FigureLinks_base {
|
|
|
135
142
|
* the middle of its round cover, not its edge. Before, a hidden part stood in for the point (robot dog, 2026-11-03).
|
|
136
143
|
*/
|
|
137
144
|
private renderThrough;
|
|
145
|
+
private pivotCache?;
|
|
146
|
+
private renderPivotPoints;
|
|
138
147
|
private renderMotion;
|
|
139
148
|
private setKind;
|
|
140
149
|
private command;
|
|
@@ -9,15 +9,26 @@ import { i18next, localize } from '@operato/i18n';
|
|
|
9
9
|
import { unitWord } from './unit-words.js';
|
|
10
10
|
import { figureFaceOverhangOf, figureMotionsOf, motionIdOf } from '@hatiolab/figure-model';
|
|
11
11
|
import { acceptsOf, AXES, canFasten, canFollow, positionIsShare, heldBy, shownWhenOf, visibilityControlsOf, fasteningOf, hasInstanceSize, holdsThings, leadersFor, motionOf, motionFormOf, motionFormRefusalOf, endPlaceKeyOf, motionJoint, controlIdFor, withoutAxis, placeFacesOf, placeIdFor, placesOn, rowAxesOf, rowBlockOf, fixedJointOf, rowOf, positionsWorkedOut, followOf, followableAxes, measureNow, freshStateSize, stateSizeIdFor, stateSizeCommandOf, stateSizeFixedOf } from './links.js';
|
|
12
|
-
import { measureFactor } from './size-response.js';
|
|
12
|
+
import { measureFactor, sizeAxisWord } from './size-response.js';
|
|
13
13
|
import { SidePanelStyles } from '@things-factory/figure-viewer/dist-client/side-panel-styles.js';
|
|
14
14
|
import { insideAlignmentOf } from './fasten-geometry.js';
|
|
15
15
|
import { fastenFormOf, fastenPlanOf, fastenSentenceOf } from './fasten-form.js';
|
|
16
16
|
import { HelpToggles } from './help.js';
|
|
17
17
|
import { groupMenu, GroupMenuStyles } from './group-menu.js';
|
|
18
18
|
import { jointAxisWord } from './joint-axis.js';
|
|
19
|
+
import { PIVOT_POINTS, pivotPointOf, pivotPointsOf } from './pivot.js';
|
|
19
20
|
import { placeTerms } from '@things-factory/figure-viewer/dist-client/detail-facts.js';
|
|
20
21
|
const freshMotion = () => ({ kind: 'slide', axis: 'x', id: '', min: 0, max: 500, follow: '', multiplier: 1, offset: 0, travel: '', travelPlus: 0 });
|
|
22
|
+
/**
|
|
23
|
+
* The motion a part's form starts from: a part hung on another part most often turns there -- a thigh at the hip, a door
|
|
24
|
+
* at its frame -- so it starts as a turn; a part on the plane, or on nothing, as a slide (review 2026-11-11: eight
|
|
25
|
+
* joints of a humanoid, each changed from slide to turn by hand).
|
|
26
|
+
*/
|
|
27
|
+
export function motionStartOf(revision, part) {
|
|
28
|
+
const own = revision ? fasteningOf(revision, part) : undefined;
|
|
29
|
+
return own && !own.toPlane && own.target ? { ...freshMotion(), kind: 'turn', min: -90, max: 90 } : freshMotion();
|
|
30
|
+
}
|
|
31
|
+
const sameMotion = (a, b) => JSON.stringify(a) === JSON.stringify(b);
|
|
21
32
|
const freshRow = () => ({ axis: '', pitch: 200, fills: true, count: 5 });
|
|
22
33
|
const freshPlace = () => ({ role: 'grip', face: 'top', label: '', accepts: '', capacity: 1 });
|
|
23
34
|
/**
|
|
@@ -79,6 +90,17 @@ let FigureLinks = class FigureLinks extends localize(i18next)(LitElement) {
|
|
|
79
90
|
:host {
|
|
80
91
|
display: block;
|
|
81
92
|
}
|
|
93
|
+
/* The turn's axis through the part's top, middle or bottom, by name, under the numbers it fills in. */
|
|
94
|
+
div[pivot-points] {
|
|
95
|
+
display: flex;
|
|
96
|
+
align-items: center;
|
|
97
|
+
gap: 8px;
|
|
98
|
+
margin: 4px 0 8px;
|
|
99
|
+
}
|
|
100
|
+
div[pivot-points] > span {
|
|
101
|
+
color: var(--md-sys-color-on-surface-variant);
|
|
102
|
+
font-size: var(--ui-t-small, 11.5px);
|
|
103
|
+
}
|
|
82
104
|
/* A group's sub-question, under its title: quieter than the title, as a label is. */
|
|
83
105
|
p[group-question] {
|
|
84
106
|
margin: 4px 0 0;
|
|
@@ -155,7 +177,7 @@ let FigureLinks = class FigureLinks extends localize(i18next)(LitElement) {
|
|
|
155
177
|
this.fixNote = '';
|
|
156
178
|
if (this.asset && this.partId && this.partId !== this.loadedFor) {
|
|
157
179
|
this.loadedFor = this.partId;
|
|
158
|
-
this.motion =
|
|
180
|
+
this.motion = motionStartOf(this.revision, this.partId);
|
|
159
181
|
this.place = freshPlace();
|
|
160
182
|
this.placeEditing = null;
|
|
161
183
|
this.row = freshRow();
|
|
@@ -164,6 +186,12 @@ let FigureLinks = class FigureLinks extends localize(i18next)(LitElement) {
|
|
|
164
186
|
this.editingMotion = false;
|
|
165
187
|
this.motionAxis = 0;
|
|
166
188
|
}
|
|
189
|
+
else if (changed.has('revision') && this.partId && !this.editingMotion) {
|
|
190
|
+
/* Fastened since the form was loaded, a form nobody has touched starts as that part's motion now does. */
|
|
191
|
+
const was = motionStartOf(changed.get('revision'), this.partId);
|
|
192
|
+
if (sameMotion(this.motion, was))
|
|
193
|
+
this.motion = motionStartOf(this.revision, this.partId);
|
|
194
|
+
}
|
|
167
195
|
}
|
|
168
196
|
updated() {
|
|
169
197
|
/* Only the sections that hold a form speak of what it would do, and only while their tab is shown: the panel has
|
|
@@ -555,7 +583,7 @@ let FigureLinks = class FigureLinks extends localize(i18next)(LitElement) {
|
|
|
555
583
|
const axes = followableAxes(asset, part);
|
|
556
584
|
if (!axes.length)
|
|
557
585
|
return nothing;
|
|
558
|
-
const word = (axis) =>
|
|
586
|
+
const word = (axis) => sizeAxisWord(asset, part, axis, i18next.t('figure.label.size-diameter'));
|
|
559
587
|
const sized = axes.flatMap(axis => {
|
|
560
588
|
const f = followOf(asset, part, axis);
|
|
561
589
|
return f.of === 'state' ? [{ axis, f }] : [];
|
|
@@ -690,7 +718,30 @@ let FigureLinks = class FigureLinks extends localize(i18next)(LitElement) {
|
|
|
690
718
|
<input type="number" step="any" aria-label=${`${i18next.t('figure.label.motion-through')} ${axis.toUpperCase()}`} .value=${String(m.through?.[axis] ?? 0)} @change=${typed(axis)} />
|
|
691
719
|
</div>`)}
|
|
692
720
|
</div>
|
|
693
|
-
</div
|
|
721
|
+
</div>
|
|
722
|
+
${this.renderPivotPoints(m)}`;
|
|
723
|
+
}
|
|
724
|
+
renderPivotPoints(m) {
|
|
725
|
+
if (!this.revision || m.throughFollows)
|
|
726
|
+
return nothing;
|
|
727
|
+
const key = `${this.revision.revision}:${this.partId}:${m.axis}`;
|
|
728
|
+
if (this.pivotCache?.key !== key)
|
|
729
|
+
this.pivotCache = { key, points: pivotPointsOf(this.revision, this.partId, m.axis) };
|
|
730
|
+
const points = this.pivotCache.points;
|
|
731
|
+
if (!points)
|
|
732
|
+
return nothing;
|
|
733
|
+
return html `<div pivot-points>
|
|
734
|
+
<span>${i18next.t('figure.label.pivot-at')}</span>
|
|
735
|
+
<ox-input-select-buttons
|
|
736
|
+
.value=${pivotPointOf(points, m.through, m.axis) ?? ''}
|
|
737
|
+
.options=${PIVOT_POINTS.map(p => ({ value: p, display: i18next.t(`figure.label.pivot-${p}`) }))}
|
|
738
|
+
@change=${(e) => {
|
|
739
|
+
const at = points[e.detail];
|
|
740
|
+
if (at)
|
|
741
|
+
this.motion = { ...m, through: { ...at } };
|
|
742
|
+
}}
|
|
743
|
+
></ox-input-select-buttons>
|
|
744
|
+
</div>`;
|
|
694
745
|
}
|
|
695
746
|
renderMotion(asset) {
|
|
696
747
|
const now = motionOf(asset, this.partId);
|
|
@@ -775,6 +826,8 @@ let FigureLinks = class FigureLinks extends localize(i18next)(LitElement) {
|
|
|
775
826
|
const adding = k > 0 && k >= figureMotionsOf(joint).length;
|
|
776
827
|
const follow = leaders.some(j => j.id === m.follow) ? m.follow : '';
|
|
777
828
|
const refusal = motionFormRefusalOf(m, follow);
|
|
829
|
+
/* Following another joint is offered after the part's own control: a row above it moved every field down a row, and
|
|
830
|
+
a name typed there chose a joint to follow (review 2026-11-11). */
|
|
778
831
|
return html `
|
|
779
832
|
${k > 0 ? html `<p motion-axis-heading><b>${i18next.t('figure.label.motion-axis-n', { n: k + 1 })}</b></p>` : nothing}
|
|
780
833
|
<div pair>
|
|
@@ -789,6 +842,35 @@ let FigureLinks = class FigureLinks extends localize(i18next)(LitElement) {
|
|
|
789
842
|
${AXES.map(a => html `<option value=${a} ?selected=${a === m.axis}>${i18next.t('figure.label.motion-axis')} ${a.toUpperCase()}</option>`)}
|
|
790
843
|
</select>`}
|
|
791
844
|
</div>
|
|
845
|
+
${m.followSum || follow
|
|
846
|
+
? nothing
|
|
847
|
+
: html `<div form>
|
|
848
|
+
${m.kind === 'slide'
|
|
849
|
+
? html `<span>${i18next.t('figure.label.motion-travel')}</span>
|
|
850
|
+
<select @change=${(e) => (this.motion = { ...m, travel: e.target.value })}>
|
|
851
|
+
${m.travelSum
|
|
852
|
+
? html `<option value="" ?selected=${!m.travel}>${m.travelSum.sum.map(t => `${t.from.of === 'input' ? t.from.input : `${t.from.of === 'part' ? t.from.part : i18next.t('figure.label.motion-travel')} · ${t.from.axis.toUpperCase()}`}${t.times !== undefined && t.times !== 1 ? ` × ${t.times}` : ''}`).join(' + ')}</option>`
|
|
853
|
+
: html `<option value="" ?selected=${!m.travel}>${i18next.t('figure.label.motion-travel-mm')}</option>`}
|
|
854
|
+
${asset.appearance
|
|
855
|
+
.map(look => look.target)
|
|
856
|
+
.filter(one => canFollow(asset, one))
|
|
857
|
+
.flatMap(one => AXES.map(a => html `<option value=${`${one}:${a}`} ?selected=${m.travel === `${one}:${a}`}>${one} · ${a.toUpperCase()}</option>`))}
|
|
858
|
+
</select>
|
|
859
|
+
${m.travel
|
|
860
|
+
? html `<span>${i18next.t('figure.label.follows-plus')}</span>
|
|
861
|
+
<input type="number" step="any" .value=${String(m.travelPlus ?? 0)} @change=${(e) => (this.motion = { ...m, travelPlus: Number(e.target.value) || 0 })} />`
|
|
862
|
+
: nothing}`
|
|
863
|
+
: nothing}
|
|
864
|
+
<span>${i18next.t('figure.label.control-id')}</span>
|
|
865
|
+
<input .value=${m.id} placeholder=${controlIdFor(this.partId, m.kind, k)} @change=${(e) => (this.motion = { ...m, id: e.target.value.trim() })} />
|
|
866
|
+
${m.kind === 'continuous' || (m.kind === 'slide' && (m.travel || m.travelSum))
|
|
867
|
+
? nothing
|
|
868
|
+
: html `<span>${i18next.t('figure.label.control-range')} (${unit})</span>
|
|
869
|
+
<div pair>
|
|
870
|
+
<input type="number" step="any" .value=${String(m.min)} @change=${(e) => (this.motion = { ...m, min: Number(e.target.value) })} />
|
|
871
|
+
<input type="number" step="any" .value=${String(m.max)} @change=${(e) => (this.motion = { ...m, max: Number(e.target.value) })} />
|
|
872
|
+
</div>`}
|
|
873
|
+
</div>`}
|
|
792
874
|
${m.followSum
|
|
793
875
|
? html `<div form>
|
|
794
876
|
<span>${i18next.t('figure.label.motion-follow')}</span>
|
|
@@ -805,42 +887,14 @@ let FigureLinks = class FigureLinks extends localize(i18next)(LitElement) {
|
|
|
805
887
|
</select>
|
|
806
888
|
</div>`
|
|
807
889
|
: nothing}
|
|
808
|
-
${m.followSum
|
|
809
|
-
?
|
|
810
|
-
: follow
|
|
811
|
-
? html `<div form>
|
|
890
|
+
${!m.followSum && follow
|
|
891
|
+
? html `<div form>
|
|
812
892
|
<span>${i18next.t('figure.label.motion-multiplier')}</span>
|
|
813
893
|
<input type="number" step="any" .value=${String(m.multiplier)} @change=${(e) => (this.motion = { ...m, multiplier: Number(e.target.value) })} />
|
|
814
894
|
<span>${i18next.t('figure.label.motion-offset')} (${unit})</span>
|
|
815
895
|
<input type="number" step="any" .value=${String(m.offset)} @change=${(e) => (this.motion = { ...m, offset: Number(e.target.value) || 0 })} />
|
|
816
896
|
</div>`
|
|
817
|
-
|
|
818
|
-
${m.kind === 'slide'
|
|
819
|
-
? html `<span>${i18next.t('figure.label.motion-travel')}</span>
|
|
820
|
-
<select @change=${(e) => (this.motion = { ...m, travel: e.target.value })}>
|
|
821
|
-
${m.travelSum
|
|
822
|
-
? html `<option value="" ?selected=${!m.travel}>${m.travelSum.sum.map(t => `${t.from.of === 'input' ? t.from.input : `${t.from.of === 'part' ? t.from.part : i18next.t('figure.label.motion-travel')} · ${t.from.axis.toUpperCase()}`}${t.times !== undefined && t.times !== 1 ? ` × ${t.times}` : ''}`).join(' + ')}</option>`
|
|
823
|
-
: html `<option value="" ?selected=${!m.travel}>${i18next.t('figure.label.motion-travel-mm')}</option>`}
|
|
824
|
-
${asset.appearance
|
|
825
|
-
.map(look => look.target)
|
|
826
|
-
.filter(one => canFollow(asset, one))
|
|
827
|
-
.flatMap(one => AXES.map(a => html `<option value=${`${one}:${a}`} ?selected=${m.travel === `${one}:${a}`}>${one} · ${a.toUpperCase()}</option>`))}
|
|
828
|
-
</select>
|
|
829
|
-
${m.travel
|
|
830
|
-
? html `<span>${i18next.t('figure.label.follows-plus')}</span>
|
|
831
|
-
<input type="number" step="any" .value=${String(m.travelPlus ?? 0)} @change=${(e) => (this.motion = { ...m, travelPlus: Number(e.target.value) || 0 })} />`
|
|
832
|
-
: nothing}`
|
|
833
|
-
: nothing}
|
|
834
|
-
<span>${i18next.t('figure.label.control-id')}</span>
|
|
835
|
-
<input .value=${m.id} placeholder=${controlIdFor(this.partId, m.kind, k)} @change=${(e) => (this.motion = { ...m, id: e.target.value.trim() })} />
|
|
836
|
-
${m.kind === 'continuous' || (m.kind === 'slide' && (m.travel || m.travelSum))
|
|
837
|
-
? nothing
|
|
838
|
-
: html `<span>${i18next.t('figure.label.control-range')} (${unit})</span>
|
|
839
|
-
<div pair>
|
|
840
|
-
<input type="number" step="any" .value=${String(m.min)} @change=${(e) => (this.motion = { ...m, min: Number(e.target.value) })} />
|
|
841
|
-
<input type="number" step="any" .value=${String(m.max)} @change=${(e) => (this.motion = { ...m, max: Number(e.target.value) })} />
|
|
842
|
-
</div>`}
|
|
843
|
-
</div>`}
|
|
897
|
+
: nothing}
|
|
844
898
|
${m.kind === 'slide' ? nothing : this.renderThrough(m)}
|
|
845
899
|
<button
|
|
846
900
|
act
|