@things-factory/figure-ui 10.1.224 → 10.1.226

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 (84) hide show
  1. package/client/modeller/consumer-capabilities.ts +15 -0
  2. package/client/modeller/editor-styles.ts +21 -3
  3. package/client/modeller/editor.ts +41 -27
  4. package/client/modeller/figure-capability-panel.ts +37 -10
  5. package/client/modeller/figure-clips.ts +3 -2
  6. package/client/modeller/figure-controls.ts +4 -3
  7. package/client/modeller/figure-data-panel.ts +41 -21
  8. package/client/modeller/figure-links.ts +5 -5
  9. package/client/modeller/figure-material-panel.ts +2 -0
  10. package/client/modeller/figure-preview.ts +115 -8
  11. package/client/modeller/figure-recipe-catalog.ts +4 -0
  12. package/client/modeller/figure-slot-layout-panel.ts +25 -8
  13. package/client/modeller/figure-verdict.ts +4 -1
  14. package/client/modeller/product-session.ts +3 -2
  15. package/client/modeller/unit-words.ts +11 -0
  16. package/client/pages/figure-modeller-page.ts +5 -4
  17. package/dist-client/modeller/consumer-capabilities.d.ts +11 -0
  18. package/dist-client/modeller/consumer-capabilities.js +14 -0
  19. package/dist-client/modeller/consumer-capabilities.js.map +1 -1
  20. package/dist-client/modeller/editor-styles.js +21 -3
  21. package/dist-client/modeller/editor-styles.js.map +1 -1
  22. package/dist-client/modeller/editor.js +43 -29
  23. package/dist-client/modeller/editor.js.map +1 -1
  24. package/dist-client/modeller/figure-capability-panel.d.ts +3 -0
  25. package/dist-client/modeller/figure-capability-panel.js +35 -11
  26. package/dist-client/modeller/figure-capability-panel.js.map +1 -1
  27. package/dist-client/modeller/figure-clips.js +3 -2
  28. package/dist-client/modeller/figure-clips.js.map +1 -1
  29. package/dist-client/modeller/figure-controls.js +4 -3
  30. package/dist-client/modeller/figure-controls.js.map +1 -1
  31. package/dist-client/modeller/figure-data-panel.js +42 -21
  32. package/dist-client/modeller/figure-data-panel.js.map +1 -1
  33. package/dist-client/modeller/figure-links.js +5 -5
  34. package/dist-client/modeller/figure-links.js.map +1 -1
  35. package/dist-client/modeller/figure-material-panel.js +2 -0
  36. package/dist-client/modeller/figure-material-panel.js.map +1 -1
  37. package/dist-client/modeller/figure-preview.d.ts +3 -0
  38. package/dist-client/modeller/figure-preview.js +124 -8
  39. package/dist-client/modeller/figure-preview.js.map +1 -1
  40. package/dist-client/modeller/figure-recipe-catalog.js +4 -0
  41. package/dist-client/modeller/figure-recipe-catalog.js.map +1 -1
  42. package/dist-client/modeller/figure-slot-layout-panel.d.ts +1 -1
  43. package/dist-client/modeller/figure-slot-layout-panel.js +25 -8
  44. package/dist-client/modeller/figure-slot-layout-panel.js.map +1 -1
  45. package/dist-client/modeller/figure-verdict.js +4 -1
  46. package/dist-client/modeller/figure-verdict.js.map +1 -1
  47. package/dist-client/modeller/product-session.d.ts +4 -2
  48. package/dist-client/modeller/product-session.js +3 -2
  49. package/dist-client/modeller/product-session.js.map +1 -1
  50. package/dist-client/modeller/unit-words.d.ts +5 -0
  51. package/dist-client/modeller/unit-words.js +12 -0
  52. package/dist-client/modeller/unit-words.js.map +1 -0
  53. package/dist-client/pages/figure-modeller-page.js +5 -4
  54. package/dist-client/pages/figure-modeller-page.js.map +1 -1
  55. package/dist-client/tsconfig.tsbuildinfo +1 -1
  56. package/package.json +10 -10
  57. package/test/ai-proposal.test.ts +2 -2
  58. package/test/browser/editing-page.js +3 -3
  59. package/test/browser/editing.check.mjs +5 -5
  60. package/test/browser/links-page.js +1 -1
  61. package/test/browser/links.check.mjs +2 -3
  62. package/test/browser/modeller-page.js +4 -4
  63. package/test/browser/modeller-revision.check.mjs +5 -5
  64. package/test/browser/modeller.check.mjs +5 -5
  65. package/test/browser/parts.check.mjs +2 -2
  66. package/test/browser/product-page.check.mjs +31 -0
  67. package/test/browser/props.check.mjs +3 -4
  68. package/test/browser/row-preview.check.mjs +3 -3
  69. package/test/browser/screen.check.mjs +13 -11
  70. package/test/browser/side-panel-sweep.check.mjs +182 -0
  71. package/test/consumer-capabilities.test.ts +7 -0
  72. package/test/figure-assistant-surface.test.ts +1 -1
  73. package/test/first-save.test.ts +2 -2
  74. package/test/links.test.ts +1 -1
  75. package/test/product-session.test.ts +5 -5
  76. package/test/proposal-record.test.ts +3 -3
  77. package/test/refusals.test.ts +1 -1
  78. package/test/revert-keeping.test.ts +1 -1
  79. package/translations/en.json +24 -12
  80. package/translations/es.json +24 -12
  81. package/translations/ja.json +25 -13
  82. package/translations/ko.json +83 -71
  83. package/translations/ms.json +24 -12
  84. package/translations/zh.json +24 -12
@@ -2,6 +2,8 @@ var FigureEditor_1;
2
2
  import { __decorate, __metadata } from "tslib";
3
3
  import { LitElement, html, nothing } from 'lit';
4
4
  import { i18next } from '@operato/i18n';
5
+ import { isMacOS } from '@operato/utils';
6
+ import { unitWord } from './unit-words.js';
5
7
  import '@operato/layout';
6
8
  import { openPopup } from '@operato/layout';
7
9
  import { customElement, property, state } from 'lit/decorators.js';
@@ -893,6 +895,14 @@ let FigureEditor = class FigureEditor extends LitElement {
893
895
  <summary><h3>${i18next.t('figure.label.group-more')}</h3></summary>
894
896
  <div more-body>
895
897
  ${tools ? html `<div group-fields>${tools}</div>` : nothing}
898
+ <figure-material-panel
899
+ show="more"
900
+ .body=${{ ...part, id: this.selected }}
901
+ .palette=${palette}
902
+ ?locked=${unavailable}
903
+ @part-edit=${(e) => this.run(() => this.session.edit(e.detail.edit))}
904
+ @part-live=${(e) => this.hold({}, e.detail.edit)}
905
+ ></figure-material-panel>
896
906
  <figure-section-panel
897
907
  embedded
898
908
  .body=${{ ...part, id: this.selected }}
@@ -904,14 +914,6 @@ let FigureEditor = class FigureEditor extends LitElement {
904
914
  @command-live=${(e) => this.holdAction(e.detail.action)}
905
915
  @section-editor-open=${() => (this.sectionEditing = this.selected)}
906
916
  ></figure-section-panel>
907
- <figure-material-panel
908
- show="more"
909
- .body=${{ ...part, id: this.selected }}
910
- .palette=${palette}
911
- ?locked=${unavailable}
912
- @part-edit=${(e) => this.run(() => this.session.edit(e.detail.edit))}
913
- @part-live=${(e) => this.hold({}, e.detail.edit)}
914
- ></figure-material-panel>
915
917
  </div>
916
918
  </details>
917
919
  </section>`;
@@ -1165,7 +1167,7 @@ let FigureEditor = class FigureEditor extends LitElement {
1165
1167
  return html `<section board-size>
1166
1168
  ${title('figure.text.board-size-range-explained')}
1167
1169
  ${['x', 'y', 'z'].map(axis => html `<div inline-field>
1168
- <label>${i18next.t('figure.label.resize-' + axis)} <span unit>mm</span></label>
1170
+ <label>${i18next.t('figure.label.resize-' + axis)} <span unit>(mm)</span></label>
1169
1171
  <div pair range>
1170
1172
  ${['min', 'max'].map((bound, i) => html `${i ? html `<span dash aria-hidden="true">–</span>` : nothing}<input
1171
1173
  aria-label=${`size.${axis}.${bound}`}
@@ -1297,7 +1299,7 @@ let FigureEditor = class FigureEditor extends LitElement {
1297
1299
  <div inline-field><label>${i18next.t('figure.label.repeat-axis')}</label>${axes.length ? html `<select aria-label=${i18next.t('figure.label.repeat-axis')} ?disabled=${unavailable} .value=${live(axis)} @change=${(e) => update({ axis: e.target.value.toUpperCase() })}>${axes.map(a => html `<option value=${a} ?selected=${a === axis}>${a.toUpperCase()}</option>`)}</select>` : html `<span value>${axis.toUpperCase()}</span>`}</div>
1298
1300
  <div inline-field><label>${i18next.t('figure.label.repeat-count')}</label>${!fits && record ? html `<input type="number" min="1" step="1" aria-label=${i18next.t('figure.label.repeat-count')} .value=${live(String(repeat.count))} ?disabled=${unavailable} @change=${(e) => update({ count: e.target.valueAsNumber })}>` : html `<span value>${repeat.count}</span>`}</div>
1299
1301
  <div inline-field>
1300
- <label>${i18next.t('figure.label.repeat-gap')} <span unit>mm</span></label>
1302
+ <label>${i18next.t('figure.label.repeat-gap')} <span unit>(mm)</span></label>
1301
1303
  ${fits ? html `<input
1302
1304
  type="number"
1303
1305
  step="any"
@@ -1391,8 +1393,8 @@ let FigureEditor = class FigureEditor extends LitElement {
1391
1393
  </label>
1392
1394
  ${open
1393
1395
  ? html `<div inline-field><label>${i18next.t('figure.label.board-name')}</label><input aria-label="figure.label.board-name" .value=${form.label} @change=${edit('label')} /></div>
1394
- <div inline-field><label>${i18next.t('figure.label.least')} <span unit>mm</span></label><input type="number" step="any" aria-label="figure.label.least" .value=${String(form.min)} @change=${edit('min')} /></div>
1395
- <div inline-field><label>${i18next.t('figure.label.most')} <span unit>mm</span></label><input type="number" step="any" aria-label="figure.label.most" .value=${String(form.max)} @change=${edit('max')} /></div>
1396
+ <div inline-field><label>${i18next.t('figure.label.least')} <span unit>(mm)</span></label><input type="number" step="any" aria-label="figure.label.least" .value=${String(form.min)} @change=${edit('min')} /></div>
1397
+ <div inline-field><label>${i18next.t('figure.label.most')} <span unit>(mm)</span></label><input type="number" step="any" aria-label="figure.label.most" .value=${String(form.max)} @change=${edit('max')} /></div>
1396
1398
  <button act publish-pitch ?disabled=${unavailable || !form.label.trim()} @click=${() => run(steps())}>
1397
1399
  <md-icon>${listed ? 'check' : 'ios_share'}</md-icon>${i18next.t(listed ? 'figure.button.apply' : 'figure.button.publish-input')}
1398
1400
  </button>`
@@ -1627,9 +1629,12 @@ let FigureEditor = class FigureEditor extends LitElement {
1627
1629
  }
1628
1630
  /** A side tab says what it is in words under its icon: the icons alone had to be learnt (designer 2026-09-27, U05). */
1629
1631
  renderTab(tab, icon, label) {
1630
- /* Its accessible name is the name it shows (designer 2026-09-27); the longer title stays as its tooltip. */
1631
- const name = i18next.t(tab === 'response' && this.selected ? 'figure.label.tab-arrangement' : 'figure.label.tab-short-' + tab);
1632
- return html `<button tab ?on=${this.tab === tab} title=${tab === 'response' && this.selected ? name : label} aria-label=${name} @click=${() => (this.tab = tab)}>
1632
+ /*
1633
+ Its accessible name is the name it shows (designer 2026-09-27); the longer title stays as its tooltip. One name
1634
+ whatever is picked: the size tab was 「반응형」 with nothing picked and 「배치」 with a part (sweep 2026-10-27 J2).
1635
+ */
1636
+ const name = i18next.t('figure.label.tab-short-' + tab);
1637
+ return html `<button tab ?on=${this.tab === tab} title=${label} aria-label=${name} @click=${() => (this.tab = tab)}>
1633
1638
  <md-icon>${icon}</md-icon><span tab-label aria-hidden="true">${name}</span>
1634
1639
  </button>`;
1635
1640
  }
@@ -1727,7 +1732,13 @@ let FigureEditor = class FigureEditor extends LitElement {
1727
1732
  ${i18next.t(kind === 'box' ? 'figure.label.primitive-cube' : `figure.label.primitive-${kind}`)}
1728
1733
  </button>`)}
1729
1734
  </div>
1730
- <small>${i18next.t('figure.text.start-shape-more')}</small>
1735
+ ${this.panes?.foldStart
1736
+ ? /* The list it points to is folded at this width: a way to it, not words about a list not there (sweep 2026-10-27 U23). */
1737
+ html `<button start-more @click=${() => {
1738
+ this.panes.foldStart = false;
1739
+ this.requestUpdate();
1740
+ }}>${i18next.t('figure.button.start-shape-more')}</button>`
1741
+ : html `<small>${i18next.t('figure.text.start-shape-more')}</small>`}
1731
1742
  </section>
1732
1743
  ${this.aiDraft
1733
1744
  ? html `<section>
@@ -1735,7 +1746,6 @@ let FigureEditor = class FigureEditor extends LitElement {
1735
1746
  <button start-button start-ai @click=${() => this.dispatchEvent(new CustomEvent('ask-ai-draft', { bubbles: true, composed: true }))}>
1736
1747
  ${i18next.t('figure.button.start-ai')}
1737
1748
  </button>
1738
- <small>${i18next.t('figure.text.start-ai-optional')}</small>
1739
1749
  </section>`
1740
1750
  : nothing}
1741
1751
  </div>
@@ -1820,8 +1830,8 @@ let FigureEditor = class FigureEditor extends LitElement {
1820
1830
  return html `<ox-canvas-bar
1821
1831
  history
1822
1832
  fit
1823
- undo-shortcut="Ctrl+Z"
1824
- redo-shortcut="Ctrl+Y"
1833
+ undo-shortcut=${isMacOS() ? '⌘Z' : 'Ctrl+Z'}
1834
+ redo-shortcut=${isMacOS() ? '⇧⌘Z' : 'Ctrl+Y'}
1825
1835
  ?can-undo=${!unavailable && view.canUndo}
1826
1836
  ?can-redo=${!unavailable && view.canRedo}
1827
1837
  .pane=${this.panes}
@@ -1851,7 +1861,7 @@ let FigureEditor = class FigureEditor extends LitElement {
1851
1861
  >
1852
1862
  <md-icon>publish</md-icon>${i18next.t('figure.button.release')}
1853
1863
  </button>
1854
- <button slot="commit" save ?disabled=${unavailable || (!view.dirty && !!view.id)} @click=${this.save}><md-icon>save</md-icon>${i18next.t('figure.button.save')}</button>
1864
+ <button slot="commit" save title=${!view.id && !view.geometry.length ? i18next.t('figure.text.save-needs-a-part') : ''} ?disabled=${unavailable || (!view.dirty && !!view.id) || (!view.id && !view.geometry.length)} @click=${this.save}><md-icon>save</md-icon>${i18next.t('figure.button.save')}</button>
1855
1865
  </ox-canvas-bar>
1856
1866
  ${this.blockersOpen && blockers.length ? this.renderReleaseBlockers(blockers, asset) : nothing}
1857
1867
  ${this.catalogOpen
@@ -1941,7 +1951,7 @@ let FigureEditor = class FigureEditor extends LitElement {
1941
1951
  ${this.renderTab('motion', 'animation', i18next.t('figure.label.motion'))}
1942
1952
  ${this.renderTab('capability', 'conveyor_belt', i18next.t('figure.label.tab-capability'))}
1943
1953
  ${this.renderTab('data', 'sensors', i18next.t('figure.label.tab-data'))}
1944
- ${this.renderTab('verdict', 'insights', i18next.t('figure.label.maturity'))}
1954
+ ${this.renderTab('verdict', 'insights', i18next.t('figure.label.tab-verdict'))}
1945
1955
  </div>
1946
1956
  <slot name="notice"></slot>
1947
1957
  <div panel ?off=${tab !== 'properties'}>
@@ -1970,15 +1980,17 @@ let FigureEditor = class FigureEditor extends LitElement {
1970
1980
  @part-live=${(e) => this.hold({}, e.detail.edit)}
1971
1981
  ></figure-material-panel>
1972
1982
  ${this.renderMore(part, view.palette ?? {}, unavailable)}`
1973
- : view.geometry.length === 0
1974
- ? html `${this.renderSubject()}<section empty-figure>
1983
+ : view.loading || !view.context
1984
+ ? nothing
1985
+ : view.geometry.length === 0
1986
+ ? html `${this.renderSubject()}<section empty-figure>
1975
1987
  <p>${i18next.t('figure.text.empty-figure-next')}</p>
1976
1988
  <details>
1977
1989
  <summary>${i18next.t('figure.label.figure-info-later')}</summary>
1978
1990
  <slot name="figure"></slot>
1979
1991
  </details>
1980
1992
  </section>`
1981
- : html `${this.renderSubject()}<slot name="figure"></slot>`}
1993
+ : html `${this.renderSubject()}<slot name="figure"></slot>`}
1982
1994
  </div>
1983
1995
  <div panel ?off=${tab !== 'response'}>
1984
1996
  ${this.renderSubject()}
@@ -2062,17 +2074,18 @@ let FigureEditor = class FigureEditor extends LitElement {
2062
2074
  return v === undefined || !Number.isFinite(v) ? '—' : String(Math.round(v * 10) / 10);
2063
2075
  };
2064
2076
  return html `<div vector-row>
2065
- <label>${i18next.t('figure.label.group-' + group.name)}${group.name === 'rotation' ? '' : html ` <span unit>${unit}</span>`}</label>
2077
+ <label>${i18next.t('figure.label.group-' + group.name)}${group.name === 'rotation' ? '' : html ` <span unit>(${unit})</span>`}</label>
2066
2078
  <div triple>
2067
2079
  ${['x', 'y', 'z'].map(axis => !group.cells[axis]
2068
2080
  ? html `<div cell held title=${i18next.t('figure.text.axis-held-by-rule')}>
2069
2081
  <span axis>${axis.toUpperCase()}</span>
2070
- <input type="text" readonly .value=${given(axis)} aria-label=${`${group.name}.${axis} · ${i18next.t('figure.text.axis-held-by-rule')}`} />
2082
+ <input type="text" readonly .value=${given(axis)} data-field=${`${group.name}.${axis}`} aria-label=${`${i18next.t('figure.label.group-' + group.name)} ${axis.toUpperCase()} · ${i18next.t('figure.text.axis-held-by-rule')}`} />
2071
2083
  </div>`
2072
2084
  : html `<div cell>
2073
2085
  <span axis ?scrub=${!unavailable} @pointerdown=${(e) => this.scrub(group.cells[axis], e, unavailable)}>${axis.toUpperCase()}</span>
2074
2086
  <input
2075
- aria-label=${group.cells[axis].id}
2087
+ data-field=${group.cells[axis].id}
2088
+ aria-label=${`${i18next.t('figure.label.group-' + group.name)} ${axis.toUpperCase()}`}
2076
2089
  type="number"
2077
2090
  step="any"
2078
2091
  .value=${String(group.cells[axis].value)}
@@ -2108,9 +2121,10 @@ let FigureEditor = class FigureEditor extends LitElement {
2108
2121
  }
2109
2122
  renderSingle(name, field, unavailable) {
2110
2123
  const words = name.split('.').map(part => i18next.t('figure.label.field-' + part, { defaultValue: part }));
2111
- return html `<span ?scrub=${!unavailable} @pointerdown=${(e) => this.scrub(field, e, unavailable)}>${words.join(' · ')} (${field.unit})</span
2124
+ return html `<span ?scrub=${!unavailable} @pointerdown=${(e) => this.scrub(field, e, unavailable)}>${words.join(' · ')} (${unitWord(field.unit)})</span
2112
2125
  ><input
2113
- aria-label=${field.id}
2126
+ data-field=${field.id}
2127
+ aria-label=${words.join(' · ')}
2114
2128
  type="number"
2115
2129
  step="any"
2116
2130
  .value=${String(field.value)}