@fmsim/machine 1.0.48 → 1.0.49

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.
@@ -4,101 +4,168 @@
4
4
 
5
5
  import '@material/web/icon/icon.js'
6
6
 
7
- import { css, html } from 'lit'
8
- import { customElement, state } from 'lit/decorators.js'
7
+ import { css, html, nothing } from 'lit'
8
+ import { customElement, state, query, queryAll } from 'lit/decorators.js'
9
9
 
10
10
  import { OxFormField } from '@operato/input'
11
- import { Node } from '../types'
12
11
 
13
12
  @customElement('ox-input-nodes')
14
13
  export class OxInputNodes extends OxFormField {
15
14
  static styles = [
16
15
  css`
17
16
  :host {
18
- display: flex;
19
- --md-icon-size: 1.4em;
20
- }
21
-
22
- fieldset {
23
- flex: 1;
24
- font-size: 0.8em;
25
- border: 0;
26
- border-bottom: 1px solid;
27
- background-color: var(--md-sys-color-surface-variant);
28
- padding: var(--spacing-medium);
29
- }
30
-
31
- ul {
32
17
  display: flex;
33
18
  flex-direction: column;
34
- gap: var(--spacing-small);
35
-
36
- padding: 0;
37
- margin: 0;
19
+ overflow: hidden;
20
+
21
+ --md-icon-size: 14px;
22
+ --spacing-large: 16px;
23
+ --spacing-medium: 8px;
24
+ --spacing-small: 4px;
25
+ --spacing-tiny: 2px;
26
+ --padding-default: 4px;
27
+ --button-color: rgba(0, 0, 0, 0.5);
28
+ --button-border: 1px solid rgba(0, 0, 0, 0.15);
29
+ --button-background-color: rgba(0, 0, 0, 0.05);
30
+ --button-background-focus-color: rgba(0, 0, 0, 0.1);
31
+ --button-active-border: 1px solid rgba(0, 0, 0, 0.2);
38
32
  }
39
33
 
40
- li {
34
+ div {
41
35
  display: flex;
42
- flex-direction: row;
43
- align-items: center;
44
- gap: var(--spacing-large);
36
+ flex-flow: row nowrap;
37
+ gap: var(--spacing-medium);
38
+ margin-bottom: var(--spacing-small);
45
39
  }
46
40
 
47
- li > * {
48
- flex: 1;
41
+ button {
42
+ border: var(--button-border);
43
+ border-radius: var(--border-radius);
44
+ background-color: var(--button-background-color);
45
+ padding: var(--spacing-small) var(--padding-default);
46
+ line-height: 0.8;
47
+ color: var(--button-color);
48
+ cursor: pointer;
49
+ }
50
+ button + button {
51
+ margin-left: -5px;
52
+ }
53
+ button:focus,
54
+ button:hover,
55
+ button:active {
56
+ border: var(--button-active-border);
57
+ background-color: var(--button-background-focus-color);
58
+ color: rgba(0, 0, 0, 0.5);
49
59
  }
50
60
 
51
- div[data-name] {
52
- text-align: right;
61
+ input {
62
+ flex: 1;
63
+ border: 0;
64
+ border: 1px solid rgba(0, 0, 0, 0.15);
65
+ padding: var(--spacing-tiny);
66
+ font: var(--input-font);
67
+ min-width: 50px;
53
68
  }
54
69
 
55
- div[data-value] {
56
- display: flex;
57
- justify-content: space-between;
70
+ input:focus {
71
+ outline: none;
72
+ border: 1px solid rgba(0, 0, 0, 0.2);
58
73
  }
59
74
  `
60
75
  ]
61
76
 
62
- @state() value: Node[] = []
77
+ @state() value: string[] = []
78
+
79
+ @queryAll('[data-record]') records!: NodeListOf<HTMLElement>
80
+ @query('[data-record-new] [data-id]') addinput!: HTMLInputElement
81
+
82
+ private _changingNow: boolean = false
83
+
84
+ firstUpdated() {
85
+ this.renderRoot.addEventListener('change', this._onChange.bind(this))
86
+ }
63
87
 
64
88
  render() {
65
- const nodes = this.value || ([] as Node[])
89
+ const value = this.value || []
66
90
 
67
91
  return html`
68
- <fieldset>
69
- <ul>
70
- ${nodes.map(
71
- ({ id, name }) => html`
72
- <li @change=${this.onChange}>
73
- <div data-id=${id}>${id}</div>
74
- <input type="text" name="name" value=${name || ''} />
75
- </li>
76
- `
77
- )}
78
- </ul>
79
- </fieldset>
92
+ ${value.map(
93
+ item => html`
94
+ <div data-record>
95
+ <input
96
+ type="text"
97
+ data-id
98
+ .value=${item}
99
+ @keyup=${(e: KeyboardEvent) => e.key === 'Enter' && this._build()}
100
+ />
101
+ <button
102
+ class="record-action"
103
+ @click=${(e: MouseEvent) => this._delete(e)}
104
+ tabindex="-1"
105
+ ?disabled=${this.disabled}
106
+ >
107
+ <md-icon>remove</md-icon>
108
+ </button>
109
+ </div>
110
+ `
111
+ )}
112
+ ${this.disabled
113
+ ? nothing
114
+ : html`
115
+ <div data-record-new>
116
+ <input type="text" data-id value="" @keyup=${(e: KeyboardEvent) => e.key === 'Enter' && this._add()} />
117
+ <button class="record-action" @click=${(e: MouseEvent) => this._add()} tabindex="-1">
118
+ <md-icon>add</md-icon>
119
+ </button>
120
+ </div>
121
+ `}
80
122
  `
81
123
  }
82
124
 
83
- onChange(e: Event) {
84
- e.stopPropagation()
125
+ _onChange(e: Event) {
126
+ if (this._changingNow) {
127
+ return
128
+ }
129
+
130
+ this._changingNow = true
85
131
 
86
- const lis = this.renderRoot.querySelectorAll('li')
132
+ const input = e.target as HTMLInputElement
133
+
134
+ const record = (e.target as Element).closest('[data-record],[data-record-new]') as HTMLElement
135
+
136
+ if (record.hasAttribute('data-record')) {
137
+ this._build()
138
+ } else if (record.hasAttribute('data-record-new') && input.hasAttribute('data-value')) {
139
+ this._add()
140
+ }
141
+
142
+ this._changingNow = false
143
+ }
144
+
145
+ _build(includeNewRecord?: boolean) {
146
+ const selector = includeNewRecord ? '[data-record],[data-record-new]' : '[data-record]'
147
+ const records = this.renderRoot.querySelectorAll(selector) as NodeListOf<HTMLElement>
148
+
149
+ this.value = Array.from(records)
150
+ .map(record => (record.querySelector('[data-id]')! as HTMLInputElement).value as string)
151
+ .filter(Boolean)
152
+ .sort()
153
+
154
+ this.dispatchEvent(new CustomEvent('change', { bubbles: true, composed: true, detail: this.value }))
155
+ }
156
+
157
+ _add() {
158
+ this._build(true)
159
+
160
+ this.addinput.value = ''
161
+ this.addinput.focus()
162
+ }
87
163
 
88
- this.value = Array.from(lis).map(li => {
89
- const id = li.querySelector('[data-id]')?.getAttribute('data-id')
90
- const name = li.querySelector('input')?.value
91
- const node = this.value.find(node => node.id === id)
164
+ _delete(e: MouseEvent) {
165
+ const record = (e.target as Element).closest('[data-record]') as HTMLElement
92
166
 
93
- return { ...node!, name }
94
- })
167
+ ;(record!.querySelector('[data-id]') as HTMLInputElement)!.value = ''
95
168
 
96
- this.dispatchEvent(
97
- new CustomEvent('change', {
98
- bubbles: true,
99
- composed: true,
100
- detail: this.value
101
- })
102
- )
169
+ this._build()
103
170
  }
104
171
  }
@@ -4,23 +4,10 @@ import { html } from 'lit'
4
4
  import { customElement } from 'lit/decorators.js'
5
5
 
6
6
  import { OxPropertyEditor, PropertySpec } from '@operato/property-editor'
7
- import { Node } from '../types'
8
7
 
9
8
  @customElement('ox-property-editor-nodes')
10
9
  export class PropertyEditorNodes extends OxPropertyEditor {
11
- editorTemplate(value: Node[], spec: PropertySpec) {
12
- // const { defaultValue = [] } = spec
13
- // value ||= []
14
-
15
- // const valueProperty = defaultValue
16
- // .map(({ name, ...others }) => {
17
- // const node = value.find(v => v.name == name)
18
- // if (node) {
19
- // return { ...others, ...node }
20
- // }
21
- // })
22
- // .filter(Boolean)
23
-
24
- return html` <ox-input-nodes .value=${value} fullwidth></ox-input-nodes> `
10
+ editorTemplate(value: string[], spec: PropertySpec) {
11
+ return html` <ox-input-nodes .value=${value}></ox-input-nodes> `
25
12
  }
26
13
  }
package/src/node.ts CHANGED
@@ -10,15 +10,15 @@ const NATURE = {
10
10
  resizable: false,
11
11
  rotatable: false,
12
12
  properties: [
13
- {
14
- type: 'string',
15
- name: 'NodeIDs',
16
- label: 'node-ids'
17
- },
18
13
  {
19
14
  type: 'string',
20
15
  name: 'NodeMachine',
21
16
  label: 'node-machine'
17
+ },
18
+ {
19
+ type: 'nodes',
20
+ label: 'nodes',
21
+ name: 'nodes'
22
22
  }
23
23
  ]
24
24
  }
@@ -42,5 +42,7 @@
42
42
  "label.shuttle-legend-name": "shuttle",
43
43
  "label.crane-legend-name": "crane",
44
44
  "label.shelf-legend-name": "shelf",
45
- "label.equipment-legend-name": "equipment"
45
+ "label.equipment-legend-name": "equipment",
46
+ "label.node-machine": "node machine",
47
+ "label.nodes": "nodes"
46
48
  }
@@ -44,5 +44,7 @@
44
44
  "label.shuttle-legend-name": "shuttle",
45
45
  "label.crane-legend-name": "crane",
46
46
  "label.shelf-legend-name": "shelf",
47
- "label.equipment-legend-name": "equipment"
47
+ "label.equipment-legend-name": "equipment",
48
+ "label.node-machine": "node machine",
49
+ "label.nodes": "nodes"
48
50
  }
@@ -45,5 +45,7 @@
45
45
  "label.shuttle-legend-name": "셔틀",
46
46
  "label.crane-legend-name": "크레인",
47
47
  "label.shelf-legend-name": "선반",
48
- "label.equipment-legend-name": "장비"
48
+ "label.equipment-legend-name": "장비",
49
+ "label.node-machine": "node machine",
50
+ "label.nodes": "nodes"
49
51
  }
@@ -44,5 +44,7 @@
44
44
  "label.shuttle-legend-name": "shuttle",
45
45
  "label.crane-legend-name": "crane",
46
46
  "label.shelf-legend-name": "shelf",
47
- "label.equipment-legend-name": "equipment"
47
+ "label.equipment-legend-name": "equipment",
48
+ "label.node-machine": "node machine",
49
+ "label.nodes": "nodes"
48
50
  }
@@ -44,5 +44,7 @@
44
44
  "label.shuttle-legend-name": "shuttle",
45
45
  "label.crane-legend-name": "crane",
46
46
  "label.shelf-legend-name": "shelf",
47
- "label.equipment-legend-name": "equipment"
47
+ "label.equipment-legend-name": "equipment",
48
+ "label.node-machine": "node machine",
49
+ "label.nodes": "nodes"
48
50
  }