@operato/board 10.19.0 → 10.21.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@operato/board",
3
- "version": "10.19.0",
3
+ "version": "10.21.0",
4
4
  "description": "Webcomponent for board following open-wc recommendations",
5
5
  "author": "heartyoh",
6
6
  "type": "module",
@@ -120,17 +120,17 @@
120
120
  "dependencies": {
121
121
  "@material/web": "^2.0.0",
122
122
  "@open-wc/scoped-elements": "^2.1.3",
123
- "@operato/app": "^10.19.0",
123
+ "@operato/app": "^10.20.0",
124
124
  "@operato/data-grist": "^10.19.0",
125
- "@operato/font": "^10.19.0",
125
+ "@operato/font": "^10.20.0",
126
126
  "@operato/graphql": "^10.16.2",
127
127
  "@operato/i18n": "^10.16.2",
128
128
  "@operato/input": "^10.16.2",
129
- "@operato/layout": "^10.16.2",
129
+ "@operato/layout": "^10.20.0",
130
130
  "@operato/markdown": "^10.16.2",
131
131
  "@operato/popup": "^10.16.2",
132
- "@operato/property-editor": "^10.19.0",
133
- "@operato/property-panel": "^10.19.0",
132
+ "@operato/property-editor": "^10.20.0",
133
+ "@operato/property-panel": "^10.20.0",
134
134
  "@operato/styles": "^10.16.2",
135
135
  "@operato/utils": "^10.16.2",
136
136
  "@types/file-saver": "^2.0.4",
@@ -144,7 +144,7 @@
144
144
  "devDependencies": {
145
145
  "@custom-elements-manifest/analyzer": "^0.10.0",
146
146
  "@hatiolab/prettier-config": "^1.0.0",
147
- "@hatiolab/things-scene": "^10.0.0",
147
+ "@hatiolab/things-scene": "^10.1.26",
148
148
  "@open-wc/eslint-config": "^12.0.3",
149
149
  "@open-wc/testing": "^4.0.0",
150
150
  "@rollup/plugin-image": "^3.0.3",
@@ -180,5 +180,5 @@
180
180
  "prettier --write"
181
181
  ]
182
182
  },
183
- "gitHead": "58bdb75a1b1f0c28936d44829e1cf7199de3c617"
183
+ "gitHead": "71c71988ded417882381cbdf55dccabfed468411"
184
184
  }
@@ -1,6 +1,6 @@
1
1
  import { expect } from '@open-wc/testing'
2
2
 
3
- import { Component, hasFigure, registerTypeResolver, resetFigures, resolveUnknownTypes } from '@hatiolab/things-scene'
3
+ import { Component, hasFigure, hasFigureV3, registerTypeResolver, resetFigures, resetFiguresV3, resolveUnknownTypes } from '@hatiolab/things-scene'
4
4
 
5
5
  import { createFigureResolver } from '../src/figure-provider.js'
6
6
 
@@ -40,6 +40,55 @@ const blueprintOf = (type: string) => ({
40
40
  ]
41
41
  })
42
42
 
43
+ /**
44
+ * The other thing the door can hand over: a V3 asset under a `format` tag (ADR-0087 decision 5).
45
+ *
46
+ * Written out rather than built with figure-model, for the same reason the blueprint above is: this package
47
+ * does not read either payload, it passes each to the scene's own registration, and a fixture that drifts from
48
+ * the format should fail loudly here rather than draw nothing at runtime. One box standing on the floor, with
49
+ * the volume it takes up declared.
50
+ */
51
+ const v3AssetOf = (type: string) => ({
52
+ version: 'figure-v3-asset-1',
53
+ name: type,
54
+ document: {
55
+ version: 'figure-v3-prototype-1',
56
+ model: {
57
+ version: 'r3-spatial-1',
58
+ inputs: [],
59
+ constants: [
60
+ { id: 'w', unit: 'mm', value: 100 },
61
+ { id: 'half', unit: 'mm', value: 50 },
62
+ { id: 'minusHalf', unit: 'mm', value: -50 },
63
+ { id: 'zero', unit: 'mm', value: 0 },
64
+ { id: 'a0', unit: 'deg', value: 0 }
65
+ ],
66
+ nodes: [
67
+ { id: 'body.shape', op: 'box-shape@1', args: ['w', 'w', 'w'], outputs: { shape: 'body.s' }, params: { frame: 'body.local' } },
68
+ {
69
+ id: 'body.pose',
70
+ op: 'rigid@1',
71
+ args: ['zero', 'half', 'zero', 'a0', 'a0', 'a0'],
72
+ outputs: { pose: 'body.p' },
73
+ params: { from: 'body.local', to: 'asset' }
74
+ },
75
+ { id: 'body', op: 'place@1', args: ['body.s', 'body.p'], outputs: { placed: 'body.placed' } }
76
+ ]
77
+ },
78
+ capabilities: { version: 'r3-capability-3', assetFrame: 'asset', bindings: [] }
79
+ },
80
+ designInputs: {},
81
+ stateDefaults: {},
82
+ palette: { 'palette.primary': '#477b9e' },
83
+ appearance: [{ target: 'body', material: { token: 'palette.primary' } }],
84
+ occupancy: {
85
+ bounds: { x: { min: 'minusHalf', max: 'half' }, y: { min: 'zero', max: 'w' }, z: { min: 'minusHalf', max: 'half' } },
86
+ placement: 'floor'
87
+ }
88
+ })
89
+
90
+ const v3PayloadOf = (type: string) => ({ format: 'v3' as const, type, asset: v3AssetOf(type) })
91
+
43
92
  /** Records what was asked for, and answers from a table. */
44
93
  function fetcherOf(published: Record<string, unknown>, failing: string[] = []) {
45
94
  const asked: string[] = []
@@ -59,6 +108,7 @@ function fetcherOf(published: Record<string, unknown>, failing: string[] = []) {
59
108
  describe('figure 공급자 — 보드가 발행된 Figure 를 받는 길', () => {
60
109
  afterEach(() => {
61
110
  resetFigures()
111
+ resetFiguresV3()
62
112
  })
63
113
 
64
114
  it('대문자 이름만 서버에 묻는다 — 씬의 기본 type 과 오타는 문을 지나지 않는다', async () => {
@@ -91,6 +141,43 @@ describe('figure 공급자 — 보드가 발행된 Figure 를 받는 길', () =>
91
141
  expect(Component.register('EQ_REGISTERED')).to.not.equal(undefined)
92
142
  })
93
143
 
144
+ it('V3 자산은 V3 문으로 등록한다 — 보드는 그것을 읽지 않고 씬에 넘긴다', async () => {
145
+ const { fetch } = fetcherOf({ EQ_V3: v3PayloadOf('EQ_V3') })
146
+
147
+ await createFigureResolver(fetch)(['EQ_V3'])
148
+
149
+ expect(hasFigureV3('EQ_V3')).to.equal(true)
150
+ expect(hasFigure('EQ_V3')).to.equal(false)
151
+ /* 도면은 판을 모른다 — 두 판 다 type 하나만 적으면 그려진다. */
152
+ expect(Component.register('EQ_V3')).to.not.equal(undefined)
153
+ })
154
+
155
+ it('한 도면에 두 판이 섞여 있어도 각자의 문으로 들어간다', async () => {
156
+ const { fetch } = fetcherOf({ EQ_OLD: blueprintOf('EQ_OLD'), EQ_NEW: v3PayloadOf('EQ_NEW') })
157
+
158
+ await createFigureResolver(fetch)(['EQ_OLD', 'EQ_NEW'])
159
+
160
+ expect(hasFigure('EQ_OLD')).to.equal(true)
161
+ expect(hasFigureV3('EQ_NEW')).to.equal(true)
162
+ })
163
+
164
+ it('읽을 수 없는 V3 자산은 그 type 만 실패로 남는다', async () => {
165
+ const broken = v3PayloadOf('EQ_V3_BROKEN')
166
+ broken.asset.appearance = []
167
+ const { fetch } = fetcherOf({ EQ_BESIDE_V3: blueprintOf('EQ_BESIDE_V3'), EQ_V3_BROKEN: broken })
168
+
169
+ let message = ''
170
+ try {
171
+ await createFigureResolver(fetch)(['EQ_BESIDE_V3', 'EQ_V3_BROKEN'])
172
+ } catch (error) {
173
+ message = error instanceof Error ? error.message : String(error)
174
+ }
175
+
176
+ expect(message).to.contain('EQ_V3_BROKEN')
177
+ expect(hasFigure('EQ_BESIDE_V3')).to.equal(true)
178
+ expect(hasFigureV3('EQ_V3_BROKEN')).to.equal(false)
179
+ })
180
+
94
181
  it('발행된 것이 없으면 조용히 자리표시로 남는다 — 거절이 아니다', async () => {
95
182
  const { fetch } = fetcherOf({})
96
183