@things-factory/figure-ui 10.1.205 → 10.1.207

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.
Files changed (105) hide show
  1. package/client/modeller/editor-styles.ts +16 -0
  2. package/client/modeller/editor.ts +53 -137
  3. package/client/modeller/fasten-form.ts +50 -11
  4. package/client/modeller/figure-facts.ts +1 -1
  5. package/client/modeller/figure-fasten-dialog.ts +3 -2
  6. package/client/modeller/figure-history-panel.ts +1 -29
  7. package/client/modeller/figure-links.ts +2 -2
  8. package/client/modeller/figure-preview.ts +10 -12
  9. package/client/modeller/figure-verdict.ts +2 -17
  10. package/client/modeller/gizmo.ts +10 -0
  11. package/client/modeller/keys.ts +10 -1
  12. package/client/modeller/links.ts +32 -41
  13. package/client/modeller/maturity.ts +11 -27
  14. package/client/modeller/palette.ts +1 -1
  15. package/client/modeller/product-session.ts +16 -4
  16. package/client/modeller/refusal-teller.ts +3 -25
  17. package/client/modeller/refusals.ts +20 -33
  18. package/client/pages/figure-modeller-page.ts +7 -22
  19. package/dist-client/modeller/editor-styles.js +16 -0
  20. package/dist-client/modeller/editor-styles.js.map +1 -1
  21. package/dist-client/modeller/editor.d.ts +8 -11
  22. package/dist-client/modeller/editor.js +57 -138
  23. package/dist-client/modeller/editor.js.map +1 -1
  24. package/dist-client/modeller/fasten-form.d.ts +16 -7
  25. package/dist-client/modeller/fasten-form.js +45 -11
  26. package/dist-client/modeller/fasten-form.js.map +1 -1
  27. package/dist-client/modeller/figure-facts.js +1 -1
  28. package/dist-client/modeller/figure-facts.js.map +1 -1
  29. package/dist-client/modeller/figure-fasten-dialog.js +3 -3
  30. package/dist-client/modeller/figure-fasten-dialog.js.map +1 -1
  31. package/dist-client/modeller/figure-history-panel.d.ts +0 -16
  32. package/dist-client/modeller/figure-history-panel.js +1 -27
  33. package/dist-client/modeller/figure-history-panel.js.map +1 -1
  34. package/dist-client/modeller/figure-links.js +2 -2
  35. package/dist-client/modeller/figure-links.js.map +1 -1
  36. package/dist-client/modeller/figure-preview.js +8 -11
  37. package/dist-client/modeller/figure-preview.js.map +1 -1
  38. package/dist-client/modeller/figure-verdict.d.ts +0 -5
  39. package/dist-client/modeller/figure-verdict.js +2 -21
  40. package/dist-client/modeller/figure-verdict.js.map +1 -1
  41. package/dist-client/modeller/gizmo.d.ts +6 -0
  42. package/dist-client/modeller/gizmo.js +11 -0
  43. package/dist-client/modeller/gizmo.js.map +1 -1
  44. package/dist-client/modeller/keys.d.ts +1 -1
  45. package/dist-client/modeller/keys.js +6 -0
  46. package/dist-client/modeller/keys.js.map +1 -1
  47. package/dist-client/modeller/links.d.ts +16 -22
  48. package/dist-client/modeller/links.js +26 -39
  49. package/dist-client/modeller/links.js.map +1 -1
  50. package/dist-client/modeller/maturity.d.ts +2 -4
  51. package/dist-client/modeller/maturity.js +12 -26
  52. package/dist-client/modeller/maturity.js.map +1 -1
  53. package/dist-client/modeller/palette.js +1 -1
  54. package/dist-client/modeller/palette.js.map +1 -1
  55. package/dist-client/modeller/product-session.d.ts +15 -13
  56. package/dist-client/modeller/product-session.js +15 -5
  57. package/dist-client/modeller/product-session.js.map +1 -1
  58. package/dist-client/modeller/refusal-teller.d.ts +1 -12
  59. package/dist-client/modeller/refusal-teller.js +3 -22
  60. package/dist-client/modeller/refusal-teller.js.map +1 -1
  61. package/dist-client/modeller/refusals.d.ts +7 -17
  62. package/dist-client/modeller/refusals.js +17 -34
  63. package/dist-client/modeller/refusals.js.map +1 -1
  64. package/dist-client/pages/figure-modeller-page.d.ts +1 -3
  65. package/dist-client/pages/figure-modeller-page.js +7 -23
  66. package/dist-client/pages/figure-modeller-page.js.map +1 -1
  67. package/dist-client/tsconfig.tsbuildinfo +1 -1
  68. package/package.json +7 -7
  69. package/test/browser/acceptance-page.js +4 -4
  70. package/test/browser/detail-page.js +1 -3
  71. package/test/browser/detail-tabs-page.js +1 -2
  72. package/test/browser/links.check.mjs +32 -50
  73. package/test/browser/modeller.check.mjs +46 -19
  74. package/test/browser/parts-page.js +2 -2
  75. package/test/browser/parts.check.mjs +51 -12
  76. package/test/browser/product-page.check.mjs +6 -9
  77. package/test/browser/product-page.js +1 -2
  78. package/test/browser/screen-page.js +2 -6
  79. package/test/browser/screen.check.mjs +8 -65
  80. package/test/browser/section.check.mjs +27 -0
  81. package/test/fasten-form.test.ts +42 -2
  82. package/test/first-minute.test.ts +2 -3
  83. package/test/fixtures/joint-column.json +1 -66
  84. package/test/fixtures/joint-roller.json +1 -66
  85. package/test/fixtures/robot-arm-6dof.json +2 -67
  86. package/test/gizmo.test.ts +12 -1
  87. package/test/keys.test.ts +11 -0
  88. package/test/links.test.ts +39 -34
  89. package/test/parts-wiring.test.ts +1 -1
  90. package/test/properties.test.ts +9 -12
  91. package/test/refusals.test.ts +20 -42
  92. package/test/resize-with-placement.test.ts +13 -15
  93. package/test/revision.test.ts +1 -2
  94. package/test/verdict.test.ts +1 -15
  95. package/translations/en.json +8 -32
  96. package/translations/es.json +8 -32
  97. package/translations/ja.json +8 -32
  98. package/translations/ko.json +8 -32
  99. package/translations/ms.json +8 -32
  100. package/translations/zh.json +8 -32
  101. package/client/modeller/occupancy.ts +0 -51
  102. package/dist-client/modeller/occupancy.d.ts +0 -31
  103. package/dist-client/modeller/occupancy.js +0 -36
  104. package/dist-client/modeller/occupancy.js.map +0 -1
  105. package/test/release-panel.test.ts +0 -53
@@ -12,6 +12,12 @@ export interface FastenForm {
12
12
  gap: number;
13
13
  /** The record's gap when it is worked out (a length that follows something): kept until a number is typed. */
14
14
  gapKept: unknown;
15
+ /**
16
+ * Where the gap came from (ADR-0140 stage 4, 「현재 상태로 붙이기」): `kept` -- the distance the part stands at, worked
17
+ * out again whenever where or how it is fastened changes, so fastening does not move it; `typed` -- the author's
18
+ * number, left as it is; `pressed` -- 0, the part put where the canvas was pressed.
19
+ */
20
+ gapFrom: 'kept' | 'typed' | 'pressed';
15
21
  align: Partial<Record<Axis, Alignment>>;
16
22
  alignMm: Partial<Record<Axis, number>>;
17
23
  alignInput: Partial<Record<Axis, string>>;
@@ -48,6 +54,12 @@ export declare function aimFasten(revision: FigureRevision, part: string, form:
48
54
  }): FastenForm;
49
55
  /** A change the drawing asks: a face, a way, a gap or a place across the face. */
50
56
  export declare function fastenChanged(revision: FigureRevision, part: string, form: FastenForm, change: FastenChange): FastenForm;
57
+ /**
58
+ * The form with the gap that keeps the part where it stands (ADR-0140 stage 4, user 2026-10-20 「현재 상태로 붙이기」):
59
+ * figure-model's `figureFastenKeptGapOf` for what it is aimed at and how it meets it. A gap the author typed, or the 0 a
60
+ * canvas press puts, is left as it is. Nothing aimed at yet, the form is as it was.
61
+ */
62
+ export declare function keptGapOf(revision: FigureRevision, part: string, form: FastenForm): FastenForm;
51
63
  /** What a form comes to: the face aimed at, the way, the drawing of the face and the command. */
52
64
  export interface FastenPlan {
53
65
  /** Nothing is aimed at until a part or the plane is chosen. */
@@ -78,15 +90,12 @@ export declare function fastenPlanOf(revision: FigureRevision, part: string, f:
78
90
  type Say = (key: string, params?: Record<string, string>) => string;
79
91
  /** 「bin의 윗면에 올려놓기」: what the fastening is, in one line -- the part is the one the window is open on, not named again. */
80
92
  export declare function fastenSentenceOf(form: FastenForm, plan: FastenPlan, planeWord: string, say: Say): string;
81
- /** What the folded details hold that is not their default, said while folded; nothing for the default. */
82
- export declare function fastenDetailWordsOf(form: FastenForm, say: Say): string[];
83
93
  /**
84
- * A part pressed on the canvas while the window is open (ADR-0140 stage 4): aimed at, on the face or the point pressed,
85
- * its middle where it was pressed -- the kernel's reading of the press (`figureFastenTargetAt`), the point and normal brought into that part's own
86
- * frame by the pose its body is drawn at (`at.id`, a row's copy too). The part itself, one hanging from it, or one with
87
- * nothing to fasten to is not aimed at; a press on a curve there is no fastening to aims at the part alone. Each says
88
- * why, by its words' key.
94
+ * What the folded details hold that is not their default, said while folded; nothing for the default. The gap's default
95
+ * is the one it starts at -- the distance the part stands at, or 0 where the canvas was pressed -- so only a number typed
96
+ * is said.
89
97
  */
98
+ export declare function fastenDetailWordsOf(form: FastenForm, say: Say): string[];
90
99
  export declare function aimFastenAt(revision: FigureRevision, part: string, form: FastenForm, at: {
91
100
  id: string;
92
101
  point?: readonly number[];
@@ -1,4 +1,4 @@
1
- import { FIGURE_FACES, figureFastenTargetAt, figurePlaneFacingOf, figureSurfaceKeptPlaceOf } from '@hatiolab/figure-model';
1
+ import { FIGURE_FACES, figureFastenKeptGapOf, figureFastenTargetAt, figurePlaneFacingOf, figureSurfaceKeptPlaceOf } from '@hatiolab/figure-model';
2
2
  import { faceViewOf } from './fasten-geometry.js';
3
3
  import { alignOf, alignRowsOf, canFasten, facesOf, fasteningOf, fastenGapOf, hangsFrom, heldBy, mountingPlaneOf, placeKeptOf, surfaceOf } from './links.js';
4
4
  import { ownerOf } from './fields.js';
@@ -15,6 +15,7 @@ export const freshFasten = () => ({
15
15
  facing: 'meet',
16
16
  gap: 0,
17
17
  gapKept: undefined,
18
+ gapFrom: 'kept',
18
19
  align: {},
19
20
  alignMm: {},
20
21
  alignInput: {}
@@ -22,7 +23,10 @@ export const freshFasten = () => ({
22
23
  /** The part's own fastening as a form, or a fresh one: a window opens on what the part has (walk 1, 2026-09-26). */
23
24
  export function fastenFormOf(revision, part) {
24
25
  const own = fasteningOf(revision, part);
25
- return own && !own.atOrigin ? { ...freshFasten(), ...own } : freshFasten();
26
+ if (!own || own.atOrigin)
27
+ return freshFasten();
28
+ /* A gap the record works out is the author's; a number is where the part stands, so aiming again keeps it there. */
29
+ return { ...freshFasten(), ...own, gapFrom: own.gapKept !== undefined ? 'typed' : 'kept' };
26
30
  }
27
31
  /** What a part may be fastened to: every other part that can be, each said whether it would close a loop. */
28
32
  export function fastenTargetsOf(revision, part) {
@@ -80,21 +84,45 @@ export function aimFasten(revision, part, form, to) {
80
84
  export function fastenChanged(revision, part, form, change) {
81
85
  const f = form;
82
86
  if ('targetFace' in change)
83
- return aimFasten(revision, part, f, { targetFace: change.targetFace });
87
+ return keptGapOf(revision, part, aimFasten(revision, part, f, { targetFace: change.targetFace }));
84
88
  if ('onSurface' in change)
85
- return aimFasten(revision, part, f, { surface: true });
89
+ return keptGapOf(revision, part, aimFasten(revision, part, f, { surface: true }));
86
90
  if ('surface' in change)
87
- return { ...f, surface: change.surface };
91
+ return keptGapOf(revision, part, { ...f, surface: change.surface });
88
92
  if ('mode' in change)
89
- return { ...f, facing: change.mode };
93
+ return keptGapOf(revision, part, { ...f, facing: change.mode });
90
94
  if ('gap' in change)
91
- return { ...f, gap: change.gap, gapKept: undefined };
95
+ return { ...f, gap: change.gap, gapKept: undefined, gapFrom: 'typed' };
92
96
  return {
93
97
  ...f,
94
98
  align: { ...f.align, [change.axis]: change.how },
95
99
  alignMm: change.how === 'mm' ? { ...f.alignMm, [change.axis]: change.mm ?? 0 } : f.alignMm
96
100
  };
97
101
  }
102
+ /**
103
+ * The form with the gap that keeps the part where it stands (ADR-0140 stage 4, user 2026-10-20 「현재 상태로 붙이기」):
104
+ * figure-model's `figureFastenKeptGapOf` for what it is aimed at and how it meets it. A gap the author typed, or the 0 a
105
+ * canvas press puts, is left as it is. Nothing aimed at yet, the form is as it was.
106
+ */
107
+ export function keptGapOf(revision, part, form) {
108
+ if (form.gapFrom !== 'kept')
109
+ return form;
110
+ const asset = revision.asset;
111
+ const theirFaces = form.target ? facesOf(asset, form.target) : FACES;
112
+ const targetFace = (theirFaces.includes(form.targetFace) ? form.targetFace : theirFaces[0]);
113
+ const planeWay = figurePlaneFacingOf(asset);
114
+ const mode = form.toPlane ? (mountingPlaneOf(asset).facings.includes(form.facing) ? form.facing : (planeWay ?? 'meet')) : form.facing;
115
+ const to = form.toPlane
116
+ ? 'plane'
117
+ : form.target && form.surface && surfaceOf(asset, form.target)
118
+ ? { part: form.target, surface: form.surface }
119
+ : form.target
120
+ ? { part: form.target, face: targetFace }
121
+ : undefined;
122
+ if (!to)
123
+ return form;
124
+ return { ...form, gap: figureFastenKeptGapOf(asset, part, to, mode, { ...revision.inputs }), gapKept: undefined };
125
+ }
98
126
  export function fastenPlanOf(revision, part, f) {
99
127
  const asset = revision.asset;
100
128
  const theirFaces = f.target ? facesOf(asset, f.target) : FACES;
@@ -151,12 +179,16 @@ export function fastenSentenceOf(form, plan, planeWord, say) {
151
179
  const to = form.toPlane ? planeWord : `${form.target}의 ${where}`;
152
180
  return say(`figure.text.fasten-sentence-${plan.mode}`, { to });
153
181
  }
154
- /** What the folded details hold that is not their default, said while folded; nothing for the default. */
182
+ /**
183
+ * What the folded details hold that is not their default, said while folded; nothing for the default. The gap's default
184
+ * is the one it starts at -- the distance the part stands at, or 0 where the canvas was pressed -- so only a number typed
185
+ * is said.
186
+ */
155
187
  export function fastenDetailWordsOf(form, say) {
156
188
  return [
157
189
  ...(form.gapKept !== undefined
158
190
  ? [say('figure.text.fasten-summary-gap-worked-out')]
159
- : form.gap
191
+ : form.gapFrom === 'typed' && form.gap
160
192
  ? [say('figure.text.fasten-summary-gap', { mm: String(form.gap) })]
161
193
  : [])
162
194
  ];
@@ -168,6 +200,8 @@ export function fastenDetailWordsOf(form, say) {
168
200
  * nothing to fasten to is not aimed at; a press on a curve there is no fastening to aims at the part alone. Each says
169
201
  * why, by its words' key.
170
202
  */
203
+ /* Put where the canvas was pressed: on the face or the surface there, with no gap (ADR-0140 stage 4). */
204
+ const PRESSED = { gap: 0, gapKept: undefined, gapFrom: 'pressed' };
171
205
  export function aimFastenAt(revision, part, form, at) {
172
206
  const target = ownerOf(at.id);
173
207
  const offered = fastenTargetsOf(revision, part).find(t => t.part === target);
@@ -188,10 +222,10 @@ export function aimFastenAt(revision, part, form, at) {
188
222
  /* On the face where it was pressed, as a point of a curved surface is: its middle there. */
189
223
  const onFace = aimFasten(revision, part, { ...aimed, surface: undefined }, { targetFace: lands.face });
190
224
  const at = lands.at;
191
- return { form: { ...onFace, align: Object.fromEntries(Object.keys(at).map(a => [a, 'mm'])), alignMm: { ...at }, alignInput: {} }, part: target };
225
+ return { form: { ...onFace, ...PRESSED, align: Object.fromEntries(Object.keys(at).map(a => [a, 'mm'])), alignMm: { ...at }, alignInput: {} }, part: target };
192
226
  }
193
227
  if ('surface' in lands)
194
- return { form: { ...aimed, toPlane: false, target, surface: lands.surface, align: {}, alignMm: {}, alignInput: {} }, part: target };
228
+ return { form: { ...aimed, ...PRESSED, toPlane: false, target, surface: lands.surface, align: {}, alignMm: {}, alignInput: {} }, part: target };
195
229
  return { form: aimed, note: 'aim-not-here', part: target };
196
230
  }
197
231
  //# sourceMappingURL=fasten-form.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"fasten-form.js","sourceRoot":"","sources":["../../client/modeller/fasten-form.ts"],"names":[],"mappings":"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","sourcesContent":["import { FIGURE_FACES, figureFastenTargetAt, figurePlaneFacingOf, figureSurfaceKeptPlaceOf } from '@hatiolab/figure-model'\nimport type { FigureAuthoringAction, FigureFace, FigureSurfacePlace } from '@hatiolab/figure-model'\n\nimport { faceViewOf, type FaceView, type FastenMode, type FastenTarget } from './fasten-geometry.js'\nimport type { FastenChange } from './figure-fasten-drawing.js'\nimport {\n alignOf,\n alignRowsOf,\n canFasten,\n facesOf,\n fasteningOf,\n fastenGapOf,\n hangsFrom,\n heldBy,\n mountingPlaneOf,\n placeKeptOf,\n surfaceOf,\n type Alignment,\n type Axis\n} from './links.js'\nimport type { FigureRevision } from './revision.js'\nimport { ownerOf } from './fields.js'\n\n/*\n * A fastening as it is chosen, before it is done: to what, which face, how, where across the face. The fastening window\n * (`figure-fasten-dialog.ts`) holds one and changes it as the author chooses; the attach command is worked out from it\n * only here, so the window, its preview and the panel's 「정렬 고치기」 send the same command for the same choice.\n */\n\nconst FACES = Object.keys(FIGURE_FACES) as FigureFace[]\n\nexport interface FastenForm {\n toPlane: boolean\n target: string\n targetFace: FigureFace\n /** How it meets the face: its near end on it, its far end on it (flush), or its middle (ADR-0140 3.11). */\n facing: FastenMode\n gap: number\n /** The record's gap when it is worked out (a length that follows something): kept until a number is typed. */\n gapKept: unknown\n align: Partial<Record<Axis, Alignment>>\n alignMm: Partial<Record<Axis, number>>\n alignInput: Partial<Record<Axis, string>>\n /** On a point of the target's curved surface instead of a face (ADR-0140 3.9): where, as the record says it. */\n surface?: FigureSurfacePlace\n}\n\nexport const freshFasten = (): FastenForm => ({\n toPlane: false,\n target: '',\n targetFace: 'top',\n facing: 'meet',\n gap: 0,\n gapKept: undefined,\n align: {},\n alignMm: {},\n alignInput: {}\n})\n\n/** The part's own fastening as a form, or a fresh one: a window opens on what the part has (walk 1, 2026-09-26). */\nexport function fastenFormOf(revision: FigureRevision, part: string): FastenForm {\n const own = fasteningOf(revision, part)\n return own && !own.atOrigin ? ({ ...freshFasten(), ...own } as FastenForm) : freshFasten()\n}\n\n/** What a part may be fastened to: every other part that can be, each said whether it would close a loop. */\nexport function fastenTargetsOf(revision: FigureRevision, part: string): Array<{ part: string; loops: boolean }> {\n const asset = revision.asset\n return (\n asset.appearance\n .map(look => look.target)\n .filter(one => one !== part && canFasten(asset, one))\n /* Not a part that hangs from this one: fastening a frame to its own roller would close a loop. */\n .map(one => ({ part: one, loops: hangsFrom(asset, one, part) }))\n )\n}\n\n/**\n * The point of a target's curved surface on the side the part stands on now (ADR-0140 3.9): the kernel's\n * (`figureSurfaceKeptPlaceOf`), or, the part standing on its axis, the surface's first point.\n */\nexport function surfaceKeptOf(revision: FigureRevision, part: string, target: string): FigureSurfacePlace | undefined {\n const surface = surfaceOf(revision.asset, target)\n if (!surface) return undefined\n return (\n figureSurfaceKeptPlaceOf(revision.asset, part, target, { ...revision.inputs }) ??\n (surface.form === 'around' ? { around: 0, along: 'centre' } : { toward: { x: 0, y: 1, z: 0 } })\n )\n}\n\n/**\n * A new aim: the plane, another part, another face of the same part, or a point of its curved surface. Where on the\n * face -- or the surface -- is filled in as where the part stands now, so fastening it keeps it there (`placeKeptOf`,\n * `surfaceKeptOf`); the author changes it from there. A part aimed at a sphere, or beside a cylinder's side within its\n * length, is aimed at the surface: it is fastened as it stands (ADR-0140 3.6).\n */\nexport function aimFasten(\n revision: FigureRevision,\n part: string,\n form: FastenForm,\n to: { plane: true } | { part: string } | { targetFace: FigureFace } | { surface: true }\n): FastenForm {\n if ('surface' in to) return { ...form, surface: surfaceKeptOf(revision, part, form.target), align: {}, alignMm: {}, alignInput: {} }\n if ('part' in to) {\n /* Beside its curved surface -- a sphere's anywhere, a cylinder's side within its length -- or with no face at all. */\n const beside = figureSurfaceKeptPlaceOf(revision.asset, part, to.part, { ...revision.inputs })\n const kept = beside ?? (!facesOf(revision.asset, to.part).length ? surfaceKeptOf(revision, part, to.part) : undefined)\n if (kept) return { ...form, toPlane: false, target: to.part, surface: kept, align: {}, alignMm: {}, alignInput: {} }\n }\n form = { ...form, surface: undefined }\n /* Aimed at the plane, it meets it toward the side the placement uses -- below a ceiling -- until the author says (ADR-0140 3.11). */\n const f: FastenForm =\n 'plane' in to\n ? { ...form, toPlane: true, target: '', facing: form.toPlane ? form.facing : (figurePlaneFacingOf(revision.asset) ?? form.facing) }\n : 'part' in to\n ? { ...form, toPlane: false, target: to.part }\n : { ...form, targetFace: to.targetFace }\n const theirFaces = f.target ? facesOf(revision.asset, f.target) : FACES\n const targetFace = (theirFaces.includes(f.targetFace) ? f.targetFace : theirFaces[0]) as FigureFace\n const aim: FastenTarget | undefined = f.toPlane\n ? 'plane'\n : f.target\n ? { part: f.target, face: targetFace }\n : undefined\n return { ...f, ...(aim ? placeKeptOf(revision, part, aim) : { align: {}, alignMm: {}, alignInput: {} }) }\n}\n\n/** A change the drawing asks: a face, a way, a gap or a place across the face. */\nexport function fastenChanged(\n revision: FigureRevision,\n part: string,\n form: FastenForm,\n change: FastenChange\n): FastenForm {\n const f = form\n if ('targetFace' in change) return aimFasten(revision, part, f, { targetFace: change.targetFace as FigureFace })\n if ('onSurface' in change) return aimFasten(revision, part, f, { surface: true })\n if ('surface' in change) return { ...f, surface: change.surface }\n if ('mode' in change) return { ...f, facing: change.mode }\n if ('gap' in change) return { ...f, gap: change.gap, gapKept: undefined }\n return {\n ...f,\n align: { ...f.align, [change.axis]: change.how },\n alignMm: change.how === 'mm' ? { ...f.alignMm, [change.axis]: change.mm ?? 0 } : f.alignMm\n }\n}\n\n/** What a form comes to: the face aimed at, the way, the drawing of the face and the command. */\nexport interface FastenPlan {\n /** Nothing is aimed at until a part or the plane is chosen. */\n aim?: FastenTarget\n theirFaces: string[]\n targetFace: FigureFace\n mode: FastenMode\n view?: FaceView\n /** The axes across the face asked in rows: where the drawing cannot set the place. */\n alignRows: { axis: Axis; edges: boolean }[]\n action?: FigureAuthoringAction\n /** The face the command would meet, lit on the canvas while it is tried. */\n face?: { part: string; face: string }\n /** On a point of the target's curved surface: which surface, about which axis, and where (ADR-0140 3.9). */\n surface?: { form: 'around' | 'toward'; axis: Axis; place: FigureSurfacePlace }\n}\n\nexport function fastenPlanOf(revision: FigureRevision, part: string, f: FastenForm): FastenPlan {\n const asset = revision.asset\n const theirFaces = f.target ? facesOf(asset, f.target) : FACES\n const targetFace = (theirFaces.includes(f.targetFace) ? f.targetFace : theirFaces[0]) as FigureFace\n const aim: FastenTarget | undefined = f.toPlane\n ? 'plane'\n : f.target\n ? { part: f.target, face: targetFace }\n : undefined\n /* The plane takes a part standing on it or hanging below it, a wall only one standing out of it (ADR-0140 3.11). */\n const planeWay = figurePlaneFacingOf(asset)\n const mode: FastenMode = f.toPlane ? (mountingPlaneOf(asset).facings.includes(f.facing) ? f.facing : (planeWay ?? 'meet')) : f.facing\n const surface = !f.toPlane && f.target && f.surface ? surfaceOf(asset, f.target) : undefined\n if (surface) {\n /* On the surface: where is the surface's own words, so no alignment goes with it (ADR-0140 3.9). */\n const action = {\n kind: 'attach',\n part,\n to: { part: f.target, surface: f.surface },\n facing: mode,\n ...fastenGapOf(f),\n replace: !!heldBy(asset, part)\n } as FigureAuthoringAction\n return { theirFaces, targetFace, mode, alignRows: [], action, surface: { ...surface, place: f.surface! } }\n }\n if (!aim) return { theirFaces, targetFace, mode, alignRows: [] }\n const align = alignOf(asset, aim, f.align, f.alignMm, f.alignInput)\n const view = faceViewOf(revision, part, aim, mode)\n const action = {\n kind: 'attach',\n part,\n to: f.toPlane ? { plane: 'mounting-plane' } : { part: f.target, face: targetFace },\n /* On the plane the kernel takes the placement's way when none is said: only another way is said. */\n ...(f.toPlane ? (mode === planeWay ? {} : { facing: mode }) : { facing: mode }),\n ...fastenGapOf(f),\n ...(align ? { align } : {}),\n replace: !!heldBy(asset, part)\n } as FigureAuthoringAction\n return {\n aim,\n theirFaces,\n targetFace,\n mode,\n view,\n alignRows: alignRowsOf(asset, aim, view, f.alignInput),\n action,\n ...(f.toPlane ? {} : { face: { part: f.target, face: targetFace } })\n }\n}\n\ntype Say = (key: string, params?: Record<string, string>) => string\n\n/** 「bin의 윗면에 올려놓기」: what the fastening is, in one line -- the part is the one the window is open on, not named again. */\nexport function fastenSentenceOf(\n form: FastenForm,\n plan: FastenPlan,\n planeWord: string,\n say: Say\n): string {\n const where = plan.surface ? say('figure.label.surface-' + plan.surface.form) : say('figure.label.face-' + plan.targetFace)\n const to = form.toPlane ? planeWord : `${form.target}의 ${where}`\n return say(`figure.text.fasten-sentence-${plan.mode}`, { to })\n}\n\n/** What the folded details hold that is not their default, said while folded; nothing for the default. */\nexport function fastenDetailWordsOf(form: FastenForm, say: Say): string[] {\n return [\n ...(form.gapKept !== undefined\n ? [say('figure.text.fasten-summary-gap-worked-out')]\n : form.gap\n ? [say('figure.text.fasten-summary-gap', { mm: String(form.gap) })]\n : [])\n ]\n}\n\n/**\n * A part pressed on the canvas while the window is open (ADR-0140 stage 4): aimed at, on the face or the point pressed,\n * its middle where it was pressed -- the kernel's reading of the press (`figureFastenTargetAt`), the point and normal brought into that part's own\n * frame by the pose its body is drawn at (`at.id`, a row's copy too). The part itself, one hanging from it, or one with\n * nothing to fasten to is not aimed at; a press on a curve there is no fastening to aims at the part alone. Each says\n * why, by its words' key.\n */\nexport function aimFastenAt(\n revision: FigureRevision,\n part: string,\n form: FastenForm,\n at: { id: string; point?: readonly number[]; normal?: readonly number[] }\n): { form?: FastenForm; note?: 'aim-self' | 'aim-cannot' | 'target-would-loop' | 'aim-not-here'; part: string } {\n const target = ownerOf(at.id)\n const offered = fastenTargetsOf(revision, part).find(t => t.part === target)\n if (target === part) return { note: 'aim-self', part: target }\n if (!offered) return { note: 'aim-cannot', part: target }\n if (offered.loops) return { note: 'target-would-loop', part: target }\n const aimed = aimFasten(revision, part, form, { part: target })\n const pose = (revision.geometry as Array<{ id: string; pose?: { r: number[][]; t: number[] } }>).find(g => g.id === at.id)?.pose\n if (!pose || !at.point || !at.normal) return { form: aimed, part: target }\n /* Into the part's own frame: rᵀ (p − t), and the normal by rᵀ. */\n const own = (v: readonly number[], from: readonly number[] = [0, 0, 0]) => [0, 1, 2].map(c => [0, 1, 2].reduce((sum, i) => sum + pose.r[i]![c]! * (v[i]! - from[i]!), 0))\n const lands = figureFastenTargetAt(revision.asset, target, own(at.point, pose.t), own(at.normal), { ...revision.inputs })\n if ('face' in lands) {\n /* On the face where it was pressed, as a point of a curved surface is: its middle there. */\n const onFace = aimFasten(revision, part, { ...aimed, surface: undefined }, { targetFace: lands.face as FigureFace })\n const at = lands.at as Partial<Record<Axis, number>>\n return { form: { ...onFace, align: Object.fromEntries(Object.keys(at).map(a => [a, 'mm'])) as FastenForm['align'], alignMm: { ...at }, alignInput: {} }, part: target }\n }\n if ('surface' in lands) return { form: { ...aimed, toPlane: false, target, surface: lands.surface, align: {}, alignMm: {}, alignInput: {} }, part: target }\n return { form: aimed, note: 'aim-not-here', part: target }\n}\n"]}
1
+ {"version":3,"file":"fasten-form.js","sourceRoot":"","sources":["../../client/modeller/fasten-form.ts"],"names":[],"mappings":"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","sourcesContent":["import { FIGURE_FACES, figureFastenKeptGapOf, figureFastenTargetAt, figurePlaneFacingOf, figureSurfaceKeptPlaceOf } from '@hatiolab/figure-model'\nimport type { FigureAuthoringAction, FigureFace, FigureSurfacePlace } from '@hatiolab/figure-model'\n\nimport { faceViewOf, type FaceView, type FastenMode, type FastenTarget } from './fasten-geometry.js'\nimport type { FastenChange } from './figure-fasten-drawing.js'\nimport {\n alignOf,\n alignRowsOf,\n canFasten,\n facesOf,\n fasteningOf,\n fastenGapOf,\n hangsFrom,\n heldBy,\n mountingPlaneOf,\n placeKeptOf,\n surfaceOf,\n type Alignment,\n type Axis\n} from './links.js'\nimport type { FigureRevision } from './revision.js'\nimport { ownerOf } from './fields.js'\n\n/*\n * A fastening as it is chosen, before it is done: to what, which face, how, where across the face. The fastening window\n * (`figure-fasten-dialog.ts`) holds one and changes it as the author chooses; the attach command is worked out from it\n * only here, so the window, its preview and the panel's 「정렬 고치기」 send the same command for the same choice.\n */\n\nconst FACES = Object.keys(FIGURE_FACES) as FigureFace[]\n\nexport interface FastenForm {\n toPlane: boolean\n target: string\n targetFace: FigureFace\n /** How it meets the face: its near end on it, its far end on it (flush), or its middle (ADR-0140 3.11). */\n facing: FastenMode\n gap: number\n /** The record's gap when it is worked out (a length that follows something): kept until a number is typed. */\n gapKept: unknown\n /**\n * Where the gap came from (ADR-0140 stage 4, 「현재 상태로 붙이기」): `kept` -- the distance the part stands at, worked\n * out again whenever where or how it is fastened changes, so fastening does not move it; `typed` -- the author's\n * number, left as it is; `pressed` -- 0, the part put where the canvas was pressed.\n */\n gapFrom: 'kept' | 'typed' | 'pressed'\n align: Partial<Record<Axis, Alignment>>\n alignMm: Partial<Record<Axis, number>>\n alignInput: Partial<Record<Axis, string>>\n /** On a point of the target's curved surface instead of a face (ADR-0140 3.9): where, as the record says it. */\n surface?: FigureSurfacePlace\n}\n\nexport const freshFasten = (): FastenForm => ({\n toPlane: false,\n target: '',\n targetFace: 'top',\n facing: 'meet',\n gap: 0,\n gapKept: undefined,\n gapFrom: 'kept',\n align: {},\n alignMm: {},\n alignInput: {}\n})\n\n/** The part's own fastening as a form, or a fresh one: a window opens on what the part has (walk 1, 2026-09-26). */\nexport function fastenFormOf(revision: FigureRevision, part: string): FastenForm {\n const own = fasteningOf(revision, part)\n if (!own || own.atOrigin) return freshFasten()\n /* A gap the record works out is the author's; a number is where the part stands, so aiming again keeps it there. */\n return { ...freshFasten(), ...own, gapFrom: own.gapKept !== undefined ? 'typed' : 'kept' } as FastenForm\n}\n\n/** What a part may be fastened to: every other part that can be, each said whether it would close a loop. */\nexport function fastenTargetsOf(revision: FigureRevision, part: string): Array<{ part: string; loops: boolean }> {\n const asset = revision.asset\n return (\n asset.appearance\n .map(look => look.target)\n .filter(one => one !== part && canFasten(asset, one))\n /* Not a part that hangs from this one: fastening a frame to its own roller would close a loop. */\n .map(one => ({ part: one, loops: hangsFrom(asset, one, part) }))\n )\n}\n\n/**\n * The point of a target's curved surface on the side the part stands on now (ADR-0140 3.9): the kernel's\n * (`figureSurfaceKeptPlaceOf`), or, the part standing on its axis, the surface's first point.\n */\nexport function surfaceKeptOf(revision: FigureRevision, part: string, target: string): FigureSurfacePlace | undefined {\n const surface = surfaceOf(revision.asset, target)\n if (!surface) return undefined\n return (\n figureSurfaceKeptPlaceOf(revision.asset, part, target, { ...revision.inputs }) ??\n (surface.form === 'around' ? { around: 0, along: 'centre' } : { toward: { x: 0, y: 1, z: 0 } })\n )\n}\n\n/**\n * A new aim: the plane, another part, another face of the same part, or a point of its curved surface. Where on the\n * face -- or the surface -- is filled in as where the part stands now, so fastening it keeps it there (`placeKeptOf`,\n * `surfaceKeptOf`); the author changes it from there. A part aimed at a sphere, or beside a cylinder's side within its\n * length, is aimed at the surface: it is fastened as it stands (ADR-0140 3.6).\n */\nexport function aimFasten(\n revision: FigureRevision,\n part: string,\n form: FastenForm,\n to: { plane: true } | { part: string } | { targetFace: FigureFace } | { surface: true }\n): FastenForm {\n if ('surface' in to) return { ...form, surface: surfaceKeptOf(revision, part, form.target), align: {}, alignMm: {}, alignInput: {} }\n if ('part' in to) {\n /* Beside its curved surface -- a sphere's anywhere, a cylinder's side within its length -- or with no face at all. */\n const beside = figureSurfaceKeptPlaceOf(revision.asset, part, to.part, { ...revision.inputs })\n const kept = beside ?? (!facesOf(revision.asset, to.part).length ? surfaceKeptOf(revision, part, to.part) : undefined)\n if (kept) return { ...form, toPlane: false, target: to.part, surface: kept, align: {}, alignMm: {}, alignInput: {} }\n }\n form = { ...form, surface: undefined }\n /* Aimed at the plane, it meets it toward the side the placement uses -- below a ceiling -- until the author says (ADR-0140 3.11). */\n const f: FastenForm =\n 'plane' in to\n ? { ...form, toPlane: true, target: '', facing: form.toPlane ? form.facing : (figurePlaneFacingOf(revision.asset) ?? form.facing) }\n : 'part' in to\n ? { ...form, toPlane: false, target: to.part }\n : { ...form, targetFace: to.targetFace }\n const theirFaces = f.target ? facesOf(revision.asset, f.target) : FACES\n const targetFace = (theirFaces.includes(f.targetFace) ? f.targetFace : theirFaces[0]) as FigureFace\n const aim: FastenTarget | undefined = f.toPlane\n ? 'plane'\n : f.target\n ? { part: f.target, face: targetFace }\n : undefined\n return { ...f, ...(aim ? placeKeptOf(revision, part, aim) : { align: {}, alignMm: {}, alignInput: {} }) }\n}\n\n/** A change the drawing asks: a face, a way, a gap or a place across the face. */\nexport function fastenChanged(\n revision: FigureRevision,\n part: string,\n form: FastenForm,\n change: FastenChange\n): FastenForm {\n const f = form\n if ('targetFace' in change) return keptGapOf(revision, part, aimFasten(revision, part, f, { targetFace: change.targetFace as FigureFace }))\n if ('onSurface' in change) return keptGapOf(revision, part, aimFasten(revision, part, f, { surface: true }))\n if ('surface' in change) return keptGapOf(revision, part, { ...f, surface: change.surface })\n if ('mode' in change) return keptGapOf(revision, part, { ...f, facing: change.mode })\n if ('gap' in change) return { ...f, gap: change.gap, gapKept: undefined, gapFrom: 'typed' }\n return {\n ...f,\n align: { ...f.align, [change.axis]: change.how },\n alignMm: change.how === 'mm' ? { ...f.alignMm, [change.axis]: change.mm ?? 0 } : f.alignMm\n }\n}\n\n/**\n * The form with the gap that keeps the part where it stands (ADR-0140 stage 4, user 2026-10-20 「현재 상태로 붙이기」):\n * figure-model's `figureFastenKeptGapOf` for what it is aimed at and how it meets it. A gap the author typed, or the 0 a\n * canvas press puts, is left as it is. Nothing aimed at yet, the form is as it was.\n */\nexport function keptGapOf(revision: FigureRevision, part: string, form: FastenForm): FastenForm {\n if (form.gapFrom !== 'kept') return form\n const asset = revision.asset\n const theirFaces = form.target ? facesOf(asset, form.target) : FACES\n const targetFace = (theirFaces.includes(form.targetFace) ? form.targetFace : theirFaces[0]) as FigureFace\n const planeWay = figurePlaneFacingOf(asset)\n const mode: FastenMode = form.toPlane ? (mountingPlaneOf(asset).facings.includes(form.facing) ? form.facing : (planeWay ?? 'meet')) : form.facing\n const to = form.toPlane\n ? ('plane' as const)\n : form.target && form.surface && surfaceOf(asset, form.target)\n ? { part: form.target, surface: form.surface }\n : form.target\n ? { part: form.target, face: targetFace }\n : undefined\n if (!to) return form\n return { ...form, gap: figureFastenKeptGapOf(asset, part, to, mode, { ...revision.inputs }), gapKept: undefined }\n}\n\n/** What a form comes to: the face aimed at, the way, the drawing of the face and the command. */\nexport interface FastenPlan {\n /** Nothing is aimed at until a part or the plane is chosen. */\n aim?: FastenTarget\n theirFaces: string[]\n targetFace: FigureFace\n mode: FastenMode\n view?: FaceView\n /** The axes across the face asked in rows: where the drawing cannot set the place. */\n alignRows: { axis: Axis; edges: boolean }[]\n action?: FigureAuthoringAction\n /** The face the command would meet, lit on the canvas while it is tried. */\n face?: { part: string; face: string }\n /** On a point of the target's curved surface: which surface, about which axis, and where (ADR-0140 3.9). */\n surface?: { form: 'around' | 'toward'; axis: Axis; place: FigureSurfacePlace }\n}\n\nexport function fastenPlanOf(revision: FigureRevision, part: string, f: FastenForm): FastenPlan {\n const asset = revision.asset\n const theirFaces = f.target ? facesOf(asset, f.target) : FACES\n const targetFace = (theirFaces.includes(f.targetFace) ? f.targetFace : theirFaces[0]) as FigureFace\n const aim: FastenTarget | undefined = f.toPlane\n ? 'plane'\n : f.target\n ? { part: f.target, face: targetFace }\n : undefined\n /* The plane takes a part standing on it or hanging below it, a wall only one standing out of it (ADR-0140 3.11). */\n const planeWay = figurePlaneFacingOf(asset)\n const mode: FastenMode = f.toPlane ? (mountingPlaneOf(asset).facings.includes(f.facing) ? f.facing : (planeWay ?? 'meet')) : f.facing\n const surface = !f.toPlane && f.target && f.surface ? surfaceOf(asset, f.target) : undefined\n if (surface) {\n /* On the surface: where is the surface's own words, so no alignment goes with it (ADR-0140 3.9). */\n const action = {\n kind: 'attach',\n part,\n to: { part: f.target, surface: f.surface },\n facing: mode,\n ...fastenGapOf(f),\n replace: !!heldBy(asset, part)\n } as FigureAuthoringAction\n return { theirFaces, targetFace, mode, alignRows: [], action, surface: { ...surface, place: f.surface! } }\n }\n if (!aim) return { theirFaces, targetFace, mode, alignRows: [] }\n const align = alignOf(asset, aim, f.align, f.alignMm, f.alignInput)\n const view = faceViewOf(revision, part, aim, mode)\n const action = {\n kind: 'attach',\n part,\n to: f.toPlane ? { plane: 'mounting-plane' } : { part: f.target, face: targetFace },\n /* On the plane the kernel takes the placement's way when none is said: only another way is said. */\n ...(f.toPlane ? (mode === planeWay ? {} : { facing: mode }) : { facing: mode }),\n ...fastenGapOf(f),\n ...(align ? { align } : {}),\n replace: !!heldBy(asset, part)\n } as FigureAuthoringAction\n return {\n aim,\n theirFaces,\n targetFace,\n mode,\n view,\n alignRows: alignRowsOf(asset, aim, view, f.alignInput),\n action,\n ...(f.toPlane ? {} : { face: { part: f.target, face: targetFace } })\n }\n}\n\ntype Say = (key: string, params?: Record<string, string>) => string\n\n/** 「bin의 윗면에 올려놓기」: what the fastening is, in one line -- the part is the one the window is open on, not named again. */\nexport function fastenSentenceOf(\n form: FastenForm,\n plan: FastenPlan,\n planeWord: string,\n say: Say\n): string {\n const where = plan.surface ? say('figure.label.surface-' + plan.surface.form) : say('figure.label.face-' + plan.targetFace)\n const to = form.toPlane ? planeWord : `${form.target}의 ${where}`\n return say(`figure.text.fasten-sentence-${plan.mode}`, { to })\n}\n\n/**\n * What the folded details hold that is not their default, said while folded; nothing for the default. The gap's default\n * is the one it starts at -- the distance the part stands at, or 0 where the canvas was pressed -- so only a number typed\n * is said.\n */\nexport function fastenDetailWordsOf(form: FastenForm, say: Say): string[] {\n return [\n ...(form.gapKept !== undefined\n ? [say('figure.text.fasten-summary-gap-worked-out')]\n : form.gapFrom === 'typed' && form.gap\n ? [say('figure.text.fasten-summary-gap', { mm: String(form.gap) })]\n : [])\n ]\n}\n\n/**\n * A part pressed on the canvas while the window is open (ADR-0140 stage 4): aimed at, on the face or the point pressed,\n * its middle where it was pressed -- the kernel's reading of the press (`figureFastenTargetAt`), the point and normal brought into that part's own\n * frame by the pose its body is drawn at (`at.id`, a row's copy too). The part itself, one hanging from it, or one with\n * nothing to fasten to is not aimed at; a press on a curve there is no fastening to aims at the part alone. Each says\n * why, by its words' key.\n */\n/* Put where the canvas was pressed: on the face or the surface there, with no gap (ADR-0140 stage 4). */\nconst PRESSED = { gap: 0, gapKept: undefined, gapFrom: 'pressed' as const }\n\nexport function aimFastenAt(\n revision: FigureRevision,\n part: string,\n form: FastenForm,\n at: { id: string; point?: readonly number[]; normal?: readonly number[] }\n): { form?: FastenForm; note?: 'aim-self' | 'aim-cannot' | 'target-would-loop' | 'aim-not-here'; part: string } {\n const target = ownerOf(at.id)\n const offered = fastenTargetsOf(revision, part).find(t => t.part === target)\n if (target === part) return { note: 'aim-self', part: target }\n if (!offered) return { note: 'aim-cannot', part: target }\n if (offered.loops) return { note: 'target-would-loop', part: target }\n const aimed = aimFasten(revision, part, form, { part: target })\n const pose = (revision.geometry as Array<{ id: string; pose?: { r: number[][]; t: number[] } }>).find(g => g.id === at.id)?.pose\n if (!pose || !at.point || !at.normal) return { form: aimed, part: target }\n /* Into the part's own frame: rᵀ (p − t), and the normal by rᵀ. */\n const own = (v: readonly number[], from: readonly number[] = [0, 0, 0]) => [0, 1, 2].map(c => [0, 1, 2].reduce((sum, i) => sum + pose.r[i]![c]! * (v[i]! - from[i]!), 0))\n const lands = figureFastenTargetAt(revision.asset, target, own(at.point, pose.t), own(at.normal), { ...revision.inputs })\n if ('face' in lands) {\n /* On the face where it was pressed, as a point of a curved surface is: its middle there. */\n const onFace = aimFasten(revision, part, { ...aimed, surface: undefined }, { targetFace: lands.face as FigureFace })\n const at = lands.at as Partial<Record<Axis, number>>\n return { form: { ...onFace, ...PRESSED, align: Object.fromEntries(Object.keys(at).map(a => [a, 'mm'])) as FastenForm['align'], alignMm: { ...at }, alignInput: {} }, part: target }\n }\n if ('surface' in lands) return { form: { ...aimed, ...PRESSED, toPlane: false, target, surface: lands.surface, align: {}, alignMm: {}, alignInput: {} }, part: target }\n return { form: aimed, note: 'aim-not-here', part: target }\n}\n"]}
@@ -10,7 +10,7 @@ export function figureFigureFacts(revision) {
10
10
  }
11
11
  function figureFactsOf(revision) {
12
12
  const asset = revision.asset;
13
- const feature = asset.occupancy?.contact?.surface?.feature;
13
+ const feature = asset.mountingFace?.surface.feature;
14
14
  const found = feature?.match(/^(.+)\.mount\.(left|right|bottom|top|back|front)\.value$/);
15
15
  return {
16
16
  name: asset.name,
@@ -1 +1 @@
1
- {"version":3,"file":"figure-facts.js","sourceRoot":"","sources":["../../client/modeller/figure-facts.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAuB,MAAM,eAAe,CAAA;AAgB9D;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAwB;IACxD,OAAO,SAAS,CAAC,QAAQ,EAAE,cAAc,EAAE,GAAG,EAAE,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAA;AAC3E,CAAC;AACD,SAAS,aAAa,CAAC,QAAwB;IAC7C,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAoB,CAAA;IAC3C,MAAM,OAAO,GAAI,KAAK,CAAC,SAAS,EAAE,OAA0D,EAAE,OAAO,EAAE,OAAO,CAAA;IAC9G,MAAM,KAAK,GAAG,OAAO,EAAE,KAAK,CAAC,0DAA0D,CAAC,CAAA;IACxF,OAAO;QACL,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,SAAS,EAAE,KAAK,CAAC,SAAkC;QACnD,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAe,EAAE,CAAC,CAAC,CAAC,SAAS;KAC/E,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,MAAM,CAAC,GAAW;IAChC,OAAO;QACL,GAAG,IAAI,GAAG,CACR,GAAG;aACA,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;aAChD,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CACjC;KACF,CAAA;AACH,CAAC","sourcesContent":["import type { FigureAsset, FigureFace } from '@hatiolab/figure-model'\n\nimport { derivedOf, type FigureRevision } from './revision.js'\n\n/*\n * What the properties tab reads, kept apart from the element so it can be tested without a browser.\n */\n\nexport type Placement = 'floor' | 'ceiling' | 'center' | 'wall'\n\n/** What the properties tab reads off the asset. Absent parts of the asset read as absent, never as a default. */\nexport interface FigureFigureFacts {\n name: string\n placement?: Placement\n /** The face named as lying on the mounting plane, when one is (`set-mounting-face`): a promise the release gate checks. */\n mounting?: { part: string; face: FigureFace }\n}\n\n/**\n * The asset's own facts, as the properties tab shows them.\n *\n * The mounting face is read back from the feature `set-mounting-face` writes (`<part>.mount.<face>`): the asset\n * records the face only as that node, so this is where the screen learns which one is named.\n */\nexport function figureFigureFacts(revision: FigureRevision): FigureFigureFacts {\n return derivedOf(revision, 'figure-facts', () => figureFactsOf(revision))\n}\nfunction figureFactsOf(revision: FigureRevision): FigureFigureFacts {\n const asset = revision.asset as FigureAsset\n const feature = (asset.occupancy?.contact as { surface?: { feature?: string } } | undefined)?.surface?.feature\n const found = feature?.match(/^(.+)\\.mount\\.(left|right|bottom|top|back|front)\\.value$/)\n return {\n name: asset.name,\n placement: asset.placement as Placement | undefined,\n mounting: found ? { part: found[1], face: found[2] as FigureFace } : undefined\n }\n}\n\n/**\n * A tag line as a list: split on commas, drop a leading `#`, keep each once. An empty\n * line is an empty list, so an author can clear every tag.\n */\nexport function tagsOf(raw: string): string[] {\n return [\n ...new Set(\n raw\n .split(',')\n .map(one => one.trim().replace(/^#+/, '').trim())\n .filter(one => one.length > 0)\n )\n ]\n}\n"]}
1
+ {"version":3,"file":"figure-facts.js","sourceRoot":"","sources":["../../client/modeller/figure-facts.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAuB,MAAM,eAAe,CAAA;AAgB9D;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAwB;IACxD,OAAO,SAAS,CAAC,QAAQ,EAAE,cAAc,EAAE,GAAG,EAAE,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAA;AAC3E,CAAC;AACD,SAAS,aAAa,CAAC,QAAwB;IAC7C,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAoB,CAAA;IAC3C,MAAM,OAAO,GAAG,KAAK,CAAC,YAAY,EAAE,OAAO,CAAC,OAAO,CAAA;IACnD,MAAM,KAAK,GAAG,OAAO,EAAE,KAAK,CAAC,0DAA0D,CAAC,CAAA;IACxF,OAAO;QACL,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,SAAS,EAAE,KAAK,CAAC,SAAkC;QACnD,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAe,EAAE,CAAC,CAAC,CAAC,SAAS;KAC/E,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,MAAM,CAAC,GAAW;IAChC,OAAO;QACL,GAAG,IAAI,GAAG,CACR,GAAG;aACA,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;aAChD,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CACjC;KACF,CAAA;AACH,CAAC","sourcesContent":["import type { FigureAsset, FigureFace } from '@hatiolab/figure-model'\n\nimport { derivedOf, type FigureRevision } from './revision.js'\n\n/*\n * What the properties tab reads, kept apart from the element so it can be tested without a browser.\n */\n\nexport type Placement = 'floor' | 'ceiling' | 'center' | 'wall'\n\n/** What the properties tab reads off the asset. Absent parts of the asset read as absent, never as a default. */\nexport interface FigureFigureFacts {\n name: string\n placement?: Placement\n /** The face named as lying on the mounting plane, when one is (`set-mounting-face`): a promise the release gate checks. */\n mounting?: { part: string; face: FigureFace }\n}\n\n/**\n * The asset's own facts, as the properties tab shows them.\n *\n * The mounting face is read back from the feature `set-mounting-face` writes (`<part>.mount.<face>`): the asset\n * records the face only as that node, so this is where the screen learns which one is named.\n */\nexport function figureFigureFacts(revision: FigureRevision): FigureFigureFacts {\n return derivedOf(revision, 'figure-facts', () => figureFactsOf(revision))\n}\nfunction figureFactsOf(revision: FigureRevision): FigureFigureFacts {\n const asset = revision.asset as FigureAsset\n const feature = asset.mountingFace?.surface.feature\n const found = feature?.match(/^(.+)\\.mount\\.(left|right|bottom|top|back|front)\\.value$/)\n return {\n name: asset.name,\n placement: asset.placement as Placement | undefined,\n mounting: found ? { part: found[1], face: found[2] as FigureFace } : undefined\n }\n}\n\n/**\n * A tag line as a list: split on commas, drop a leading `#`, keep each once. An empty\n * line is an empty list, so an author can clear every tag.\n */\nexport function tagsOf(raw: string): string[] {\n return [\n ...new Set(\n raw\n .split(',')\n .map(one => one.trim().replace(/^#+/, '').trim())\n .filter(one => one.length > 0)\n )\n ]\n}\n"]}
@@ -10,7 +10,7 @@ import { CommonPopupStyles } from '@operato/styles';
10
10
  import { SidePanelStyles } from '@things-factory/figure-viewer/dist-client/side-panel-styles.js';
11
11
  import './figure-fasten-drawing.js';
12
12
  import { turnsInPlace } from './fasten-geometry.js';
13
- import { aimFasten, aimFastenAt, fastenChanged, fastenDetailWordsOf, fastenFormOf, fastenPlanOf, fastenSentenceOf, fastenTargetsOf } from './fasten-form.js';
13
+ import { aimFasten, aimFastenAt, keptGapOf, fastenChanged, fastenDetailWordsOf, fastenFormOf, fastenPlanOf, fastenSentenceOf, fastenTargetsOf } from './fasten-form.js';
14
14
  import { fieldWordsOf, hasInstanceSize, heldBy, mountingPlaneOf, surfaceOf } from './links.js';
15
15
  /** The target list's entry for the plane the figure stands by. */
16
16
  const PLANE = '__plane';
@@ -263,7 +263,7 @@ let FigureFastenDialog = class FigureFastenDialog extends localize(i18next)(LitE
263
263
  step="any"
264
264
  .value=${f.gapKept !== undefined ? '' : String(f.gap)}
265
265
  placeholder=${f.gapKept !== undefined ? i18next.t('figure.label.follows-expression') : ''}
266
- @change=${(e) => this.set({ gap: Number(e.target.value) || 0, gapKept: undefined })}
266
+ @change=${(e) => this.set({ gap: Number(e.target.value) || 0, gapKept: undefined, gapFrom: 'typed' })}
267
267
  />
268
268
  </div>
269
269
  </details>
@@ -332,7 +332,7 @@ let FigureFastenDialog = class FigureFastenDialog extends localize(i18next)(LitE
332
332
  const chosen = this.form.toPlane ? PLANE : this.form.target;
333
333
  if (part === chosen)
334
334
  return;
335
- this.form = aimFasten(this.revision, this.partId, this.form, part === PLANE ? { plane: true } : { part });
335
+ this.form = keptGapOf(this.revision, this.partId, aimFasten(this.revision, this.partId, this.form, part === PLANE ? { plane: true } : { part }));
336
336
  }
337
337
  /**
338
338
  * A part pressed on the canvas while the window is open (ADR-0140 stage 4): aimed at, on the face or the point pressed
@@ -1 +1 @@
1
- {"version":3,"file":"figure-fasten-dialog.js","sourceRoot":"","sources":["../../client/modeller/figure-fasten-dialog.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/button/filled-button.js'\nimport '@material/web/button/text-button.js'\n\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport '@operato/input/ox-input-select-buttons.js'\nimport '@operato/popup/ox-popup-actions.js'\nimport { CommonPopupStyles } from '@operato/styles'\nimport { SidePanelStyles } from '@things-factory/figure-viewer/dist-client/side-panel-styles.js'\n\nimport './figure-fasten-drawing.js'\nimport type { FastenChange } from './figure-fasten-drawing.js'\nimport { turnsInPlace, type FastenMode } from './fasten-geometry.js'\nimport {\n aimFasten,\n aimFastenAt,\n fastenChanged,\n fastenDetailWordsOf,\n fastenFormOf,\n fastenPlanOf,\n fastenSentenceOf,\n fastenTargetsOf,\n type FastenForm\n} from './fasten-form.js'\nimport { fieldWordsOf, hasInstanceSize, heldBy, mountingPlaneOf, surfaceOf, type Alignment, type Axis } from './links.js'\nimport type { FigureRevision } from './revision.js'\n\n/** The target list's entry for the plane the figure stands by. */\nconst PLANE = '__plane'\n\n/**\n * 붙이기 창: what the selected part is fastened to, on which face, how -- chosen with room to see it, in the standard\n * popup the editor opens (`openPopup`: its title, its close, moved by its head; no backdrop, so the canvas can be\n * pressed while it is open) (user 2026-10-17: 「속성에는 심플하고 직관적인 결과 위주로, 편집은 팝업에서 넓은 공간을\n * 써서」; 2026-10-18: the standard popup, not a window of its own; put back 2026-10-20).\n *\n * Everything chosen here is tried, not done: the command it comes to is told to the editor as it changes\n * (`preview-command`), and the canvas draws it. 「적용」 sends it once (`fasten-apply`), one step of the history;\n * 「취소」 and Esc close it with nothing written (`fasten-cancel`). A row of the target list under the pointer or the\n * arrows asks the canvas to light that part (`fasten-hover`). The window is the only one telling the preview while it\n * is open; the editor keeps the panel quiet.\n */\n@customElement('figure-fasten-dialog')\nexport class FigureFastenDialog extends localize(i18next)(LitElement) {\n static styles = [\n SidePanelStyles,\n CommonPopupStyles,\n css`\n /*\n The popup holds it at its own height and cuts what is past the screen: the window scrolls itself, within the\n screen less the popup's head and margins, 취소 · 적용 kept at its foot (below).\n */\n :host {\n display: grid;\n gap: 16px;\n padding: var(--popup-padding, 16px);\n overflow: auto;\n max-height: calc(100dvh - 32px - 56px);\n }\n /* The result in one line, at the top: it changes with every choice below it. */\n p[fasten-sentence] {\n margin: 0;\n font-size: var(--ui-t-body, 13px);\n font-weight: 600;\n }\n div[question] {\n display: grid;\n align-content: start;\n gap: 6px;\n }\n h4 {\n margin: 0;\n font-size: var(--ui-t-small, 11.5px);\n font-weight: 600;\n color: var(--md-sys-color-on-surface-variant);\n }\n /* The chips are part names, identifiers: shown as they are written, not capitalized as filter words are. */\n ox-input-select-buttons {\n --ox-input-select-buttons-label-text-transform: none;\n }\n p[loops] {\n margin: 0;\n }\n details[fasten-detail] {\n margin: 0;\n }\n details[fasten-detail] > div[form] {\n margin-top: 8px;\n max-width: 320px;\n }\n span[fasten-summary] {\n opacity: 0.8;\n }\n ul[preview-words] {\n margin: 0;\n padding: 8px 12px 8px 26px;\n border-radius: 6px;\n background: var(--md-sys-color-surface-container, #8881);\n display: grid;\n gap: 4px;\n }\n p[preview-words] {\n margin: 0;\n padding: 8px 12px;\n border-radius: 6px;\n background: var(--md-sys-color-surface-container, #8881);\n }\n p[error] {\n margin: 0;\n color: var(--md-sys-color-error);\n }\n /* 취소 · 적용 stay in sight at the window's foot when what is above them is taller than the screen. */\n ox-popup-actions {\n position: sticky;\n bottom: calc(-1 * var(--popup-padding, 16px));\n margin-bottom: calc(-1 * var(--popup-padding, 16px));\n padding-bottom: var(--popup-padding, 16px);\n background: var(--md-sys-color-surface-container-lowest);\n }\n `\n ]\n\n /** The figure at the version on screen. */\n @property({ attribute: false }) revision?: FigureRevision\n /** The part being fastened. */\n @property() partId = ''\n @property({ type: Boolean }) locked = false\n /** What the command would do, in words (the editor works it out: `command-preview.ts`). */\n @property({ attribute: false }) previewWords: string[] = []\n /** Why the last 「적용」 was refused, in the editor's words. */\n @property() error = ''\n\n @state() private form?: FastenForm\n /** Why a press on the canvas aimed at nothing, or only at the part (ADR-0140 stage 4); cleared by the next choice. */\n @state() private aimNote = ''\n /** The command the part's own fastening comes to, as opened: tried unchanged, nothing new is said of it. */\n private opened?: string\n private told = ''\n private loadedFor?: string\n private hovered: string | null = null\n\n willUpdate() {\n /* Opened on what the part has now; another part is another window's. */\n if (this.revision && this.partId && this.partId !== this.loadedFor) {\n this.loadedFor = this.partId\n this.form = fastenFormOf(this.revision, this.partId)\n this.opened = JSON.stringify(fastenPlanOf(this.revision, this.partId, this.form).action ?? null)\n }\n }\n\n async firstUpdated() {\n /* Into the list, on what is chosen, so the arrows go from there. */\n const list = this.renderRoot.querySelector<HTMLElement & { updateComplete?: Promise<unknown> }>(\n 'ox-input-select-buttons'\n )\n await list?.updateComplete\n const chips = list?.shadowRoot?.querySelectorAll<HTMLElement>('md-filter-chip')\n ;([...(chips ?? [])].find(c => c.hasAttribute('selected')) ?? chips?.[0])?.focus()\n }\n\n updated() {\n const plan = this.revision && this.form ? fastenPlanOf(this.revision, this.partId, this.form) : undefined\n const candidate = plan?.action ? { action: plan.action, ...(plan.face ? { face: plan.face } : {}) } : null\n const said = JSON.stringify(candidate)\n if (said === this.told) return\n this.told = said\n this.dispatchEvent(new CustomEvent('preview-command', { detail: candidate, bubbles: true, composed: true }))\n }\n\n disconnectedCallback() {\n super.disconnectedCallback()\n /* Closed: what it showed goes with it. */\n if (this.told && this.told !== 'null')\n this.dispatchEvent(new CustomEvent('preview-command', { detail: null, bubbles: true, composed: true }))\n this.told = ''\n this.hover(null)\n }\n\n render() {\n const revision = this.revision\n const f = this.form\n if (!revision || !f) return nothing\n const asset = revision.asset\n const held = !!heldBy(asset, this.partId)\n const plan = fastenPlanOf(revision, this.partId, f)\n const planeWord = i18next.t('figure.label.resize-place-' + (asset.placement ?? 'floor'))\n const modes: FastenMode[] = f.toPlane\n ? mountingPlaneOf(asset).facings\n : ['meet', 'flush', ...(turnsInPlace(asset, this.partId) ? (['centre'] as FastenMode[]) : [])]\n const detail = fastenDetailWordsOf(f, (key, params) => i18next.t(key, params))\n const drawing = (show: 'face' | 'how') =>\n html`<figure-fasten-drawing\n show=${show}\n .target=${f.toPlane ? '' : f.target}\n .planeWord=${planeWord}\n .faces=${plan.theirFaces}\n .face=${plan.targetFace}\n .modes=${modes}\n .mode=${plan.mode}\n .view=${plan.view}\n .align=${f.align}\n .alignMm=${f.alignMm}\n .gap=${f.gap}\n .partName=${this.partId}\n .surfaceForm=${f.toPlane || !f.target ? '' : (surfaceOf(asset, f.target)?.form ?? '')}\n .surface=${plan.surface}\n ?locked=${this.locked}\n @fasten-change=${(e: CustomEvent<FastenChange>) => {\n this.aimNote = ''\n this.form = fastenChanged(revision, this.partId, this.form!, e.detail)\n }}\n ></figure-fasten-drawing>`\n return html`\n ${\n plan.aim || plan.surface\n ? html`<p fasten-sentence role=\"status\">\n ${fastenSentenceOf(f, plan, planeWord, (key, params) => i18next.t(key, params))}\n </p>`\n : html`<p hint fasten-sentence>${i18next.t('figure.text.fasten-target-first')}</p>`\n }\n <div question=\"what\">\n <h4 id=\"what\">${i18next.t('figure.label.fasten-what')}</h4>\n ${this.renderTargets(revision, f, planeWord)}\n </div>\n ${\n plan.aim || plan.surface\n ? html`<div question=\"face\">\n <h4>\n ${\n /* The face asked is the target's, named: the part meets it by its real shape, by no face of its own. */ f.toPlane\n ? i18next.t('figure.label.fasten-face-on-plane', { plane: planeWord })\n : /* A sphere has no face to choose: where on its surface. */ plan.theirFaces.length\n ? i18next.t('figure.label.fasten-face-on-part', { part: f.target })\n : i18next.t('figure.label.fasten-face-on-surface', { part: f.target })\n }\n </h4>\n ${drawing('face')}\n </div>\n ${\n modes.length > 1\n ? html`<div question=\"how\">\n <h4>${i18next.t('figure.label.fasten-how')}</h4>\n ${drawing('how')}\n </div>`\n : nothing\n }\n <div question=\"detail\">\n <details fasten-detail>\n <summary>\n ${i18next.t('figure.label.fasten-detail')}${detail.length ? html` · <span fasten-summary>${detail.join(' · ')}</span>` : nothing}\n </summary>\n ${plan.alignRows.length ? this.renderAlignment(plan.alignRows) : nothing}\n <div form>\n <span>${i18next.t('figure.label.gap')}</span>\n <input\n gap\n type=\"number\"\n step=\"any\"\n .value=${f.gapKept !== undefined ? '' : String(f.gap)}\n placeholder=${f.gapKept !== undefined ? i18next.t('figure.label.follows-expression') : ''}\n @change=${(e: Event) => this.set({ gap: Number((e.target as HTMLInputElement).value) || 0, gapKept: undefined })}\n />\n </div>\n </details>\n </div>\n ${/* The one it has, tried unchanged: that it stays where it is goes without saying. */ JSON.stringify(plan.action ?? null) === this.opened ? nothing : this.renderPreviewWords()}`\n : nothing\n }\n ${this.aimNote ? html`<p hint aim-note role=\"status\">${this.aimNote}</p>` : nothing}\n ${this.error ? html`<p error role=\"alert\">${this.error}</p>` : nothing}\n <ox-popup-actions>\n <md-text-button slot=\"cancel\" cancel @click=${this.cancel}>${i18next.t('figure.button.cancel')}</md-text-button>\n <md-filled-button slot=\"confirm\" apply ?disabled=${this.locked || !plan.action} @click=${this.apply}>\n ${i18next.t(held ? 'figure.button.apply' : 'figure.button.fasten')}\n </md-filled-button>\n </ox-popup-actions>\n `\n }\n\n /**\n * What to fasten to: the plane and the other parts, as the standard choice chips. The arrows move among them and\n * the canvas lights the part under the focus or the pointer; a part hanging from this one is not offered, and why is\n * said under them.\n */\n private renderTargets(revision: FigureRevision, f: FastenForm, planeWord: string) {\n const chosen = f.toPlane ? PLANE : f.target\n const targets = fastenTargetsOf(revision, this.partId)\n const chipOf = (e: Event) =>\n (e.composedPath().find(n => (n as Element).localName === 'md-filter-chip') as Element | undefined)?.getAttribute(\n 'data-value'\n ) ?? null\n return html`<ox-input-select-buttons\n targets\n aria-labelledby=\"what\"\n .options=${[{ value: PLANE, display: planeWord }, ...targets.filter(t => !t.loops).map(t => ({ value: t.part, display: t.part }))]}\n .value=${chosen || undefined}\n ?disabled=${this.locked}\n @change=${(e: CustomEvent) => {\n /* A chip pressed again lets go of it; what to fasten to is always one thing once chosen. */\n if (e.detail) this.aim(e.detail)\n else (e.target as HTMLElement & { value?: string }).value = chosen || undefined\n }}\n @pointerover=${(e: Event) => this.hover(chipOf(e))}\n @pointerleave=${() => this.hover(null)}\n @focusin=${(e: Event) => this.hover(chipOf(e))}\n @keyup=${(e: KeyboardEvent) => {\n /* The arrows move the focus among the chips inside the list, which tells nothing outside it: read where it is. */\n const at = (e.currentTarget as Element).shadowRoot?.activeElement\n if (at?.localName === 'md-filter-chip') this.hover(at.getAttribute('data-value'))\n }}\n ></ox-input-select-buttons>\n ${this.renderLoops(targets.filter(t => t.loops).map(t => t.part))}`\n }\n\n /**\n * The parts that hang from this one, in one line: a line each made a list longer than the chips (2026-10-18, :3300,\n * the robot arm's forearm and the six parts it carries).\n */\n private renderLoops(parts: string[]) {\n if (!parts.length) return nothing\n return html`<p hint loops targets=${parts.join(',')}>\n ${i18next.t('figure.text.target-would-loop', { part: parts.join(', '), mine: this.partId })}\n </p>`\n }\n\n private aim(part: string) {\n if (this.locked || !this.revision || !this.form) return\n this.aimNote = ''\n const chosen = this.form.toPlane ? PLANE : this.form.target\n if (part === chosen) return\n this.form = aimFasten(this.revision, this.partId, this.form, part === PLANE ? { plane: true } : { part })\n }\n\n /**\n * A part pressed on the canvas while the window is open (ADR-0140 stage 4): aimed at, on the face or the point pressed\n * -- the kernel's reading of the press (`figureFastenTargetAt`), the point and normal brought into that part's own\n * frame by the pose it is drawn at. The part itself, or one hanging from it, is not aimed at; and a press on a curve\n * there is no fastening to aims at the part alone. Each is said.\n */\n aimAt(at: { id: string; point?: number[]; normal?: number[] }) {\n if (this.locked || !this.revision || !this.form) return\n const aimed = aimFastenAt(this.revision, this.partId, this.form, at)\n this.aimNote = aimed.note ? i18next.t(`figure.text.${aimed.note}`, { part: aimed.part, mine: this.partId }) : ''\n if (aimed.form) this.form = aimed.form\n }\n\n /** The part under the pointer or the focus in the list, for the canvas to light; the plane lights nothing. */\n private hover(part: string | null) {\n const lit = part && part !== PLANE ? part : null\n if (lit === this.hovered) return\n this.hovered = lit\n const face =\n lit && this.revision && this.form\n ? fastenPlanOf(this.revision, this.partId, aimFasten(this.revision, this.partId, this.form, { part: lit }))\n .targetFace\n : undefined\n this.dispatchEvent(\n new CustomEvent('fasten-hover', { detail: lit ? { part: lit, face } : null, bubbles: true, composed: true })\n )\n }\n\n private set(change: Partial<FastenForm>) {\n this.form = { ...this.form!, ...change }\n }\n\n /**\n * Where on the target face the part sits, on the axes the drawing cannot set: centred, level with the target's edge on\n * either side, a distance off centre, a share of the figure's size, or the position field it follows.\n */\n private renderAlignment(axes: { axis: Axis; edges: boolean }[]) {\n const f = this.form!\n const set = (axis: Axis, how: Alignment) => this.set({ align: { ...f.align, [axis]: how } })\n const setMm = (axis: Axis, mm: number) => this.set({ alignMm: { ...f.alignMm, [axis]: mm } })\n return html`<div form>\n ${axes.map(({ axis, edges }) => {\n const how =\n f.align[axis] === 'min' || f.align[axis] === 'max'\n ? edges\n ? f.align[axis]!\n : 'centre'\n : (f.align[axis] ?? 'centre')\n return html`<span>${i18next.t('figure.label.align-' + axis)}</span>\n <select @change=${(e: Event) => set(axis, (e.target as HTMLSelectElement).value as Alignment)}>\n <option value=\"centre\" ?selected=${how === 'centre'}>${i18next.t('figure.label.align-centre')}</option>\n ${\n edges\n ? html`<option value=\"min\" ?selected=${how === 'min'}>\n ${i18next.t(`figure.label.align-${axis}-min`)}\n </option>\n <option value=\"max\" ?selected=${how === 'max'}>\n ${i18next.t(`figure.label.align-${axis}-max`)}\n </option>`\n : nothing\n }\n ${\n f.alignInput?.[axis]\n ? html`<option value=\"input\" ?selected=${how === 'input'}>\n ${i18next.t('figure.label.align-input', { field: fieldWordsOf(f.alignInput[axis]!, key => i18next.t(key)) })}\n </option>`\n : nothing\n }\n <option value=\"mm\" ?selected=${how === 'mm'}>${i18next.t('figure.label.align-mm')}</option>\n ${\n this.revision && hasInstanceSize(this.revision.asset, axis)\n ? html`<option value=\"share\" ?selected=${how === 'share'}>\n ${i18next.t('figure.label.align-share')}\n </option>`\n : nothing\n }\n </select>\n ${\n how === 'mm' || how === 'share'\n ? html`<span></span\n ><input\n type=\"number\"\n step=\"any\"\n aria-label=${i18next.t('figure.label.align-mm')}\n .value=${String(f.alignMm[axis] ?? 0)}\n @change=${(e: Event) => setMm(axis, Number((e.target as HTMLInputElement).value) || 0)}\n />`\n : nothing\n }`\n })}\n </div>`\n }\n\n private renderPreviewWords() {\n if (this.previewWords.length === 1) return html`<p preview-words role=\"status\">${this.previewWords[0]}</p>`\n return this.previewWords.length\n ? html`<ul preview-words role=\"status\">\n ${this.previewWords.map(line => html`<li>${line}</li>`)}\n </ul>`\n : nothing\n }\n\n /** Enter applies what is chosen, Esc closes with nothing written; a key the window does not take goes on. */\n connectedCallback() {\n super.connectedCallback()\n this.setAttribute('role', 'dialog')\n this.setAttribute('aria-label', i18next.t('figure.label.fastening'))\n this.addEventListener('keydown', this.onKey)\n /* The popup's fitting width is the overlay's own setting; the window asks it for room for the face and the way side by side. */\n this.closest<HTMLElement>('ox-floating-overlay')?.style.setProperty('--overlay-center-fit-width', '640px')\n }\n\n private onKey = async (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.stopPropagation()\n e.preventDefault()\n this.cancel()\n return\n }\n if (e.key !== 'Enter' || e.isComposing) return\n const path = e.composedPath() as Element[]\n const target = path[0] as HTMLElement\n /* On a chip of the list Enter applies, as it does anywhere in the window; a chip is chosen by Space or a press. */\n const onChip = path.some(n => n.localName === 'ox-input-select-buttons')\n /* A button, a fold or a list of options does what Enter does to it. */\n if (\n !onChip &&\n (target.localName === 'button' ||\n target.localName === 'summary' ||\n target.localName === 'select' ||\n /^md-.*button$/.test(target.localName))\n )\n return\n e.preventDefault()\n e.stopPropagation()\n /* A number typed and Enter: the number first, as leaving the field would take it. */\n if (target.localName === 'input') target.dispatchEvent(new Event('change', { bubbles: true, composed: true }))\n await this.updateComplete\n this.apply()\n }\n\n private apply = () => {\n const plan = this.revision && this.form ? fastenPlanOf(this.revision, this.partId, this.form) : undefined\n if (this.locked || !plan?.action) return\n this.dispatchEvent(\n new CustomEvent('fasten-apply', { detail: { action: plan.action }, bubbles: true, composed: true })\n )\n }\n\n private cancel = () => {\n this.dispatchEvent(new CustomEvent('fasten-cancel', { bubbles: true, composed: true }))\n }\n}\n"]}
1
+ {"version":3,"file":"figure-fasten-dialog.js","sourceRoot":"","sources":["../../client/modeller/figure-fasten-dialog.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/button/filled-button.js'\nimport '@material/web/button/text-button.js'\n\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport '@operato/input/ox-input-select-buttons.js'\nimport '@operato/popup/ox-popup-actions.js'\nimport { CommonPopupStyles } from '@operato/styles'\nimport { SidePanelStyles } from '@things-factory/figure-viewer/dist-client/side-panel-styles.js'\n\nimport './figure-fasten-drawing.js'\nimport type { FastenChange } from './figure-fasten-drawing.js'\nimport { turnsInPlace, type FastenMode } from './fasten-geometry.js'\nimport {\n aimFasten,\n aimFastenAt,\n keptGapOf,\n fastenChanged,\n fastenDetailWordsOf,\n fastenFormOf,\n fastenPlanOf,\n fastenSentenceOf,\n fastenTargetsOf,\n type FastenForm\n} from './fasten-form.js'\nimport { fieldWordsOf, hasInstanceSize, heldBy, mountingPlaneOf, surfaceOf, type Alignment, type Axis } from './links.js'\nimport type { FigureRevision } from './revision.js'\n\n/** The target list's entry for the plane the figure stands by. */\nconst PLANE = '__plane'\n\n/**\n * 붙이기 창: what the selected part is fastened to, on which face, how -- chosen with room to see it, in the standard\n * popup the editor opens (`openPopup`: its title, its close, moved by its head; no backdrop, so the canvas can be\n * pressed while it is open) (user 2026-10-17: 「속성에는 심플하고 직관적인 결과 위주로, 편집은 팝업에서 넓은 공간을\n * 써서」; 2026-10-18: the standard popup, not a window of its own; put back 2026-10-20).\n *\n * Everything chosen here is tried, not done: the command it comes to is told to the editor as it changes\n * (`preview-command`), and the canvas draws it. 「적용」 sends it once (`fasten-apply`), one step of the history;\n * 「취소」 and Esc close it with nothing written (`fasten-cancel`). A row of the target list under the pointer or the\n * arrows asks the canvas to light that part (`fasten-hover`). The window is the only one telling the preview while it\n * is open; the editor keeps the panel quiet.\n */\n@customElement('figure-fasten-dialog')\nexport class FigureFastenDialog extends localize(i18next)(LitElement) {\n static styles = [\n SidePanelStyles,\n CommonPopupStyles,\n css`\n /*\n The popup holds it at its own height and cuts what is past the screen: the window scrolls itself, within the\n screen less the popup's head and margins, 취소 · 적용 kept at its foot (below).\n */\n :host {\n display: grid;\n gap: 16px;\n padding: var(--popup-padding, 16px);\n overflow: auto;\n max-height: calc(100dvh - 32px - 56px);\n }\n /* The result in one line, at the top: it changes with every choice below it. */\n p[fasten-sentence] {\n margin: 0;\n font-size: var(--ui-t-body, 13px);\n font-weight: 600;\n }\n div[question] {\n display: grid;\n align-content: start;\n gap: 6px;\n }\n h4 {\n margin: 0;\n font-size: var(--ui-t-small, 11.5px);\n font-weight: 600;\n color: var(--md-sys-color-on-surface-variant);\n }\n /* The chips are part names, identifiers: shown as they are written, not capitalized as filter words are. */\n ox-input-select-buttons {\n --ox-input-select-buttons-label-text-transform: none;\n }\n p[loops] {\n margin: 0;\n }\n details[fasten-detail] {\n margin: 0;\n }\n details[fasten-detail] > div[form] {\n margin-top: 8px;\n max-width: 320px;\n }\n span[fasten-summary] {\n opacity: 0.8;\n }\n ul[preview-words] {\n margin: 0;\n padding: 8px 12px 8px 26px;\n border-radius: 6px;\n background: var(--md-sys-color-surface-container, #8881);\n display: grid;\n gap: 4px;\n }\n p[preview-words] {\n margin: 0;\n padding: 8px 12px;\n border-radius: 6px;\n background: var(--md-sys-color-surface-container, #8881);\n }\n p[error] {\n margin: 0;\n color: var(--md-sys-color-error);\n }\n /* 취소 · 적용 stay in sight at the window's foot when what is above them is taller than the screen. */\n ox-popup-actions {\n position: sticky;\n bottom: calc(-1 * var(--popup-padding, 16px));\n margin-bottom: calc(-1 * var(--popup-padding, 16px));\n padding-bottom: var(--popup-padding, 16px);\n background: var(--md-sys-color-surface-container-lowest);\n }\n `\n ]\n\n /** The figure at the version on screen. */\n @property({ attribute: false }) revision?: FigureRevision\n /** The part being fastened. */\n @property() partId = ''\n @property({ type: Boolean }) locked = false\n /** What the command would do, in words (the editor works it out: `command-preview.ts`). */\n @property({ attribute: false }) previewWords: string[] = []\n /** Why the last 「적용」 was refused, in the editor's words. */\n @property() error = ''\n\n @state() private form?: FastenForm\n /** Why a press on the canvas aimed at nothing, or only at the part (ADR-0140 stage 4); cleared by the next choice. */\n @state() private aimNote = ''\n /** The command the part's own fastening comes to, as opened: tried unchanged, nothing new is said of it. */\n private opened?: string\n private told = ''\n private loadedFor?: string\n private hovered: string | null = null\n\n willUpdate() {\n /* Opened on what the part has now; another part is another window's. */\n if (this.revision && this.partId && this.partId !== this.loadedFor) {\n this.loadedFor = this.partId\n this.form = fastenFormOf(this.revision, this.partId)\n this.opened = JSON.stringify(fastenPlanOf(this.revision, this.partId, this.form).action ?? null)\n }\n }\n\n async firstUpdated() {\n /* Into the list, on what is chosen, so the arrows go from there. */\n const list = this.renderRoot.querySelector<HTMLElement & { updateComplete?: Promise<unknown> }>(\n 'ox-input-select-buttons'\n )\n await list?.updateComplete\n const chips = list?.shadowRoot?.querySelectorAll<HTMLElement>('md-filter-chip')\n ;([...(chips ?? [])].find(c => c.hasAttribute('selected')) ?? chips?.[0])?.focus()\n }\n\n updated() {\n const plan = this.revision && this.form ? fastenPlanOf(this.revision, this.partId, this.form) : undefined\n const candidate = plan?.action ? { action: plan.action, ...(plan.face ? { face: plan.face } : {}) } : null\n const said = JSON.stringify(candidate)\n if (said === this.told) return\n this.told = said\n this.dispatchEvent(new CustomEvent('preview-command', { detail: candidate, bubbles: true, composed: true }))\n }\n\n disconnectedCallback() {\n super.disconnectedCallback()\n /* Closed: what it showed goes with it. */\n if (this.told && this.told !== 'null')\n this.dispatchEvent(new CustomEvent('preview-command', { detail: null, bubbles: true, composed: true }))\n this.told = ''\n this.hover(null)\n }\n\n render() {\n const revision = this.revision\n const f = this.form\n if (!revision || !f) return nothing\n const asset = revision.asset\n const held = !!heldBy(asset, this.partId)\n const plan = fastenPlanOf(revision, this.partId, f)\n const planeWord = i18next.t('figure.label.resize-place-' + (asset.placement ?? 'floor'))\n const modes: FastenMode[] = f.toPlane\n ? mountingPlaneOf(asset).facings\n : ['meet', 'flush', ...(turnsInPlace(asset, this.partId) ? (['centre'] as FastenMode[]) : [])]\n const detail = fastenDetailWordsOf(f, (key, params) => i18next.t(key, params))\n const drawing = (show: 'face' | 'how') =>\n html`<figure-fasten-drawing\n show=${show}\n .target=${f.toPlane ? '' : f.target}\n .planeWord=${planeWord}\n .faces=${plan.theirFaces}\n .face=${plan.targetFace}\n .modes=${modes}\n .mode=${plan.mode}\n .view=${plan.view}\n .align=${f.align}\n .alignMm=${f.alignMm}\n .gap=${f.gap}\n .partName=${this.partId}\n .surfaceForm=${f.toPlane || !f.target ? '' : (surfaceOf(asset, f.target)?.form ?? '')}\n .surface=${plan.surface}\n ?locked=${this.locked}\n @fasten-change=${(e: CustomEvent<FastenChange>) => {\n this.aimNote = ''\n this.form = fastenChanged(revision, this.partId, this.form!, e.detail)\n }}\n ></figure-fasten-drawing>`\n return html`\n ${\n plan.aim || plan.surface\n ? html`<p fasten-sentence role=\"status\">\n ${fastenSentenceOf(f, plan, planeWord, (key, params) => i18next.t(key, params))}\n </p>`\n : html`<p hint fasten-sentence>${i18next.t('figure.text.fasten-target-first')}</p>`\n }\n <div question=\"what\">\n <h4 id=\"what\">${i18next.t('figure.label.fasten-what')}</h4>\n ${this.renderTargets(revision, f, planeWord)}\n </div>\n ${\n plan.aim || plan.surface\n ? html`<div question=\"face\">\n <h4>\n ${\n /* The face asked is the target's, named: the part meets it by its real shape, by no face of its own. */ f.toPlane\n ? i18next.t('figure.label.fasten-face-on-plane', { plane: planeWord })\n : /* A sphere has no face to choose: where on its surface. */ plan.theirFaces.length\n ? i18next.t('figure.label.fasten-face-on-part', { part: f.target })\n : i18next.t('figure.label.fasten-face-on-surface', { part: f.target })\n }\n </h4>\n ${drawing('face')}\n </div>\n ${\n modes.length > 1\n ? html`<div question=\"how\">\n <h4>${i18next.t('figure.label.fasten-how')}</h4>\n ${drawing('how')}\n </div>`\n : nothing\n }\n <div question=\"detail\">\n <details fasten-detail>\n <summary>\n ${i18next.t('figure.label.fasten-detail')}${detail.length ? html` · <span fasten-summary>${detail.join(' · ')}</span>` : nothing}\n </summary>\n ${plan.alignRows.length ? this.renderAlignment(plan.alignRows) : nothing}\n <div form>\n <span>${i18next.t('figure.label.gap')}</span>\n <input\n gap\n type=\"number\"\n step=\"any\"\n .value=${f.gapKept !== undefined ? '' : String(f.gap)}\n placeholder=${f.gapKept !== undefined ? i18next.t('figure.label.follows-expression') : ''}\n @change=${(e: Event) => this.set({ gap: Number((e.target as HTMLInputElement).value) || 0, gapKept: undefined, gapFrom: 'typed' })}\n />\n </div>\n </details>\n </div>\n ${/* The one it has, tried unchanged: that it stays where it is goes without saying. */ JSON.stringify(plan.action ?? null) === this.opened ? nothing : this.renderPreviewWords()}`\n : nothing\n }\n ${this.aimNote ? html`<p hint aim-note role=\"status\">${this.aimNote}</p>` : nothing}\n ${this.error ? html`<p error role=\"alert\">${this.error}</p>` : nothing}\n <ox-popup-actions>\n <md-text-button slot=\"cancel\" cancel @click=${this.cancel}>${i18next.t('figure.button.cancel')}</md-text-button>\n <md-filled-button slot=\"confirm\" apply ?disabled=${this.locked || !plan.action} @click=${this.apply}>\n ${i18next.t(held ? 'figure.button.apply' : 'figure.button.fasten')}\n </md-filled-button>\n </ox-popup-actions>\n `\n }\n\n /**\n * What to fasten to: the plane and the other parts, as the standard choice chips. The arrows move among them and\n * the canvas lights the part under the focus or the pointer; a part hanging from this one is not offered, and why is\n * said under them.\n */\n private renderTargets(revision: FigureRevision, f: FastenForm, planeWord: string) {\n const chosen = f.toPlane ? PLANE : f.target\n const targets = fastenTargetsOf(revision, this.partId)\n const chipOf = (e: Event) =>\n (e.composedPath().find(n => (n as Element).localName === 'md-filter-chip') as Element | undefined)?.getAttribute(\n 'data-value'\n ) ?? null\n return html`<ox-input-select-buttons\n targets\n aria-labelledby=\"what\"\n .options=${[{ value: PLANE, display: planeWord }, ...targets.filter(t => !t.loops).map(t => ({ value: t.part, display: t.part }))]}\n .value=${chosen || undefined}\n ?disabled=${this.locked}\n @change=${(e: CustomEvent) => {\n /* A chip pressed again lets go of it; what to fasten to is always one thing once chosen. */\n if (e.detail) this.aim(e.detail)\n else (e.target as HTMLElement & { value?: string }).value = chosen || undefined\n }}\n @pointerover=${(e: Event) => this.hover(chipOf(e))}\n @pointerleave=${() => this.hover(null)}\n @focusin=${(e: Event) => this.hover(chipOf(e))}\n @keyup=${(e: KeyboardEvent) => {\n /* The arrows move the focus among the chips inside the list, which tells nothing outside it: read where it is. */\n const at = (e.currentTarget as Element).shadowRoot?.activeElement\n if (at?.localName === 'md-filter-chip') this.hover(at.getAttribute('data-value'))\n }}\n ></ox-input-select-buttons>\n ${this.renderLoops(targets.filter(t => t.loops).map(t => t.part))}`\n }\n\n /**\n * The parts that hang from this one, in one line: a line each made a list longer than the chips (2026-10-18, :3300,\n * the robot arm's forearm and the six parts it carries).\n */\n private renderLoops(parts: string[]) {\n if (!parts.length) return nothing\n return html`<p hint loops targets=${parts.join(',')}>\n ${i18next.t('figure.text.target-would-loop', { part: parts.join(', '), mine: this.partId })}\n </p>`\n }\n\n private aim(part: string) {\n if (this.locked || !this.revision || !this.form) return\n this.aimNote = ''\n const chosen = this.form.toPlane ? PLANE : this.form.target\n if (part === chosen) return\n this.form = keptGapOf(this.revision, this.partId, aimFasten(this.revision, this.partId, this.form, part === PLANE ? { plane: true } : { part }))\n }\n\n /**\n * A part pressed on the canvas while the window is open (ADR-0140 stage 4): aimed at, on the face or the point pressed\n * -- the kernel's reading of the press (`figureFastenTargetAt`), the point and normal brought into that part's own\n * frame by the pose it is drawn at. The part itself, or one hanging from it, is not aimed at; and a press on a curve\n * there is no fastening to aims at the part alone. Each is said.\n */\n aimAt(at: { id: string; point?: number[]; normal?: number[] }) {\n if (this.locked || !this.revision || !this.form) return\n const aimed = aimFastenAt(this.revision, this.partId, this.form, at)\n this.aimNote = aimed.note ? i18next.t(`figure.text.${aimed.note}`, { part: aimed.part, mine: this.partId }) : ''\n if (aimed.form) this.form = aimed.form\n }\n\n /** The part under the pointer or the focus in the list, for the canvas to light; the plane lights nothing. */\n private hover(part: string | null) {\n const lit = part && part !== PLANE ? part : null\n if (lit === this.hovered) return\n this.hovered = lit\n const face =\n lit && this.revision && this.form\n ? fastenPlanOf(this.revision, this.partId, aimFasten(this.revision, this.partId, this.form, { part: lit }))\n .targetFace\n : undefined\n this.dispatchEvent(\n new CustomEvent('fasten-hover', { detail: lit ? { part: lit, face } : null, bubbles: true, composed: true })\n )\n }\n\n private set(change: Partial<FastenForm>) {\n this.form = { ...this.form!, ...change }\n }\n\n /**\n * Where on the target face the part sits, on the axes the drawing cannot set: centred, level with the target's edge on\n * either side, a distance off centre, a share of the figure's size, or the position field it follows.\n */\n private renderAlignment(axes: { axis: Axis; edges: boolean }[]) {\n const f = this.form!\n const set = (axis: Axis, how: Alignment) => this.set({ align: { ...f.align, [axis]: how } })\n const setMm = (axis: Axis, mm: number) => this.set({ alignMm: { ...f.alignMm, [axis]: mm } })\n return html`<div form>\n ${axes.map(({ axis, edges }) => {\n const how =\n f.align[axis] === 'min' || f.align[axis] === 'max'\n ? edges\n ? f.align[axis]!\n : 'centre'\n : (f.align[axis] ?? 'centre')\n return html`<span>${i18next.t('figure.label.align-' + axis)}</span>\n <select @change=${(e: Event) => set(axis, (e.target as HTMLSelectElement).value as Alignment)}>\n <option value=\"centre\" ?selected=${how === 'centre'}>${i18next.t('figure.label.align-centre')}</option>\n ${\n edges\n ? html`<option value=\"min\" ?selected=${how === 'min'}>\n ${i18next.t(`figure.label.align-${axis}-min`)}\n </option>\n <option value=\"max\" ?selected=${how === 'max'}>\n ${i18next.t(`figure.label.align-${axis}-max`)}\n </option>`\n : nothing\n }\n ${\n f.alignInput?.[axis]\n ? html`<option value=\"input\" ?selected=${how === 'input'}>\n ${i18next.t('figure.label.align-input', { field: fieldWordsOf(f.alignInput[axis]!, key => i18next.t(key)) })}\n </option>`\n : nothing\n }\n <option value=\"mm\" ?selected=${how === 'mm'}>${i18next.t('figure.label.align-mm')}</option>\n ${\n this.revision && hasInstanceSize(this.revision.asset, axis)\n ? html`<option value=\"share\" ?selected=${how === 'share'}>\n ${i18next.t('figure.label.align-share')}\n </option>`\n : nothing\n }\n </select>\n ${\n how === 'mm' || how === 'share'\n ? html`<span></span\n ><input\n type=\"number\"\n step=\"any\"\n aria-label=${i18next.t('figure.label.align-mm')}\n .value=${String(f.alignMm[axis] ?? 0)}\n @change=${(e: Event) => setMm(axis, Number((e.target as HTMLInputElement).value) || 0)}\n />`\n : nothing\n }`\n })}\n </div>`\n }\n\n private renderPreviewWords() {\n if (this.previewWords.length === 1) return html`<p preview-words role=\"status\">${this.previewWords[0]}</p>`\n return this.previewWords.length\n ? html`<ul preview-words role=\"status\">\n ${this.previewWords.map(line => html`<li>${line}</li>`)}\n </ul>`\n : nothing\n }\n\n /** Enter applies what is chosen, Esc closes with nothing written; a key the window does not take goes on. */\n connectedCallback() {\n super.connectedCallback()\n this.setAttribute('role', 'dialog')\n this.setAttribute('aria-label', i18next.t('figure.label.fastening'))\n this.addEventListener('keydown', this.onKey)\n /* The popup's fitting width is the overlay's own setting; the window asks it for room for the face and the way side by side. */\n this.closest<HTMLElement>('ox-floating-overlay')?.style.setProperty('--overlay-center-fit-width', '640px')\n }\n\n private onKey = async (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.stopPropagation()\n e.preventDefault()\n this.cancel()\n return\n }\n if (e.key !== 'Enter' || e.isComposing) return\n const path = e.composedPath() as Element[]\n const target = path[0] as HTMLElement\n /* On a chip of the list Enter applies, as it does anywhere in the window; a chip is chosen by Space or a press. */\n const onChip = path.some(n => n.localName === 'ox-input-select-buttons')\n /* A button, a fold or a list of options does what Enter does to it. */\n if (\n !onChip &&\n (target.localName === 'button' ||\n target.localName === 'summary' ||\n target.localName === 'select' ||\n /^md-.*button$/.test(target.localName))\n )\n return\n e.preventDefault()\n e.stopPropagation()\n /* A number typed and Enter: the number first, as leaving the field would take it. */\n if (target.localName === 'input') target.dispatchEvent(new Event('change', { bubbles: true, composed: true }))\n await this.updateComplete\n this.apply()\n }\n\n private apply = () => {\n const plan = this.revision && this.form ? fastenPlanOf(this.revision, this.partId, this.form) : undefined\n if (this.locked || !plan?.action) return\n this.dispatchEvent(\n new CustomEvent('fasten-apply', { detail: { action: plan.action }, bubbles: true, composed: true })\n )\n }\n\n private cancel = () => {\n this.dispatchEvent(new CustomEvent('fasten-cancel', { bubbles: true, composed: true }))\n }\n}\n"]}
@@ -78,22 +78,6 @@ export declare class FigureHistoryPanel extends FigureHistoryPanel_base {
78
78
  * 준다 — 화면이 문장을 지으면 서버가 거절할 때와 다른 말을 하게 된다.
79
79
  */
80
80
  private renderFinding;
81
- /**
82
- * 넘친 것을 담는 길 하나를 여기서도 내민다 — **같은 동작이 속성 패널에도 있다**(「부품에 맞추기」).
83
- *
84
- * 그 단추를 아는 저작자는 거기서 누른다. 발행이 막혔다는 말을 여기서 읽은 사람은 그 단추가 있는
85
- * 것을 모르고, 문구는 그것을 가리킬 수 없다 — 문장은 형식이 쓰고 형식은 화면의 단추를 모른다.
86
- * 그래서 화면이 자기 자리에서 같은 동작을 낸다. 누르면 상자만 커지고 부품은 제자리이며, 저장은
87
- * 여전히 저작자가 따로 한다.
88
- */
89
- /**
90
- * 「부품에 맞추기」를 내미는 판정: 공간을 부품에서 다시 선언한다(`declare-occupancy`) — 부품은 그대로 두고 선언만
91
- * 바꾼다. 공간을 아직 선언하지 않은 도형도 같은 단추로 선언한다: 새로 만든 도형은 전부 그 판정으로 막히고, 화면에
92
- * 다른 길이 없다. 장착면이 떠 있는 것은 여기 없다 — 부품 하나를 평면에 붙여도 거기 붙지 않은 것은 따라오지 않는다.
93
- * 판정의 「어떻게」가 할 일을 말한다.
94
- */
95
- private offersFit;
96
- private fitBase;
97
81
  /** Where one released version downloads as a package file, or undefined before the figure has a full name. */
98
82
  private packageHref;
99
83
  private renderVersion;
@@ -359,33 +359,7 @@ let FigureHistoryPanel = class FigureHistoryPanel extends localize(i18next)(LitE
359
359
  * 준다 — 화면이 문장을 지으면 서버가 거절할 때와 다른 말을 하게 된다.
360
360
  */
361
361
  renderFinding(finding, blocking) {
362
- return renderGateFinding(finding, blocking, html `
363
- ${this.offersFit(finding.code)
364
- ? html `<button fit-base @click=${() => this.fitBase()}>
365
- ${i18next.t('figure.button.fit-base-to-parts')}
366
- </button>`
367
- : nothing}
368
- `);
369
- }
370
- /**
371
- * 넘친 것을 담는 길 하나를 여기서도 내민다 — **같은 동작이 속성 패널에도 있다**(「부품에 맞추기」).
372
- *
373
- * 그 단추를 아는 저작자는 거기서 누른다. 발행이 막혔다는 말을 여기서 읽은 사람은 그 단추가 있는
374
- * 것을 모르고, 문구는 그것을 가리킬 수 없다 — 문장은 형식이 쓰고 형식은 화면의 단추를 모른다.
375
- * 그래서 화면이 자기 자리에서 같은 동작을 낸다. 누르면 상자만 커지고 부품은 제자리이며, 저장은
376
- * 여전히 저작자가 따로 한다.
377
- */
378
- /**
379
- * 「부품에 맞추기」를 내미는 판정: 공간을 부품에서 다시 선언한다(`declare-occupancy`) — 부품은 그대로 두고 선언만
380
- * 바꾼다. 공간을 아직 선언하지 않은 도형도 같은 단추로 선언한다: 새로 만든 도형은 전부 그 판정으로 막히고, 화면에
381
- * 다른 길이 없다. 장착면이 떠 있는 것은 여기 없다 — 부품 하나를 평면에 붙여도 거기 붙지 않은 것은 따라오지 않는다.
382
- * 판정의 「어떻게」가 할 일을 말한다.
383
- */
384
- offersFit(code) {
385
- return code === 'part-outside-occupancy' || code === 'occupancy-undeclared';
386
- }
387
- fitBase() {
388
- this.dispatchEvent(new CustomEvent('fit-base-to-parts', { bubbles: true, composed: true }));
362
+ return renderGateFinding(finding, blocking, nothing);
389
363
  }
390
364
  /** Where one released version downloads as a package file, or undefined before the figure has a full name. */
391
365
  packageHref(version) {