@things-factory/figure-ui 10.1.53 → 10.1.54
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/modeller/v3-editor.ts +2 -7
- package/client/modeller/v3-links.ts +3 -3
- package/client/modeller/v3-refusals.ts +19 -0
- package/client/pages/figure-v3-modeller-page.ts +3 -0
- package/dist-client/modeller/v3-clips.d.ts +1 -1
- package/dist-client/modeller/v3-editor.js +2 -7
- package/dist-client/modeller/v3-editor.js.map +1 -1
- package/dist-client/modeller/v3-links.js +3 -3
- package/dist-client/modeller/v3-links.js.map +1 -1
- package/dist-client/modeller/v3-refusals.d.ts +6 -0
- package/dist-client/modeller/v3-refusals.js +23 -0
- package/dist-client/modeller/v3-refusals.js.map +1 -1
- package/dist-client/pages/figure-v3-modeller-page.js +3 -0
- package/dist-client/pages/figure-v3-modeller-page.js.map +1 -1
- package/dist-client/route.d.ts +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -5
- package/test/v3-first-save.test.ts +8 -0
- package/test/v3-links.test.ts +12 -0
- package/test/v3-parts-wiring.test.ts +4 -2
- package/test/v3-refusals.test.ts +30 -0
- package/translations/en.json +5 -1
- package/translations/ja.json +5 -1
- package/translations/ko.json +5 -1
- package/translations/ms.json +5 -1
- package/translations/zh.json +5 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@things-factory/figure-ui",
|
|
3
|
-
"version": "10.1.
|
|
3
|
+
"version": "10.1.54",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public",
|
|
6
6
|
"@things-factory:registry": "https://registry.npmjs.org"
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"clean": "npm run clean:server && npm run clean:client"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@hatiolab/figure-model": "^0.1.
|
|
31
|
-
"@hatiolab/things-scene": "^10.1.
|
|
30
|
+
"@hatiolab/figure-model": "^0.1.63",
|
|
31
|
+
"@hatiolab/things-scene": "^10.1.40",
|
|
32
32
|
"@material/web": "^2.0.0",
|
|
33
33
|
"@operato/data-grist": "^10.0.0",
|
|
34
34
|
"@operato/graphql": "^10.0.0",
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
"@operato/styles": "^10.0.0",
|
|
41
41
|
"@operato/utils": "^10.0.0",
|
|
42
42
|
"@things-factory/ai-assistant": "^10.1.53",
|
|
43
|
-
"@things-factory/figure-service": "^10.1.
|
|
43
|
+
"@things-factory/figure-service": "^10.1.54",
|
|
44
44
|
"three": "^0.185.1"
|
|
45
45
|
},
|
|
46
|
-
"gitHead": "
|
|
46
|
+
"gitHead": "0bc2238c6df9cb041b22146c85181ed7efe38f40"
|
|
47
47
|
}
|
|
@@ -82,3 +82,11 @@ test('처음 저장한 도형은 주소가 제 것이 된다 — 모델러를
|
|
|
82
82
|
/* The early return that kept the old figure reads the route id; it now matches only the figure the address names. */
|
|
83
83
|
assert.match(page, /if \(this\.session\.read\(\)\.context && id === this\.routeId && !changes\.active\) return/)
|
|
84
84
|
})
|
|
85
|
+
|
|
86
|
+
test('다른 도형을 열면 행을 먼저 비운다 — 앞 도형의 타입이 칸에 남지 않는다 (C2, 2026-09-25)', async () => {
|
|
87
|
+
const { readFileSync } = await import('node:fs')
|
|
88
|
+
const page = readFileSync(new URL('../client/pages/figure-v3-modeller-page.ts', import.meta.url), 'utf8')
|
|
89
|
+
const updated = page.slice(page.indexOf('async pageUpdated'), page.indexOf('private askFirstSave'))
|
|
90
|
+
const opening = updated.slice(updated.indexOf('if (id) {'), updated.indexOf('this.session.open(id'))
|
|
91
|
+
assert.match(opening, /this\.row = \{ version: 0 \}/, '열기 전에 행을 비운다')
|
|
92
|
+
})
|
package/test/v3-links.test.ts
CHANGED
|
@@ -423,3 +423,15 @@ test('면 위 거리를 도형 크기 비율로 — 도형이 커지면 그 자
|
|
|
423
423
|
assert.equal(x(1000), 300)
|
|
424
424
|
assert.equal(x(2000), 600, '도형이 두 배면 거리도 두 배')
|
|
425
425
|
})
|
|
426
|
+
|
|
427
|
+
test('선언할 크기는 부품이 쉬고 있을 때의 크기 — 문짝이 도는 자리까지 재지 않는다 (2026-09-25)', async () => {
|
|
428
|
+
const { instanceRangeToDeclare } = await import('../client/modeller/v3-links.ts')
|
|
429
|
+
let asset = createV3Asset('Door')
|
|
430
|
+
asset = addV3Box(asset, { id: 'jamb', size: { x: 100, y: 2100, z: 150 }, position: { x: 0, y: 0, z: 0 } })
|
|
431
|
+
asset = addV3Box(asset, { id: 'leaf', size: { x: 890, y: 2095, z: 40 }, position: { x: 0, y: 0, z: 0 } })
|
|
432
|
+
asset = applyV3Authoring(asset, { kind: 'attach', part: 'jamb', face: 'bottom', to: { plane: 'mounting-plane' } })
|
|
433
|
+
asset = applyV3Authoring(asset, { kind: 'attach', part: 'leaf', face: 'left', to: { part: 'jamb', face: 'right' }, align: { y: 'min', z: 'max' }, gap: 5 })
|
|
434
|
+
const j = asset.joints!.find(o => o.id === 'leaf')!
|
|
435
|
+
asset = applyV3Authoring(asset, { kind: 'set-joint', joint: { ...j, type: 'revolute', axis: 'Y', lowerLimit: -90, upperLimit: 0, state: { id: 'open' } } })
|
|
436
|
+
assert.deepEqual(instanceRangeToDeclare(asset)!.at, { x: 995, y: 2100, z: 150 })
|
|
437
|
+
})
|
|
@@ -37,10 +37,12 @@ test('작업대에서 가린 부품은 캔버스에서 빠지고, 다른 도형
|
|
|
37
37
|
})
|
|
38
38
|
|
|
39
39
|
test('지울 수 없는 부품은 사람의 말로 거절한다 — 다섯 말 모두', () => {
|
|
40
|
-
|
|
40
|
+
/* Since 2026-09-25 the reason is told apart (partRefusalOf, tested in v3-refusals); the editor hands the refusal to it. */
|
|
41
|
+
assert.match(editor, /private removePart[\s\S]*?partRefusalOf\(error, id,/)
|
|
41
42
|
for (const lang of ['ko', 'en', 'ja', 'zh', 'ms']) {
|
|
42
43
|
const table = JSON.parse(read(`../translations/${lang}.json`))
|
|
43
|
-
|
|
44
|
+
for (const key of ['part-is-referenced', 'part-holds-others', 'part-in-declared-space', 'part-is-followed', 'part-is-led'])
|
|
45
|
+
assert.ok(table[`figure.text.${key}`]?.includes('{part}'), `${lang} ${key}`)
|
|
44
46
|
}
|
|
45
47
|
})
|
|
46
48
|
|
package/test/v3-refusals.test.ts
CHANGED
|
@@ -47,3 +47,33 @@ test('범위가 받을 수 없는 연결은 같은 연결을 범위를 좁혀
|
|
|
47
47
|
assert.doesNotThrow(() => applyV3Authoring(asset, offer.retry as never), '권한 것은 받아들여진다')
|
|
48
48
|
assert.equal(narrowingRetryOf({ kind: 'attach' }, error, say), null, '연결이 아닌 명령에는 권하지 않는다')
|
|
49
49
|
})
|
|
50
|
+
|
|
51
|
+
test('부품을 못 지우는 까닭을 넷으로 가려 말한다 — 매단 것 · 공간 선언 · 크기를 따르는 것 · 따라 움직이는 것 (2026-09-25)', async () => {
|
|
52
|
+
const { partRefusalOf } = await import('../client/modeller/v3-refusals.ts')
|
|
53
|
+
const fm = await import('@hatiolab/figure-model')
|
|
54
|
+
const say = (key: string, p: Record<string, string>) => `${key} ${JSON.stringify(p)}`
|
|
55
|
+
let a = fm.createV3Asset('Bench')
|
|
56
|
+
a = fm.addV3Box(a, { id: 'leg', size: { x: 60, y: 700, z: 60 }, position: { x: 0, y: 0, z: 0 } })
|
|
57
|
+
a = fm.addV3Box(a, { id: 'top', size: { x: 1200, y: 40, z: 600 }, position: { x: 0, y: 0, z: 0 } })
|
|
58
|
+
a = fm.addV3Box(a, { id: 'lamp', size: { x: 80, y: 80, z: 80 }, position: { x: 0, y: 0, z: 0 } })
|
|
59
|
+
a = fm.addV3Box(a, { id: 'shade', size: { x: 40, y: 40, z: 40 }, position: { x: 0, y: 0, z: 0 } })
|
|
60
|
+
a = fm.applyV3Authoring(a, { kind: 'attach', part: 'leg', face: 'bottom', to: { plane: 'mounting-plane' } })
|
|
61
|
+
a = fm.applyV3Authoring(a, { kind: 'attach', part: 'top', face: 'bottom', to: { part: 'leg', face: 'top' } })
|
|
62
|
+
a = fm.applyV3Authoring(a, { kind: 'attach', part: 'lamp', face: 'bottom', to: { part: 'top', face: 'top' }, align: { x: { mm: -300 } } })
|
|
63
|
+
a = fm.applyV3Authoring(a, { kind: 'attach', part: 'shade', face: 'bottom', to: { part: 'top', face: 'top' }, align: { x: { mm: 300 } } })
|
|
64
|
+
const turn = (asset: typeof a, part: string, extra: object) => fm.applyV3Authoring(asset, { kind: 'set-joint', joint: { ...asset.joints!.find(j => j.body1.part === part)!, type: 'revolute', axis: 'Y', ...extra } as never })
|
|
65
|
+
a = turn(a, 'lamp', { state: { id: 'lamp-turn' } })
|
|
66
|
+
a = turn(a, 'shade', { mimic: { joint: 'lamp', multiplier: 1 } })
|
|
67
|
+
const why = (asset: typeof a, part: string) => {
|
|
68
|
+
try {
|
|
69
|
+
fm.editV3Part(asset, { kind: 'remove-part', target: part })
|
|
70
|
+
return 'removed'
|
|
71
|
+
} catch (e) {
|
|
72
|
+
return partRefusalOf(e, part, say)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
assert.match(why(a, 'top')!, /part-holds-others .*"others":"lamp, shade"/)
|
|
76
|
+
assert.match(why(a, 'lamp')!, /part-is-led .*"others":"shade"/)
|
|
77
|
+
const declared = fm.applyV3Authoring(a, { kind: 'declare-occupancy', proposal: fm.proposeV3Occupancy(a), placement: 'floor' })
|
|
78
|
+
assert.match(why(declared, 'shade')!, /part-in-declared-space .*"part":"shade"/, '잎인데 공간 선언에 들어 있다')
|
|
79
|
+
})
|
package/translations/en.json
CHANGED
|
@@ -720,5 +720,9 @@
|
|
|
720
720
|
"figure.text.link-needs-smaller-range": "with this link {part} is gone when the figure's {axis} is under {mm} mm, and the declared sizes go below that.",
|
|
721
721
|
"figure.button.narrow-range-from": "narrow {axis} to {mm} mm and up, and link",
|
|
722
722
|
"figure.text.link-needs-larger-range": "with this link the figure cannot be drawn when its {axis} is over {mm} mm, and the declared sizes go above that.",
|
|
723
|
-
"figure.button.narrow-range-to": "narrow {axis} to {mm} mm and under, and link"
|
|
723
|
+
"figure.button.narrow-range-to": "narrow {axis} to {mm} mm and under, and link",
|
|
724
|
+
"figure.text.part-holds-others": "'{part}' holds {others}; take them off first.",
|
|
725
|
+
"figure.text.part-in-declared-space": "'{part}' is in the declared space; declare the space again without it, or fit it to the parts, first.",
|
|
726
|
+
"figure.text.part-is-followed": "{others} follow the size or place of '{part}'; make them their own numbers first.",
|
|
727
|
+
"figure.text.part-is-led": "{others} move with '{part}'; give them their own control first."
|
|
724
728
|
}
|
package/translations/ja.json
CHANGED
|
@@ -720,5 +720,9 @@
|
|
|
720
720
|
"figure.text.link-needs-smaller-range": "この連結で図形の {axis} が {mm} mm 未満だと {part} がなくなります。宣言された置けるサイズはそれより小さくまで開いています。",
|
|
721
721
|
"figure.button.narrow-range-from": "{axis} を {mm} mm からに絞って連結",
|
|
722
722
|
"figure.text.link-needs-larger-range": "この連結で図形の {axis} が {mm} mm を超えると描けません。宣言された置けるサイズはそれより大きくまで開いています。",
|
|
723
|
-
"figure.button.narrow-range-to": "{axis} を {mm} mm までに絞って連結"
|
|
723
|
+
"figure.button.narrow-range-to": "{axis} を {mm} mm までに絞って連結",
|
|
724
|
+
"figure.text.part-holds-others": "'{part}' に {others} が付いているため削除できません。先に外してください。",
|
|
725
|
+
"figure.text.part-in-declared-space": "'{part}' は宣言された空間に含まれるため削除できません。この部品なしで空間を宣言し直すか「部品に合わせる」をしてから削除してください。",
|
|
726
|
+
"figure.text.part-is-followed": "{others} が '{part}' のサイズか位置に従っているため削除できません。先に自分の数値に変えてください。",
|
|
727
|
+
"figure.text.part-is-led": "{others} が '{part}' に連動しているため削除できません。先に自分の操作値に変えてください。"
|
|
724
728
|
}
|
package/translations/ko.json
CHANGED
|
@@ -720,5 +720,9 @@
|
|
|
720
720
|
"figure.text.link-needs-smaller-range": "이 연결로 {part} 부품은 도형 {axis} 가 {mm} mm 보다 작으면 사라집니다. 지금 선언된 놓일 수 있는 크기는 그보다 작은 데까지 열려 있습니다.",
|
|
721
721
|
"figure.button.narrow-range-from": "{axis} 를 {mm} mm 부터로 좁히고 연결",
|
|
722
722
|
"figure.text.link-needs-larger-range": "이 연결로 도형 {axis} 가 {mm} mm 보다 크면 그릴 수 없습니다. 지금 선언된 놓일 수 있는 크기는 그보다 큰 데까지 열려 있습니다.",
|
|
723
|
-
"figure.button.narrow-range-to": "{axis} 를 {mm} mm 까지로 좁히고 연결"
|
|
723
|
+
"figure.button.narrow-range-to": "{axis} 를 {mm} mm 까지로 좁히고 연결",
|
|
724
|
+
"figure.text.part-holds-others": "'{part}' 에 {others} 이 매달려 있어 지울 수 없습니다. 먼저 떼어 주세요.",
|
|
725
|
+
"figure.text.part-in-declared-space": "'{part}' 는 선언된 공간에 들어 있어 지울 수 없습니다. 이 부품 없이 공간을 다시 선언하거나 「부품에 맞추기」를 한 뒤 지우세요.",
|
|
726
|
+
"figure.text.part-is-followed": "{others} 이 '{part}' 의 크기나 자리를 따르고 있어 지울 수 없습니다. 먼저 그 부품을 제 숫자로 바꾸세요.",
|
|
727
|
+
"figure.text.part-is-led": "{others} 이 '{part}' 를 따라 움직여 지울 수 없습니다. 먼저 제 조작값으로 바꾸세요."
|
|
724
728
|
}
|
package/translations/ms.json
CHANGED
|
@@ -720,5 +720,9 @@
|
|
|
720
720
|
"figure.text.link-needs-smaller-range": "dengan pautan ini {part} hilang apabila {axis} rajah di bawah {mm} mm, dan saiz yang diisytihar pergi lebih rendah.",
|
|
721
721
|
"figure.button.narrow-range-from": "sempitkan {axis} dari {mm} mm dan pautkan",
|
|
722
722
|
"figure.text.link-needs-larger-range": "dengan pautan ini rajah tidak boleh dilukis apabila {axis} melebihi {mm} mm, dan saiz yang diisytihar pergi lebih tinggi.",
|
|
723
|
-
"figure.button.narrow-range-to": "sempitkan {axis} hingga {mm} mm dan pautkan"
|
|
723
|
+
"figure.button.narrow-range-to": "sempitkan {axis} hingga {mm} mm dan pautkan",
|
|
724
|
+
"figure.text.part-holds-others": "'{part}' memegang {others}; tanggalkan dahulu.",
|
|
725
|
+
"figure.text.part-in-declared-space": "'{part}' berada dalam ruang yang diisytihar; isytihar semula ruang tanpanya, atau muatkan pada bahagian, dahulu.",
|
|
726
|
+
"figure.text.part-is-followed": "{others} mengikut saiz atau tempat '{part}'; jadikan nombor sendiri dahulu.",
|
|
727
|
+
"figure.text.part-is-led": "{others} bergerak bersama '{part}'; beri kawalan sendiri dahulu."
|
|
724
728
|
}
|
package/translations/zh.json
CHANGED
|
@@ -720,5 +720,9 @@
|
|
|
720
720
|
"figure.text.link-needs-smaller-range": "此连接下,图形 {axis} 小于 {mm} mm 时 {part} 会消失,而声明的可放置尺寸低于此值。",
|
|
721
721
|
"figure.button.narrow-range-from": "将 {axis} 收窄为 {mm} mm 起并连接",
|
|
722
722
|
"figure.text.link-needs-larger-range": "此连接下,图形 {axis} 大于 {mm} mm 时无法绘制,而声明的可放置尺寸高于此值。",
|
|
723
|
-
"figure.button.narrow-range-to": "将 {axis} 收窄为 {mm} mm 以内并连接"
|
|
723
|
+
"figure.button.narrow-range-to": "将 {axis} 收窄为 {mm} mm 以内并连接",
|
|
724
|
+
"figure.text.part-holds-others": "'{part}' 上挂着 {others},无法删除。请先卸下。",
|
|
725
|
+
"figure.text.part-in-declared-space": "'{part}' 在已声明的空间内,无法删除。请先在不含它的情况下重新声明空间或「贴合部件」。",
|
|
726
|
+
"figure.text.part-is-followed": "{others} 跟随 '{part}' 的尺寸或位置,无法删除。请先改为自身数值。",
|
|
727
|
+
"figure.text.part-is-led": "{others} 跟随 '{part}' 运动,无法删除。请先改为自身控制值。"
|
|
724
728
|
}
|