@operato/input 8.0.0-beta.0 → 8.0.0-beta.1

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 (98) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/package.json +7 -7
  3. package/.editorconfig +0 -29
  4. package/.storybook/main.js +0 -3
  5. package/.storybook/preview.js +0 -52
  6. package/.storybook/server.mjs +0 -8
  7. package/src/index.ts +0 -35
  8. package/src/locale/locale-codes.ts +0 -18
  9. package/src/locale/locale-picker.ts +0 -43
  10. package/src/locale/localization.ts +0 -15
  11. package/src/locales/en.ts +0 -30
  12. package/src/locales/ko.ts +0 -30
  13. package/src/locales/ms.ts +0 -30
  14. package/src/locales/zh.ts +0 -30
  15. package/src/ox-buttons-radio.ts +0 -140
  16. package/src/ox-checkbox.ts +0 -181
  17. package/src/ox-form-field.ts +0 -53
  18. package/src/ox-input-3axis.ts +0 -77
  19. package/src/ox-input-3dish.ts +0 -211
  20. package/src/ox-input-angle.ts +0 -73
  21. package/src/ox-input-barcode.ts +0 -318
  22. package/src/ox-input-code.ts +0 -139
  23. package/src/ox-input-color-gradient.ts +0 -349
  24. package/src/ox-input-color-stops.ts +0 -525
  25. package/src/ox-input-color.ts +0 -338
  26. package/src/ox-input-container.ts +0 -32
  27. package/src/ox-input-crontab.ts +0 -595
  28. package/src/ox-input-data.ts +0 -219
  29. package/src/ox-input-direction.ts +0 -92
  30. package/src/ox-input-duration.ts +0 -175
  31. package/src/ox-input-file.ts +0 -209
  32. package/src/ox-input-hashtags.ts +0 -185
  33. package/src/ox-input-i18n-label.ts +0 -140
  34. package/src/ox-input-image.ts +0 -168
  35. package/src/ox-input-key-values.ts +0 -301
  36. package/src/ox-input-layout/ox-input-card-layout.ts +0 -58
  37. package/src/ox-input-layout/ox-input-grid-layout.ts +0 -64
  38. package/src/ox-input-layout/ox-input-layout.ts +0 -77
  39. package/src/ox-input-mass-fraction.ts +0 -437
  40. package/src/ox-input-multiple-colors.ts +0 -135
  41. package/src/ox-input-options.ts +0 -216
  42. package/src/ox-input-partition-keys.ts +0 -303
  43. package/src/ox-input-privilege.ts +0 -163
  44. package/src/ox-input-quantifier.ts +0 -62
  45. package/src/ox-input-range.ts +0 -146
  46. package/src/ox-input-scene-component-id.ts +0 -73
  47. package/src/ox-input-search.ts +0 -126
  48. package/src/ox-input-select-buttons.ts +0 -75
  49. package/src/ox-input-signature.ts +0 -208
  50. package/src/ox-input-stack.ts +0 -136
  51. package/src/ox-input-switch.ts +0 -117
  52. package/src/ox-input-table-column-config.ts +0 -211
  53. package/src/ox-input-table.ts +0 -404
  54. package/src/ox-input-textarea.ts +0 -86
  55. package/src/ox-input-unit-number.ts +0 -354
  56. package/src/ox-input-value-map.ts +0 -342
  57. package/src/ox-input-value-ranges.ts +0 -363
  58. package/src/ox-input-work-shift.ts +0 -290
  59. package/src/ox-select-floor.ts +0 -246
  60. package/src/ox-select.ts +0 -219
  61. package/stories/image-for-select-floor.ts +0 -2
  62. package/stories/ox-buttons-radio.stories.ts +0 -89
  63. package/stories/ox-checkbox.stories.ts +0 -111
  64. package/stories/ox-input-3axis.stories.ts +0 -77
  65. package/stories/ox-input-3dish.stories.ts +0 -106
  66. package/stories/ox-input-angle.stories.ts +0 -84
  67. package/stories/ox-input-barcode.stories.ts +0 -117
  68. package/stories/ox-input-code.stories.ts +0 -99
  69. package/stories/ox-input-crontab.stories.ts +0 -82
  70. package/stories/ox-input-data.stories.ts +0 -82
  71. package/stories/ox-input-direction.stories.ts +0 -91
  72. package/stories/ox-input-duration.stories.ts +0 -84
  73. package/stories/ox-input-file.stories.ts +0 -111
  74. package/stories/ox-input-hashtags.stories.ts +0 -82
  75. package/stories/ox-input-i18n-label.stories.ts +0 -103
  76. package/stories/ox-input-key-values.stories.ts +0 -97
  77. package/stories/ox-input-mass-fraction.stories.ts +0 -102
  78. package/stories/ox-input-multiple-colors.stories.ts +0 -72
  79. package/stories/ox-input-options.stories.ts +0 -80
  80. package/stories/ox-input-partition-keys.stories.ts +0 -84
  81. package/stories/ox-input-privilege.stories.ts +0 -108
  82. package/stories/ox-input-quantifier.stories.ts +0 -80
  83. package/stories/ox-input-range.stories.ts +0 -89
  84. package/stories/ox-input-search.stories.ts +0 -91
  85. package/stories/ox-input-select-buttons.stories.ts +0 -118
  86. package/stories/ox-input-signature.stories.ts +0 -75
  87. package/stories/ox-input-switch.stories.ts +0 -91
  88. package/stories/ox-input-table-column-config.stories.ts +0 -109
  89. package/stories/ox-input-unit.stories.ts +0 -151
  90. package/stories/ox-input-value-map.stories.ts +0 -92
  91. package/stories/ox-input-value-ranges.stories.ts +0 -92
  92. package/stories/ox-input-work-shift.stories.ts +0 -106
  93. package/stories/ox-select-floor.stories.ts +0 -197
  94. package/stories/ox-select-set-options.stories.ts +0 -208
  95. package/stories/ox-select.stories.ts +0 -181
  96. package/tsconfig.json +0 -25
  97. package/web-dev-server.config.mjs +0 -27
  98. package/web-test-runner.config.mjs +0 -41
@@ -1,318 +0,0 @@
1
- /**
2
- * @license Copyright © HatioLab Inc. All rights reserved.
3
- */
4
-
5
- import '@operato/popup/ox-popup.js'
6
-
7
- import { css, html } from 'lit'
8
- import { customElement, property, query, state } from 'lit/decorators.js'
9
- import { scanImageData } from '@undecaf/zbar-wasm'
10
-
11
- import { OxPopup } from '@operato/popup'
12
-
13
- import { OxFormField } from './ox-form-field.js'
14
-
15
- const barcodeIcon = `data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAYBAMAAAAfR1CMAAADKGlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDUgNzkuMTYzNDk5LCAyMDE4LzA4LzEzLTE2OjQwOjIyICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgMjAxOSAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpFNjM4RURDQkQ1OUExMUU5QkExMkQ4NUY3NkMxNzBFOSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpFNjM4RURDQ0Q1OUExMUU5QkExMkQ4NUY3NkMxNzBFOSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkU2MzhFREM5RDU5QTExRTlCQTEyRDg1Rjc2QzE3MEU5IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkU2MzhFRENBRDU5QTExRTlCQTEyRDg1Rjc2QzE3MEU5Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+55pr/QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAAkUExURQAAAEdwTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEus/7UCWQwAAAALdFJOU9YAg3wKBFBDSz9PnvQNDgAAAE9JREFUGNNjEEQFDKLJSnCOklkgg9QUJFn3RgZhRyS+iCGDEIp2RSBfQICRkRGIgTSQL4jCF6ScvxsZYOFT2T50/6D7Fz080MMLPTzRwhsAHVspfelur08AAAAASUVORK5CYII=`
16
-
17
- /**
18
- * Custom input component for barcode scanning.
19
- *
20
- * This component provides a text input field and a barcode scanning button. Users can input text
21
- * manually or scan barcodes using the device camera. Supported barcode formats include:
22
- *
23
- * - Code-39
24
- * - Code-93
25
- * - Code-128
26
- * - Codabar
27
- * - Databar/Expanded
28
- * - EAN/GTIN-5/8/13
29
- * - ISBN-10/13
30
- * - ISBN-13+2
31
- * - ISBN-13+5
32
- * - ITF (Interleaved 2 of 5)
33
- * - QR Code
34
- * - UPC-A/E
35
- *
36
- * @fires CustomEvent#change - Dispatched when the input value changes.
37
- * @fires KeyboardEvent#keydown - Dispatched when the Enter key is pressed (if not withoutEnter).
38
- *
39
- * @cssprop {String} --barcodescan-input-button-icon - Icon for the barcode scanning button.
40
- *
41
- * @customElement
42
- */
43
- @customElement('ox-input-barcode')
44
- export class OxInputBarcode extends OxFormField {
45
- static styles = [
46
- css`
47
- :host {
48
- display: flex;
49
- align-items: center;
50
- border: none;
51
- background-color: transparent;
52
- height: var(--ox-input-height, var(--form-element-height-medium));
53
- }
54
-
55
- * {
56
- align-self: stretch;
57
- }
58
-
59
- *:focus {
60
- outline: none;
61
- }
62
-
63
- input {
64
- flex: 1;
65
- width: 10px; /* intentionally width set */
66
- border: var(--ox-input-border, 1px solid var(--md-sys-color-outline));
67
- border-radius: var(--ox-input-radius, var(--md-sys-shape-corner-small));
68
- background-color: var(--ox-input-background-color, var(--md-sys-color-on-primary));
69
- color: var(--ox-input-color, var(--md-sys-color-on-primary-container));
70
- font-size: var(--md-sys-typescale-label-large-size, 0.875rem);
71
-
72
- box-sizing: border-box;
73
- padding-right: 35px;
74
- }
75
-
76
- input:focus {
77
- outline: none;
78
- border-color: var(--md-sys-color-secondary-fixed-dim);
79
- }
80
-
81
- #scan-button {
82
- display: block;
83
- position: relative;
84
- margin-left: -35px;
85
- width: 35px;
86
- border: none;
87
- background: var(--barcodescan-input-button-icon) no-repeat center center;
88
- }
89
-
90
- #scan-button[hidden] {
91
- display: none;
92
- }
93
- `
94
- ]
95
-
96
- /**
97
- * Indicates whether barcode scanning is enabled.
98
- * @property {Boolean} scannable
99
- */
100
- @property({ type: Boolean, attribute: true }) scannable?: boolean
101
-
102
- /**
103
- * If true, the "Enter" key press event is not fired after scanning a barcode.
104
- * @property {Boolean} withoutEnter
105
- */
106
- @property({ attribute: 'without-enter', type: Boolean }) withoutEnter?: boolean
107
-
108
- /**
109
- * The value of the input field.
110
- * @property {String} declare value
111
- */
112
- @property({ type: String }) declare value?: string
113
-
114
- /**
115
- * If true, only English characters are allowed in the input field.
116
- * @property {Boolean} englishOnly
117
- */
118
- @property({ attribute: 'english-only', type: Boolean }) englishOnly?: boolean
119
-
120
- /**
121
- * If true, the input field is automatically selected after a change event.
122
- * @property {Boolean} selectAfterChange
123
- */
124
- @property({ attribute: 'select-after-change', type: Boolean }) selectAfterChange?: boolean
125
-
126
- @state() stream?: MediaStream
127
-
128
- @query('input') input!: HTMLInputElement
129
-
130
- private popup: OxPopup | null = null
131
- private video: HTMLVideoElement | null = null
132
-
133
- connectedCallback() {
134
- super.connectedCallback()
135
-
136
- if (navigator.mediaDevices) {
137
- ;(async () => {
138
- try {
139
- var stream = await navigator.mediaDevices.getUserMedia({ audio: false, video: { facingMode: 'environment' } })
140
- if (stream) {
141
- stream.getTracks().forEach(track => track.stop())
142
- this.scannable = true
143
- }
144
- } catch (e) {
145
- this.scannable = false
146
- console.warn('this device not support camera for barcode scan', e)
147
- }
148
- })()
149
- } else {
150
- this.scannable = false
151
- }
152
- }
153
-
154
- disconnectedCallback() {
155
- this.stopScan()
156
- }
157
-
158
- render() {
159
- this.style.setProperty('--barcodescan-input-button-icon', `url(${barcodeIcon})`)
160
-
161
- return html`
162
- <input
163
- type="text"
164
- .value=${this.value || ''}
165
- @change=${(e: Event) => this.onInputChange(e)}
166
- @keydown=${(e: KeyboardEvent) => this.onInputKeyDown(e)}
167
- ?disabled=${this.disabled}
168
- />
169
- <button
170
- ?hidden=${!this.scannable}
171
- id="scan-button"
172
- @click=${(e: MouseEvent) => {
173
- this.scan(e)
174
- }}
175
- ?disabled=${this.disabled}
176
- ></button>
177
- `
178
- }
179
-
180
- onInputChange(e: Event) {
181
- e.stopPropagation()
182
-
183
- if (this.englishOnly) {
184
- /* englishOnly 인 경우에는 멀티바이트 문자들을 모두 제거한다. */
185
- this.value = this.input.value = this.input.value?.replace(/[^\x00-\x7F]/g, '')
186
- } else {
187
- this.value = this.input.value
188
- }
189
-
190
- if (this.selectAfterChange) {
191
- requestAnimationFrame(() => {
192
- this.input.select()
193
- })
194
- }
195
-
196
- this.dispatchEvent(
197
- new CustomEvent('change', {
198
- detail: this.value
199
- })
200
- )
201
- }
202
-
203
- onInputKeyDown(e: KeyboardEvent) {
204
- if (e.key === 'Enter' && !e.isComposing) {
205
- /* Even if the value has not changed, the enter key triggers a change event. */
206
- e.preventDefault() /* Prevent change event from occurring twice. */
207
-
208
- this.input.dispatchEvent(new CustomEvent('change'))
209
- } else if (this.englishOnly && !e.metaKey && !e.ctrlKey && !e.altKey && /^Key/.test(e.code)) {
210
- e.stopPropagation()
211
- e.preventDefault()
212
-
213
- /* englishOnly 인 경우에 문자들은 여기에서 처리한다. 멀티바이트 문자들이 대부분 알파벳의 자모음을 조합하므로, ... */
214
- const key = e.shiftKey ? e.code.charAt(3) : e.code.charAt(3).toLowerCase()
215
- const value = this.input.value
216
-
217
- const start = this.input.selectionStart || 0
218
- const end = this.input.selectionEnd || start
219
-
220
- this.input.value = [value.substring(0, start), key, value.substring(end)].join('')
221
- this.input.setSelectionRange(start + 1, start + 1)
222
- }
223
- }
224
-
225
- async scan(e: MouseEvent) {
226
- try {
227
- if (this.popup) {
228
- this.stopScan()
229
- }
230
-
231
- this.popup = OxPopup.open({
232
- template: html`
233
- <video></video>
234
- <md-icon
235
- style="position: fixed; right: 0; top: 0; color: red; tabindex: 0"
236
- @click=${() => {
237
- this.stopScan()
238
- }}
239
- >close</md-icon
240
- >
241
- `,
242
- width: '100vw',
243
- height: '100dvh'
244
- })
245
-
246
- this.video! = this.popup.querySelector('video') as HTMLVideoElement
247
-
248
- var constraints = { audio: false, video: { facingMode: 'environment' } } /* backside camera first */
249
- this.stream = await navigator.mediaDevices.getUserMedia(constraints)
250
-
251
- this.video.srcObject = this.stream
252
- this.video.play()
253
-
254
- this.video.onloadedmetadata = async e => {
255
- var canvas = new OffscreenCanvas(
256
- this.video!.videoWidth || this.video!.width,
257
- this.video!.videoHeight || this.video!.height
258
- )
259
-
260
- var context = canvas.getContext('2d', {
261
- willReadFrequently: true
262
- })
263
-
264
- const detect = async () => {
265
- try {
266
- if (!this.stream?.active) {
267
- return
268
- }
269
-
270
- context!.drawImage(this.video!, 0, 0, canvas.width, canvas.height)
271
- const imageData = context!.getImageData(0, 0, canvas.width, canvas.height)
272
- const symbols = await scanImageData(imageData)
273
- const result = symbols[0]?.decode()
274
-
275
- if (result) {
276
- this.stopScan()
277
-
278
- var input = this.input
279
- input.focus()
280
- this.value = input.value = String(result)
281
-
282
- if (!this.withoutEnter) {
283
- input.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }))
284
- }
285
- } else {
286
- requestAnimationFrame(async () => await detect())
287
- }
288
- } catch (e) {
289
- console.warn(e)
290
- this.stopScan()
291
- }
292
- }
293
-
294
- await detect()
295
- }
296
- } catch (err) {
297
- /*
298
- * 1. stream device 문제로 예외 발생한 경우.
299
- * 2. 뒤로가기 등으로 popup이 종료된 경우에도 NotFoundException: Video stream has ended before any code could be detected. 이 발생한다.
300
- */
301
- console.warn(err)
302
- }
303
- }
304
-
305
- stopScan() {
306
- if (this.video) {
307
- this.video.pause()
308
- this.video.srcObject = null
309
- }
310
-
311
- if (this.popup) {
312
- this.popup.close()
313
- this.popup = null
314
- }
315
-
316
- this.stream?.getTracks().forEach(track => track.stop())
317
- }
318
- }
@@ -1,139 +0,0 @@
1
- /**
2
- * @license Copyright © HatioLab Inc. All rights reserved.
3
- */
4
-
5
- import { css, PropertyValues } from 'lit'
6
- import { customElement, property } from 'lit/decorators.js'
7
-
8
- import { minimalSetup } from 'codemirror'
9
- import { history, historyKeymap, indentWithTab } from '@codemirror/commands'
10
- import { EditorView, highlightActiveLine, keymap, lineNumbers } from '@codemirror/view'
11
- import { autocompletion, closeBrackets } from '@codemirror/autocomplete'
12
- import { bracketMatching, LanguageSupport, syntaxHighlighting } from '@codemirror/language'
13
- import { oneDarkHighlightStyle, oneDark } from '@codemirror/theme-one-dark'
14
-
15
- import { javascript } from '@codemirror/lang-javascript'
16
- import { sql } from '@codemirror/lang-sql'
17
- import { json } from '@codemirror/lang-json'
18
-
19
- import { ScrollbarStyles } from '@operato/styles'
20
- import { togglefullscreen } from '@operato/utils'
21
-
22
- import { OxFormField } from './ox-form-field'
23
-
24
- /**
25
- WEB Component for code-mirror code editor.
26
-
27
- Example:
28
-
29
- <ox-input-code .value=${text} language="javascript" show-line-numbers>
30
- </ox-input-code>
31
- */
32
- @customElement('ox-input-code')
33
- export class OxInputCode extends OxFormField {
34
- static styles = [
35
- ScrollbarStyles,
36
- css`
37
- :host {
38
- display: flex;
39
- flex-direction: column;
40
- position: relative;
41
- background: white;
42
- overflow: auto;
43
- border:1px solid var(--md-sys-color-outline);
44
- border-radius:var(--md-sys-shape-corner-small);
45
- }
46
-
47
- .cm-editor {
48
- flex: 1;
49
-
50
- }
51
- `
52
- ]
53
-
54
- /**
55
- * `value`는 에디터에서 작성중인 contents이다.
56
- */
57
- @property({ type: String }) value: string = ''
58
- @property({ type: Boolean, attribute: 'show-line-numbers' }) showLineNumbers: boolean = false
59
- @property({ type: String }) language?: string = 'javascript'
60
-
61
- private _self_changing: boolean = false
62
- private _editor?: EditorView
63
- private _changed: boolean = false
64
-
65
- updated(changes: PropertyValues<this>) {
66
- if (changes.has('value') && this.editor && !this._self_changing) {
67
- const to = this.editor.state.doc.toString().length
68
- this.editor.dispatch({
69
- changes: { from: 0, to, insert: this.value === undefined ? '' : String(this.value) }
70
- })
71
- }
72
- }
73
-
74
- get editor() {
75
- if (!this._editor) {
76
- let language: LanguageSupport[] = []
77
- switch (this.language) {
78
- case 'sql':
79
- language = [sql()]
80
- break
81
- case 'json':
82
- language = [json()]
83
- break
84
- case 'javascript':
85
- language = [javascript()]
86
- break
87
- default:
88
- break
89
- }
90
-
91
- this._editor = new EditorView({
92
- doc: this.value,
93
- extensions: [
94
- minimalSetup,
95
- ...language,
96
- ...(this.showLineNumbers ? [lineNumbers()] : []),
97
- bracketMatching(),
98
- closeBrackets(),
99
- history(),
100
- autocompletion(),
101
- oneDark,
102
- syntaxHighlighting(oneDarkHighlightStyle),
103
- highlightActiveLine(),
104
- keymap.of([...historyKeymap, indentWithTab]),
105
- EditorView.updateListener.of(async v => {
106
- if (v.docChanged) {
107
- this._self_changing = true
108
- this._changed = true
109
-
110
- await this.updateComplete
111
-
112
- this._self_changing = false
113
- }
114
- })
115
- ],
116
- parent: this.renderRoot
117
- })
118
- }
119
-
120
- this._editor.contentDOM.addEventListener('keydown', event => {
121
- event.stopPropagation()
122
-
123
- if (event.key === 'Escape') {
124
- togglefullscreen(this._editor!.contentDOM)
125
- }
126
- })
127
-
128
- this._editor.contentDOM.addEventListener('blur', e => {
129
- if (!this._changed) {
130
- return
131
- }
132
-
133
- this.value = this._editor!.state.doc.toString()
134
- this.dispatchEvent(new CustomEvent('change', { bubbles: true, composed: true, detail: this.value }))
135
- })
136
-
137
- return this._editor
138
- }
139
- }