@operato/input 8.0.0-alpha.2 → 8.0.0-alpha.20

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 (31) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/dist/src/ox-input-file.js +3 -2
  3. package/dist/src/ox-input-file.js.map +1 -1
  4. package/dist/src/ox-input-signature.d.ts +4 -5
  5. package/dist/src/ox-input-signature.js +31 -20
  6. package/dist/src/ox-input-signature.js.map +1 -1
  7. package/dist/src/ox-select-floor.d.ts +38 -0
  8. package/dist/src/ox-select-floor.js +245 -0
  9. package/dist/src/ox-select-floor.js.map +1 -0
  10. package/dist/stories/image-for-select-floor.d.ts +1 -0
  11. package/dist/stories/image-for-select-floor.js +2 -0
  12. package/dist/stories/image-for-select-floor.js.map +1 -0
  13. package/dist/stories/{ox-input-/bsignature.stories.js → ox-input-signature.stories.js} +1 -1
  14. package/dist/stories/ox-input-signature.stories.js.map +1 -0
  15. package/dist/stories/ox-select-floor.stories.d.ts +41 -0
  16. package/dist/stories/ox-select-floor.stories.js +139 -0
  17. package/dist/stories/ox-select-floor.stories.js.map +1 -0
  18. package/dist/tsconfig.tsbuildinfo +1 -1
  19. package/package.json +8 -4
  20. package/src/ox-input-file.ts +3 -2
  21. package/src/ox-input-signature.ts +30 -21
  22. package/src/ox-select-floor.ts +257 -0
  23. package/stories/image-for-select-floor.ts +2 -0
  24. package/stories/ox-select-floor.stories.ts +168 -0
  25. package/assets/images/icon-editor-gradient-direction.png +0 -0
  26. package/assets/images/icon-properties-label.png +0 -0
  27. package/assets/images/icon-properties-line-type.png +0 -0
  28. package/assets/images/icon-properties-table.png +0 -0
  29. package/dist/stories/ox-input-/bsignature.stories.js.map +0 -1
  30. /package/dist/stories/{ox-input-/bsignature.stories.d.ts" → ox-input-signature.stories.d.ts} +0 -0
  31. /package/stories/{ox-input-/bsignature.stories.ts" → ox-input-signature.stories.ts} +0 -0
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@operato/input",
3
3
  "description": "Webcomponents for input following open-wc recommendations",
4
4
  "author": "heartyoh@hatiolab.com",
5
- "version": "8.0.0-alpha.2",
5
+ "version": "8.0.0-alpha.20",
6
6
  "main": "dist/src/index.js",
7
7
  "module": "dist/src/index.js",
8
8
  "license": "MIT",
@@ -58,6 +58,7 @@
58
58
  "./ox-input-textarea.js": "./dist/src/ox-input-textarea.js",
59
59
  "./ox-input-direction.js": "./dist/src/ox-input-direction.js",
60
60
  "./ox-input-signature.js": "./dist/src/ox-input-signature.js",
61
+ "./ox-select-floor.js": "./dist/src/ox-select-floor.js",
61
62
  "./ox-input-table-column-config.js": "./dist/src/ox-input-table-column-config.js"
62
63
  },
63
64
  "typesVersions": {
@@ -179,6 +180,9 @@
179
180
  "./ox-input-signature.js": [
180
181
  "./dist/src/ox-input-signature.d.ts"
181
182
  ],
183
+ "./ox-select-floor.js": [
184
+ "./dist/src/ox-select-floor.d.ts"
185
+ ],
182
186
  "./ox-input-table-column-config.js": [
183
187
  "./dist/src/ox-input-table-column-config.d.ts"
184
188
  ]
@@ -212,8 +216,8 @@
212
216
  "@material/web": "^2.0.0",
213
217
  "@operato/color-picker": "^8.0.0-alpha.0",
214
218
  "@operato/i18n": "^8.0.0-alpha.0",
215
- "@operato/popup": "^8.0.0-alpha.0",
216
- "@operato/styles": "^8.0.0-alpha.0",
219
+ "@operato/popup": "^8.0.0-alpha.4",
220
+ "@operato/styles": "^8.0.0-alpha.4",
217
221
  "@operato/utils": "^8.0.0-alpha.0",
218
222
  "@polymer/paper-dropdown-menu": "^3.2.0",
219
223
  "@polymer/paper-item": "^3.0.1",
@@ -258,5 +262,5 @@
258
262
  "prettier --write"
259
263
  ]
260
264
  },
261
- "gitHead": "868f7fd1dfcf1758b0fd8f8c7f198489b3b3bbf8"
265
+ "gitHead": "c8a1305148d5f9190d79f7107001455e46906b8e"
262
266
  }
@@ -79,12 +79,13 @@ export class OxInputFile extends OxFormField {
79
79
  border-bottom: var(--file-uploader-li-border-bottom);
80
80
  font-size: var(--md-sys-typescale-label-large-size, 0.875rem);
81
81
  color: var(--md-sys-color-on-primary-container);
82
+ display: flex;
83
+ align-items: center;
82
84
  }
83
85
  li md-icon {
84
- float: right;
85
86
  cursor: pointer;
86
- margin: var(--file-uploader-li-icon-margin);
87
87
  font-size: var(--icon-size-small);
88
+ margin-left: auto;
88
89
  }
89
90
  li md-icon:hover,
90
91
  li md-icon:active {
@@ -1,7 +1,7 @@
1
1
  import '@material/web/icon/icon.js'
2
2
 
3
3
  import { css, html, nothing } from 'lit'
4
- import { customElement, property } from 'lit/decorators.js'
4
+ import { customElement, property, query, state } from 'lit/decorators.js'
5
5
 
6
6
  import { OxFormField } from './ox-form-field.js'
7
7
 
@@ -10,27 +10,19 @@ export class OxInputSignature extends OxFormField {
10
10
  static styles = [
11
11
  css`
12
12
  :host {
13
- position: relative;
14
- box-sizing: border-box;
15
-
16
13
  display: flex;
17
14
  flex-direction: column;
18
- place-content: center;
19
- border-radius: var(--border-radius);
20
- padding: var(--padding-default, 9px);
21
- min-height: 100px;
22
- text-transform: capitalize;
15
+ min-height: var(--signature-min-height, 80px);
16
+ min-width: var(--signature-min-width, 120px);
23
17
 
24
- border: var(--file-uploader-border);
25
- background-color: var(--md-sys-color-background);
26
- font: var(--file-uploader-font) !important;
27
- color: var(--file-uploader-color);
18
+ background-color: var(--signature-background-color, white);
28
19
 
29
20
  overflow: hidden;
30
21
  }
31
22
 
32
23
  .signature-preview {
33
24
  flex: 1;
25
+ align-self: stretch;
34
26
 
35
27
  border: 1px solid var(--md-sys-color-outline);
36
28
  background-size: contain;
@@ -46,18 +38,28 @@ export class OxInputSignature extends OxFormField {
46
38
 
47
39
  .controls {
48
40
  margin-top: 10px;
41
+ display: flex;
42
+ flex-direction: row;
43
+ gap: var(--spacing-medium);
44
+ }
45
+
46
+ .filler {
47
+ flex: 1;
49
48
  }
50
49
  `
51
50
  ]
52
51
 
53
- @property({ type: Boolean }) isDrawing = false
54
52
  @property({ type: String }) value: string | null = null
55
53
 
56
- private ctx!: CanvasRenderingContext2D
57
- private canvas!: HTMLCanvasElement
58
- private dialog!: HTMLDialogElement
54
+ @query('.signature-preview')
59
55
  private previewDiv!: HTMLDivElement
60
- private previewCtx!: CanvasRenderingContext2D
56
+ @query('dialog')
57
+ private dialog!: HTMLDialogElement
58
+ @query('canvas')
59
+ private canvas!: HTMLCanvasElement
60
+
61
+ private ctx!: CanvasRenderingContext2D
62
+ private isDrawing = false
61
63
 
62
64
  render() {
63
65
  return html`
@@ -77,6 +79,7 @@ export class OxInputSignature extends OxFormField {
77
79
  ></canvas>
78
80
  <div class="controls">
79
81
  <button @click="${this.clearCanvas}">Clear</button>
82
+ <div class="filler"></div>
80
83
  <button @click="${this.saveSignature}">Save</button>
81
84
  <button @click="${this.closeDialog}">Close</button>
82
85
  </div>
@@ -85,9 +88,6 @@ export class OxInputSignature extends OxFormField {
85
88
  }
86
89
 
87
90
  firstUpdated() {
88
- this.previewDiv = this.shadowRoot!.querySelector('.signature-preview')!
89
- this.dialog = this.shadowRoot!.querySelector('dialog')!
90
- this.canvas = this.dialog.querySelector('canvas')!
91
91
  this.ctx = this.canvas.getContext('2d')!
92
92
  this.ctx.strokeStyle = '#000'
93
93
  this.ctx.lineWidth = 2
@@ -101,6 +101,15 @@ export class OxInputSignature extends OxFormField {
101
101
  openDialog() {
102
102
  if (this.disabled) return
103
103
  this.dialog.showModal()
104
+
105
+ // 다이아로그가 열릴 때 현재 value를 캔버스에 그리기
106
+ if (this.value) {
107
+ const img = new Image()
108
+ img.onload = () => {
109
+ this.ctx.drawImage(img, 0, 0, this.canvas.width, this.canvas.height)
110
+ }
111
+ img.src = this.value
112
+ }
104
113
  }
105
114
 
106
115
  closeDialog() {
@@ -0,0 +1,257 @@
1
+ import { css, html, PropertyValues } from 'lit'
2
+ import { customElement, property, query, state } from 'lit/decorators.js'
3
+ import { OxFormField } from './ox-form-field'
4
+
5
+ type Card = {
6
+ name: string
7
+ image: string
8
+ }
9
+
10
+ @customElement('ox-select-floor')
11
+ export class OxSelectFloor extends OxFormField {
12
+ static styles = [
13
+ css`
14
+ :host {
15
+ display: block;
16
+ position: relative;
17
+ overflow: hidden;
18
+ height: 100%;
19
+
20
+ --ox-select-floor-rotate-x: 60deg;
21
+ --ox-select-floor-rotate-x-active: 40deg;
22
+ --ox-select-floor-perspective: 1200px;
23
+ }
24
+
25
+ .carousel-container {
26
+ position: relative;
27
+ height: 100%;
28
+ width: 100%;
29
+ overflow: hidden;
30
+ user-select: none;
31
+ }
32
+
33
+ .card {
34
+ position: absolute;
35
+ bottom: 0;
36
+ width: 100%;
37
+ background-color: white;
38
+ transition:
39
+ transform 0.3s ease,
40
+ opacity 0.3s ease,
41
+ box-shadow 0.3s ease,
42
+ border 0.3s ease;
43
+ transform-origin: bottom;
44
+ transform: perspective(var(--ox-select-floor-perspective)) rotateX(var(--ox-select-floor-rotate-x));
45
+ opacity: 0.5;
46
+ border: 2px solid transparent;
47
+ border-radius: 12px;
48
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
49
+ }
50
+
51
+ .card img {
52
+ width: 100%;
53
+ height: auto;
54
+ display: block;
55
+ pointer-events: none;
56
+ border-radius: 12px;
57
+ }
58
+
59
+ .selected {
60
+ z-index: 10;
61
+ opacity: 0.8;
62
+ border: 4px solid #3b82f6;
63
+ box-shadow: 0 8px 16px rgba(59, 130, 246, 0.4);
64
+ }
65
+
66
+ .selected.active {
67
+ opacity: 1;
68
+ transform: perspective(var(--ox-select-floor-perspective)) rotateX(var(--ox-select-floor-rotate-x-active));
69
+ box-shadow: 0 12px 24px rgba(59, 130, 246, 0.4);
70
+ }
71
+
72
+ [template-container] {
73
+ position: absolute;
74
+ right: 10px;
75
+ z-index: 20;
76
+ }
77
+ `
78
+ ]
79
+
80
+ @property({ type: Array }) cards: Card[] = []
81
+ @property({ type: String }) value?: string
82
+ @property({ type: Number }) bottomLimit = 70
83
+
84
+ @state() private selectedIndex = -1
85
+ @state() private activeIndex: number | null = null
86
+ @query('.carousel-container') private carouselContainer!: HTMLDivElement
87
+
88
+ private isDragging = false
89
+ private lastTouchY = 0
90
+ private lastMouseY = 0
91
+
92
+ render() {
93
+ const length = this.cards.length
94
+ const cards = this.cards
95
+
96
+ return html`
97
+ <div
98
+ class="carousel-container"
99
+ @wheel=${this.handleWheel}
100
+ @mousedown=${this.handleMouseDown}
101
+ @mousemove=${this.handleMouseMove}
102
+ @mouseup=${this.handleMouseUp}
103
+ @mouseleave=${this.handleMouseLeave}
104
+ @touchstart=${this.handleTouchStart}
105
+ @touchmove=${this.handleTouchMove}
106
+ @touchend=${this.handleTouchEnd}
107
+ >
108
+ ${cards.map(({ image, name }, index) => {
109
+ return html`
110
+ <div
111
+ class="card ${this.getClassForCard(index)} ${this.isActive(index) ? 'active' : ''}"
112
+ style="bottom: ${(this.bottomLimit * index) / length}%;"
113
+ @click=${() => this.selectCard(index)}
114
+ @tap=${() => this.toggleActiveCard(index)}
115
+ >
116
+ <img src="${image}" @load=${(e: Event) => this.adjustCardHeight(e, index)} />
117
+ </div>
118
+ `
119
+ })}
120
+ ${cards.map(({ image, name }, index) => {
121
+ return html`
122
+ <div
123
+ style="bottom: ${(this.bottomLimit * index) / length}%;"
124
+ @click=${() => this.selectCard(index)}
125
+ template-container
126
+ >
127
+ <slot name="template-${index}"></slot>
128
+ </div>
129
+ `
130
+ })}
131
+ </div>
132
+ `
133
+ }
134
+
135
+ updated(changes: PropertyValues<this>) {
136
+ if (changes.has('value')) {
137
+ if (this.value) {
138
+ this.selectedIndex = this.cards.findIndex(card => card.name == this.value)
139
+ } else {
140
+ this.selectedIndex = -1
141
+ }
142
+ }
143
+ }
144
+
145
+ firstUpdated() {
146
+ this.scrollToSelectedCard()
147
+ }
148
+
149
+ getClassForCard(index: number) {
150
+ return index === this.selectedIndex ? 'selected' : 'compressed'
151
+ }
152
+
153
+ isActive(index: number): boolean {
154
+ return this.activeIndex === index
155
+ }
156
+
157
+ handleWheel(event: WheelEvent) {
158
+ event.preventDefault()
159
+ const delta = Math.sign(event.deltaY)
160
+ this.updateSelectedIndex(this.selectedIndex + delta)
161
+ }
162
+
163
+ handleTouchStart(event: TouchEvent) {
164
+ this.lastTouchY = event.touches[0].clientY
165
+ }
166
+
167
+ handleTouchMove(event: TouchEvent) {
168
+ const touch = event.touches[0]
169
+ const deltaY = touch.clientY - this.lastTouchY
170
+ this.lastTouchY = touch.clientY
171
+
172
+ if (Math.abs(deltaY) > 30) {
173
+ const direction = deltaY < 0 ? -1 : 1
174
+ this.updateSelectedIndex(this.selectedIndex + direction)
175
+ }
176
+ }
177
+
178
+ handleTouchEnd() {
179
+ this.isDragging = false
180
+ }
181
+
182
+ handleMouseDown(event: MouseEvent) {
183
+ this.isDragging = true
184
+ this.lastMouseY = event.clientY
185
+ }
186
+
187
+ handleMouseMove(event: MouseEvent) {
188
+ if (!this.isDragging) {
189
+ return
190
+ }
191
+
192
+ const deltaY = event.clientY - this.lastMouseY
193
+
194
+ if (!this.lastMouseY) {
195
+ this.lastMouseY = event.clientY
196
+ }
197
+
198
+ if (Math.abs(deltaY) > 30) {
199
+ this.lastMouseY = event.clientY
200
+ const direction = deltaY > 0 ? -1 : 1
201
+ this.updateSelectedIndex(this.selectedIndex + direction)
202
+ }
203
+ }
204
+
205
+ handleMouseUp() {
206
+ this.isDragging = false
207
+ }
208
+
209
+ handleMouseLeave() {
210
+ this.isDragging = false
211
+ }
212
+
213
+ private toggleActiveCard(index: number) {
214
+ if (this.activeIndex === index) {
215
+ this.activeIndex = null
216
+ } else {
217
+ this.activeIndex = index
218
+ }
219
+ }
220
+
221
+ private updateSelectedIndex(newIndex: number) {
222
+ this.activeIndex = null
223
+
224
+ this.selectedIndex = Math.max(-1, Math.min(newIndex, this.cards.length - 1))
225
+ this.scrollToSelectedCard()
226
+ }
227
+
228
+ private scrollToSelectedCard() {
229
+ const cardHeight = 320
230
+ const targetScrollTop = this.selectedIndex * cardHeight - (window.innerHeight / 2 - cardHeight / 2)
231
+
232
+ this.carouselContainer.scrollTo({ top: targetScrollTop, behavior: 'smooth' })
233
+ }
234
+
235
+ private selectCard(index: number) {
236
+ this.selectedIndex = index
237
+ this._notifySelection()
238
+ this.scrollToSelectedCard()
239
+ }
240
+
241
+ private _notifySelection() {
242
+ this.value = this.selectedIndex !== -1 ? this.cards[this.selectedIndex]?.name : undefined
243
+
244
+ this.dispatchEvent(
245
+ new CustomEvent('change', {
246
+ detail: this.value
247
+ })
248
+ )
249
+ }
250
+
251
+ private adjustCardHeight(e: Event, index: number) {
252
+ const imgElement = e.target as HTMLImageElement
253
+ const aspectRatio = imgElement.naturalWidth / imgElement.naturalHeight
254
+ const newHeight = imgElement.offsetWidth / aspectRatio
255
+ imgElement.style.height = `${newHeight}px`
256
+ }
257
+ }