@things-factory/figure-ui 10.1.272 → 10.1.273
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/data-interface.ts +30 -18
- package/client/modeller/editor-styles.ts +17 -6
- package/client/modeller/editor.ts +2 -0
- package/client/modeller/fasten-form.ts +12 -2
- package/client/modeller/fasten-geometry.ts +5 -3
- package/client/modeller/figure-data-panel.ts +384 -200
- package/client/modeller/figure-fasten-drawing.ts +21 -13
- package/client/modeller/figure-links.ts +24 -9
- package/client/modeller/figure-parts.ts +7 -11
- package/client/modeller/figure-preview.ts +258 -76
- package/dist-client/modeller/clips.d.ts +1 -4
- package/dist-client/modeller/data-interface.d.ts +11 -8
- package/dist-client/modeller/data-interface.js +27 -17
- package/dist-client/modeller/data-interface.js.map +1 -1
- package/dist-client/modeller/editor-styles.js +17 -6
- package/dist-client/modeller/editor-styles.js.map +1 -1
- package/dist-client/modeller/editor.js +2 -0
- package/dist-client/modeller/editor.js.map +1 -1
- package/dist-client/modeller/fasten-form.d.ts +5 -0
- package/dist-client/modeller/fasten-form.js +8 -2
- package/dist-client/modeller/fasten-form.js.map +1 -1
- package/dist-client/modeller/fasten-geometry.d.ts +3 -2
- package/dist-client/modeller/fasten-geometry.js +5 -3
- package/dist-client/modeller/fasten-geometry.js.map +1 -1
- package/dist-client/modeller/figure-data-panel.d.ts +10 -19
- package/dist-client/modeller/figure-data-panel.js +382 -190
- package/dist-client/modeller/figure-data-panel.js.map +1 -1
- package/dist-client/modeller/figure-fasten-drawing.js +21 -13
- package/dist-client/modeller/figure-fasten-drawing.js.map +1 -1
- package/dist-client/modeller/figure-links.js +31 -16
- package/dist-client/modeller/figure-links.js.map +1 -1
- package/dist-client/modeller/figure-parts.js +7 -11
- package/dist-client/modeller/figure-parts.js.map +1 -1
- package/dist-client/modeller/figure-preview.d.ts +13 -0
- package/dist-client/modeller/figure-preview.js +257 -77
- package/dist-client/modeller/figure-preview.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -7
- package/test/browser/editing-page.js +1 -1
- package/test/browser/links.check.mjs +30 -0
- package/test/browser/modeller.check.mjs +2 -2
- package/test/browser/parts-page.js +4 -0
- package/test/browser/parts.check.mjs +16 -10
- package/test/browser/screen-page.js +12 -1
- package/test/browser/screen.check.mjs +142 -11
- package/test/browser/serve-response.mjs +5 -2
- package/test/browser/side-panel-sweep.check.mjs +171 -10
- package/test/data-motion.test.ts +39 -8
- package/test/fasten-form.test.ts +25 -0
- package/test/fasten-geometry.test.ts +13 -0
- package/translations/en.json +23 -11
- package/translations/es.json +22 -10
- package/translations/ja.json +22 -10
- package/translations/ko.json +24 -12
- package/translations/ms.json +22 -10
- package/translations/zh.json +22 -10
|
@@ -94,13 +94,14 @@ import { methodOf, type DataMethod } from '@things-factory/figure-viewer/dist-cl
|
|
|
94
94
|
export { methodOf, type DataMethod }
|
|
95
95
|
|
|
96
96
|
/**
|
|
97
|
-
* The methods a field allows (ADR-0166 2): a number as it is, scaled
|
|
98
|
-
*
|
|
97
|
+
* The methods a field allows (ADR-0166 2, amendment 1): a number as it is, scaled, by a code table (status codes sent as
|
|
98
|
+
* numbers, 4002) or by a range table; a text or true/false by a code table, or as it is where a behavior takes it so; a
|
|
99
|
+
* list as it is (its items). A new field is made by a table.
|
|
99
100
|
*/
|
|
100
101
|
export function methodsOf(node: FigureDataNode | null, choices: BehaviorChoice[]): DataMethod[] {
|
|
101
102
|
if (!node) return ['code', 'ranges']
|
|
102
103
|
const fitting = choices.some(c => fitsField(node, c))
|
|
103
|
-
if (node.kind === 'number') return [...(fitting ? (['value', 'scale'] as const) : []), 'ranges']
|
|
104
|
+
if (node.kind === 'number') return [...(fitting ? (['value', 'scale'] as const) : []), 'code', 'ranges']
|
|
104
105
|
if (node.kind === 'text' || node.kind === 'boolean') return [...(fitting ? (['value'] as const) : []), 'code']
|
|
105
106
|
return fitting ? ['value'] : []
|
|
106
107
|
}
|
|
@@ -170,6 +171,12 @@ export function bindingDraftOf(asset: FigureAsset, accessor: string, node: Figur
|
|
|
170
171
|
/* ---------------------------------------------------------------- tables (ADR-0166 3) */
|
|
171
172
|
|
|
172
173
|
/** The first code a new code table names, and the next ones: `CODE`, `CODE2`, … */
|
|
174
|
+
/** A new code for a number field's code table: one past the largest taken, or 0 (ADR-0166 amendment 1). */
|
|
175
|
+
export function freeNumberCodeOf(taken: string[]): string {
|
|
176
|
+
const numbers = taken.map(Number).filter(n => Number.isInteger(n) && n >= 0)
|
|
177
|
+
return String(numbers.length ? Math.max(...numbers) + 1 : 0)
|
|
178
|
+
}
|
|
179
|
+
|
|
173
180
|
export function freeCodeOf(taken: string[]): string {
|
|
174
181
|
if (!taken.includes('CODE')) return 'CODE'
|
|
175
182
|
let n = 2
|
|
@@ -186,28 +193,26 @@ export const legendRoleOf = (id: string): string =>
|
|
|
186
193
|
|
|
187
194
|
/**
|
|
188
195
|
* A first table on a field (ADR-0166 10): a row per value of a closed field, an open field's rows typed later, one
|
|
189
|
-
* interval over the whole of a number.
|
|
190
|
-
* table's keys, starting with one code; a range table's a number. Returns the binding and, for a new field, the schema
|
|
191
|
-
* with it.
|
|
196
|
+
* interval over the whole of a number. The field is one the schema has: the data tab adds a binding in the field's row.
|
|
192
197
|
*/
|
|
193
198
|
export function tableDraftOf(
|
|
194
199
|
asset: FigureAsset,
|
|
195
|
-
field: { path: string; node: FigureDataNode }
|
|
200
|
+
field: { path: string; node: FigureDataNode },
|
|
196
201
|
method: 'code' | 'ranges',
|
|
197
202
|
targets: FigureDataTargets
|
|
198
|
-
): { binding: FigureDataTableBinding
|
|
203
|
+
): { binding: FigureDataTableBinding } {
|
|
199
204
|
const taken = (asset.dataInterface?.bindings ?? []).map(b => b.id)
|
|
200
|
-
const
|
|
201
|
-
const name = made ? field.name : (field.path.replace(/\[\]/g, '').split('.').pop() ?? field.path)
|
|
205
|
+
const name = field.path.replace(/\[\]/g, '').split('.').pop() ?? field.path
|
|
202
206
|
const id = freeIdOf(taken, name.toLowerCase())
|
|
203
|
-
const node
|
|
204
|
-
const accessor =
|
|
207
|
+
const node = field.node
|
|
208
|
+
const accessor = accessorOfRow(field.path)
|
|
205
209
|
const table: Record<string, FigureDataTableEntry> =
|
|
206
|
-
method === 'code'
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
210
|
+
method === 'code'
|
|
211
|
+
? node.kind === 'number'
|
|
212
|
+
? { [freeNumberCodeOf([])]: {} }
|
|
213
|
+
: Object.fromEntries(domainOf(node).map(v => [String(v), {}]))
|
|
214
|
+
: { [`${node.kind === 'number' ? (node.min ?? '') : ''}~`]: {} }
|
|
215
|
+
return { binding: { id, accessor, rule: 'table', lookup: method, targets: tidyTargets(targets), table } }
|
|
211
216
|
}
|
|
212
217
|
|
|
213
218
|
/** Targets with empty lists left out, as the kernel keeps them. */
|
|
@@ -217,8 +222,9 @@ const tidyTargets = (t: FigureDataTargets): FigureDataTargets => ({
|
|
|
217
222
|
...(t.group ? { group: t.group } : {})
|
|
218
223
|
})
|
|
219
224
|
|
|
220
|
-
/** A look with only the columns its targets take: a target taken away takes its columns with it. */
|
|
225
|
+
/** A look with only the columns its targets take: a target taken away takes its columns with it. A look that keeps stays so. */
|
|
221
226
|
function lookFor(look: FigureDataTableEntry, t: FigureDataTargets): FigureDataTableEntry {
|
|
227
|
+
if (look.keep) return { keep: true }
|
|
222
228
|
const out: FigureDataTableEntry = {}
|
|
223
229
|
if (t.parts?.length) {
|
|
224
230
|
if (look.color !== undefined) out.color = look.color
|
|
@@ -245,6 +251,12 @@ export function tableWithTargets(b: FigureDataTableBinding, targets: FigureDataT
|
|
|
245
251
|
/** The table with one look set: the whole look given, a column left out cleared. */
|
|
246
252
|
export const tableWithLook = (b: FigureDataTableBinding, key: string, look: FigureDataTableEntry): FigureDataTableBinding => ({ ...b, table: { ...b.table, [key]: lookFor(look, b.targets) } })
|
|
247
253
|
|
|
254
|
+
/**
|
|
255
|
+
* The table whose other values keep what it last showed, or go to the default look (an empty one): the 「그대로 둠」 of
|
|
256
|
+
* the 「그 밖의 값」 row (ADR-0166 amendment 1).
|
|
257
|
+
*/
|
|
258
|
+
export const tableWithKeep = (b: FigureDataTableBinding, keep: boolean): FigureDataTableBinding => ({ ...b, table: { ...b.table, default: keep ? { keep: true } : {} } })
|
|
259
|
+
|
|
248
260
|
/** The table's rows renamed, added or taken away, in order; `default` kept last. */
|
|
249
261
|
export function tableWithKeys(b: FigureDataTableBinding, rows: Array<[string, FigureDataTableEntry]>): FigureDataTableBinding {
|
|
250
262
|
const d = b.table.default
|
|
@@ -411,14 +411,25 @@ export const EditorStyles = css`
|
|
|
411
411
|
z-index: 2;
|
|
412
412
|
display: grid;
|
|
413
413
|
gap: 4px;
|
|
414
|
-
padding:
|
|
415
|
-
|
|
416
|
-
|
|
414
|
+
padding: 6px 12px;
|
|
415
|
+
/* Solid where a theme gives no colour: a sticky line with none let the rows scrolled under it show through. */
|
|
416
|
+
background: var(--md-sys-color-surface-container-lowest, #fff);
|
|
417
|
+
border-bottom: 1px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, 0.12));
|
|
417
418
|
}
|
|
418
|
-
/*
|
|
419
|
+
/*
|
|
420
|
+
The part's name and its kind on one line: two lines on every tab, over a name field saying it again on the
|
|
421
|
+
properties tab, took the panel's top (user 2026-11-12).
|
|
422
|
+
*/
|
|
419
423
|
div[subject-summary] {
|
|
420
|
-
display:
|
|
421
|
-
|
|
424
|
+
display: flex;
|
|
425
|
+
align-items: baseline;
|
|
426
|
+
gap: 6px;
|
|
427
|
+
min-width: 0;
|
|
428
|
+
}
|
|
429
|
+
div[subject-summary] > * {
|
|
430
|
+
overflow: hidden;
|
|
431
|
+
white-space: nowrap;
|
|
432
|
+
text-overflow: ellipsis;
|
|
422
433
|
}
|
|
423
434
|
div[subject-summary] b {
|
|
424
435
|
font-size: var(--ui-t-body, 13px);
|
|
@@ -2215,6 +2215,8 @@ export class FigureEditor extends LitElement {
|
|
|
2215
2215
|
.asset=${asset}
|
|
2216
2216
|
.selected=${this.selected}
|
|
2217
2217
|
?locked=${unavailable}
|
|
2218
|
+
?previewing=${this.middle === 'preview'}
|
|
2219
|
+
@show-preview=${() => (this.middle = 'preview')}
|
|
2218
2220
|
@data-sample=${(e: CustomEvent) => (this.dataSample = e.detail.data)}
|
|
2219
2221
|
@legend-sample=${(e: CustomEvent) => (this.legendSample = e.detail.legends)}
|
|
2220
2222
|
@part-edit=${(e: CustomEvent) => this.run(() => this.session!.edit(e.detail.edit))}
|
|
@@ -51,6 +51,11 @@ export interface FastenForm {
|
|
|
51
51
|
alignInput: Partial<Record<Axis, string>>
|
|
52
52
|
/** On a point of the target's curved surface instead of a face (ADR-0140 3.9): where, as the record says it. */
|
|
53
53
|
surface?: FigureSurfacePlace
|
|
54
|
+
/**
|
|
55
|
+
* Opened on the part's own fastening: aimed again, it goes there with that fastening's gap and place across the face
|
|
56
|
+
* (tutorial 2026-11-12). 「현재 상태로 붙이기」 -- where it stands kept -- is a loose part's.
|
|
57
|
+
*/
|
|
58
|
+
fastened?: boolean
|
|
54
59
|
}
|
|
55
60
|
|
|
56
61
|
export const freshFasten = (): FastenForm => ({
|
|
@@ -73,8 +78,12 @@ export function fastenFormOf(revision: FigureRevision, part: string): FastenForm
|
|
|
73
78
|
/* A part still where it was added was put nowhere by the author: fastened, it goes on the face, no gap to keep. */
|
|
74
79
|
return addedUnplaced(revision, part) ? { ...freshFasten(), gapFrom: 'pressed' } : freshFasten()
|
|
75
80
|
}
|
|
76
|
-
/*
|
|
77
|
-
|
|
81
|
+
/*
|
|
82
|
+
Its fastening is the author's, gap and place: aimed at another face or part through 「바꾸기」 it goes there with them
|
|
83
|
+
(tutorial 2026-11-12: a pillar copied from the front one and turned to the body's back face stayed in front, its gap
|
|
84
|
+
worked out as the whole body's depth).
|
|
85
|
+
*/
|
|
86
|
+
return { ...freshFasten(), ...own, gapFrom: 'typed', fastened: true } as FastenForm
|
|
78
87
|
}
|
|
79
88
|
|
|
80
89
|
/** A part fastened to nothing that still stands where the palette put it: the author has put it nowhere to keep. */
|
|
@@ -195,6 +204,7 @@ export function aimFasten(
|
|
|
195
204
|
* arm aimed at the body's side stood off the face, out of reach of the drawing).
|
|
196
205
|
*/
|
|
197
206
|
const centred = { align: {}, alignMm: {}, alignInput: {} }
|
|
207
|
+
if (f.fastened) return f
|
|
198
208
|
return { ...f, ...(aim && !addedUnplaced(revision, part) ? placeKeptOf(revision, part, aim) : centred) }
|
|
199
209
|
}
|
|
200
210
|
|
|
@@ -188,8 +188,10 @@ export function fastenLabelsOf(
|
|
|
188
188
|
/**
|
|
189
189
|
* How much of an axis the face drawing shows, mm: room around the face for the part to go past its edges by about half
|
|
190
190
|
* itself, and for a part bigger than the face lined up with one of its edges (a mast flush with a low body's bottom) to
|
|
191
|
-
* show whole; a plane with no size, three parts wide.
|
|
191
|
+
* show whole; a plane with no size, three parts wide. A part standing `at` mm off the centre is reached too, its far
|
|
192
|
+
* edge inside (roll cradle tutorial 2026-11-12: a box left far up had its size label cut off the drawing).
|
|
192
193
|
*/
|
|
193
|
-
export function drawingSpanOf(face: number | undefined, part: number): number {
|
|
194
|
-
|
|
194
|
+
export function drawingSpanOf(face: number | undefined, part: number, at = 0): number {
|
|
195
|
+
const room = face !== undefined ? Math.max(face + part, 2 * part - face) : part * 3
|
|
196
|
+
return Math.max(room, 2 * Math.abs(at) + part)
|
|
195
197
|
}
|