@operato/input 10.0.0 → 10.2.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.
Files changed (107) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/STYLING.md +194 -0
  3. package/dist/src/index.d.ts +1 -0
  4. package/dist/src/index.js +1 -0
  5. package/dist/src/index.js.map +1 -1
  6. package/dist/src/input-styles.d.ts +38 -0
  7. package/dist/src/input-styles.js +108 -0
  8. package/dist/src/input-styles.js.map +1 -0
  9. package/dist/src/ox-buttons-radio.js +6 -4
  10. package/dist/src/ox-buttons-radio.js.map +1 -1
  11. package/dist/src/ox-form-field.d.ts +41 -0
  12. package/dist/src/ox-form-field.js +68 -1
  13. package/dist/src/ox-form-field.js.map +1 -1
  14. package/dist/src/ox-input-3axis.js +3 -1
  15. package/dist/src/ox-input-3axis.js.map +1 -1
  16. package/dist/src/ox-input-3dish.js +4 -2
  17. package/dist/src/ox-input-3dish.js.map +1 -1
  18. package/dist/src/ox-input-audio.js +4 -2
  19. package/dist/src/ox-input-audio.js.map +1 -1
  20. package/dist/src/ox-input-barcode.js +3 -1
  21. package/dist/src/ox-input-barcode.js.map +1 -1
  22. package/dist/src/ox-input-code.js +3 -1
  23. package/dist/src/ox-input-code.js.map +1 -1
  24. package/dist/src/ox-input-color.js +4 -2
  25. package/dist/src/ox-input-color.js.map +1 -1
  26. package/dist/src/ox-input-crontab.d.ts +1 -1
  27. package/dist/src/ox-input-crontab.js +6 -5
  28. package/dist/src/ox-input-crontab.js.map +1 -1
  29. package/dist/src/ox-input-data.js +5 -3
  30. package/dist/src/ox-input-data.js.map +1 -1
  31. package/dist/src/ox-input-duration.d.ts +1 -1
  32. package/dist/src/ox-input-duration.js +5 -4
  33. package/dist/src/ox-input-duration.js.map +1 -1
  34. package/dist/src/ox-input-file.js +3 -1
  35. package/dist/src/ox-input-file.js.map +1 -1
  36. package/dist/src/ox-input-formula-help-popup.js +30 -28
  37. package/dist/src/ox-input-formula-help-popup.js.map +1 -1
  38. package/dist/src/ox-input-formula.js +112 -111
  39. package/dist/src/ox-input-formula.js.map +1 -1
  40. package/dist/src/ox-input-hashtags.d.ts +1 -1
  41. package/dist/src/ox-input-hashtags.js +9 -8
  42. package/dist/src/ox-input-hashtags.js.map +1 -1
  43. package/dist/src/ox-input-i18n-label.d.ts +1 -1
  44. package/dist/src/ox-input-i18n-label.js +5 -4
  45. package/dist/src/ox-input-i18n-label.js.map +1 -1
  46. package/dist/src/ox-input-image.js +4 -2
  47. package/dist/src/ox-input-image.js.map +1 -1
  48. package/dist/src/ox-input-key-values.d.ts +1 -1
  49. package/dist/src/ox-input-key-values.js +10 -9
  50. package/dist/src/ox-input-key-values.js.map +1 -1
  51. package/dist/src/ox-input-mass-fraction.js +7 -5
  52. package/dist/src/ox-input-mass-fraction.js.map +1 -1
  53. package/dist/src/ox-input-multiple-colors.d.ts +1 -1
  54. package/dist/src/ox-input-multiple-colors.js +5 -4
  55. package/dist/src/ox-input-multiple-colors.js.map +1 -1
  56. package/dist/src/ox-input-options.d.ts +1 -1
  57. package/dist/src/ox-input-options.js +8 -7
  58. package/dist/src/ox-input-options.js.map +1 -1
  59. package/dist/src/ox-input-partition-keys.d.ts +1 -1
  60. package/dist/src/ox-input-partition-keys.js +10 -9
  61. package/dist/src/ox-input-partition-keys.js.map +1 -1
  62. package/dist/src/ox-input-privilege.d.ts +1 -1
  63. package/dist/src/ox-input-privilege.js +9 -8
  64. package/dist/src/ox-input-privilege.js.map +1 -1
  65. package/dist/src/ox-input-quantifier.d.ts +1 -1
  66. package/dist/src/ox-input-quantifier.js +6 -5
  67. package/dist/src/ox-input-quantifier.js.map +1 -1
  68. package/dist/src/ox-input-range.js +9 -8
  69. package/dist/src/ox-input-range.js.map +1 -1
  70. package/dist/src/ox-input-search.js +3 -1
  71. package/dist/src/ox-input-search.js.map +1 -1
  72. package/dist/src/ox-input-secret.js +3 -1
  73. package/dist/src/ox-input-secret.js.map +1 -1
  74. package/dist/src/ox-input-select-buttons.d.ts +1 -1
  75. package/dist/src/ox-input-select-buttons.js +4 -3
  76. package/dist/src/ox-input-select-buttons.js.map +1 -1
  77. package/dist/src/ox-input-signature.js +5 -3
  78. package/dist/src/ox-input-signature.js.map +1 -1
  79. package/dist/src/ox-input-stack.js +3 -1
  80. package/dist/src/ox-input-stack.js.map +1 -1
  81. package/dist/src/ox-input-table-column-config.js +5 -3
  82. package/dist/src/ox-input-table-column-config.js.map +1 -1
  83. package/dist/src/ox-input-table.js +5 -3
  84. package/dist/src/ox-input-table.js.map +1 -1
  85. package/dist/src/ox-input-unit-number.js +5 -3
  86. package/dist/src/ox-input-unit-number.js.map +1 -1
  87. package/dist/src/ox-input-value-map.d.ts +1 -1
  88. package/dist/src/ox-input-value-map.js +10 -9
  89. package/dist/src/ox-input-value-map.js.map +1 -1
  90. package/dist/src/ox-input-value-ranges.d.ts +1 -1
  91. package/dist/src/ox-input-value-ranges.js +11 -10
  92. package/dist/src/ox-input-value-ranges.js.map +1 -1
  93. package/dist/src/ox-input-video.js +4 -2
  94. package/dist/src/ox-input-video.js.map +1 -1
  95. package/dist/src/ox-input-work-shift.d.ts +1 -1
  96. package/dist/src/ox-input-work-shift.js +10 -9
  97. package/dist/src/ox-input-work-shift.js.map +1 -1
  98. package/dist/src/ox-select-floor.js +5 -3
  99. package/dist/src/ox-select-floor.js.map +1 -1
  100. package/dist/src/ox-select.js +20 -11
  101. package/dist/src/ox-select.js.map +1 -1
  102. package/dist/test/ox-form-field.test.d.ts +1 -0
  103. package/dist/test/ox-form-field.test.js +125 -0
  104. package/dist/test/ox-form-field.test.js.map +1 -0
  105. package/dist/tsconfig.tsbuildinfo +1 -1
  106. package/package.json +4 -4
  107. package/test/ox-form-field.test.ts +159 -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": "10.0.0",
5
+ "version": "10.2.0",
6
6
  "type": "module",
7
7
  "main": "dist/src/index.js",
8
8
  "module": "dist/src/index.js",
@@ -245,8 +245,8 @@
245
245
  "@material/web": "^2.0.0",
246
246
  "@operato/i18n": "^10.0.0",
247
247
  "@operato/pickr": "^10.0.0",
248
- "@operato/popup": "^10.0.0",
249
- "@operato/styles": "^10.0.0",
248
+ "@operato/popup": "^10.2.0",
249
+ "@operato/styles": "^10.2.0",
250
250
  "@operato/utils": "^10.0.0",
251
251
  "@types/codemirror": "^5.60.5",
252
252
  "@undecaf/zbar-wasm": "^0.11.0",
@@ -288,5 +288,5 @@
288
288
  "prettier --write"
289
289
  ]
290
290
  },
291
- "gitHead": "6731331f3b751ac2d60218645a2b488c56f7d37d"
291
+ "gitHead": "76b17317691c6dbc0e2804812c108241bf11b1c0"
292
292
  }
@@ -0,0 +1,159 @@
1
+ import { html } from 'lit'
2
+ import { customElement } from 'lit/decorators.js'
3
+ import { fixture, expect } from '@open-wc/testing'
4
+
5
+ import { OxFormField } from '../src/ox-form-field.js'
6
+
7
+ /**
8
+ * OxFormField 계약 테스트.
9
+ *
10
+ * 이 기반 클래스는 51개 입력 컴포넌트가 상속하므로, 계약이 깨지면 전 패키지에 파급된다.
11
+ * 검증 대상:
12
+ * - 상태 속성의 attribute reflect (InputStyles 의 :host([...]) 선택자가 동작하기 위한 전제)
13
+ * - required 기반 검증(checkValidity / invalid / invalid 이벤트)
14
+ * - isEmpty 의 경계값(0·false 는 유효한 값)
15
+ * - 폼 데이터 수집(formdata) 과 disabled 제외 규칙
16
+ */
17
+
18
+ /** 테스트용 최소 구현체 — 기반 계약만 노출한다. */
19
+ @customElement('test-form-field')
20
+ class TestFormField extends OxFormField<any> {
21
+ render() {
22
+ return html`<span>field</span>`
23
+ }
24
+
25
+ /* 테스트에서 보호된 멤버를 확인하기 위한 창구 */
26
+ public callIsEmpty(): boolean {
27
+ return this.isEmpty()
28
+ }
29
+ }
30
+
31
+ async function makeField(template = html`<test-form-field></test-form-field>`) {
32
+ return (await fixture(template)) as TestFormField
33
+ }
34
+
35
+ describe('OxFormField — 상태 계약', () => {
36
+ it('상태 속성이 attribute 로 reflect 된다 (프로퍼티로 설정해도 :host([...]) 가 동작)', async () => {
37
+ const el = await makeField()
38
+
39
+ el.disabled = true
40
+ el.readonly = true
41
+ el.required = true
42
+ el.invalid = true
43
+ await el.updateComplete
44
+
45
+ expect(el.hasAttribute('disabled')).to.be.true
46
+ expect(el.hasAttribute('readonly')).to.be.true
47
+ expect(el.hasAttribute('required')).to.be.true
48
+ expect(el.hasAttribute('invalid')).to.be.true
49
+ })
50
+
51
+ it('상태를 해제하면 attribute 도 제거된다', async () => {
52
+ const el = await makeField(html`<test-form-field disabled readonly></test-form-field>`)
53
+
54
+ expect(el.disabled).to.be.true
55
+ expect(el.readonly).to.be.true
56
+
57
+ el.disabled = false
58
+ el.readonly = false
59
+ await el.updateComplete
60
+
61
+ expect(el.hasAttribute('disabled')).to.be.false
62
+ expect(el.hasAttribute('readonly')).to.be.false
63
+ })
64
+ })
65
+
66
+ describe('OxFormField — isEmpty 경계값', () => {
67
+ it('nullish / 빈 문자열 / 공백 / 빈 배열은 비어 있다', async () => {
68
+ const el = await makeField()
69
+
70
+ for (const v of [undefined, null, '', ' ', [] as any[]]) {
71
+ el.value = v
72
+ expect(el.callIsEmpty(), `value=${JSON.stringify(v)}`).to.be.true
73
+ }
74
+ })
75
+
76
+ it('숫자 0 과 false 는 유효한 값이므로 비어 있지 않다', async () => {
77
+ const el = await makeField()
78
+
79
+ el.value = 0
80
+ expect(el.callIsEmpty(), 'value=0').to.be.false
81
+
82
+ el.value = false
83
+ expect(el.callIsEmpty(), 'value=false').to.be.false
84
+ })
85
+ })
86
+
87
+ describe('OxFormField — 검증', () => {
88
+ it('required 가 아니면 값이 비어도 유효하다', async () => {
89
+ const el = await makeField()
90
+
91
+ expect(el.checkValidity()).to.be.true
92
+ expect(el.invalid).to.be.false
93
+ })
94
+
95
+ it('required 인데 값이 비면 invalid 가 되고 invalid 이벤트가 올라온다', async () => {
96
+ const el = await makeField(html`<test-form-field required name="f"></test-form-field>`)
97
+
98
+ let detail: any = null
99
+ el.addEventListener('invalid', (e: Event) => {
100
+ detail = (e as CustomEvent).detail
101
+ })
102
+
103
+ expect(el.checkValidity()).to.be.false
104
+ expect(el.invalid).to.be.true
105
+ expect(detail).to.deep.equal({ field: 'f' })
106
+ })
107
+
108
+ it('값을 채우면 다시 유효해지고 invalid 가 해제된다', async () => {
109
+ const el = await makeField(html`<test-form-field required></test-form-field>`)
110
+
111
+ expect(el.checkValidity()).to.be.false
112
+
113
+ el.value = 'filled'
114
+ expect(el.checkValidity()).to.be.true
115
+ expect(el.invalid).to.be.false
116
+ })
117
+ })
118
+
119
+ describe('OxFormField — 폼 데이터 수집', () => {
120
+ async function collect(fieldTemplate: unknown) {
121
+ const form = (await fixture(html`<form>${fieldTemplate}</form>`)) as HTMLFormElement
122
+ return new FormData(form)
123
+ }
124
+
125
+ it('name 이 있으면 값이 폼 데이터에 담긴다', async () => {
126
+ const data = await collect(html`<test-form-field name="a" .value=${'1'}></test-form-field>`)
127
+
128
+ expect(data.get('a')).to.equal('1')
129
+ })
130
+
131
+ it('배열 값은 여러 항목으로 담긴다', async () => {
132
+ const data = await collect(html`<test-form-field name="b" .value=${['x', 'y']}></test-form-field>`)
133
+
134
+ expect(data.getAll('b')).to.deep.equal(['x', 'y'])
135
+ })
136
+
137
+ it('disabled 는 폼 데이터에 포함되지 않는다 (HTML 표준 거동)', async () => {
138
+ const data = await collect(html`<test-form-field name="c" disabled .value=${'skip'}></test-form-field>`)
139
+
140
+ expect(data.has('c')).to.be.false
141
+ })
142
+
143
+ it('readonly 는 수정만 막는 상태이므로 폼 데이터에 포함된다', async () => {
144
+ const data = await collect(html`<test-form-field name="d" readonly .value=${'keep'}></test-form-field>`)
145
+
146
+ expect(data.get('d')).to.equal('keep')
147
+ })
148
+
149
+ it('name 이 없으면 수집되지 않는다', async () => {
150
+ const form = (await fixture(
151
+ html`<form><test-form-field .value=${'anon'}></test-form-field></form>`
152
+ )) as HTMLFormElement
153
+ const data = new FormData(form)
154
+
155
+ /* name 이 없으면 어떤 키로도 담기지 않는다 */
156
+ expect(data.has('')).to.be.false
157
+ expect(data.get('undefined')).to.be.null
158
+ })
159
+ })