@operato/input 7.1.1 → 7.1.2

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/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": "7.1.1",
5
+ "version": "7.1.2",
6
6
  "main": "dist/src/index.js",
7
7
  "module": "dist/src/index.js",
8
8
  "license": "MIT",
@@ -57,6 +57,7 @@
57
57
  "./ox-input-mass-fraction.js": "./dist/src/ox-input-mass-fraction.js",
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
+ "./ox-input-signature.js": "./dist/src/ox-input-signature.js",
60
61
  "./ox-input-table-column-config.js": "./dist/src/ox-input-table-column-config.js"
61
62
  },
62
63
  "typesVersions": {
@@ -175,6 +176,9 @@
175
176
  "./ox-input-direction.js": [
176
177
  "./dist/src/ox-input-direction.d.ts"
177
178
  ],
179
+ "./ox-input-signature.js": [
180
+ "./dist/src/ox-input-signature.d.ts"
181
+ ],
178
182
  "./ox-input-table-column-config.js": [
179
183
  "./dist/src/ox-input-table-column-config.d.ts"
180
184
  ]
@@ -254,5 +258,5 @@
254
258
  "prettier --write"
255
259
  ]
256
260
  },
257
- "gitHead": "ae4071a0210106d56dd9b2499400e44b79d93940"
261
+ "gitHead": "9e40d6c5fce98a720ef628b576eec76a2283c59e"
258
262
  }
package/src/index.ts CHANGED
@@ -31,3 +31,4 @@ export * from './ox-input-textarea.js'
31
31
  export * from './ox-input-direction.js'
32
32
  export * from './ox-input-table-column-config.js'
33
33
  export * from './ox-input-search.js'
34
+ export * from './ox-input-signature.js'
@@ -0,0 +1,154 @@
1
+ import '@material/web/icon/icon.js'
2
+
3
+ import { css, html, nothing } from 'lit'
4
+ import { customElement, property } from 'lit/decorators.js'
5
+
6
+ import { OxFormField } from './ox-form-field.js'
7
+
8
+ @customElement('ox-input-signature')
9
+ export class OxInputSignature extends OxFormField {
10
+ static styles = [
11
+ css`
12
+ :host {
13
+ position: relative;
14
+ box-sizing: border-box;
15
+
16
+ display: flex;
17
+ 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;
23
+
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);
28
+
29
+ overflow: hidden;
30
+ }
31
+
32
+ canvas {
33
+ width: 100%;
34
+ border: 1px solid #000;
35
+ }
36
+
37
+ .controls {
38
+ margin-top: 10px;
39
+ }
40
+ `
41
+ ]
42
+
43
+ @property({ type: Boolean }) isDrawing = false
44
+ @property({ type: String }) value: string | null = null
45
+
46
+ private ctx!: CanvasRenderingContext2D
47
+ private canvas!: HTMLCanvasElement
48
+
49
+ render() {
50
+ return html`
51
+ <canvas
52
+ width="400"
53
+ height="200"
54
+ @mousedown=${this.startDrawing}
55
+ @mouseup=${this.stopDrawing}
56
+ @mousemove=${this.draw}
57
+ @mouseleave=${this.stopDrawing}
58
+ @touchstart=${this.startDrawing}
59
+ @touchend=${this.stopDrawing}
60
+ @touchmove=${this.draw}
61
+ ></canvas>
62
+
63
+ ${!this.disabled
64
+ ? html` <div class="controls">
65
+ <button @click="${this.clearCanvas}">Clear</button>
66
+ <button @click="${this.saveSignature}">Save</button>
67
+ </div>`
68
+ : nothing}
69
+ `
70
+ }
71
+
72
+ firstUpdated() {
73
+ this.canvas = this.shadowRoot!.querySelector('canvas')!
74
+ this.ctx = this.canvas.getContext('2d')!
75
+ this.ctx.strokeStyle = '#000'
76
+ this.ctx.lineWidth = 2
77
+
78
+ // 처음 로딩 시 서명 데이터를 캔버스에 표시
79
+ if (this.value) {
80
+ this.loadSignature(this.value)
81
+ }
82
+ }
83
+
84
+ updated(changedProperties: Map<string | number | symbol, unknown>) {
85
+ if (changedProperties.has('value') && this.value) {
86
+ this.loadSignature(this.value)
87
+ }
88
+ }
89
+
90
+ startDrawing(event: MouseEvent | TouchEvent) {
91
+ if (this.disabled) {
92
+ return
93
+ }
94
+
95
+ this.isDrawing = true
96
+ this.ctx.beginPath()
97
+ const position = this.getEventPosition(event)
98
+ this.ctx.moveTo(position.x, position.y)
99
+ }
100
+
101
+ stopDrawing() {
102
+ this.isDrawing = false
103
+ }
104
+
105
+ draw(event: MouseEvent | TouchEvent) {
106
+ if (!this.isDrawing) return
107
+ const position = this.getEventPosition(event)
108
+ this.ctx.lineTo(position.x, position.y)
109
+ this.ctx.stroke()
110
+ }
111
+
112
+ clearCanvas() {
113
+ this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
114
+ }
115
+
116
+ saveSignature() {
117
+ this.value = this.canvas.toDataURL()
118
+ this._notifyChange()
119
+ }
120
+
121
+ loadSignature(dataUrl: string) {
122
+ const image = new Image()
123
+ image.onload = () => {
124
+ this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height) // 이전 내용을 지움
125
+ this.ctx.drawImage(image, 0, 0) // 이미지를 캔버스에 그림
126
+ }
127
+ image.src = dataUrl
128
+ }
129
+
130
+ getEventPosition(event: MouseEvent | TouchEvent) {
131
+ const rect = this.canvas.getBoundingClientRect()
132
+
133
+ // 캔버스의 실제 크기와 CSS 크기 간의 비율을 계산
134
+ const scaleX = this.canvas.width / rect.width
135
+ const scaleY = this.canvas.height / rect.height
136
+
137
+ // 실제 좌표 계산
138
+ const isTouchEvent = event instanceof TouchEvent
139
+ const x = (isTouchEvent ? event.touches[0].clientX - rect.left : (event as MouseEvent).clientX - rect.left) * scaleX
140
+ const y = (isTouchEvent ? event.touches[0].clientY - rect.top : (event as MouseEvent).clientY - rect.top) * scaleY
141
+
142
+ return { x, y }
143
+ }
144
+
145
+ _notifyChange() {
146
+ this.dispatchEvent(
147
+ new CustomEvent('change', {
148
+ bubbles: true,
149
+ composed: true,
150
+ detail: this.value
151
+ })
152
+ )
153
+ }
154
+ }
@@ -0,0 +1,71 @@
1
+ import '../src/ox-input-signature.js'
2
+
3
+ import { html, TemplateResult } from 'lit'
4
+ import { styles as MDTypeScaleStyles } from '@material/web/typography/md-typescale-styles'
5
+
6
+ export default {
7
+ title: 'ox-input-signature',
8
+ component: 'ox-input-signature',
9
+ argTypes: {
10
+ disabled: { control: 'boolean' }
11
+ }
12
+ }
13
+
14
+ interface Story<T> {
15
+ (args: T): TemplateResult
16
+ args?: Partial<T>
17
+ argTypes?: Record<string, unknown>
18
+ }
19
+
20
+ interface ArgTypes {
21
+ label?: string
22
+ name?: string
23
+ disabled?: boolean
24
+ }
25
+
26
+ const Template: Story<ArgTypes> = ({ label = 'signature', name = 'signature', disabled }: ArgTypes) => html`
27
+ <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap" rel="stylesheet" />
28
+
29
+ <link href="/themes/light.css" rel="stylesheet" />
30
+ <link href="/themes/dark.css" rel="stylesheet" />
31
+ <link href="/themes/spacing.css" rel="stylesheet" />
32
+
33
+ <link
34
+ href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL@20..48,100..700,0..1"
35
+ rel="stylesheet"
36
+ />
37
+ <link
38
+ href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL@20..48,100..700,0..1"
39
+ rel="stylesheet"
40
+ />
41
+ <link
42
+ href="https://fonts.googleapis.com/css2?family=Material+Symbols+Sharp:opsz,wght,FILL@20..48,100..700,0..1"
43
+ rel="stylesheet"
44
+ />
45
+
46
+ <style>
47
+ ${MDTypeScaleStyles.cssText}
48
+ </style>
49
+
50
+ <style>
51
+ .container {
52
+ height: 500px;
53
+ text-align: center;
54
+ padding: 20px;
55
+
56
+ background-color: var(--md-sys-color-primary-container);
57
+ color: var(--md-sys-color-on-primary-container);
58
+ }
59
+ </style>
60
+
61
+ <div class="container md-typescale-body-large-prominent">
62
+ <ox-input-signature
63
+ ?disabled=${disabled}
64
+ @change=${(e: Event) => console.log(((e as CustomEvent).target as any)!.value)}
65
+ >
66
+ </ox-input-signature>
67
+ </div>
68
+ `
69
+
70
+ export const Regular = Template.bind({})
71
+ Regular.args = {}