@operato/board 10.22.0 → 10.24.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/CHANGELOG.md CHANGED
@@ -3,6 +3,38 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [10.24.0](https://github.com/hatiolab/operato/compare/v10.23.0...v10.24.0) (2026-09-24)
7
+
8
+ **Note:** Version bump only for package @operato/board
9
+
10
+
11
+
12
+
13
+
14
+ ## [10.23.0](https://github.com/hatiolab/operato/compare/v10.22.0...v10.23.0) (2026-09-24)
15
+
16
+
17
+ ### :sparkles: Styling
18
+
19
+ * **property-panel,input,styles:** quiet inspector, one vocabulary in both schemes ([40e67e9](https://github.com/hatiolab/operato/commit/40e67e9aced202151a4f2f8d7ef96ec840defc18))
20
+
21
+
22
+ ### :bug: Bug Fix
23
+
24
+ * **board:** centre the compact toolbar's icons in the bar; new fullscreen and panel glyphs ([37f135f](https://github.com/hatiolab/operato/commit/37f135f74e064377d16378765604e028c29fdafa))
25
+ * **board:** the compact modeller toolbar draws glyphs in the scheme's ink ([6385901](https://github.com/hatiolab/operato/commit/63859013e60445b53e9d5d1e5a3f6122527ea3e7))
26
+
27
+
28
+ ### :rocket: New Features
29
+
30
+ * **board,property-panel:** docked placement for the contextual bar; quieter effect/binding cards ([c6ad7bb](https://github.com/hatiolab/operato/commit/c6ad7bbcd4c20890f27eba1680322058da453110))
31
+ * **board:** contextual floating toolbar in the modeller ([02fa968](https://github.com/hatiolab/operato/commit/02fa9682ac905ca7d7d995da0e4b5971e28bab78))
32
+ * **board:** palette rail with one Material glyph and a caption per group ([ee53d2b](https://github.com/hatiolab/operato/commit/ee53d2b8f5eba3271fe136af08de2cc2645dfa21))
33
+ * **data-grist,property-panel:** card reorder, quiet gutters, panel heading ([3ad5843](https://github.com/hatiolab/operato/commit/3ad5843287c75007b52bbf18d6117fcffdbd1a83))
34
+ * **property-panel:** one start flow for data binding and event handlers; quiet Specific tab ([2059375](https://github.com/hatiolab/operato/commit/20593753327d169954f1913bbe531359f8bfc944))
35
+
36
+
37
+
6
38
  ## [10.22.0](https://github.com/hatiolab/operato/compare/v10.21.0...v10.22.0) (2026-09-24)
7
39
 
8
40
  **Note:** Version bump only for package @operato/board
@@ -119,7 +119,7 @@ ComponentMenu.styles = [
119
119
 
120
120
  overflow: visible;
121
121
 
122
- border: 2px solid var(--component-menu-border-color, var(--md-sys-color-secondary));
122
+ border: 1px solid var(--component-menu-border-color, var(--md-sys-color-outline-variant));
123
123
  box-sizing: border-box;
124
124
 
125
125
  position: absolute;
@@ -129,11 +129,11 @@ ComponentMenu.styles = [
129
129
  }
130
130
 
131
131
  h2 {
132
- background-color: var(--component-menu-border-color, var(--md-sys-color-secondary));
133
- padding: 1px 5px;
132
+ background-color: var(--component-menu-title-background, var(--md-sys-color-surface-container-highest));
133
+ padding: 4px 8px;
134
134
  margin: 0;
135
135
  font: var(--component-menu-title);
136
- color: var(--md-sys-color-on-secondary);
136
+ color: var(--component-menu-title-color, var(--md-sys-color-on-surface));
137
137
  text-transform: capitalize;
138
138
  }
139
139
 
@@ -154,7 +154,7 @@ ComponentMenu.styles = [
154
154
  align-items: center;
155
155
  min-height: var(--component-menu-item-icon-size);
156
156
  padding: 0 5px 0 0;
157
- border-bottom: 1px solid rgba(0, 0, 0, 0.1);
157
+ border-bottom: 1px solid var(--md-sys-color-outline-variant);
158
158
  font-size: 11px;
159
159
  color: var(--component-menu-item-color, var(--md-sys-color-on-secondary-container));
160
160
  text-transform: capitalize;
@@ -1 +1 @@
1
- {"version":3,"file":"component-menu.js","sourceRoot":"","sources":["../../../../src/modeller/component-toolbar/component-menu.ts"],"names":[],"mappings":"AAAA;;GAEG;;AAEH,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAkB,MAAM,KAAK,CAAA;AAC3D,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAG1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAGvC,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAEvD,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,2CAA2C,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAA;AAE1F,MAAM,OAAO,aAAc,SAAQ,mBAAmB,CAAC,UAAU,CAAC;IAAlE;;QAuF8B,WAAM,GAAa,EAAE,CAAA;QACrB,UAAK,GAAiB,IAAI,CAAA;QAC1B,UAAK,GAAkB,EAAE,CAAA;QAE5C,cAAS,GAAiB,EAAE,CAAA;IA+FvC,CAAC;IA1FC,MAAM,KAAK,cAAc;QACvB,OAAO;YACL,kBAAkB,EAAE,eAAe;SACpC,CAAA;IACH,CAAC;IAED,MAAM;QACJ,OAAO,IAAI,CAAC,KAAK;YACf,CAAC,CAAC,IAAI,CAAA;wBACY,CAAC,CAAa,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe,EAAE;cAChD,CAAA;;;kEAGqD,EAAE;cACvD,OAAO,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,KAAK,EAAE,EAAE,EAAE,YAAY,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;cAC9D,OAAO,CAAC,CAAC,CAAC,YAAY,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC;;;sCAGzB,CAAC,CAAa,EAAE,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;cACnE,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE;gBACtC,MAAM,EAAE,IAAI,EAAE,GAAG,QAAQ,CAAA;gBAEzB,OAAO,IAAI,CAAA;8BACK,IAAI,CAAC,eAAe,cAAc,IAAI;6BACvC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,MAAM,OAAO,CAAC,CAAC,CAAC,aAAa,IAAI,EAAE,CAAC;;eAErF,CAAA;YACH,CAAC,CAAC;;;;;wBAKU,GAAG,EAAE;gBACf,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAA;YACtB,CAAC;wBACW,IAAI,CAAC,QAAQ;;;;SAI5B;YACH,CAAC,CAAC,IAAI,CAAA,EAAE,CAAA;IACZ,CAAC;IAED,OAAO,CAAC,OAA6B;;QACnC,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;YACzB,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;gBAChB,IAAI,CAAC,SAAS,GAAG,EAAE,CAAA;gBACnB,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAA;YACjC,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,SAAS,GAAG,CAAA,MAAA,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,KAAK,CAAC,0CAAE,SAAS,KAAI,EAAE,CAAA;gBACxF,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAA;YAChC,CAAC;QACH,CAAC;QAED,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;YAC5B,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK;gBAClC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,QAAQ,CAAC;gBACvC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAA;QAC5C,CAAC;IACH,CAAC;IAED,YAAY,CAAC,IAA+B;QAC1C,IAAI,CAAC,QAAQ,GAAG,IAAI,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,IAAI,IAAI,CAAC,CAAA;IAChF,CAAC;IAED,gBAAgB,CAAC,CAAa;;QAC5B,MAAM,MAAM,GAAG,CAAC,CAAC,MAAqB,CAAA;QACtC,IAAI,CAAC,YAAY,CAAC,MAAA,MAAO,CAAC,OAAO,CAAC,aAAa,CAAC,0CAAE,YAAY,CAAC,WAAW,CAAC,CAAC,CAAA;IAC9E,CAAC;IAED,eAAe,CAAC,CAAa;;QAC3B,IAAI,IAAI,GAAG,CAAC,CAAC,MAAqB,CAAA;QAClC,IAAI,IAAI,GAAG,MAAA,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,0CAAE,YAAY,CAAC,WAAW,CAAC,CAAA;QAEjE,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAM;QACR,CAAC;QAED,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,MAAA,IAAI,CAAC,KAAK,CAAC,aAAa,0CAAE,OAAO,CAAC,SAAS,CAAC,CAAA,CAAC,2BAA2B;YACxE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,IAAI,IAAI,CAAC,CAAA;YACtE,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;QAC3F,CAAC;QAED,IAAI,CAAC,KAAK,GAAG,IAAI,CAAA;IACnB,CAAC;IAED,YAAY,CAAC,QAAoB;QAC/B,OAAO,QAAQ,CAAC,IAAI,IAAI,OAAO,CAAA;IACjC,CAAC;;AAxLM,oBAAM,GAAG;IACd,eAAe;IACf,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAiFF;CACF,AApFY,CAoFZ;AAE2B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;6CAAsB;AACrB;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;4CAA2B;AAC1B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;4CAA0B;AAE5C;IAAR,KAAK,EAAE;gDAA6B;AAC5B;IAAR,KAAK,EAAE;+CAA2B;AAER;IAA1B,KAAK,CAAC,kBAAkB,CAAC;6CAAqB","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport { css, html, LitElement, PropertyValues } from 'lit'\nimport { property, query, state } from 'lit/decorators.js'\n\nimport { Scene } from '@hatiolab/things-scene'\nimport { ScopedElementsMixin } from '@open-wc/scoped-elements'\nimport { ScrollbarStyles } from '@operato/styles'\nimport { i18next } from '@operato/i18n'\n\nimport { Pallet, PalletItem } from '../../types.js'\nimport { ComponentDetail } from './component-detail.js'\n\nconst noImage = new URL('../../../../icons/components/no-image.png', import.meta.url).href\n\nexport class ComponentMenu extends ScopedElementsMixin(LitElement) {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n align-content: stretch;\n\n background-color: var(--component-menu-background-color, var(--md-sys-color-secondary-container));\n color: var(--component-menu-color, var(--md-sys-color-on-secondary-container));\n margin: 0px;\n padding: 0px;\n\n width: 180px;\n height: 100%;\n\n overflow: visible;\n\n border: 2px solid var(--component-menu-border-color, var(--md-sys-color-secondary));\n box-sizing: border-box;\n\n position: absolute;\n top: 0px;\n\n z-index: 1;\n }\n\n h2 {\n background-color: var(--component-menu-border-color, var(--md-sys-color-secondary));\n padding: 1px 5px;\n margin: 0;\n font: var(--component-menu-title);\n color: var(--md-sys-color-on-secondary);\n text-transform: capitalize;\n }\n\n [templates] {\n flex: 1;\n\n display: block;\n margin: 0;\n padding: 0;\n overflow-y: auto;\n\n background-color: var(--component-menu-background-color, var(--md-sys-color-secondary-container));\n color: var(--component-menu-color, var(--md-sys-color-on-secondary-container));\n }\n\n [template] {\n display: flex;\n align-items: center;\n min-height: var(--component-menu-item-icon-size);\n padding: 0 5px 0 0;\n border-bottom: 1px solid rgba(0, 0, 0, 0.1);\n font-size: 11px;\n color: var(--component-menu-item-color, var(--md-sys-color-on-secondary-container));\n text-transform: capitalize;\n }\n\n [template]:hover,\n [template]:focus {\n color: var(--component-menu-item-hover-color, var(--md-sys-color-secondary));\n font-weight: bold;\n cursor: pointer;\n }\n\n [template] img {\n margin: 5px;\n width: var(--component-menu-item-icon-size);\n height: var(--component-menu-item-icon-size);\n }\n\n component-detail {\n position: absolute;\n top: 0;\n left: 180px;\n height: 100%;\n outline: none;\n }\n\n component-detail[hidden] {\n display: none;\n }\n `\n ]\n\n @property({ type: Object }) groups: Pallet[] = []\n @property({ type: Object }) scene: Scene | null = null\n @property({ type: String }) group: string | null = ''\n\n @state() templates: PalletItem[] = []\n @state() template: PalletItem | any\n\n @query('component-detail') detail!: HTMLElement\n\n static get scopedElements() {\n return {\n 'component-detail': ComponentDetail\n }\n }\n\n render() {\n return this.group\n ? html`\n <h2 onclick=${(e: MouseEvent) => e.stopPropagation()}>\n ${/* group label — translate via group.<name> key, fall back to the\n raw group name so untranslated groups keep working.\n \"list\" is also translatable; defaults to the literal \"list\"\n which is what users have been seeing all along. */ ''}\n ${i18next.t(`group.${this.group}`, { defaultValue: this.group })}\n ${i18next.t('label.list', { defaultValue: 'list' })}\n </h2>\n\n <div templates @mouseover=${(e: MouseEvent) => this.onHoverComponent(e)}>\n ${(this.templates || []).map(template => {\n const { type } = template\n\n return html`\n <div @click=${this.onClickTemplate} data-type=${type} template>\n <img src=${String(this.templateIcon(template))} />${i18next.t(`component.${type}`)}\n </div>\n `\n })}\n </div>\n\n <component-detail\n tabindex=\"-1\"\n @focusout=${() => {\n this.template = null\n }}\n .template=${this.template}\n hidden\n >\n </component-detail>\n `\n : html``\n }\n\n updated(changes: PropertyValues<this>) {\n if (changes.has('group')) {\n if (!this.group) {\n this.templates = []\n this.setAttribute('hidden', '')\n } else {\n this.templates = this.groups.find((g: Pallet) => g.name === this.group)?.templates || []\n this.removeAttribute('active')\n }\n }\n\n if (changes.has('template')) {\n this.template && this.template.about\n ? this.detail.removeAttribute('hidden')\n : this.detail.setAttribute('hidden', '')\n }\n }\n\n findTemplate(type: string | null | undefined) {\n this.template = type && this.templates.find(template => template.type == type)\n }\n\n onHoverComponent(e: MouseEvent) {\n const button = e.target as HTMLElement\n this.findTemplate(button!.closest('[data-type]')?.getAttribute('data-type'))\n }\n\n onClickTemplate(e: MouseEvent) {\n var item = e.target as HTMLElement\n var type = item.closest('[data-type]')?.getAttribute('data-type')\n\n if (!type) {\n return\n }\n\n if (this.scene) {\n this.scene.rootContainer?.trigger('addstop') // 새로운 컴포넌트 클릭시 이전 추가 모드 정지\n this.template = this.templates.find(template => template.type == type)\n this.template && this.scene.startAddMode(JSON.parse(JSON.stringify(this.template.model)))\n }\n\n this.group = null\n }\n\n templateIcon(template: PalletItem) {\n return template.icon || noImage\n }\n}\n"]}
1
+ {"version":3,"file":"component-menu.js","sourceRoot":"","sources":["../../../../src/modeller/component-toolbar/component-menu.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport { css, html, LitElement, PropertyValues } from 'lit'\nimport { property, query, state } from 'lit/decorators.js'\n\nimport { Scene } from '@hatiolab/things-scene'\nimport { ScopedElementsMixin } from '@open-wc/scoped-elements'\nimport { ScrollbarStyles } from '@operato/styles'\nimport { i18next } from '@operato/i18n'\n\nimport { Pallet, PalletItem } from '../../types.js'\nimport { ComponentDetail } from './component-detail.js'\n\nconst noImage = new URL('../../../../icons/components/no-image.png', import.meta.url).href\n\nexport class ComponentMenu extends ScopedElementsMixin(LitElement) {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n align-content: stretch;\n\n background-color: var(--component-menu-background-color, var(--md-sys-color-secondary-container));\n color: var(--component-menu-color, var(--md-sys-color-on-secondary-container));\n margin: 0px;\n padding: 0px;\n\n width: 180px;\n height: 100%;\n\n overflow: visible;\n\n border: 1px solid var(--component-menu-border-color, var(--md-sys-color-outline-variant));\n box-sizing: border-box;\n\n position: absolute;\n top: 0px;\n\n z-index: 1;\n }\n\n h2 {\n background-color: var(--component-menu-title-background, var(--md-sys-color-surface-container-highest));\n padding: 4px 8px;\n margin: 0;\n font: var(--component-menu-title);\n color: var(--component-menu-title-color, var(--md-sys-color-on-surface));\n text-transform: capitalize;\n }\n\n [templates] {\n flex: 1;\n\n display: block;\n margin: 0;\n padding: 0;\n overflow-y: auto;\n\n background-color: var(--component-menu-background-color, var(--md-sys-color-secondary-container));\n color: var(--component-menu-color, var(--md-sys-color-on-secondary-container));\n }\n\n [template] {\n display: flex;\n align-items: center;\n min-height: var(--component-menu-item-icon-size);\n padding: 0 5px 0 0;\n border-bottom: 1px solid var(--md-sys-color-outline-variant);\n font-size: 11px;\n color: var(--component-menu-item-color, var(--md-sys-color-on-secondary-container));\n text-transform: capitalize;\n }\n\n [template]:hover,\n [template]:focus {\n color: var(--component-menu-item-hover-color, var(--md-sys-color-secondary));\n font-weight: bold;\n cursor: pointer;\n }\n\n [template] img {\n margin: 5px;\n width: var(--component-menu-item-icon-size);\n height: var(--component-menu-item-icon-size);\n }\n\n component-detail {\n position: absolute;\n top: 0;\n left: 180px;\n height: 100%;\n outline: none;\n }\n\n component-detail[hidden] {\n display: none;\n }\n `\n ]\n\n @property({ type: Object }) groups: Pallet[] = []\n @property({ type: Object }) scene: Scene | null = null\n @property({ type: String }) group: string | null = ''\n\n @state() templates: PalletItem[] = []\n @state() template: PalletItem | any\n\n @query('component-detail') detail!: HTMLElement\n\n static get scopedElements() {\n return {\n 'component-detail': ComponentDetail\n }\n }\n\n render() {\n return this.group\n ? html`\n <h2 onclick=${(e: MouseEvent) => e.stopPropagation()}>\n ${/* group label — translate via group.<name> key, fall back to the\n raw group name so untranslated groups keep working.\n \"list\" is also translatable; defaults to the literal \"list\"\n which is what users have been seeing all along. */ ''}\n ${i18next.t(`group.${this.group}`, { defaultValue: this.group })}\n ${i18next.t('label.list', { defaultValue: 'list' })}\n </h2>\n\n <div templates @mouseover=${(e: MouseEvent) => this.onHoverComponent(e)}>\n ${(this.templates || []).map(template => {\n const { type } = template\n\n return html`\n <div @click=${this.onClickTemplate} data-type=${type} template>\n <img src=${String(this.templateIcon(template))} />${i18next.t(`component.${type}`)}\n </div>\n `\n })}\n </div>\n\n <component-detail\n tabindex=\"-1\"\n @focusout=${() => {\n this.template = null\n }}\n .template=${this.template}\n hidden\n >\n </component-detail>\n `\n : html``\n }\n\n updated(changes: PropertyValues<this>) {\n if (changes.has('group')) {\n if (!this.group) {\n this.templates = []\n this.setAttribute('hidden', '')\n } else {\n this.templates = this.groups.find((g: Pallet) => g.name === this.group)?.templates || []\n this.removeAttribute('active')\n }\n }\n\n if (changes.has('template')) {\n this.template && this.template.about\n ? this.detail.removeAttribute('hidden')\n : this.detail.setAttribute('hidden', '')\n }\n }\n\n findTemplate(type: string | null | undefined) {\n this.template = type && this.templates.find(template => template.type == type)\n }\n\n onHoverComponent(e: MouseEvent) {\n const button = e.target as HTMLElement\n this.findTemplate(button!.closest('[data-type]')?.getAttribute('data-type'))\n }\n\n onClickTemplate(e: MouseEvent) {\n var item = e.target as HTMLElement\n var type = item.closest('[data-type]')?.getAttribute('data-type')\n\n if (!type) {\n return\n }\n\n if (this.scene) {\n this.scene.rootContainer?.trigger('addstop') // 새로운 컴포넌트 클릭시 이전 추가 모드 정지\n this.template = this.templates.find(template => template.type == type)\n this.template && this.scene.startAddMode(JSON.parse(JSON.stringify(this.template.model)))\n }\n\n this.group = null\n }\n\n templateIcon(template: PalletItem) {\n return template.icon || noImage\n }\n}\n"]}
@@ -1,6 +1,4 @@
1
- /**
2
- * @license Copyright © HatioLab Inc. All rights reserved.
3
- */
1
+ import '@material/web/icon/icon.js';
4
2
  import { LitElement, PropertyValues } from 'lit';
5
3
  import { Scene, SceneMode } from '@hatiolab/things-scene';
6
4
  import { ComponentGroup } from '../../types.js';
@@ -8,15 +6,15 @@ import { ComponentMenu } from './component-menu.js';
8
6
  declare const ComponentToolbar_base: typeof LitElement & import("@open-wc/dedupe-mixin").Constructor<import("@open-wc/scoped-elements/types.js").ScopedElementsHost>;
9
7
  export declare class ComponentToolbar extends ComponentToolbar_base {
10
8
  static styles: import("lit").CSSResult[];
9
+ static readonly GROUP_SYMBOLS: Record<string, string>;
11
10
  componentGroupList: ComponentGroup[];
12
11
  group?: string | null;
13
12
  scene: Scene;
14
13
  mode: SceneMode;
15
- shift: HTMLImageElement;
14
+ shift: HTMLElement;
16
15
  private menu;
17
16
  private componentsContainer;
18
17
  private groups;
19
- private icons;
20
18
  updated(changes: PropertyValues<this>): void;
21
19
  static get scopedElements(): {
22
20
  'component-menu': typeof ComponentMenu;
@@ -1,35 +1,21 @@
1
+ import { __decorate } from "tslib";
2
+ import '@material/web/icon/icon.js';
1
3
  /**
2
4
  * @license Copyright © HatioLab Inc. All rights reserved.
3
5
  */
4
- import { __decorate } from "tslib";
6
+ import { i18next } from '@operato/i18n';
5
7
  import { css, html, LitElement } from 'lit';
6
8
  import { property, query, queryAll } from 'lit/decorators.js';
7
9
  import { SCENE_MODE } from '@hatiolab/things-scene';
8
10
  import { ScopedElementsMixin } from '@open-wc/scoped-elements';
9
11
  import { ComponentMenu } from './component-menu.js';
10
- import { ICON_EDIT_MODE, ICON_SHIFT_MODE } from './mode-icons.js';
11
12
  export class ComponentToolbar extends ScopedElementsMixin(LitElement) {
12
13
  constructor() {
13
14
  super(...arguments);
14
15
  this.componentGroupList = [];
15
16
  this.mode = SCENE_MODE.EDIT;
16
- this.icons = {};
17
17
  }
18
18
  updated(changes) {
19
- if (changes.has('componentGroupList')) {
20
- const color = getComputedStyle(this, null).getPropertyValue('--md-sys-color-primary');
21
- this.icons = (this.componentGroupList || [])
22
- .filter(group => { var _a; return ((_a = group.templates) === null || _a === void 0 ? void 0 : _a.length) > 0; })
23
- .reduce((sum, group) => {
24
- sum[group.name] =
25
- 'data:image/svg+xml;charset=UTF-8;base64,' + btoa(group.icon.replace(/{{strokeColor}}/g, color));
26
- return sum;
27
- }, {});
28
- this.icons['mode-edit'] =
29
- 'data:image/svg+xml;charset=UTF-8;base64,' + btoa(ICON_EDIT_MODE.replace(/{{strokeColor}}/g, color));
30
- this.icons['mode-shift'] =
31
- 'data:image/svg+xml;charset=UTF-8;base64,' + btoa(ICON_SHIFT_MODE.replace(/{{strokeColor}}/g, color));
32
- }
33
19
  if (changes.has('group')) {
34
20
  this.groups.forEach(group => {
35
21
  group.getAttribute('data-group') === this.group
@@ -46,20 +32,29 @@ export class ComponentToolbar extends ScopedElementsMixin(LitElement) {
46
32
  }
47
33
  render() {
48
34
  const componentList = this.componentGroupList || [];
49
- const modeIcon = this.icons[this.mode === SCENE_MODE.SHIFT ? 'mode-shift' : 'mode-edit'];
35
+ const shift = this.mode === SCENE_MODE.SHIFT;
50
36
  return html `
51
37
  <div components @mousewheel=${(e) => this.onWheelEvent(e)}>
52
- <img id="shift" .src=${modeIcon} @click=${(e) => this._onClickShift(e)} />
38
+ <div
39
+ id="shift"
40
+ ?active=${shift}
41
+ title=${shift ? 'pan (shift)' : 'select (edit)'}
42
+ @click=${(e) => this._onClickShift(e)}
43
+ >
44
+ <md-icon>${shift ? 'pan_tool' : 'arrow_selector_tool'}</md-icon>
45
+ </div>
53
46
 
54
47
  ${componentList
55
48
  .filter(group => { var _a; return ((_a = group.templates) === null || _a === void 0 ? void 0 : _a.length) > 0; })
56
- .map(group => html `
57
- <img
58
- data-group=${group.name}
59
- @click=${(e) => this._onClickGroup(e)}
60
- .src=${this.icons[group.name]}
61
- />
62
- `)}
49
+ .map(group => {
50
+ const caption = i18next.t(`group.${group.name}`, { defaultValue: group.name });
51
+ return html `
52
+ <div group data-group=${group.name} title=${caption} @click=${(e) => this._onClickGroup(e)}>
53
+ <md-icon>${group.symbol || ComponentToolbar.GROUP_SYMBOLS[group.name] || 'category'}</md-icon>
54
+ <span>${caption}</span>
55
+ </div>
56
+ `;
57
+ })}
63
58
  </div>
64
59
 
65
60
  <component-menu
@@ -89,15 +84,7 @@ export class ComponentToolbar extends ScopedElementsMixin(LitElement) {
89
84
  }));
90
85
  }
91
86
  _onClickShift(e) {
92
- const shift = this.shift;
93
- if (shift.hasAttribute('active')) {
94
- shift.removeAttribute('active');
95
- this._setMode(SCENE_MODE.EDIT);
96
- }
97
- else {
98
- shift.setAttribute('active', '');
99
- this._setMode(SCENE_MODE.SHIFT);
100
- }
87
+ this._setMode(this.mode === SCENE_MODE.SHIFT ? SCENE_MODE.EDIT : SCENE_MODE.SHIFT);
101
88
  }
102
89
  async _onClickGroup(e) {
103
90
  var _a, _b;
@@ -111,6 +98,13 @@ export class ComponentToolbar extends ScopedElementsMixin(LitElement) {
111
98
  }
112
99
  ComponentToolbar.styles = [
113
100
  css `
101
+ /*
102
+ * The palette rail: one glyph and one word per group, in the same Material family and ink
103
+ * as the toolbar and the panel tabs. The old rail was a column of filled pictograms (a
104
+ * factory with smoke, a forklift) drawn at different densities, with no captions - a
105
+ * person hunting for a component had to guess from a picture. The caption is the point;
106
+ * the rail is a little wider to hold it.
107
+ */
114
108
  :host {
115
109
  left: 0;
116
110
  display: block;
@@ -118,34 +112,86 @@ ComponentToolbar.styles = [
118
112
 
119
113
  width: var(--component-toolbar-icon-size);
120
114
  background-color: var(--component-toolbar-background-color);
115
+ border-right: var(--component-toolbar-border);
116
+ box-sizing: border-box;
121
117
  }
122
118
 
123
119
  [components] {
124
120
  display: block;
125
- padding: 0;
121
+ padding: 4px 0;
126
122
  margin: 0;
127
123
 
128
124
  width: 100%;
129
125
  height: 100%;
130
126
  overflow: hidden;
127
+ box-sizing: border-box;
131
128
  }
132
129
 
133
- [components] > img {
130
+ [components] > [group],
131
+ [components] > #shift {
134
132
  display: flex;
135
- flex-direction: row;
136
-
137
- width: var(--component-toolbar-icon-size);
138
- height: var(--component-toolbar-icon-size);
139
- min-width: 50%;
133
+ flex-direction: column;
134
+ align-items: center;
135
+ justify-content: center;
136
+ gap: 3px;
140
137
 
141
- border-bottom: var(--component-toolbar-border);
142
- margin: 0;
143
- padding: 6px;
138
+ width: calc(100% - 8px);
139
+ min-height: 50px;
140
+ margin: 0 4px 2px;
141
+ padding: 6px 2px 5px;
144
142
  box-sizing: border-box;
143
+ border-radius: 8px;
144
+
145
+ color: var(--component-toolbar-icon-color, var(--md-sys-color-on-surface-variant));
146
+ cursor: pointer;
147
+ user-select: none;
148
+ }
149
+
150
+ [components] > [group] md-icon,
151
+ [components] > #shift md-icon {
152
+ --md-icon-size: 22px;
153
+ font-variation-settings: 'wght' 300, 'opsz' 24;
154
+ }
155
+
156
+ [components] > [group] span {
157
+ max-width: 100%;
158
+ font-size: 0.58rem;
159
+ line-height: 1.15;
160
+ letter-spacing: 0.01em;
161
+ text-align: center;
162
+ overflow: hidden;
163
+ display: -webkit-box;
164
+ -webkit-line-clamp: 2;
165
+ -webkit-box-orient: vertical;
166
+ /* Break between words only; a long single word gets the full width, never a hyphen-less split. */
167
+ word-break: normal;
168
+ overflow-wrap: normal;
169
+ }
170
+
171
+ [components] > [group]:hover,
172
+ [components] > #shift:hover {
173
+ color: var(--md-sys-color-on-surface);
174
+ background-color: var(--component-toolbar-hover-background, var(--md-sys-color-surface-container-high));
175
+ }
176
+
177
+ /* The open group and the pressed mode read as pressed, in the scheme's own container tone. */
178
+ [components] > [group][active],
179
+ [components] > #shift[active] {
180
+ color: var(--md-sys-color-on-secondary-container);
181
+ background-color: var(--component-toolbar-active-background, var(--md-sys-color-secondary-container));
182
+ }
183
+
184
+ [components] > [group][active] md-icon,
185
+ [components] > #shift[active] md-icon {
186
+ font-variation-settings: 'wght' 500, 'opsz' 24, 'FILL' 1;
145
187
  }
146
188
 
147
- #shift[active] {
148
- background-color: #beb9b3;
189
+ /* The mode switch stands apart from the groups below it. */
190
+ [components] > #shift {
191
+ min-height: 40px;
192
+ margin-bottom: 6px;
193
+ border-bottom: 1px solid var(--md-sys-color-outline-variant);
194
+ border-radius: 8px 8px 0 0;
149
195
  }
150
196
 
151
197
  component-menu {
@@ -161,6 +207,27 @@ ComponentToolbar.styles = [
161
207
  }
162
208
  `
163
209
  ];
210
+ /* One glyph per known group; a group registered with its own `symbol` wins. */
211
+ ComponentToolbar.GROUP_SYMBOLS = {
212
+ line: 'timeline',
213
+ shape: 'category',
214
+ textAndMedia: 'text_fields',
215
+ chartAndGauge: 'bar_chart',
216
+ table: 'table_chart',
217
+ container: 'space_dashboard',
218
+ dataSource: 'database',
219
+ IoT: 'sensors',
220
+ '3D': 'view_in_ar',
221
+ facility: 'factory',
222
+ conveyance: 'conveyor_belt',
223
+ storage: 'warehouse',
224
+ warehouse: 'inventory_2',
225
+ transport: 'forklift',
226
+ manufacturing: 'precision_manufacturing',
227
+ form: 'list_alt',
228
+ materialDesign: 'widgets',
229
+ etc: 'more_horiz'
230
+ };
164
231
  __decorate([
165
232
  property({ type: Array })
166
233
  ], ComponentToolbar.prototype, "componentGroupList", void 0);
@@ -1 +1 @@
1
- {"version":3,"file":"component-toolbar.js","sourceRoot":"","sources":["../../../../src/modeller/component-toolbar/component-toolbar.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport { css, html, LitElement, PropertyValues } from 'lit'\nimport { property, query, queryAll } from 'lit/decorators.js'\n\nimport { Scene, SCENE_MODE, SceneMode } from '@hatiolab/things-scene'\nimport { ScopedElementsMixin } from '@open-wc/scoped-elements'\n\nimport { ComponentGroup } from '../../types.js'\nimport { ComponentMenu } from './component-menu.js'\nimport { ICON_EDIT_MODE, ICON_SHIFT_MODE } from './mode-icons.js'\n\nexport class ComponentToolbar extends ScopedElementsMixin(LitElement) {\n static styles = [\n css`\n :host {\n left: 0;\n display: block;\n position: relative;\n\n width: var(--component-toolbar-icon-size);\n background-color: var(--component-toolbar-background-color);\n }\n\n [components] {\n display: block;\n padding: 0;\n margin: 0;\n\n width: 100%;\n height: 100%;\n overflow: hidden;\n }\n\n [components] > img {\n display: flex;\n flex-direction: row;\n\n width: var(--component-toolbar-icon-size);\n height: var(--component-toolbar-icon-size);\n min-width: 50%;\n\n border-bottom: var(--component-toolbar-border);\n margin: 0;\n padding: 6px;\n box-sizing: border-box;\n }\n\n #shift[active] {\n background-color: #beb9b3;\n }\n\n component-menu {\n position: absolute;\n top: 0;\n left: var(--component-toolbar-icon-size);\n height: 100%;\n outline: none;\n }\n\n component-menu[hidden] {\n display: none;\n }\n `\n ]\n\n @property({ type: Array }) componentGroupList: ComponentGroup[] = []\n @property({ type: String }) group?: string | null\n @property({ type: Object }) scene!: Scene\n @property({ type: Number }) mode: SceneMode = SCENE_MODE.EDIT\n\n @query('#shift') shift!: HTMLImageElement\n @query('component-menu') private menu!: HTMLElement\n @query('div[components]') private componentsContainer!: HTMLElement\n @queryAll('[data-group]') private groups!: NodeListOf<HTMLElement>\n\n private icons: { [name: string]: string } = {}\n\n updated(changes: PropertyValues<this>) {\n if (changes.has('componentGroupList')) {\n const color = getComputedStyle(this, null).getPropertyValue('--md-sys-color-primary')\n\n this.icons = (this.componentGroupList || [])\n .filter(group => group.templates?.length > 0)\n .reduce(\n (sum, group: ComponentGroup) => {\n sum[group.name] =\n 'data:image/svg+xml;charset=UTF-8;base64,' + btoa(group.icon.replace(/{{strokeColor}}/g, color))\n return sum\n },\n {} as { [name: string]: string }\n )\n\n this.icons['mode-edit'] =\n 'data:image/svg+xml;charset=UTF-8;base64,' + btoa(ICON_EDIT_MODE.replace(/{{strokeColor}}/g, color))\n this.icons['mode-shift'] =\n 'data:image/svg+xml;charset=UTF-8;base64,' + btoa(ICON_SHIFT_MODE.replace(/{{strokeColor}}/g, color))\n }\n\n if (changes.has('group')) {\n this.groups.forEach(group => {\n group.getAttribute('data-group') === this.group\n ? group.setAttribute('active', '')\n : group.removeAttribute('active')\n })\n\n this.group ? this.menu.removeAttribute('hidden') : this.menu.setAttribute('hidden', '')\n }\n }\n\n static get scopedElements() {\n return {\n 'component-menu': ComponentMenu\n }\n }\n\n render() {\n const componentList = this.componentGroupList || []\n const modeIcon = this.icons[this.mode === SCENE_MODE.SHIFT ? 'mode-shift' : 'mode-edit']\n\n return html`\n <div components @mousewheel=${(e: MouseEvent) => this.onWheelEvent(e)}>\n <img id=\"shift\" .src=${modeIcon} @click=${(e: MouseEvent) => this._onClickShift(e)} />\n\n ${componentList\n .filter(group => group.templates?.length > 0)\n .map(\n group => html`\n <img\n data-group=${group.name}\n @click=${(e: MouseEvent) => this._onClickGroup(e)}\n .src=${this.icons[group.name]}\n />\n `\n )}\n </div>\n\n <component-menu\n tabindex=\"-1\"\n @focusout=${() => {\n this.group = null\n }}\n .scene=${this.scene}\n .group=${this.group}\n .groups=${componentList}\n hidden\n >\n </component-menu>\n `\n }\n\n onWheelEvent(e: Event) {\n var delta = Math.max(-1, Math.min(1, (e as WheelEvent).deltaY || -(e as WheelEvent).detail))\n this.componentsContainer.scrollTop += delta * 10\n\n e.preventDefault()\n }\n\n _setMode(mode: SceneMode) {\n this.mode = mode\n\n this.dispatchEvent(\n new CustomEvent('mode-changed', {\n bubbles: true,\n composed: true,\n detail: { value: mode }\n })\n )\n }\n\n _onClickShift(e: MouseEvent) {\n const shift = this.shift\n\n if (shift.hasAttribute('active')) {\n shift.removeAttribute('active')\n this._setMode(SCENE_MODE.EDIT)\n } else {\n shift.setAttribute('active', '')\n this._setMode(SCENE_MODE.SHIFT)\n }\n }\n\n async _onClickGroup(e: MouseEvent) {\n var button = e.target as HTMLElement\n\n this.group = button!.closest('[data-group]')?.getAttribute('data-group')\n\n if (!this.group) return\n\n await this.updateComplete\n\n this.menu?.focus()\n }\n}\n"]}
1
+ {"version":3,"file":"component-toolbar.js","sourceRoot":"","sources":["../../../../src/modeller/component-toolbar/component-toolbar.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\n/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport { i18next } from '@operato/i18n'\nimport { css, html, LitElement, PropertyValues } from 'lit'\nimport { property, query, queryAll } from 'lit/decorators.js'\n\nimport { Scene, SCENE_MODE, SceneMode } from '@hatiolab/things-scene'\nimport { ScopedElementsMixin } from '@open-wc/scoped-elements'\n\nimport { ComponentGroup } from '../../types.js'\nimport { ComponentMenu } from './component-menu.js'\n\nexport class ComponentToolbar extends ScopedElementsMixin(LitElement) {\n static styles = [\n css`\n /*\n * The palette rail: one glyph and one word per group, in the same Material family and ink\n * as the toolbar and the panel tabs. The old rail was a column of filled pictograms (a\n * factory with smoke, a forklift) drawn at different densities, with no captions - a\n * person hunting for a component had to guess from a picture. The caption is the point;\n * the rail is a little wider to hold it.\n */\n :host {\n left: 0;\n display: block;\n position: relative;\n\n width: var(--component-toolbar-icon-size);\n background-color: var(--component-toolbar-background-color);\n border-right: var(--component-toolbar-border);\n box-sizing: border-box;\n }\n\n [components] {\n display: block;\n padding: 4px 0;\n margin: 0;\n\n width: 100%;\n height: 100%;\n overflow: hidden;\n box-sizing: border-box;\n }\n\n [components] > [group],\n [components] > #shift {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 3px;\n\n width: calc(100% - 8px);\n min-height: 50px;\n margin: 0 4px 2px;\n padding: 6px 2px 5px;\n box-sizing: border-box;\n border-radius: 8px;\n\n color: var(--component-toolbar-icon-color, var(--md-sys-color-on-surface-variant));\n cursor: pointer;\n user-select: none;\n }\n\n [components] > [group] md-icon,\n [components] > #shift md-icon {\n --md-icon-size: 22px;\n font-variation-settings: 'wght' 300, 'opsz' 24;\n }\n\n [components] > [group] span {\n max-width: 100%;\n font-size: 0.58rem;\n line-height: 1.15;\n letter-spacing: 0.01em;\n text-align: center;\n overflow: hidden;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n /* Break between words only; a long single word gets the full width, never a hyphen-less split. */\n word-break: normal;\n overflow-wrap: normal;\n }\n\n [components] > [group]:hover,\n [components] > #shift:hover {\n color: var(--md-sys-color-on-surface);\n background-color: var(--component-toolbar-hover-background, var(--md-sys-color-surface-container-high));\n }\n\n /* The open group and the pressed mode read as pressed, in the scheme's own container tone. */\n [components] > [group][active],\n [components] > #shift[active] {\n color: var(--md-sys-color-on-secondary-container);\n background-color: var(--component-toolbar-active-background, var(--md-sys-color-secondary-container));\n }\n\n [components] > [group][active] md-icon,\n [components] > #shift[active] md-icon {\n font-variation-settings: 'wght' 500, 'opsz' 24, 'FILL' 1;\n }\n\n /* The mode switch stands apart from the groups below it. */\n [components] > #shift {\n min-height: 40px;\n margin-bottom: 6px;\n border-bottom: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 8px 8px 0 0;\n }\n\n component-menu {\n position: absolute;\n top: 0;\n left: var(--component-toolbar-icon-size);\n height: 100%;\n outline: none;\n }\n\n component-menu[hidden] {\n display: none;\n }\n `\n ]\n\n /* One glyph per known group; a group registered with its own `symbol` wins. */\n static readonly GROUP_SYMBOLS: Record<string, string> = {\n line: 'timeline',\n shape: 'category',\n textAndMedia: 'text_fields',\n chartAndGauge: 'bar_chart',\n table: 'table_chart',\n container: 'space_dashboard',\n dataSource: 'database',\n IoT: 'sensors',\n '3D': 'view_in_ar',\n facility: 'factory',\n conveyance: 'conveyor_belt',\n storage: 'warehouse',\n warehouse: 'inventory_2',\n transport: 'forklift',\n manufacturing: 'precision_manufacturing',\n form: 'list_alt',\n materialDesign: 'widgets',\n etc: 'more_horiz'\n }\n\n @property({ type: Array }) componentGroupList: ComponentGroup[] = []\n @property({ type: String }) group?: string | null\n @property({ type: Object }) scene!: Scene\n @property({ type: Number }) mode: SceneMode = SCENE_MODE.EDIT\n\n @query('#shift') shift!: HTMLElement\n @query('component-menu') private menu!: HTMLElement\n @query('div[components]') private componentsContainer!: HTMLElement\n @queryAll('[data-group]') private groups!: NodeListOf<HTMLElement>\n\n updated(changes: PropertyValues<this>) {\n if (changes.has('group')) {\n this.groups.forEach(group => {\n group.getAttribute('data-group') === this.group\n ? group.setAttribute('active', '')\n : group.removeAttribute('active')\n })\n\n this.group ? this.menu.removeAttribute('hidden') : this.menu.setAttribute('hidden', '')\n }\n }\n\n static get scopedElements() {\n return {\n 'component-menu': ComponentMenu\n }\n }\n\n render() {\n const componentList = this.componentGroupList || []\n const shift = this.mode === SCENE_MODE.SHIFT\n\n return html`\n <div components @mousewheel=${(e: MouseEvent) => this.onWheelEvent(e)}>\n <div\n id=\"shift\"\n ?active=${shift}\n title=${shift ? 'pan (shift)' : 'select (edit)'}\n @click=${(e: MouseEvent) => this._onClickShift(e)}\n >\n <md-icon>${shift ? 'pan_tool' : 'arrow_selector_tool'}</md-icon>\n </div>\n\n ${componentList\n .filter(group => group.templates?.length > 0)\n .map(group => {\n const caption = i18next.t(`group.${group.name}`, { defaultValue: group.name })\n return html`\n <div group data-group=${group.name} title=${caption} @click=${(e: MouseEvent) => this._onClickGroup(e)}>\n <md-icon>${group.symbol || ComponentToolbar.GROUP_SYMBOLS[group.name] || 'category'}</md-icon>\n <span>${caption}</span>\n </div>\n `\n })}\n </div>\n\n <component-menu\n tabindex=\"-1\"\n @focusout=${() => {\n this.group = null\n }}\n .scene=${this.scene}\n .group=${this.group}\n .groups=${componentList}\n hidden\n >\n </component-menu>\n `\n }\n\n onWheelEvent(e: Event) {\n var delta = Math.max(-1, Math.min(1, (e as WheelEvent).deltaY || -(e as WheelEvent).detail))\n this.componentsContainer.scrollTop += delta * 10\n\n e.preventDefault()\n }\n\n _setMode(mode: SceneMode) {\n this.mode = mode\n\n this.dispatchEvent(\n new CustomEvent('mode-changed', {\n bubbles: true,\n composed: true,\n detail: { value: mode }\n })\n )\n }\n\n _onClickShift(e: MouseEvent) {\n this._setMode(this.mode === SCENE_MODE.SHIFT ? SCENE_MODE.EDIT : SCENE_MODE.SHIFT)\n }\n\n async _onClickGroup(e: MouseEvent) {\n var button = e.target as HTMLElement\n\n this.group = button!.closest('[data-group]')?.getAttribute('data-group')\n\n if (!this.group) return\n\n await this.updateComplete\n\n this.menu?.focus()\n }\n}\n"]}
@@ -24,6 +24,9 @@ export const style = css `
24
24
  [tools] {
25
25
  display: flex;
26
26
  align-items: center;
27
+ /* The row fills the bar, so centring the icons means the bar's middle, not the row's. */
28
+ height: 100%;
29
+ box-sizing: border-box;
27
30
  overflow: hidden;
28
31
  padding: 0px 10px;
29
32
  }
@@ -43,8 +46,8 @@ export const style = css `
43
46
  [tools] > .vline {
44
47
  display: block;
45
48
  flex: none;
46
- border-left: 1px solid rgba(255, 255, 255, 0.2);
47
- border-right: 1px solid rgba(0, 0, 0, 0.15);
49
+ border-left: 1px solid var(--md-sys-color-outline-variant);
50
+ border-right: 0;
48
51
  width: 0px;
49
52
  height: 18px;
50
53
  margin: 0 3px;
@@ -56,13 +59,42 @@ export const style = css `
56
59
  background: var(--url-icon-htoolbar) no-repeat;
57
60
  background-position-x: 50%;
58
61
  opacity: 0.8;
62
+ /* The sprite is white art; on a light bar the theme sets a filter that darkens it. */
63
+ filter: var(--edit-toolbar-icon-filter, none);
59
64
  }
60
65
  span[button]:hover {
61
66
  opacity: 1;
62
- background-color: rgba(0, 0, 0, 0.1);
67
+ background-color: var(--md-sys-color-surface-container-highest);
63
68
  cursor: pointer;
64
69
  }
65
70
 
71
+ /* Glyph buttons (the compact row): no sprite, the scheme's ink, a soft hover. */
72
+ span[button][icon] {
73
+ display: inline-flex;
74
+ align-items: center;
75
+ justify-content: center;
76
+ min-width: 32px;
77
+ min-height: 32px;
78
+ margin: 0 1px;
79
+ border-radius: 6px;
80
+ background: transparent;
81
+ filter: none;
82
+ opacity: 1;
83
+ color: var(--md-sys-color-on-surface-variant);
84
+ }
85
+ span[button][icon] md-icon {
86
+ --md-icon-size: 19px;
87
+ font-variation-settings: 'wght' 400;
88
+ }
89
+ span[button][icon]:hover {
90
+ color: var(--md-sys-color-on-surface);
91
+ background-color: var(--md-sys-color-surface-container-highest);
92
+ }
93
+ span[button][icon][disabled] {
94
+ opacity: 0.35;
95
+ pointer-events: none;
96
+ }
97
+
66
98
  #fullscreen,
67
99
  #toggle-property {
68
100
  flex: none;
@@ -276,5 +308,17 @@ export const style = css `
276
308
  #toggle-property[active] {
277
309
  background: var(--url-icon-collapse-active) 80% 10px no-repeat;
278
310
  }
311
+
312
+ /* Glyph buttons win over the id rules above (an id outranks an attribute): no sprite, no
313
+ * bigger-icon box, no left rule, whatever the id says. */
314
+ span[button][icon]#fullscreen,
315
+ span[button][icon]#toggle-property,
316
+ span[button][icon]#toggle-property[active] {
317
+ background: transparent;
318
+ width: auto;
319
+ height: auto;
320
+ border-left: 0;
321
+ float: none;
322
+ }
279
323
  `;
280
324
  //# sourceMappingURL=edit-toolbar-style.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"edit-toolbar-style.js","sourceRoot":"","sources":["../../../src/modeller/edit-toolbar-style.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAA;AAEzB,MAAM,CAAC,MAAM,KAAK,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkRvB,CAAA","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport { css } from 'lit'\n\nexport const style = css`\n /*\n * 편집 툴바는 도구 표면이다. 기본값이 secondary 였는데, 그 역할은 어두운 표면 위에 놓는\n * 강조색이라 다크 스킴에서 밝은 색이 된다 — 툴바 전체가 밝은 갈색 띠로 보였다.\n * 표면 계단을 쓰고 아래쪽 캔버스와의 경계는 경계선으로 준다.\n */\n :host {\n background-color: var(--edit-toolbar-background-color, var(--md-sys-color-surface-container-high));\n color: var(--edit-toolbar-color, var(--md-sys-color-on-surface));\n /*\n * 아래 구분선을 border 로 주면 1px 이 레이아웃을 늘린다. overflow-x: hidden 은 CSS 규칙상\n * overflow-y 를 auto 로 만들기 때문에, 그 1px 때문에 툴바에 세로 스크롤바가 생겼다.\n * inset box-shadow 는 레이아웃에 영향을 주지 않으므로 같은 선을 안전하게 얻는다.\n */\n box-shadow: inset 0 -1px 0 var(--md-sys-color-outline-variant);\n\n overflow: hidden;\n }\n\n [tools] {\n display: flex;\n align-items: center;\n overflow: hidden;\n padding: 0px 10px;\n }\n\n [tools] > * {\n padding: 0px;\n }\n\n [tools] > span[button] {\n min-width: 30px;\n }\n\n [tools] > span[padding] {\n flex: 1;\n }\n\n [tools] > .vline {\n display: block;\n flex: none;\n border-left: 1px solid rgba(255, 255, 255, 0.2);\n border-right: 1px solid rgba(0, 0, 0, 0.15);\n width: 0px;\n height: 18px;\n margin: 0 3px;\n }\n\n span[button] {\n min-height: 35px;\n\n background: var(--url-icon-htoolbar) no-repeat;\n background-position-x: 50%;\n opacity: 0.8;\n }\n span[button]:hover {\n opacity: 1;\n background-color: rgba(0, 0, 0, 0.1);\n cursor: pointer;\n }\n\n #fullscreen,\n #toggle-property {\n flex: none;\n }\n\n #align-left {\n background-position-y: 8px;\n }\n\n #align-center {\n background-position-y: -42px;\n }\n\n #align-right {\n background-position-y: -92px;\n }\n\n #align-top {\n background-position-y: -142px;\n }\n\n #align-middle {\n background-position-y: -192px;\n }\n\n #align-bottom {\n background-position-y: -242px;\n }\n\n #undo {\n background-position-y: -592px;\n }\n\n #redo {\n background-position-y: -642px;\n }\n\n #front {\n background-position-y: -292px;\n }\n\n #back {\n background-position-y: -342px;\n }\n\n #forward {\n background-position-y: -392px;\n }\n\n #backward {\n background-position-y: -442px;\n }\n\n #symmetry-x {\n background-position-y: -492px;\n }\n\n #symmetry-y {\n background-position-y: -542px;\n }\n\n #group {\n background-position-y: -492px;\n }\n\n #ungroup {\n background-position-y: -542px;\n }\n\n #fullscreen {\n background-position-y: -692px;\n }\n\n #toggle-property {\n background-position-y: -692px;\n float: right;\n }\n\n #zoomin {\n background-position-y: -742px;\n }\n\n #zoomout {\n background-position-y: -792px;\n }\n\n #fit-scene {\n background-position-y: -1492px;\n }\n\n #cut {\n background-position-y: -842px;\n }\n\n #copy {\n background-position-y: -892px;\n }\n\n #paste {\n background-position-y: -942px;\n }\n\n #delete {\n background-position-y: -992px;\n }\n\n #font-increase {\n background-position-y: -1042px;\n }\n\n #font-decrease {\n background-position-y: -1092px;\n }\n\n #style-copy {\n background-position-y: -1142px;\n }\n\n #databind-copy {\n background-position-y: -1692px;\n }\n\n #context-menu {\n background-position-y: -692px;\n }\n\n #symmetry-x {\n background-position-y: -1192px;\n }\n\n #symmetry-y {\n background-position-y: -1242px;\n }\n\n #rotate-cw {\n background-position-y: -1292px;\n }\n\n #rotate-ccw {\n background-position-y: -1342px;\n }\n\n #distribute-horizontal {\n background-position-y: -1542px;\n }\n\n #distribute-vertical {\n background-position-y: -1593px;\n }\n\n #align-z-front {\n background-position-y: -142px;\n filter: hue-rotate(180deg);\n }\n\n #align-z-middle {\n background-position-y: -192px;\n filter: hue-rotate(180deg);\n }\n\n #align-z-back {\n background-position-y: -242px;\n filter: hue-rotate(180deg);\n }\n\n #distribute-z {\n background-position-y: -1593px;\n filter: hue-rotate(180deg);\n }\n\n .gizmo-btn {\n background: none !important;\n color: rgba(255, 255, 255, 0.5);\n min-width: 24px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n border-radius: 3px;\n padding: 2px;\n }\n\n .gizmo-btn[disabled] {\n opacity: 0.3;\n pointer-events: none;\n }\n\n #toggle-property {\n background-position-y: -1392px;\n }\n\n #preview {\n background-position-y: -1640px;\n }\n\n /* bigger buttons */\n #fullscreen {\n background: var(--url-icon-fullscreen) 50% 10px no-repeat;\n width: var(--edit-toolbar-bigger-icon-size);\n height: var(--edit-toolbar-bigger-icon-size);\n border-left: var(--edit-toolbar-bigger-icon-line);\n }\n\n #toggle-property {\n background: var(--url-icon-collapse) 80% 10px no-repeat;\n width: var(--edit-toolbar-bigger-icon-size);\n height: var(--edit-toolbar-bigger-icon-size);\n border-left: var(--edit-toolbar-bigger-icon-line);\n }\n\n #toggle-property[active] {\n background: var(--url-icon-collapse-active) 80% 10px no-repeat;\n }\n`\n"]}
1
+ {"version":3,"file":"edit-toolbar-style.js","sourceRoot":"","sources":["../../../src/modeller/edit-toolbar-style.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAA;AAEzB,MAAM,CAAC,MAAM,KAAK,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8TvB,CAAA","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport { css } from 'lit'\n\nexport const style = css`\n /*\n * 편집 툴바는 도구 표면이다. 기본값이 secondary 였는데, 그 역할은 어두운 표면 위에 놓는\n * 강조색이라 다크 스킴에서 밝은 색이 된다 — 툴바 전체가 밝은 갈색 띠로 보였다.\n * 표면 계단을 쓰고 아래쪽 캔버스와의 경계는 경계선으로 준다.\n */\n :host {\n background-color: var(--edit-toolbar-background-color, var(--md-sys-color-surface-container-high));\n color: var(--edit-toolbar-color, var(--md-sys-color-on-surface));\n /*\n * 아래 구분선을 border 로 주면 1px 이 레이아웃을 늘린다. overflow-x: hidden 은 CSS 규칙상\n * overflow-y 를 auto 로 만들기 때문에, 그 1px 때문에 툴바에 세로 스크롤바가 생겼다.\n * inset box-shadow 는 레이아웃에 영향을 주지 않으므로 같은 선을 안전하게 얻는다.\n */\n box-shadow: inset 0 -1px 0 var(--md-sys-color-outline-variant);\n\n overflow: hidden;\n }\n\n [tools] {\n display: flex;\n align-items: center;\n /* The row fills the bar, so centring the icons means the bar's middle, not the row's. */\n height: 100%;\n box-sizing: border-box;\n overflow: hidden;\n padding: 0px 10px;\n }\n\n [tools] > * {\n padding: 0px;\n }\n\n [tools] > span[button] {\n min-width: 30px;\n }\n\n [tools] > span[padding] {\n flex: 1;\n }\n\n [tools] > .vline {\n display: block;\n flex: none;\n border-left: 1px solid var(--md-sys-color-outline-variant);\n border-right: 0;\n width: 0px;\n height: 18px;\n margin: 0 3px;\n }\n\n span[button] {\n min-height: 35px;\n\n background: var(--url-icon-htoolbar) no-repeat;\n background-position-x: 50%;\n opacity: 0.8;\n /* The sprite is white art; on a light bar the theme sets a filter that darkens it. */\n filter: var(--edit-toolbar-icon-filter, none);\n }\n span[button]:hover {\n opacity: 1;\n background-color: var(--md-sys-color-surface-container-highest);\n cursor: pointer;\n }\n\n /* Glyph buttons (the compact row): no sprite, the scheme's ink, a soft hover. */\n span[button][icon] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 32px;\n min-height: 32px;\n margin: 0 1px;\n border-radius: 6px;\n background: transparent;\n filter: none;\n opacity: 1;\n color: var(--md-sys-color-on-surface-variant);\n }\n span[button][icon] md-icon {\n --md-icon-size: 19px;\n font-variation-settings: 'wght' 400;\n }\n span[button][icon]:hover {\n color: var(--md-sys-color-on-surface);\n background-color: var(--md-sys-color-surface-container-highest);\n }\n span[button][icon][disabled] {\n opacity: 0.35;\n pointer-events: none;\n }\n\n #fullscreen,\n #toggle-property {\n flex: none;\n }\n\n #align-left {\n background-position-y: 8px;\n }\n\n #align-center {\n background-position-y: -42px;\n }\n\n #align-right {\n background-position-y: -92px;\n }\n\n #align-top {\n background-position-y: -142px;\n }\n\n #align-middle {\n background-position-y: -192px;\n }\n\n #align-bottom {\n background-position-y: -242px;\n }\n\n #undo {\n background-position-y: -592px;\n }\n\n #redo {\n background-position-y: -642px;\n }\n\n #front {\n background-position-y: -292px;\n }\n\n #back {\n background-position-y: -342px;\n }\n\n #forward {\n background-position-y: -392px;\n }\n\n #backward {\n background-position-y: -442px;\n }\n\n #symmetry-x {\n background-position-y: -492px;\n }\n\n #symmetry-y {\n background-position-y: -542px;\n }\n\n #group {\n background-position-y: -492px;\n }\n\n #ungroup {\n background-position-y: -542px;\n }\n\n #fullscreen {\n background-position-y: -692px;\n }\n\n #toggle-property {\n background-position-y: -692px;\n float: right;\n }\n\n #zoomin {\n background-position-y: -742px;\n }\n\n #zoomout {\n background-position-y: -792px;\n }\n\n #fit-scene {\n background-position-y: -1492px;\n }\n\n #cut {\n background-position-y: -842px;\n }\n\n #copy {\n background-position-y: -892px;\n }\n\n #paste {\n background-position-y: -942px;\n }\n\n #delete {\n background-position-y: -992px;\n }\n\n #font-increase {\n background-position-y: -1042px;\n }\n\n #font-decrease {\n background-position-y: -1092px;\n }\n\n #style-copy {\n background-position-y: -1142px;\n }\n\n #databind-copy {\n background-position-y: -1692px;\n }\n\n #context-menu {\n background-position-y: -692px;\n }\n\n #symmetry-x {\n background-position-y: -1192px;\n }\n\n #symmetry-y {\n background-position-y: -1242px;\n }\n\n #rotate-cw {\n background-position-y: -1292px;\n }\n\n #rotate-ccw {\n background-position-y: -1342px;\n }\n\n #distribute-horizontal {\n background-position-y: -1542px;\n }\n\n #distribute-vertical {\n background-position-y: -1593px;\n }\n\n #align-z-front {\n background-position-y: -142px;\n filter: hue-rotate(180deg);\n }\n\n #align-z-middle {\n background-position-y: -192px;\n filter: hue-rotate(180deg);\n }\n\n #align-z-back {\n background-position-y: -242px;\n filter: hue-rotate(180deg);\n }\n\n #distribute-z {\n background-position-y: -1593px;\n filter: hue-rotate(180deg);\n }\n\n .gizmo-btn {\n background: none !important;\n color: rgba(255, 255, 255, 0.5);\n min-width: 24px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n border-radius: 3px;\n padding: 2px;\n }\n\n .gizmo-btn[disabled] {\n opacity: 0.3;\n pointer-events: none;\n }\n\n #toggle-property {\n background-position-y: -1392px;\n }\n\n #preview {\n background-position-y: -1640px;\n }\n\n /* bigger buttons */\n #fullscreen {\n background: var(--url-icon-fullscreen) 50% 10px no-repeat;\n width: var(--edit-toolbar-bigger-icon-size);\n height: var(--edit-toolbar-bigger-icon-size);\n border-left: var(--edit-toolbar-bigger-icon-line);\n }\n\n #toggle-property {\n background: var(--url-icon-collapse) 80% 10px no-repeat;\n width: var(--edit-toolbar-bigger-icon-size);\n height: var(--edit-toolbar-bigger-icon-size);\n border-left: var(--edit-toolbar-bigger-icon-line);\n }\n\n #toggle-property[active] {\n background: var(--url-icon-collapse-active) 80% 10px no-repeat;\n }\n\n /* Glyph buttons win over the id rules above (an id outranks an attribute): no sprite, no\n * bigger-icon box, no left rule, whatever the id says. */\n span[button][icon]#fullscreen,\n span[button][icon]#toggle-property,\n span[button][icon]#toggle-property[active] {\n background: transparent;\n width: auto;\n height: auto;\n border-left: 0;\n float: none;\n }\n`\n"]}
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * @license Copyright © HatioLab Inc. All rights reserved.
3
3
  */
4
+ import '@material/web/icon/icon.js';
4
5
  import { LitElement, PropertyValues } from 'lit';
5
6
  import { Component, Scene } from '@hatiolab/things-scene';
6
7
  import './bulk-create-dialog.js';
@@ -9,12 +10,17 @@ export declare class EditToolbar extends LitElement {
9
10
  scene?: Scene;
10
11
  selected: any[];
11
12
  hideProperty: boolean;
13
+ compact: boolean;
12
14
  private _dimension;
13
15
  private _gizmoAttached;
14
16
  private cliped?;
17
+ connectedCallback(): void;
18
+ disconnectedCallback(): void;
15
19
  firstUpdated(): void;
16
20
  updated(changes: PropertyValues<this>): void;
17
21
  render(): import("lit-html").TemplateResult<1>;
22
+ private renderWindowButtons;
23
+ private _onFullscreenChange;
18
24
  onWheelEvent(e: Event): void;
19
25
  getSymbol(key: string): string;
20
26
  private getShortcutString;