@things-factory/figure-ui 10.1.167 → 10.1.169
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/figure-assistant.ts +15 -1
- package/client/modeller/ai-proposal.ts +60 -11
- package/client/modeller/figure-properties.ts +1 -3
- package/client/modeller/product-session.ts +32 -13
- package/client/modeller/refusals.ts +14 -0
- package/client/pages/figure-modeller-page.ts +14 -10
- package/dist-client/figure-assistant.d.ts +6 -0
- package/dist-client/figure-assistant.js +14 -1
- package/dist-client/figure-assistant.js.map +1 -1
- package/dist-client/modeller/ai-proposal.d.ts +23 -5
- package/dist-client/modeller/ai-proposal.js +55 -13
- package/dist-client/modeller/ai-proposal.js.map +1 -1
- package/dist-client/modeller/clips.d.ts +1 -1
- package/dist-client/modeller/figure-properties.d.ts +1 -2
- package/dist-client/modeller/figure-properties.js +1 -3
- package/dist-client/modeller/figure-properties.js.map +1 -1
- package/dist-client/modeller/product-session.d.ts +14 -4
- package/dist-client/modeller/product-session.js +31 -13
- package/dist-client/modeller/product-session.js.map +1 -1
- package/dist-client/modeller/refusals.d.ts +1 -5
- package/dist-client/modeller/refusals.js +14 -1
- package/dist-client/modeller/refusals.js.map +1 -1
- package/dist-client/pages/figure-modeller-page.js +14 -9
- package/dist-client/pages/figure-modeller-page.js.map +1 -1
- package/dist-client/route.d.ts +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/package.json +7 -7
- package/test/ai-proposal.test.ts +115 -5
- package/test/browser/acceptance-page.js +3 -1
- package/test/browser/product-page.check.mjs +63 -3
- package/test/browser/product-page.js +7 -2
- package/test/figure-assistant-surface.test.ts +65 -1
- package/test/proposal-record.test.ts +18 -6
- package/translations/en.json +6 -12
- package/translations/es.json +6 -12
- package/translations/ja.json +6 -12
- package/translations/ko.json +6 -12
- package/translations/ms.json +6 -12
- package/translations/zh.json +6 -12
- package/client/modeller/carrier-declaration.ts +0 -63
- package/client/modeller/figure-carrier.ts +0 -117
- package/dist-client/modeller/carrier-declaration.d.ts +0 -31
- package/dist-client/modeller/carrier-declaration.js +0 -53
- package/dist-client/modeller/carrier-declaration.js.map +0 -1
- package/dist-client/modeller/figure-carrier.d.ts +0 -26
- package/dist-client/modeller/figure-carrier.js +0 -123
- package/dist-client/modeller/figure-carrier.js.map +0 -1
- package/test/carrier-declaration.test.ts +0 -69
package/translations/ms.json
CHANGED
|
@@ -712,6 +712,7 @@
|
|
|
712
712
|
"figure.text.proposal-applied": "{n} arahan digunakan sebagai satu langkah.",
|
|
713
713
|
"figure.text.proposal-saved-into": "Disimpan ke dalam: {names}",
|
|
714
714
|
"figure.text.proposal-needs-modeller": "cadangan ini hanya boleh digunakan semasa rajahnya dibuka dalam pemodel.",
|
|
715
|
+
"figure.text.proposal-empty": "cadangan ini tiada arahan, jadi tiada apa-apa digunakan. minta sekali lagi.",
|
|
715
716
|
"figure.text.proposal-new-figure-unsaved": "rajah baharu sedang dibuat, jadi cadangan tidak digunakan. simpan atau buang dahulu, kemudian jalankan semula.",
|
|
716
717
|
"figure.text.proposal-not-opened": "rajah baharu tidak dapat dibuka dalam pemodel, jadi cadangan tidak digunakan.",
|
|
717
718
|
"figure.text.proposal-refused": "pemodel tidak menggunakan cadangan: {reason}",
|
|
@@ -754,6 +755,11 @@
|
|
|
754
755
|
"figure.text.removal-bindings": "{places} turut dipadam.",
|
|
755
756
|
"figure.text.removal-mounting-face": "Muka pemasangan dilepaskan.",
|
|
756
757
|
"figure.text.edit-refused": "Suntingan ini tidak boleh dibuat. ({code})",
|
|
758
|
+
"figure.text.session-not-open": "buka model terlebih dahulu.",
|
|
759
|
+
"figure.text.session-saving": "tunggu sehingga simpanan selesai, kemudian sunting.",
|
|
760
|
+
"figure.text.session-version-missing": "suntingan AI memerlukan versi model semasa ia diminta.",
|
|
761
|
+
"figure.text.session-new-figure-touched": "ini hanya boleh digunakan pada model baharu yang belum disunting.",
|
|
762
|
+
"figure.text.session-proposal-key": "pengecam cadangan tidak sah.",
|
|
757
763
|
"figure.text.edit-refused-node-limit": "Rajah terlalu besar untuk ditambah. Ia memuatkan sehingga {max} nod.",
|
|
758
764
|
"figure.text.document-too-large": "Rajah ini {at} KiB, melebihi had simpanan {max} KiB.",
|
|
759
765
|
"figure.text.document-too-large-unmeasured": "Rajah ini melebihi had simpanan {max} KiB.",
|
|
@@ -973,18 +979,6 @@
|
|
|
973
979
|
"figure.text.detail-unreleased": "Belum diterbitkan. Draf yang disimpan dipaparkan.",
|
|
974
980
|
"figure.button.detail-edit": "Buka editor",
|
|
975
981
|
"figure.button.download-package": "muat turun pakej",
|
|
976
|
-
"figure.label.group-carrier": "Pembawa",
|
|
977
|
-
"figure.label.carrier-type": "Jenis pembawa",
|
|
978
|
-
"figure.text.carrier-type-placeholder": "CARRIERTYPE",
|
|
979
|
-
"figure.label.carrier-size": "Saiz fizikal",
|
|
980
|
-
"figure.label.carrier-width": "Lebar",
|
|
981
|
-
"figure.label.carrier-length": "Panjang",
|
|
982
|
-
"figure.label.carrier-height": "Tinggi",
|
|
983
|
-
"figure.button.declare-carrier": "Isytihar pembawa",
|
|
984
|
-
"figure.button.clear-carrier": "Kosongkan",
|
|
985
|
-
"figure.text.carrier-type-required": "Masukkan kod jenis pembawa.",
|
|
986
|
-
"figure.text.carrier-type-too-long": "Kod jenis pembawa paling banyak {max} aksara.",
|
|
987
|
-
"figure.text.carrier-length-positive": "{axis} mesti lebih besar daripada 0.",
|
|
988
982
|
"figure.button.import-mesh": "import GLB",
|
|
989
983
|
"figure.text.import-mesh-hint": "membawa masuk fail GLB sebagai bahagian: seluruh fail, atau satu bahagian daripadanya.",
|
|
990
984
|
"figure.text.mesh-whole-file": "seluruh fail",
|
package/translations/zh.json
CHANGED
|
@@ -712,6 +712,7 @@
|
|
|
712
712
|
"figure.text.proposal-applied": "已将 {n} 条命令作为一步应用。",
|
|
713
713
|
"figure.text.proposal-saved-into": "已保存到图形: {names}",
|
|
714
714
|
"figure.text.proposal-needs-modeller": "只有在建模器中打开该图形时才能应用此提案。",
|
|
715
|
+
"figure.text.proposal-empty": "此提案没有任何命令,因此未应用。请重新请求。",
|
|
715
716
|
"figure.text.proposal-new-figure-unsaved": "正在制作一个新图形,因此未应用该提案。请保存或放弃后再运行。",
|
|
716
717
|
"figure.text.proposal-not-opened": "无法在建模器中打开新图形,因此未应用该提案。",
|
|
717
718
|
"figure.text.proposal-refused": "建模器未应用该提案:{reason}",
|
|
@@ -754,6 +755,11 @@
|
|
|
754
755
|
"figure.text.removal-bindings": "{places} 也一并删除。",
|
|
755
756
|
"figure.text.removal-mounting-face": "安装面已解除。",
|
|
756
757
|
"figure.text.edit-refused": "无法进行此编辑。({code})",
|
|
758
|
+
"figure.text.session-not-open": "请先正常打开模型。",
|
|
759
|
+
"figure.text.session-saving": "请在保存完成后再编辑。",
|
|
760
|
+
"figure.text.session-version-missing": "AI 编辑需要提出请求时的模型版本。",
|
|
761
|
+
"figure.text.session-new-figure-touched": "只能用于尚未编辑的新模型。",
|
|
762
|
+
"figure.text.session-proposal-key": "提案标识符无效。",
|
|
757
763
|
"figure.text.edit-refused-node-limit": "图形过大,无法再添加。节点上限为 {max} 个。",
|
|
758
764
|
"figure.text.document-too-large": "图形为 {at} KiB,超过可保存的上限 {max} KiB。",
|
|
759
765
|
"figure.text.document-too-large-unmeasured": "图形超过可保存的上限 {max} KiB。",
|
|
@@ -973,18 +979,6 @@
|
|
|
973
979
|
"figure.text.detail-unreleased": "尚未发布。显示已保存的草稿。",
|
|
974
980
|
"figure.button.detail-edit": "打开编辑页面",
|
|
975
981
|
"figure.button.download-package": "下载包",
|
|
976
|
-
"figure.label.group-carrier": "载具",
|
|
977
|
-
"figure.label.carrier-type": "载具类型",
|
|
978
|
-
"figure.text.carrier-type-placeholder": "CARRIERTYPE",
|
|
979
|
-
"figure.label.carrier-size": "实物尺寸",
|
|
980
|
-
"figure.label.carrier-width": "宽",
|
|
981
|
-
"figure.label.carrier-length": "长",
|
|
982
|
-
"figure.label.carrier-height": "高",
|
|
983
|
-
"figure.button.declare-carrier": "声明为载具",
|
|
984
|
-
"figure.button.clear-carrier": "取消声明",
|
|
985
|
-
"figure.text.carrier-type-required": "请输入载具类型代码。",
|
|
986
|
-
"figure.text.carrier-type-too-long": "载具类型代码最多 {max} 个字符。",
|
|
987
|
-
"figure.text.carrier-length-positive": "{axis}必须大于 0。",
|
|
988
982
|
"figure.button.import-mesh": "导入 GLB",
|
|
989
983
|
"figure.text.import-mesh-hint": "将 GLB 文件导入为部件:整个文件,或其中的一部分。",
|
|
990
984
|
"figure.text.mesh-whole-file": "整个文件",
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* A figure that is a carrier type declares so (ADR-0123): the CARRIERTYPE code a material handling system reports, and
|
|
3
|
-
* the carrier's physical size in mm. Kept apart from the element so it is tested without a browser.
|
|
4
|
-
*
|
|
5
|
-
* The rule is figure-model's (`carrierDeclarationRefusal`); the field asks it before sending `set-carrier`, so a value
|
|
6
|
-
* the kernel refuses is said beside the field and never becomes a step of the history. The size is what the author
|
|
7
|
-
* types, never read off the occupied room.
|
|
8
|
-
*/
|
|
9
|
-
import { carrierDeclarationRefusal, FIGURE_CARRIER_TYPE_MAX, normalizeCarrierType, type FigureAsset, type FigureAuthoringAction } from '@hatiolab/figure-model'
|
|
10
|
-
|
|
11
|
-
type Say = (key: string, params: Record<string, string>) => string
|
|
12
|
-
type Declaration = NonNullable<FigureAsset['carrier']>
|
|
13
|
-
|
|
14
|
-
export const CARRIER_AXES = ['width', 'length', 'height'] as const
|
|
15
|
-
export type CarrierAxis = (typeof CARRIER_AXES)[number]
|
|
16
|
-
|
|
17
|
-
/** What the field holds while the author types: the code and the three lengths as typed. */
|
|
18
|
-
export type CarrierDraft = { type: string } & Record<CarrierAxis, string>
|
|
19
|
-
|
|
20
|
-
/** The field's values for a declaration, or blank for a figure that declares none. */
|
|
21
|
-
export function carrierDraftOf(carrier?: Declaration): CarrierDraft {
|
|
22
|
-
return {
|
|
23
|
-
type: carrier?.type ?? '',
|
|
24
|
-
width: carrier ? String(carrier.dimensions.width) : '',
|
|
25
|
-
length: carrier ? String(carrier.dimensions.length) : '',
|
|
26
|
-
height: carrier ? String(carrier.dimensions.height) : ''
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/** Whether the field says what is declared already: nothing to send. */
|
|
31
|
-
export function draftIsDeclared(draft: CarrierDraft, carrier?: Declaration): boolean {
|
|
32
|
-
const declared = carrierDraftOf(carrier)
|
|
33
|
-
return normalizeCarrierType(draft.type) === declared.type && CARRIER_AXES.every(axis => Object.is(lengthOf(draft[axis]), lengthOf(declared[axis])))
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/** A typed length as a number; blank is no length. */
|
|
37
|
-
const lengthOf = (typed: string) => (typed.trim() === '' ? Number.NaN : Number(typed))
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* The `set-carrier` command for what the field holds, or why the kernel would refuse it in the author's words. The
|
|
41
|
-
* code is sent as the kernel stores it (trimmed, upper case).
|
|
42
|
-
*/
|
|
43
|
-
export function carrierCommandOf(draft: CarrierDraft, say: Say): { action: FigureAuthoringAction } | { refusal: string } {
|
|
44
|
-
const carrier = {
|
|
45
|
-
type: normalizeCarrierType(draft.type),
|
|
46
|
-
dimensions: { width: lengthOf(draft.width), length: lengthOf(draft.length), height: lengthOf(draft.height) }
|
|
47
|
-
}
|
|
48
|
-
const refused = carrierDeclarationRefusal(carrier)
|
|
49
|
-
if (refused) return { refusal: carrierRefusalOf(refused, carrier.type, say) }
|
|
50
|
-
return { action: { kind: 'set-carrier', carrier } }
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* A carrier declaration refused, said from its code and path (ADR-0127): the code missing or too long, or the length
|
|
55
|
-
* the path names. The kernel's English is never shown; a code the field has no words for is said with the code.
|
|
56
|
-
*/
|
|
57
|
-
export function carrierRefusalOf(refused: { code: string; path: string }, type: string, say: Say): string {
|
|
58
|
-
if (refused.code === 'CARRIER_TYPE')
|
|
59
|
-
return type ? say('figure.text.carrier-type-too-long', { max: String(FIGURE_CARRIER_TYPE_MAX) }) : say('figure.text.carrier-type-required', {})
|
|
60
|
-
const axis = CARRIER_AXES.find(one => refused.path.endsWith(`.${one}`))
|
|
61
|
-
if (refused.code === 'CARRIER_DIMENSIONS' && axis) return say('figure.text.carrier-length-positive', { axis: say(`figure.label.carrier-${axis}`, {}) })
|
|
62
|
-
return say('figure.text.edit-refused', { code: refused.code })
|
|
63
|
-
}
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import { css, html, LitElement, nothing, type PropertyValues } from 'lit'
|
|
2
|
-
import { customElement, property, state } from 'lit/decorators.js'
|
|
3
|
-
import { live } from 'lit/directives/live.js'
|
|
4
|
-
|
|
5
|
-
import { i18next, localize } from '@operato/i18n'
|
|
6
|
-
import type { FigureAsset, FigureAuthoringAction } from '@hatiolab/figure-model'
|
|
7
|
-
|
|
8
|
-
import { CARRIER_AXES, carrierCommandOf, carrierDraftOf, draftIsDeclared, type CarrierAxis, type CarrierDraft } from './carrier-declaration.js'
|
|
9
|
-
import { SidePanelStyles } from '@things-factory/figure-viewer/dist-client/side-panel-styles.js'
|
|
10
|
-
|
|
11
|
-
const AXIS_LETTER: Record<CarrierAxis, string> = { width: 'W', length: 'L', height: 'H' }
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* 캐리어 — the CARRIERTYPE code and physical size a carrier figure declares (ADR-0123), in the properties tab.
|
|
15
|
-
*
|
|
16
|
-
* Declaring and clearing are `set-carrier` commands, sent up as `command` like the tab's others, so the page runs them as
|
|
17
|
-
* steps of the session's history: undo takes them back and they are saved with the figure. A value the kernel refuses
|
|
18
|
-
* is said here and sends nothing.
|
|
19
|
-
*/
|
|
20
|
-
@customElement('figure-carrier')
|
|
21
|
-
export class FigureCarrier extends localize(i18next)(LitElement) {
|
|
22
|
-
static styles = [SidePanelStyles, css`
|
|
23
|
-
div[row] {
|
|
24
|
-
display: flex;
|
|
25
|
-
gap: 6px;
|
|
26
|
-
}
|
|
27
|
-
div[row] > button[act] {
|
|
28
|
-
flex: 1;
|
|
29
|
-
margin-top: 0;
|
|
30
|
-
}
|
|
31
|
-
small[role='alert'] {
|
|
32
|
-
color: var(--md-sys-color-error);
|
|
33
|
-
}
|
|
34
|
-
`]
|
|
35
|
-
|
|
36
|
-
/** What the figure on screen declares; absent when it is not a carrier type. */
|
|
37
|
-
@property({ attribute: false }) carrier?: FigureAsset['carrier']
|
|
38
|
-
@state() private draft: CarrierDraft = carrierDraftOf()
|
|
39
|
-
@state() private refusal = ''
|
|
40
|
-
/* The declaration the field was last filled from: other edits draw the tab again and must not wipe what is being typed. */
|
|
41
|
-
private filledFrom?: string
|
|
42
|
-
|
|
43
|
-
willUpdate(changed: PropertyValues<this>) {
|
|
44
|
-
if (!changed.has('carrier')) return
|
|
45
|
-
const declared = JSON.stringify(this.carrier ?? null)
|
|
46
|
-
if (declared === this.filledFrom) return
|
|
47
|
-
this.filledFrom = declared
|
|
48
|
-
this.draft = carrierDraftOf(this.carrier)
|
|
49
|
-
this.refusal = ''
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
render() {
|
|
53
|
-
const pending = !draftIsDeclared(this.draft, this.carrier)
|
|
54
|
-
return html`<section>
|
|
55
|
-
<h3>${i18next.t('figure.label.group-carrier')}</h3>
|
|
56
|
-
<div field>
|
|
57
|
-
<label for="carrier-type">${i18next.t('figure.label.carrier-type')}</label>
|
|
58
|
-
<input
|
|
59
|
-
id="carrier-type"
|
|
60
|
-
.value=${live(this.draft.type)}
|
|
61
|
-
placeholder=${i18next.t('figure.text.carrier-type-placeholder')}
|
|
62
|
-
@input=${(e: Event) => this.type('type', e)}
|
|
63
|
-
@keydown=${this.enter}
|
|
64
|
-
/>
|
|
65
|
-
</div>
|
|
66
|
-
<div vector-row>
|
|
67
|
-
<label>${i18next.t('figure.label.carrier-size')} <span unit>mm</span></label>
|
|
68
|
-
<div triple>
|
|
69
|
-
${CARRIER_AXES.map(
|
|
70
|
-
axis => html`<div cell>
|
|
71
|
-
<span axis>${AXIS_LETTER[axis]}</span>
|
|
72
|
-
<input
|
|
73
|
-
type="number"
|
|
74
|
-
min="0"
|
|
75
|
-
step="any"
|
|
76
|
-
aria-label=${i18next.t(`figure.label.carrier-${axis}`)}
|
|
77
|
-
.value=${live(this.draft[axis])}
|
|
78
|
-
@input=${(e: Event) => this.type(axis, e)}
|
|
79
|
-
@keydown=${this.enter}
|
|
80
|
-
/>
|
|
81
|
-
</div>`
|
|
82
|
-
)}
|
|
83
|
-
</div>
|
|
84
|
-
</div>
|
|
85
|
-
${this.refusal ? html`<small role="alert">${this.refusal}</small>` : nothing}
|
|
86
|
-
<div row>
|
|
87
|
-
<button act ?disabled=${!pending} @click=${this.declare}>
|
|
88
|
-
<md-icon>check</md-icon>${i18next.t('figure.button.declare-carrier')}
|
|
89
|
-
</button>
|
|
90
|
-
<button act ?disabled=${!this.carrier} @click=${this.clear}>
|
|
91
|
-
<md-icon>close</md-icon>${i18next.t('figure.button.clear-carrier')}
|
|
92
|
-
</button>
|
|
93
|
-
</div>
|
|
94
|
-
</section>`
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
private type(key: keyof CarrierDraft, event: Event) {
|
|
98
|
-
this.draft = { ...this.draft, [key]: (event.target as HTMLInputElement).value }
|
|
99
|
-
this.refusal = ''
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
private enter = (event: KeyboardEvent) => {
|
|
103
|
-
if (event.key === 'Enter' && !draftIsDeclared(this.draft, this.carrier)) this.declare()
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
private declare = () => {
|
|
107
|
-
const made = carrierCommandOf(this.draft, (key, params) => i18next.t(key, params))
|
|
108
|
-
if ('refusal' in made) this.refusal = made.refusal
|
|
109
|
-
else this.command(made.action)
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
private clear = () => this.command({ kind: 'set-carrier', carrier: null })
|
|
113
|
-
|
|
114
|
-
private command(action: FigureAuthoringAction) {
|
|
115
|
-
this.dispatchEvent(new CustomEvent('command', { detail: { action }, bubbles: true, composed: true }))
|
|
116
|
-
}
|
|
117
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { type FigureAsset, type FigureAuthoringAction } from '@hatiolab/figure-model';
|
|
2
|
-
type Say = (key: string, params: Record<string, string>) => string;
|
|
3
|
-
type Declaration = NonNullable<FigureAsset['carrier']>;
|
|
4
|
-
export declare const CARRIER_AXES: readonly ["width", "length", "height"];
|
|
5
|
-
export type CarrierAxis = (typeof CARRIER_AXES)[number];
|
|
6
|
-
/** What the field holds while the author types: the code and the three lengths as typed. */
|
|
7
|
-
export type CarrierDraft = {
|
|
8
|
-
type: string;
|
|
9
|
-
} & Record<CarrierAxis, string>;
|
|
10
|
-
/** The field's values for a declaration, or blank for a figure that declares none. */
|
|
11
|
-
export declare function carrierDraftOf(carrier?: Declaration): CarrierDraft;
|
|
12
|
-
/** Whether the field says what is declared already: nothing to send. */
|
|
13
|
-
export declare function draftIsDeclared(draft: CarrierDraft, carrier?: Declaration): boolean;
|
|
14
|
-
/**
|
|
15
|
-
* The `set-carrier` command for what the field holds, or why the kernel would refuse it in the author's words. The
|
|
16
|
-
* code is sent as the kernel stores it (trimmed, upper case).
|
|
17
|
-
*/
|
|
18
|
-
export declare function carrierCommandOf(draft: CarrierDraft, say: Say): {
|
|
19
|
-
action: FigureAuthoringAction;
|
|
20
|
-
} | {
|
|
21
|
-
refusal: string;
|
|
22
|
-
};
|
|
23
|
-
/**
|
|
24
|
-
* A carrier declaration refused, said from its code and path (ADR-0127): the code missing or too long, or the length
|
|
25
|
-
* the path names. The kernel's English is never shown; a code the field has no words for is said with the code.
|
|
26
|
-
*/
|
|
27
|
-
export declare function carrierRefusalOf(refused: {
|
|
28
|
-
code: string;
|
|
29
|
-
path: string;
|
|
30
|
-
}, type: string, say: Say): string;
|
|
31
|
-
export {};
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* A figure that is a carrier type declares so (ADR-0123): the CARRIERTYPE code a material handling system reports, and
|
|
3
|
-
* the carrier's physical size in mm. Kept apart from the element so it is tested without a browser.
|
|
4
|
-
*
|
|
5
|
-
* The rule is figure-model's (`carrierDeclarationRefusal`); the field asks it before sending `set-carrier`, so a value
|
|
6
|
-
* the kernel refuses is said beside the field and never becomes a step of the history. The size is what the author
|
|
7
|
-
* types, never read off the occupied room.
|
|
8
|
-
*/
|
|
9
|
-
import { carrierDeclarationRefusal, FIGURE_CARRIER_TYPE_MAX, normalizeCarrierType } from '@hatiolab/figure-model';
|
|
10
|
-
export const CARRIER_AXES = ['width', 'length', 'height'];
|
|
11
|
-
/** The field's values for a declaration, or blank for a figure that declares none. */
|
|
12
|
-
export function carrierDraftOf(carrier) {
|
|
13
|
-
return {
|
|
14
|
-
type: carrier?.type ?? '',
|
|
15
|
-
width: carrier ? String(carrier.dimensions.width) : '',
|
|
16
|
-
length: carrier ? String(carrier.dimensions.length) : '',
|
|
17
|
-
height: carrier ? String(carrier.dimensions.height) : ''
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
/** Whether the field says what is declared already: nothing to send. */
|
|
21
|
-
export function draftIsDeclared(draft, carrier) {
|
|
22
|
-
const declared = carrierDraftOf(carrier);
|
|
23
|
-
return normalizeCarrierType(draft.type) === declared.type && CARRIER_AXES.every(axis => Object.is(lengthOf(draft[axis]), lengthOf(declared[axis])));
|
|
24
|
-
}
|
|
25
|
-
/** A typed length as a number; blank is no length. */
|
|
26
|
-
const lengthOf = (typed) => (typed.trim() === '' ? Number.NaN : Number(typed));
|
|
27
|
-
/**
|
|
28
|
-
* The `set-carrier` command for what the field holds, or why the kernel would refuse it in the author's words. The
|
|
29
|
-
* code is sent as the kernel stores it (trimmed, upper case).
|
|
30
|
-
*/
|
|
31
|
-
export function carrierCommandOf(draft, say) {
|
|
32
|
-
const carrier = {
|
|
33
|
-
type: normalizeCarrierType(draft.type),
|
|
34
|
-
dimensions: { width: lengthOf(draft.width), length: lengthOf(draft.length), height: lengthOf(draft.height) }
|
|
35
|
-
};
|
|
36
|
-
const refused = carrierDeclarationRefusal(carrier);
|
|
37
|
-
if (refused)
|
|
38
|
-
return { refusal: carrierRefusalOf(refused, carrier.type, say) };
|
|
39
|
-
return { action: { kind: 'set-carrier', carrier } };
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* A carrier declaration refused, said from its code and path (ADR-0127): the code missing or too long, or the length
|
|
43
|
-
* the path names. The kernel's English is never shown; a code the field has no words for is said with the code.
|
|
44
|
-
*/
|
|
45
|
-
export function carrierRefusalOf(refused, type, say) {
|
|
46
|
-
if (refused.code === 'CARRIER_TYPE')
|
|
47
|
-
return type ? say('figure.text.carrier-type-too-long', { max: String(FIGURE_CARRIER_TYPE_MAX) }) : say('figure.text.carrier-type-required', {});
|
|
48
|
-
const axis = CARRIER_AXES.find(one => refused.path.endsWith(`.${one}`));
|
|
49
|
-
if (refused.code === 'CARRIER_DIMENSIONS' && axis)
|
|
50
|
-
return say('figure.text.carrier-length-positive', { axis: say(`figure.label.carrier-${axis}`, {}) });
|
|
51
|
-
return say('figure.text.edit-refused', { code: refused.code });
|
|
52
|
-
}
|
|
53
|
-
//# sourceMappingURL=carrier-declaration.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"carrier-declaration.js","sourceRoot":"","sources":["../../client/modeller/carrier-declaration.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,yBAAyB,EAAE,uBAAuB,EAAE,oBAAoB,EAAgD,MAAM,wBAAwB,CAAA;AAK/J,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAU,CAAA;AAMlE,sFAAsF;AACtF,MAAM,UAAU,cAAc,CAAC,OAAqB;IAClD,OAAO;QACL,IAAI,EAAE,OAAO,EAAE,IAAI,IAAI,EAAE;QACzB,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;QACtD,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE;QACxD,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE;KACzD,CAAA;AACH,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,eAAe,CAAC,KAAmB,EAAE,OAAqB;IACxE,MAAM,QAAQ,GAAG,cAAc,CAAC,OAAO,CAAC,CAAA;IACxC,OAAO,oBAAoB,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,QAAQ,CAAC,IAAI,IAAI,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;AACrJ,CAAC;AAED,sDAAsD;AACtD,MAAM,QAAQ,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;AAEtF;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAmB,EAAE,GAAQ;IAC5D,MAAM,OAAO,GAAG;QACd,IAAI,EAAE,oBAAoB,CAAC,KAAK,CAAC,IAAI,CAAC;QACtC,UAAU,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE;KAC7G,CAAA;IACD,MAAM,OAAO,GAAG,yBAAyB,CAAC,OAAO,CAAC,CAAA;IAClD,IAAI,OAAO;QAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,CAAA;IAC7E,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,EAAE,CAAA;AACrD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAuC,EAAE,IAAY,EAAE,GAAQ;IAC9F,IAAI,OAAO,CAAC,IAAI,KAAK,cAAc;QACjC,OAAO,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,mCAAmC,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC,uBAAuB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,mCAAmC,EAAE,EAAE,CAAC,CAAA;IACjJ,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC,CAAA;IACvE,IAAI,OAAO,CAAC,IAAI,KAAK,oBAAoB,IAAI,IAAI;QAAE,OAAO,GAAG,CAAC,qCAAqC,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,wBAAwB,IAAI,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAA;IACvJ,OAAO,GAAG,CAAC,0BAA0B,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAA;AAChE,CAAC","sourcesContent":["/*\n * A figure that is a carrier type declares so (ADR-0123): the CARRIERTYPE code a material handling system reports, and\n * the carrier's physical size in mm. Kept apart from the element so it is tested without a browser.\n *\n * The rule is figure-model's (`carrierDeclarationRefusal`); the field asks it before sending `set-carrier`, so a value\n * the kernel refuses is said beside the field and never becomes a step of the history. The size is what the author\n * types, never read off the occupied room.\n */\nimport { carrierDeclarationRefusal, FIGURE_CARRIER_TYPE_MAX, normalizeCarrierType, type FigureAsset, type FigureAuthoringAction } from '@hatiolab/figure-model'\n\ntype Say = (key: string, params: Record<string, string>) => string\ntype Declaration = NonNullable<FigureAsset['carrier']>\n\nexport const CARRIER_AXES = ['width', 'length', 'height'] as const\nexport type CarrierAxis = (typeof CARRIER_AXES)[number]\n\n/** What the field holds while the author types: the code and the three lengths as typed. */\nexport type CarrierDraft = { type: string } & Record<CarrierAxis, string>\n\n/** The field's values for a declaration, or blank for a figure that declares none. */\nexport function carrierDraftOf(carrier?: Declaration): CarrierDraft {\n return {\n type: carrier?.type ?? '',\n width: carrier ? String(carrier.dimensions.width) : '',\n length: carrier ? String(carrier.dimensions.length) : '',\n height: carrier ? String(carrier.dimensions.height) : ''\n }\n}\n\n/** Whether the field says what is declared already: nothing to send. */\nexport function draftIsDeclared(draft: CarrierDraft, carrier?: Declaration): boolean {\n const declared = carrierDraftOf(carrier)\n return normalizeCarrierType(draft.type) === declared.type && CARRIER_AXES.every(axis => Object.is(lengthOf(draft[axis]), lengthOf(declared[axis])))\n}\n\n/** A typed length as a number; blank is no length. */\nconst lengthOf = (typed: string) => (typed.trim() === '' ? Number.NaN : Number(typed))\n\n/**\n * The `set-carrier` command for what the field holds, or why the kernel would refuse it in the author's words. The\n * code is sent as the kernel stores it (trimmed, upper case).\n */\nexport function carrierCommandOf(draft: CarrierDraft, say: Say): { action: FigureAuthoringAction } | { refusal: string } {\n const carrier = {\n type: normalizeCarrierType(draft.type),\n dimensions: { width: lengthOf(draft.width), length: lengthOf(draft.length), height: lengthOf(draft.height) }\n }\n const refused = carrierDeclarationRefusal(carrier)\n if (refused) return { refusal: carrierRefusalOf(refused, carrier.type, say) }\n return { action: { kind: 'set-carrier', carrier } }\n}\n\n/**\n * A carrier declaration refused, said from its code and path (ADR-0127): the code missing or too long, or the length\n * the path names. The kernel's English is never shown; a code the field has no words for is said with the code.\n */\nexport function carrierRefusalOf(refused: { code: string; path: string }, type: string, say: Say): string {\n if (refused.code === 'CARRIER_TYPE')\n return type ? say('figure.text.carrier-type-too-long', { max: String(FIGURE_CARRIER_TYPE_MAX) }) : say('figure.text.carrier-type-required', {})\n const axis = CARRIER_AXES.find(one => refused.path.endsWith(`.${one}`))\n if (refused.code === 'CARRIER_DIMENSIONS' && axis) return say('figure.text.carrier-length-positive', { axis: say(`figure.label.carrier-${axis}`, {}) })\n return say('figure.text.edit-refused', { code: refused.code })\n}\n"]}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { LitElement, type PropertyValues } from 'lit';
|
|
2
|
-
import type { FigureAsset } from '@hatiolab/figure-model';
|
|
3
|
-
declare const FigureCarrier_base: (new (...args: any[]) => LitElement) & typeof LitElement;
|
|
4
|
-
/**
|
|
5
|
-
* 캐리어 — the CARRIERTYPE code and physical size a carrier figure declares (ADR-0123), in the properties tab.
|
|
6
|
-
*
|
|
7
|
-
* Declaring and clearing are `set-carrier` commands, sent up as `command` like the tab's others, so the page runs them as
|
|
8
|
-
* steps of the session's history: undo takes them back and they are saved with the figure. A value the kernel refuses
|
|
9
|
-
* is said here and sends nothing.
|
|
10
|
-
*/
|
|
11
|
-
export declare class FigureCarrier extends FigureCarrier_base {
|
|
12
|
-
static styles: import("lit").CSSResult[];
|
|
13
|
-
/** What the figure on screen declares; absent when it is not a carrier type. */
|
|
14
|
-
carrier?: FigureAsset['carrier'];
|
|
15
|
-
private draft;
|
|
16
|
-
private refusal;
|
|
17
|
-
private filledFrom?;
|
|
18
|
-
willUpdate(changed: PropertyValues<this>): void;
|
|
19
|
-
render(): import("lit-html").TemplateResult<1>;
|
|
20
|
-
private type;
|
|
21
|
-
private enter;
|
|
22
|
-
private declare;
|
|
23
|
-
private clear;
|
|
24
|
-
private command;
|
|
25
|
-
}
|
|
26
|
-
export {};
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import { __decorate, __metadata } from "tslib";
|
|
2
|
-
import { css, html, LitElement, nothing } from 'lit';
|
|
3
|
-
import { customElement, property, state } from 'lit/decorators.js';
|
|
4
|
-
import { live } from 'lit/directives/live.js';
|
|
5
|
-
import { i18next, localize } from '@operato/i18n';
|
|
6
|
-
import { CARRIER_AXES, carrierCommandOf, carrierDraftOf, draftIsDeclared } from './carrier-declaration.js';
|
|
7
|
-
import { SidePanelStyles } from '@things-factory/figure-viewer/dist-client/side-panel-styles.js';
|
|
8
|
-
const AXIS_LETTER = { width: 'W', length: 'L', height: 'H' };
|
|
9
|
-
/**
|
|
10
|
-
* 캐리어 — the CARRIERTYPE code and physical size a carrier figure declares (ADR-0123), in the properties tab.
|
|
11
|
-
*
|
|
12
|
-
* Declaring and clearing are `set-carrier` commands, sent up as `command` like the tab's others, so the page runs them as
|
|
13
|
-
* steps of the session's history: undo takes them back and they are saved with the figure. A value the kernel refuses
|
|
14
|
-
* is said here and sends nothing.
|
|
15
|
-
*/
|
|
16
|
-
let FigureCarrier = class FigureCarrier extends localize(i18next)(LitElement) {
|
|
17
|
-
constructor() {
|
|
18
|
-
super(...arguments);
|
|
19
|
-
this.draft = carrierDraftOf();
|
|
20
|
-
this.refusal = '';
|
|
21
|
-
this.enter = (event) => {
|
|
22
|
-
if (event.key === 'Enter' && !draftIsDeclared(this.draft, this.carrier))
|
|
23
|
-
this.declare();
|
|
24
|
-
};
|
|
25
|
-
this.declare = () => {
|
|
26
|
-
const made = carrierCommandOf(this.draft, (key, params) => i18next.t(key, params));
|
|
27
|
-
if ('refusal' in made)
|
|
28
|
-
this.refusal = made.refusal;
|
|
29
|
-
else
|
|
30
|
-
this.command(made.action);
|
|
31
|
-
};
|
|
32
|
-
this.clear = () => this.command({ kind: 'set-carrier', carrier: null });
|
|
33
|
-
}
|
|
34
|
-
static { this.styles = [SidePanelStyles, css `
|
|
35
|
-
div[row] {
|
|
36
|
-
display: flex;
|
|
37
|
-
gap: 6px;
|
|
38
|
-
}
|
|
39
|
-
div[row] > button[act] {
|
|
40
|
-
flex: 1;
|
|
41
|
-
margin-top: 0;
|
|
42
|
-
}
|
|
43
|
-
small[role='alert'] {
|
|
44
|
-
color: var(--md-sys-color-error);
|
|
45
|
-
}
|
|
46
|
-
`]; }
|
|
47
|
-
willUpdate(changed) {
|
|
48
|
-
if (!changed.has('carrier'))
|
|
49
|
-
return;
|
|
50
|
-
const declared = JSON.stringify(this.carrier ?? null);
|
|
51
|
-
if (declared === this.filledFrom)
|
|
52
|
-
return;
|
|
53
|
-
this.filledFrom = declared;
|
|
54
|
-
this.draft = carrierDraftOf(this.carrier);
|
|
55
|
-
this.refusal = '';
|
|
56
|
-
}
|
|
57
|
-
render() {
|
|
58
|
-
const pending = !draftIsDeclared(this.draft, this.carrier);
|
|
59
|
-
return html `<section>
|
|
60
|
-
<h3>${i18next.t('figure.label.group-carrier')}</h3>
|
|
61
|
-
<div field>
|
|
62
|
-
<label for="carrier-type">${i18next.t('figure.label.carrier-type')}</label>
|
|
63
|
-
<input
|
|
64
|
-
id="carrier-type"
|
|
65
|
-
.value=${live(this.draft.type)}
|
|
66
|
-
placeholder=${i18next.t('figure.text.carrier-type-placeholder')}
|
|
67
|
-
@input=${(e) => this.type('type', e)}
|
|
68
|
-
@keydown=${this.enter}
|
|
69
|
-
/>
|
|
70
|
-
</div>
|
|
71
|
-
<div vector-row>
|
|
72
|
-
<label>${i18next.t('figure.label.carrier-size')} <span unit>mm</span></label>
|
|
73
|
-
<div triple>
|
|
74
|
-
${CARRIER_AXES.map(axis => html `<div cell>
|
|
75
|
-
<span axis>${AXIS_LETTER[axis]}</span>
|
|
76
|
-
<input
|
|
77
|
-
type="number"
|
|
78
|
-
min="0"
|
|
79
|
-
step="any"
|
|
80
|
-
aria-label=${i18next.t(`figure.label.carrier-${axis}`)}
|
|
81
|
-
.value=${live(this.draft[axis])}
|
|
82
|
-
@input=${(e) => this.type(axis, e)}
|
|
83
|
-
@keydown=${this.enter}
|
|
84
|
-
/>
|
|
85
|
-
</div>`)}
|
|
86
|
-
</div>
|
|
87
|
-
</div>
|
|
88
|
-
${this.refusal ? html `<small role="alert">${this.refusal}</small>` : nothing}
|
|
89
|
-
<div row>
|
|
90
|
-
<button act ?disabled=${!pending} @click=${this.declare}>
|
|
91
|
-
<md-icon>check</md-icon>${i18next.t('figure.button.declare-carrier')}
|
|
92
|
-
</button>
|
|
93
|
-
<button act ?disabled=${!this.carrier} @click=${this.clear}>
|
|
94
|
-
<md-icon>close</md-icon>${i18next.t('figure.button.clear-carrier')}
|
|
95
|
-
</button>
|
|
96
|
-
</div>
|
|
97
|
-
</section>`;
|
|
98
|
-
}
|
|
99
|
-
type(key, event) {
|
|
100
|
-
this.draft = { ...this.draft, [key]: event.target.value };
|
|
101
|
-
this.refusal = '';
|
|
102
|
-
}
|
|
103
|
-
command(action) {
|
|
104
|
-
this.dispatchEvent(new CustomEvent('command', { detail: { action }, bubbles: true, composed: true }));
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
|
-
__decorate([
|
|
108
|
-
property({ attribute: false }),
|
|
109
|
-
__metadata("design:type", Object)
|
|
110
|
-
], FigureCarrier.prototype, "carrier", void 0);
|
|
111
|
-
__decorate([
|
|
112
|
-
state(),
|
|
113
|
-
__metadata("design:type", Object)
|
|
114
|
-
], FigureCarrier.prototype, "draft", void 0);
|
|
115
|
-
__decorate([
|
|
116
|
-
state(),
|
|
117
|
-
__metadata("design:type", Object)
|
|
118
|
-
], FigureCarrier.prototype, "refusal", void 0);
|
|
119
|
-
FigureCarrier = __decorate([
|
|
120
|
-
customElement('figure-carrier')
|
|
121
|
-
], FigureCarrier);
|
|
122
|
-
export { FigureCarrier };
|
|
123
|
-
//# sourceMappingURL=figure-carrier.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"figure-carrier.js","sourceRoot":"","sources":["../../client/modeller/figure-carrier.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement, nothing, type PropertyValues } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { live } from 'lit/directives/live.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport type { FigureAsset, FigureAuthoringAction } from '@hatiolab/figure-model'\n\nimport { CARRIER_AXES, carrierCommandOf, carrierDraftOf, draftIsDeclared, type CarrierAxis, type CarrierDraft } from './carrier-declaration.js'\nimport { SidePanelStyles } from '@things-factory/figure-viewer/dist-client/side-panel-styles.js'\n\nconst AXIS_LETTER: Record<CarrierAxis, string> = { width: 'W', length: 'L', height: 'H' }\n\n/**\n * 캐리어 — the CARRIERTYPE code and physical size a carrier figure declares (ADR-0123), in the properties tab.\n *\n * Declaring and clearing are `set-carrier` commands, sent up as `command` like the tab's others, so the page runs them as\n * steps of the session's history: undo takes them back and they are saved with the figure. A value the kernel refuses\n * is said here and sends nothing.\n */\n@customElement('figure-carrier')\nexport class FigureCarrier extends localize(i18next)(LitElement) {\n static styles = [SidePanelStyles, css`\n div[row] {\n display: flex;\n gap: 6px;\n }\n div[row] > button[act] {\n flex: 1;\n margin-top: 0;\n }\n small[role='alert'] {\n color: var(--md-sys-color-error);\n }\n `]\n\n /** What the figure on screen declares; absent when it is not a carrier type. */\n @property({ attribute: false }) carrier?: FigureAsset['carrier']\n @state() private draft: CarrierDraft = carrierDraftOf()\n @state() private refusal = ''\n /* The declaration the field was last filled from: other edits draw the tab again and must not wipe what is being typed. */\n private filledFrom?: string\n\n willUpdate(changed: PropertyValues<this>) {\n if (!changed.has('carrier')) return\n const declared = JSON.stringify(this.carrier ?? null)\n if (declared === this.filledFrom) return\n this.filledFrom = declared\n this.draft = carrierDraftOf(this.carrier)\n this.refusal = ''\n }\n\n render() {\n const pending = !draftIsDeclared(this.draft, this.carrier)\n return html`<section>\n <h3>${i18next.t('figure.label.group-carrier')}</h3>\n <div field>\n <label for=\"carrier-type\">${i18next.t('figure.label.carrier-type')}</label>\n <input\n id=\"carrier-type\"\n .value=${live(this.draft.type)}\n placeholder=${i18next.t('figure.text.carrier-type-placeholder')}\n @input=${(e: Event) => this.type('type', e)}\n @keydown=${this.enter}\n />\n </div>\n <div vector-row>\n <label>${i18next.t('figure.label.carrier-size')} <span unit>mm</span></label>\n <div triple>\n ${CARRIER_AXES.map(\n axis => html`<div cell>\n <span axis>${AXIS_LETTER[axis]}</span>\n <input\n type=\"number\"\n min=\"0\"\n step=\"any\"\n aria-label=${i18next.t(`figure.label.carrier-${axis}`)}\n .value=${live(this.draft[axis])}\n @input=${(e: Event) => this.type(axis, e)}\n @keydown=${this.enter}\n />\n </div>`\n )}\n </div>\n </div>\n ${this.refusal ? html`<small role=\"alert\">${this.refusal}</small>` : nothing}\n <div row>\n <button act ?disabled=${!pending} @click=${this.declare}>\n <md-icon>check</md-icon>${i18next.t('figure.button.declare-carrier')}\n </button>\n <button act ?disabled=${!this.carrier} @click=${this.clear}>\n <md-icon>close</md-icon>${i18next.t('figure.button.clear-carrier')}\n </button>\n </div>\n </section>`\n }\n\n private type(key: keyof CarrierDraft, event: Event) {\n this.draft = { ...this.draft, [key]: (event.target as HTMLInputElement).value }\n this.refusal = ''\n }\n\n private enter = (event: KeyboardEvent) => {\n if (event.key === 'Enter' && !draftIsDeclared(this.draft, this.carrier)) this.declare()\n }\n\n private declare = () => {\n const made = carrierCommandOf(this.draft, (key, params) => i18next.t(key, params))\n if ('refusal' in made) this.refusal = made.refusal\n else this.command(made.action)\n }\n\n private clear = () => this.command({ kind: 'set-carrier', carrier: null })\n\n private command(action: FigureAuthoringAction) {\n this.dispatchEvent(new CustomEvent('command', { detail: { action }, bubbles: true, composed: true }))\n }\n}\n"]}
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* The properties tab's carrier field (ADR-0123): what it sends as `set-carrier`, what it says when the kernel would
|
|
3
|
-
* refuse, and that the declaration is a step of the session's history -- undo takes it back, the save carries it.
|
|
4
|
-
*/
|
|
5
|
-
import { test } from 'node:test'
|
|
6
|
-
import assert from 'node:assert/strict'
|
|
7
|
-
import { addFigureBox, createFigureAsset, parseFigureAsset, serializeFigureAsset } from '@hatiolab/figure-model'
|
|
8
|
-
|
|
9
|
-
import { carrierCommandOf, carrierDraftOf, draftIsDeclared, type CarrierDraft } from '../client/modeller/carrier-declaration.ts'
|
|
10
|
-
import { createFigureProductSession } from '../client/modeller/product-session.ts'
|
|
11
|
-
|
|
12
|
-
const say = (key: string, params: Record<string, string>) => `${key}${Object.keys(params).length ? ' ' + JSON.stringify(params) : ''}`
|
|
13
|
-
const draft = (type: string, width = '1000', length = '600', height = '200'): CarrierDraft => ({ type, width, length, height })
|
|
14
|
-
|
|
15
|
-
const source = serializeFigureAsset(addFigureBox(createFigureAsset('roll'), { id: 'body', size: { x: 100, y: 100, z: 100 }, position: { x: 0, y: 50, z: 0 } }))
|
|
16
|
-
const store = {
|
|
17
|
-
load: async (id: string) => ({ id, source }),
|
|
18
|
-
save: async (q: { id?: string; source: string }) => ({ id: q.id ?? 'saved', source: q.source })
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
test('the field sends the code as the kernel stores it and the three lengths as numbers', () => {
|
|
22
|
-
assert.deepEqual(carrierCommandOf(draft(' foup '), say), {
|
|
23
|
-
action: { kind: 'set-carrier', carrier: { type: 'FOUP', dimensions: { width: 1000, length: 600, height: 200 } } }
|
|
24
|
-
})
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
test('a value the kernel refuses is said from its code and path, and nothing is sent', () => {
|
|
28
|
-
assert.deepEqual(carrierCommandOf(draft(' '), say), { refusal: 'figure.text.carrier-type-required' })
|
|
29
|
-
assert.deepEqual(carrierCommandOf(draft('X'.repeat(65)), say), { refusal: 'figure.text.carrier-type-too-long {"max":"64"}' })
|
|
30
|
-
assert.deepEqual(carrierCommandOf(draft('FOUP', '1000', ''), say), {
|
|
31
|
-
refusal: 'figure.text.carrier-length-positive {"axis":"figure.label.carrier-length"}'
|
|
32
|
-
})
|
|
33
|
-
assert.deepEqual(carrierCommandOf(draft('FOUP', '1000', '600', '-5'), say), {
|
|
34
|
-
refusal: 'figure.text.carrier-length-positive {"axis":"figure.label.carrier-height"}'
|
|
35
|
-
})
|
|
36
|
-
assert.deepEqual(carrierCommandOf(draft('FOUP', '0'), say), {
|
|
37
|
-
refusal: 'figure.text.carrier-length-positive {"axis":"figure.label.carrier-width"}'
|
|
38
|
-
})
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
test('the field reads a declaration back, and what is declared already has nothing to send', () => {
|
|
42
|
-
const declared = { type: 'FOUP', dimensions: { width: 1000, length: 600, height: 200 } }
|
|
43
|
-
assert.deepEqual(carrierDraftOf(declared), draft('FOUP'))
|
|
44
|
-
assert.deepEqual(carrierDraftOf(), draft('', '', '', ''))
|
|
45
|
-
assert.equal(draftIsDeclared(draft('foup ', '1000.0'), declared), true)
|
|
46
|
-
assert.equal(draftIsDeclared(draft('FOUP', '1001'), declared), false)
|
|
47
|
-
assert.equal(draftIsDeclared(draft('', '', '', ''), undefined), true)
|
|
48
|
-
assert.equal(draftIsDeclared(draft('FOUP'), undefined), false)
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
test('declaring and clearing are steps of the history: undo takes each back and the save carries the declaration', async () => {
|
|
52
|
-
const session = createFigureProductSession(store)
|
|
53
|
-
await session.open('A')
|
|
54
|
-
const made = carrierCommandOf(draft('foup'), say)
|
|
55
|
-
assert.ok('action' in made)
|
|
56
|
-
|
|
57
|
-
session.command(made.action)
|
|
58
|
-
const declared = { type: 'FOUP', dimensions: { width: 1000, length: 600, height: 200 } }
|
|
59
|
-
assert.deepEqual(session.revisionNow()?.asset.carrier, declared)
|
|
60
|
-
assert.deepEqual(parseFigureAsset(session.source()).carrier, declared)
|
|
61
|
-
|
|
62
|
-
session.command({ kind: 'set-carrier', carrier: null })
|
|
63
|
-
assert.equal(session.revisionNow()?.asset.carrier, undefined)
|
|
64
|
-
|
|
65
|
-
session.undo()
|
|
66
|
-
assert.deepEqual(session.revisionNow()?.asset.carrier, declared, 'undoing the clear brings the declaration back')
|
|
67
|
-
session.undo()
|
|
68
|
-
assert.equal(session.revisionNow()?.asset.carrier, undefined, 'undoing the declaration leaves the figure no carrier')
|
|
69
|
-
})
|