kmaterialize 2.0.0 → 2.3.3-1.0.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 (150) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +55 -91
  3. package/components/appbar/_navbar.old.scss +223 -0
  4. package/components/appbar/appbar.css +235 -0
  5. package/components/appbar/appbar.mjs +54 -0
  6. package/components/appbar/appbar.test.mjs +9 -0
  7. package/components/atomic/atomic.mjs +19 -0
  8. package/components/atomic/component.mjs +67 -0
  9. package/components/badge/_badges.scss +75 -0
  10. package/components/badge/badge.mjs +11 -0
  11. package/components/breadcrumb/_breadcrumb.scss +27 -0
  12. package/components/button/_buttons.scss +352 -0
  13. package/components/button/button.mjs +11 -0
  14. package/components/button/buttons.stories.ts +150 -0
  15. package/components/button/buttons.ts +282 -0
  16. package/components/button/examples.iso.js +18 -0
  17. package/components/button/fabSpec.js +65 -0
  18. package/components/button/test-button.mjs +16 -0
  19. package/components/card/_cards.scss +229 -0
  20. package/components/card/card.mjs +10 -0
  21. package/components/card/cards.ts +185 -0
  22. package/components/card/cardsSpec.js +269 -0
  23. package/components/carousel/_carousel.scss +93 -0
  24. package/components/carousel/_slider.scss +119 -0
  25. package/components/carousel/carousel.ts +693 -0
  26. package/components/carousel/carouselSpec.js +61 -0
  27. package/components/carousel/slider.ts +431 -0
  28. package/components/carousel/sliderSpec.js +99 -0
  29. package/components/checkbox/_checkboxes.scss +281 -0
  30. package/components/checkbox/checkbox.mdx +24 -0
  31. package/components/checkbox/checkbox.stories.ts +120 -0
  32. package/components/chip/chip.mjs +37 -0
  33. package/components/chip/chip.test.mjs +10 -0
  34. package/components/chip/chips.css +126 -0
  35. package/components/chip/chips.mdx +33 -0
  36. package/components/chip/chips.ts +440 -0
  37. package/components/chip/chipsSpec.js +165 -0
  38. package/components/chip/readme.md +323 -0
  39. package/components/collapsible/_collapsible.scss +82 -0
  40. package/components/collapsible/collapsible.ts +230 -0
  41. package/components/collapsible/collapsibleSpec.js +240 -0
  42. package/components/datepicker/_datepicker.scss +268 -0
  43. package/components/datepicker/datepicker.ts +1450 -0
  44. package/components/datepicker/datepickerSpec.js +162 -0
  45. package/components/dialog/_materialbox.scss +42 -0
  46. package/components/dialog/_modal.scss +79 -0
  47. package/components/dialog/materialbox.ts +446 -0
  48. package/components/dialog/materialboxSpec.js +37 -0
  49. package/components/dialog/modal.ts +111 -0
  50. package/components/dialog/modalSpec.js +83 -0
  51. package/components/dialog/readme.md +5 -0
  52. package/components/divider/readme.md +15 -0
  53. package/components/dropdown/_dropdown.scss +83 -0
  54. package/components/dropdown/dropdown.ts +653 -0
  55. package/components/dropdown/dropdownSpec.js +108 -0
  56. package/components/list/_collection.scss +114 -0
  57. package/components/list/_list.scss +6 -0
  58. package/components/list/list.mjs +58 -0
  59. package/components/list/list.test.mjs +16 -0
  60. package/components/loading/loading.mjs +26 -0
  61. package/components/loading/loading.test.mjs +10 -0
  62. package/components/navigation-bar/_old +582 -0
  63. package/components/navigation-bar/navigation-bar.mdx +20 -0
  64. package/components/navigation-bar/navigation-bar.stories.ts +39 -0
  65. package/components/navigation-drawer/_sidenav.scss +247 -0
  66. package/components/navigation-drawer/sidenav.ts +546 -0
  67. package/components/navigation-drawer/sidenavSpec.js +124 -0
  68. package/components/pagination/_pagination.scss +47 -0
  69. package/components/progress/_preloader.scss +416 -0
  70. package/components/radio-button/_radio-buttons.scss +112 -0
  71. package/components/radio-button/radio-buttons.mdx +28 -0
  72. package/components/radio-button/radio-buttons.stories.ts +51 -0
  73. package/components/search/autocomplete.ts +620 -0
  74. package/components/search/autocompleteSpec.js +321 -0
  75. package/components/slider/_range.scss +157 -0
  76. package/components/slider/range.ts +216 -0
  77. package/components/snackbar/_toast.scss +68 -0
  78. package/components/snackbar/toastSpec.js +132 -0
  79. package/components/snackbar/toasts.ts +312 -0
  80. package/components/switch/_switches.scss +121 -0
  81. package/components/tabs/_tabs.scss +171 -0
  82. package/components/tabs/tabs.mjs +31 -0
  83. package/components/tabs/tabs.ts +358 -0
  84. package/components/tabs/tabsSpec.js +180 -0
  85. package/components/textfield/_file-input.scss +41 -0
  86. package/components/textfield/_input-fields.scss +368 -0
  87. package/components/textfield/_select.scss +104 -0
  88. package/components/textfield/formfields.css +311 -0
  89. package/components/textfield/forms.ts +182 -0
  90. package/components/textfield/formsSpec.js +142 -0
  91. package/components/textfield/select.ts +472 -0
  92. package/components/textfield/selectSpec.js +390 -0
  93. package/components/textfield/textfield.mjs +29 -0
  94. package/components/textfield/textfield.test.mjs +10 -0
  95. package/components/timepicker/_timepicker.scss +362 -0
  96. package/components/timepicker/timepicker.ts +905 -0
  97. package/components/tooltip/_tooltip.scss +40 -0
  98. package/components/tooltip/tooltip.ts +380 -0
  99. package/components/tooltip/tooltipSpec.js +145 -0
  100. package/dist/css/materialize.colors.min.css +6 -0
  101. package/dist/css/materialize.css +7578 -6326
  102. package/dist/css/materialize.min.css +6 -13
  103. package/dist/css/materialize.min.css.map +1 -0
  104. package/dist/js/materialize.cjs.js +8410 -0
  105. package/dist/js/materialize.d.ts +2625 -0
  106. package/dist/js/materialize.js +8415 -12374
  107. package/dist/js/materialize.min.js +6 -6
  108. package/dist/js/materialize.mjs +8382 -0
  109. package/package.json +82 -47
  110. package/sass/_colors.scss +417 -0
  111. package/sass/_global.scss +490 -0
  112. package/sass/_grid.scss +172 -0
  113. package/sass/_table_of_contents.scss +28 -0
  114. package/sass/_tapTarget.scss +102 -0
  115. package/sass/_typography.scss +58 -0
  116. package/sass/_variables.scss +56 -0
  117. package/sass/materialize.scss +51 -0
  118. package/sass/mixins.module.scss +168 -0
  119. package/extras/noUiSlider/nouislider.css +0 -406
  120. package/extras/noUiSlider/nouislider.js +0 -2147
  121. package/extras/noUiSlider/nouislider.min.js +0 -1
  122. package/js/anime.min.js +0 -34
  123. package/js/autocomplete.js +0 -448
  124. package/js/buttons.js +0 -354
  125. package/js/cards.js +0 -40
  126. package/js/carousel.js +0 -717
  127. package/js/cash.js +0 -960
  128. package/js/characterCounter.js +0 -136
  129. package/js/chips.js +0 -481
  130. package/js/collapsible.js +0 -275
  131. package/js/component.js +0 -44
  132. package/js/datepicker.js +0 -975
  133. package/js/dropdown.js +0 -635
  134. package/js/forms.js +0 -275
  135. package/js/global.js +0 -444
  136. package/js/materialbox.js +0 -453
  137. package/js/modal.js +0 -382
  138. package/js/parallax.js +0 -138
  139. package/js/pushpin.js +0 -148
  140. package/js/range.js +0 -263
  141. package/js/scrollspy.js +0 -295
  142. package/js/select.js +0 -450
  143. package/js/sidenav.js +0 -580
  144. package/js/slider.js +0 -359
  145. package/js/tabs.js +0 -402
  146. package/js/tapTarget.js +0 -314
  147. package/js/timepicker.js +0 -647
  148. package/js/toasts.js +0 -310
  149. package/js/tooltip.js +0 -303
  150. package/js/waves.js +0 -335
@@ -0,0 +1,311 @@
1
+ /**
2
+ new approach for floating labels aka "form-fields" (css only)
3
+ - also use for selects, autocomplete, etc.
4
+
5
+ <div class="row g-1 p-3">
6
+ <!-- Animated -->
7
+ <fieldset class="form-field animated s12 m4">
8
+ <legend>Given Name</legend>
9
+ <input type="text" id="my-input-1" placeholder=" "/>
10
+ <label for="my-input-1">Given Name</label>
11
+ </fieldset>
12
+ <!-- Disabled-->
13
+ <fieldset class="form-field s12 m4" disabled>
14
+ <legend>Family Name</legend>
15
+ <input type="text" id="my-input-2" placeholder="e.g. Doe" />
16
+ <label for="my-input-2">Family Name</label>
17
+ </fieldset>
18
+ <!-- different placeholder than label + required -->
19
+ <fieldset class="form-field s12 m4">
20
+ <legend>Birthmonth</legend>
21
+ <input type="text" id="my-input-3" placeholder="e.g. April" required />
22
+ <label for="my-input-3">Birthmonth</label>
23
+ </fieldset>
24
+ </div>
25
+ */
26
+
27
+ :root {
28
+ --mw-font-size: 16px;
29
+ --mw-border-radius: 8px;
30
+ --mw-input-height: 56px;
31
+ --mw-idle-color: var(--md-sys-color-outline);
32
+ --mw-border-width: 1px;
33
+ --mw-hover-color: var(--md-sys-color-on-primary-container);
34
+ --mw-hover-border-width: 1px;
35
+ --mw-focus-color: var(--md-sys-color-primary);
36
+ --mw-focus-border-width: 2px;
37
+ --mw-disabled-color: #8886;
38
+ --mw-padding-left: 16px;
39
+ --mw-input-padding-x: var(--mw-padding-left);
40
+ --mw-input-padding-r: 12px;
41
+ --mw-label-padding: 4px;
42
+ --mw-inputlabel-duration: 0.2s;
43
+ --mw-inset: 5px;
44
+ /* calclated properties */
45
+ --label-size: calc(var(--mw-font-size) * 0.75);
46
+ --label-margin-left: calc(var(--mw-padding-left) - var(--mw-label-padding));
47
+ --half-inp: calc((-0.5 * var(--mw-input-height)));
48
+ --half-lbl: calc((0.5 * var(--label-size)));
49
+ --distY: calc(var(--half-inp) + var(--half-lbl));
50
+ }
51
+
52
+ /*=== idle */
53
+ fieldset.form-field {
54
+ position: relative;
55
+ border-width: var(--mw-border-width);
56
+ border-color: var(--mw-idle-color);
57
+ border-style: solid;
58
+ border-radius: var(--mw-border-radius);
59
+ cursor: text;
60
+ height: var(--mw-input-height);
61
+ user-select: none;
62
+ padding: 0;
63
+ margin: 0;
64
+ display: grid;
65
+ grid-auto-flow: column;
66
+ align-items: baseline;
67
+ font-size: var(--mw-font-size);
68
+ padding: 0 calc(var(--mw-inset) - var(--mw-border-width));
69
+ }
70
+ fieldset.form-field legend {
71
+ color: var(--mw-idle-color);
72
+ font-size: var(--label-size);
73
+ padding: 0 var(--mw-label-padding);
74
+ margin: 0;
75
+ margin-left: calc(var(--mw-padding-left) - var(--mw-label-padding) - var(--mw-border-width));
76
+ cursor: text;
77
+ /* color: transparent; */
78
+ user-select: none;
79
+ }
80
+ fieldset.form-field input,
81
+ fieldset.form-field select {
82
+ --mw-calc-input-height: calc(
83
+ var(--mw-input-height) - var(--label-size) + 2 * var(--mw-border-width)
84
+ );
85
+ box-sizing: border-box;
86
+ font-size: var(--mw-font-size);
87
+ padding: 0;
88
+ margin: 0;
89
+ width: 100%;
90
+ height: var(--mw-calc-input-height);
91
+ max-height: var(--mw-calc-input-height);
92
+ margin-top: calc(-1 * var(--half-lbl));
93
+ padding-left: calc(var(--mw-padding-left) - var(--mw-border-width));
94
+ border: none;
95
+ line-height: normal;
96
+ outline: none;
97
+ background: none;
98
+ /* background-color: #0f05 !important; */
99
+ }
100
+ fieldset.form-field select {
101
+ padding: 0;
102
+ /* margin: 0; */
103
+ padding-left: calc(var(--mw-padding-left) - var(--mw-label-padding));
104
+ /* background-color: #f005 !important; */
105
+ z-index: 2;
106
+ }
107
+ fieldset.form-field select option {
108
+ background-color: black;
109
+ color: white;
110
+ }
111
+ fieldset.form-field input::placeholder {
112
+ color: var(--mw-idle-color);
113
+ font-size: var(--mw-font-size);
114
+ }
115
+ fieldset.form-field label {
116
+ position: absolute;
117
+ top: calc(var(--mw-input-height) / 2 - var(--label-size) - var(--mw-font-size) / 2);
118
+ margin-left: calc(var(--mw-inset) - var(--mw-border-width));
119
+ font-size: var(--mw-font-size);
120
+ cursor: text;
121
+ user-select: none;
122
+ color: transparent;
123
+ /* color: green; */
124
+ z-index: 1; /* for not blocking klicks */
125
+ pointer-events: none;
126
+ }
127
+
128
+ /* fixes from other inputs */
129
+ fieldset.form-field .select-wrapper {
130
+ outline: none !important;
131
+ }
132
+
133
+ /*--- idle animated */
134
+ fieldset.form-field.animated legend::before {
135
+ content: '';
136
+ position: absolute;
137
+ display: block;
138
+ width: calc(100% - var(--mw-border-radius));
139
+ right: calc(0.5 * var(--mw-border-radius));
140
+ height: 0;
141
+ border-top: var(--mw-border-width) solid var(--mw-idle-color);
142
+ align-self: center;
143
+ transition: width calc(var(--mw-inputlabel-duration) * 0.8);
144
+ }
145
+ fieldset.form-field.animated legend {
146
+ color: transparent;
147
+ }
148
+ fieldset.form-field.animated input::placeholder {
149
+ opacity: 1;
150
+ transition: opacity var(--mw-inputlabel-duration) step-end;
151
+ }
152
+ fieldset.form-field.animated label {
153
+ position: absolute;
154
+ left: calc(var(--mw-input-padding-x) - var(--mw-border-width));
155
+ font-size: var(--mw-font-size);
156
+ transition:
157
+ font-size var(--mw-inputlabel-duration),
158
+ transform var(--mw-inputlabel-duration),
159
+ opacity var(--mw-inputlabel-duration) step-end;
160
+ }
161
+ /*--- idle animated populated */
162
+ fieldset.form-field.animated:has(input:not(:placeholder-shown)) legend::before {
163
+ width: 0;
164
+ }
165
+ fieldset.form-field.animated:has(input:not(:placeholder-shown)) legend {
166
+ color: var(--mw-idle-color);
167
+ }
168
+ fieldset.form-field.animated:has(input:not(:placeholder-shown)) label {
169
+ color: transparent;
170
+ }
171
+
172
+ /*===== hovered */
173
+ fieldset.form-field:hover {
174
+ border-width: var(--mw-hover-border-width);
175
+ border-color: var(--mw-hover-color);
176
+ padding: 0 calc(var(--mw-inset) - var(--mw-hover-border-width));
177
+ }
178
+ fieldset.form-field:hover legend::before {
179
+ border-width: var(--mw-hover-border-width);
180
+ border-color: var(--mw-hover-color);
181
+ }
182
+ fieldset.form-field:hover legend {
183
+ color: var(--mw-hover-color);
184
+ }
185
+ /* hovered animated */
186
+ fieldset.form-field.animated:hover legend {
187
+ color: transparent;
188
+ }
189
+ fieldset.form-field.animated:has(input:placeholder-shown):hover input::placeholder {
190
+ color: transparent;
191
+ }
192
+ fieldset.form-field.animated:has(input:not(:placeholder-shown)):hover legend {
193
+ color: var(--mw-hover-color);
194
+ }
195
+ fieldset.form-field.animated:hover label {
196
+ /* color: transparent; */
197
+ color: var(--mw-hover-color);
198
+ left: calc(var(--mw-input-padding-x) - var(--mw-hover-border-width));
199
+ top: calc(
200
+ 0.5 * var(--mw-input-height) - var(--label-size) * 0.5 - var(--mw-font-size) +
201
+ var(--mw-hover-border-width)
202
+ );
203
+ }
204
+
205
+ /*===== focused */
206
+ fieldset.form-field:focus-within {
207
+ border-width: var(--mw-focus-border-width);
208
+ border-color: var(--mw-focus-color);
209
+ padding: 0 calc(var(--mw-inset) - var(--mw-focus-border-width));
210
+ }
211
+ fieldset.form-field:focus-within legend::before {
212
+ border-width: var(--mw-focus-border-width);
213
+ border-color: var(--mw-focus-color);
214
+ }
215
+ fieldset.form-field:focus-within legend {
216
+ color: var(--mw-focus-color);
217
+ }
218
+ fieldset.form-field select:focus {
219
+ color: var(--mw-focus-color);
220
+ }
221
+ /* focused animated */
222
+ fieldset.form-field.animated:focus-within legend::before {
223
+ width: 0;
224
+ }
225
+ fieldset.form-field.animated:focus-within legend {
226
+ color: var(--mw-focus-color);
227
+ }
228
+ fieldset.form-field.animated:has(input:not(:placeholder-shown)):focus-within legend {
229
+ color: var(--mw-focus-color);
230
+ }
231
+ fieldset.form-field.animated:focus-within input::placeholder {
232
+ color: transparent;
233
+ }
234
+ fieldset.form-field.animated:focus-within label {
235
+ color: transparent;
236
+ left: calc(var(--mw-input-padding-x) - var(--mw-hover-border-width));
237
+ }
238
+
239
+ /*
240
+ fieldset.form-field.animated input:not(:placeholder-shown) ~ legend::before {
241
+ width: 0;
242
+ }
243
+ fieldset.form-field.animated input:not(:placeholder-shown) ~ label {
244
+ font-size: var(--label-size);
245
+ transform: translateY(0);
246
+ opacity: 1;
247
+ }
248
+ fieldset.form-field.animated label {
249
+ opacity: 1;
250
+ color: var(--mw-focus-color);
251
+ font-size: var(--label-size);
252
+ transform: translateY(var(--distY)) translateX(var(--mw-input-padding-x));
253
+ transition: font-size var(--mw-inputlabel-duration), transform var(--mw-inputlabel-duration), opacity 0s;
254
+ }
255
+ fieldset.form-field.animated:focus-within legend::before,
256
+ fieldset.form-field.animated:has(input:not(:placeholder-shown)) legend::before {
257
+ border-top: var(--mw-focus-border-width) solid var(--mw-focus-color);
258
+ width: 0;
259
+ }
260
+ fieldset.form-field.animated:focus-within input::placeholder {
261
+ opacity: 0;
262
+ transition: opacity 0s;
263
+ }
264
+ */
265
+
266
+ /* disabled*/
267
+ fieldset.form-field[disabled],
268
+ fieldset.form-field[disabled]:hover {
269
+ background-color: transparent;
270
+ border-color: var(--mw-disabled-color);
271
+ user-select: none;
272
+ cursor: not-allowed;
273
+ padding: 0 calc(var(--mw-inset) - var(--mw-border-width));
274
+ }
275
+ fieldset.form-field[disabled] input {
276
+ cursor: not-allowed;
277
+ }
278
+ fieldset.form-field[disabled] legend,
279
+ fieldset.form-field[disabled] input::placeholder {
280
+ color: var(--mw-disabled-color);
281
+ cursor: not-allowed;
282
+ }
283
+ fieldset.form-field[disabled] input {
284
+ height: calc(var(--mw-input-height) - var(--label-size) + 2 * var(--mw-border-width));
285
+ margin-top: calc(-1 * var(--half-lbl));
286
+ }
287
+ fieldset.form-field[disabled]:hover {
288
+ border-width: var(--mw-border-width);
289
+ }
290
+ fieldset.form-field[disabled]:hover input,
291
+ fieldset.form-field[disabled]:hover select {
292
+ padding-left: calc(var(--mw-padding-left) - var(--mw-border-width));
293
+ }
294
+ fieldset.form-field[disabled]:hover legend {
295
+ margin-left: calc(var(--mw-padding-left) - var(--mw-label-padding) - var(--mw-border-width));
296
+ border-color: transparent;
297
+ border-color: var(--mw-disabled-color);
298
+ color: var(--mw-disabled-color);
299
+ cursor: not-allowed;
300
+ }
301
+ fieldset.form-field[disabled] label {
302
+ cursor: not-allowed;
303
+ }
304
+
305
+ /* special: required */
306
+ fieldset.form-field:has([required]) legend::after {
307
+ content: ' *';
308
+ }
309
+ fieldset.form-field:has([required]) label::after {
310
+ content: ' *';
311
+ }
@@ -0,0 +1,182 @@
1
+ import { Utils } from '../../src/utils';
2
+
3
+ export class Forms {
4
+ /**
5
+ * Checks if the label has validation and apply
6
+ * the correct class and styles
7
+ * @param textfield
8
+ */
9
+ static validateField(textfield: HTMLInputElement) {
10
+ if (!textfield) {
11
+ console.error('No text field element found');
12
+ return;
13
+ }
14
+
15
+ const hasLength = textfield.getAttribute('data-length') !== null;
16
+ const lenAttr = parseInt(textfield.getAttribute('data-length'));
17
+ const len = textfield.value.length;
18
+
19
+ if (
20
+ len === 0 &&
21
+ textfield.validity.badInput === false &&
22
+ !textfield.required &&
23
+ textfield.classList.contains('validate')
24
+ ) {
25
+ textfield.classList.remove('invalid');
26
+ } else if (textfield.classList.contains('validate')) {
27
+ // Check for character counter attributes
28
+ if (
29
+ (textfield.validity.valid && hasLength && len <= lenAttr) ||
30
+ (textfield.validity.valid && !hasLength)
31
+ ) {
32
+ textfield.classList.remove('invalid');
33
+ } else {
34
+ textfield.classList.add('invalid');
35
+ }
36
+ }
37
+ }
38
+
39
+ /**
40
+ * Resizes the given TextArea after updating the
41
+ * value content dynamically.
42
+ * @param e EventTarget
43
+ */
44
+ static textareaAutoResize(e: EventTarget) {
45
+ const textarea = e as HTMLTextAreaElement;
46
+ // if (!textarea) {
47
+ // console.error('No textarea element found');
48
+ // return;
49
+ // }
50
+ // Textarea Auto Resize
51
+ let hiddenDiv: HTMLDivElement = document.querySelector('.hiddendiv');
52
+ if (!hiddenDiv) {
53
+ hiddenDiv = document.createElement('div');
54
+ hiddenDiv.classList.add('hiddendiv', 'common');
55
+ document.body.append(hiddenDiv);
56
+ }
57
+ const style = getComputedStyle(textarea);
58
+ // Set font properties of hiddenDiv
59
+ const fontFamily = style.fontFamily; //textarea.css('font-family');
60
+ const fontSize = style.fontSize; //textarea.css('font-size');
61
+ const lineHeight = style.lineHeight; //textarea.css('line-height');
62
+ // Firefox can't handle padding shorthand.
63
+ const paddingTop = style.paddingTop; //getComputedStyle(textarea).css('padding-top');
64
+ const paddingRight = style.paddingRight; //textarea.css('padding-right');
65
+ const paddingBottom = style.paddingBottom; //textarea.css('padding-bottom');
66
+ const paddingLeft = style.paddingLeft; //textarea.css('padding-left');
67
+
68
+ if (fontSize) hiddenDiv.style.fontSize = fontSize; //('font-size', fontSize);
69
+ if (fontFamily) hiddenDiv.style.fontFamily = fontFamily; //css('font-family', fontFamily);
70
+ if (lineHeight) hiddenDiv.style.lineHeight = lineHeight; //css('line-height', lineHeight);
71
+ if (paddingTop) hiddenDiv.style.paddingTop = paddingTop; //ss('padding-top', paddingTop);
72
+ if (paddingRight) hiddenDiv.style.paddingRight = paddingRight; //css('padding-right', paddingRight);
73
+ if (paddingBottom) hiddenDiv.style.paddingBottom = paddingBottom; //css('padding-bottom', paddingBottom);
74
+ if (paddingLeft) hiddenDiv.style.paddingLeft = paddingLeft; //css('padding-left', paddingLeft);
75
+
76
+ // Set original-height, if none
77
+ if (!textarea.hasAttribute('original-height'))
78
+ textarea.setAttribute('original-height', textarea.getBoundingClientRect().height.toString());
79
+
80
+ if (textarea.getAttribute('wrap') === 'off') {
81
+ hiddenDiv.style.overflowWrap = 'normal'; // ('overflow-wrap', 'normal')
82
+ hiddenDiv.style.whiteSpace = 'pre'; //.css('white-space', 'pre');
83
+ }
84
+
85
+ hiddenDiv.innerText = textarea.value + '\n';
86
+ hiddenDiv.innerHTML = hiddenDiv.innerHTML.replace(/\n/g, '<br>');
87
+
88
+ // When textarea is hidden, width goes crazy.
89
+ // Approximate with half of window size
90
+ if (textarea.offsetWidth > 0 && textarea.offsetHeight > 0) {
91
+ hiddenDiv.style.width = textarea.getBoundingClientRect().width + 'px'; // ('width', textarea.width() + 'px');
92
+ } else {
93
+ hiddenDiv.style.width = window.innerWidth / 2 + 'px'; //css('width', window.innerWidth / 2 + 'px');
94
+ }
95
+
96
+ // Resize if the new height is greater than the
97
+ // original height of the textarea
98
+ const originalHeight = parseInt(textarea.getAttribute('original-height'));
99
+ const prevLength = parseInt(textarea.getAttribute('previous-length'));
100
+ if (isNaN(originalHeight)) return;
101
+ if (originalHeight <= hiddenDiv.clientHeight) {
102
+ textarea.style.height = hiddenDiv.clientHeight + 'px'; //css('height', hiddenDiv.innerHeight() + 'px');
103
+ } else if (textarea.value.length < prevLength) {
104
+ // In case the new height is less than original height, it
105
+ // means the textarea has less text than before
106
+ // So we set the height to the original one
107
+ textarea.style.height = originalHeight + 'px';
108
+ }
109
+ textarea.setAttribute('previous-length', (textarea.value || '').length.toString());
110
+ }
111
+
112
+ static Init() {
113
+ if (typeof document !== 'undefined')
114
+ document?.addEventListener('DOMContentLoaded', () => {
115
+ document.addEventListener('change', (e: KeyboardEvent) => {
116
+ const target = <HTMLInputElement>e.target;
117
+ if (target instanceof HTMLInputElement) {
118
+ if (target.value.length !== 0 || target.getAttribute('placeholder') !== null) {
119
+ for (const child of target.parentNode.children) {
120
+ if (child.tagName == 'label') {
121
+ child.classList.add('active');
122
+ }
123
+ }
124
+ }
125
+ Forms.validateField(target);
126
+ }
127
+ });
128
+
129
+ document.addEventListener('keyup', (e: KeyboardEvent) => {
130
+ const target = <HTMLInputElement>e.target;
131
+ // Radio and Checkbox focus class
132
+ if (target instanceof HTMLInputElement && ['radio', 'checkbox'].includes(target.type)) {
133
+ // TAB, check if tabbing to radio or checkbox.
134
+ if (Utils.keys.TAB.includes(e.key)) {
135
+ target.classList.add('tabbed');
136
+ target.addEventListener('blur', () => target.classList.remove('tabbed'), {
137
+ once: true
138
+ });
139
+ }
140
+ }
141
+ });
142
+
143
+ document
144
+ .querySelectorAll('.materialize-textarea')
145
+ .forEach((textArea: HTMLTextAreaElement) => {
146
+ Forms.InitTextarea(textArea);
147
+ });
148
+
149
+ // File Input Path
150
+ document
151
+ .querySelectorAll('.file-field input[type="file"]')
152
+ .forEach((fileInput: HTMLInputElement) => {
153
+ Forms.InitFileInputPath(fileInput);
154
+ });
155
+ });
156
+ }
157
+
158
+ static InitTextarea(textarea: HTMLTextAreaElement) {
159
+ // Save Data in Element
160
+ textarea.setAttribute('original-height', textarea.getBoundingClientRect().height.toString());
161
+ textarea.setAttribute('previous-length', (textarea.value || '').length.toString());
162
+ Forms.textareaAutoResize(textarea);
163
+ textarea.addEventListener('keyup', (e) => Forms.textareaAutoResize(e.target));
164
+ textarea.addEventListener('keydown', (e) => Forms.textareaAutoResize(e.target));
165
+ }
166
+
167
+ static InitFileInputPath(fileInput: HTMLInputElement) {
168
+ fileInput.addEventListener('change', () => {
169
+ const fileField = fileInput.closest('.file-field');
170
+ const pathInput = <HTMLInputElement>fileField.querySelector('input.file-path');
171
+ const files = fileInput.files;
172
+ const filenames = [];
173
+ for (let i = 0; i < files.length; i++) {
174
+ filenames.push(files[i].name);
175
+ }
176
+ pathInput.value = filenames.join(', ');
177
+ pathInput.dispatchEvent(
178
+ new Event('change', { bubbles: true, cancelable: true, composed: true })
179
+ );
180
+ });
181
+ }
182
+ }
@@ -0,0 +1,142 @@
1
+ const MULTILINE_TEXT =
2
+ 'This is line 1.\nThis is line 2.\nThis is line 3.\nThis is line 4.\nThis is line 5.\nAnd this is line 6.';
3
+
4
+ describe('Forms:', () => {
5
+ const fixture = `<div class="input-field">
6
+ <label for="text-input">text</label>
7
+ <input id="text-input" type="text" />
8
+ </div>
9
+ <div class="input-field">
10
+ <label for="character-counter">character counter</label>
11
+ <input id="character-counter" type="text" maxlength="10" />
12
+ </div>
13
+ <div class="input-field">
14
+ <label for="no-type-attribute">no type attribute</label>
15
+ <input id="no-type-attribute" />
16
+ </div>
17
+ <div class="input-field">
18
+ <label for="password-input">password</label>
19
+ <input id="password-input" type="password" />
20
+ </div>
21
+ <div class="input-field">
22
+ <label for="email-input">email</label>
23
+ <input id="email-input" type="email" />
24
+ </div>
25
+ <div class="input-field">
26
+ <label for="url-input">url</label>
27
+ <input id="url-input" type="url" />
28
+ </div>
29
+ <div class="input-field">
30
+ <label for="tel-input">tel</label>
31
+ <input id="tel-input" type="tel" />
32
+ </div>
33
+ <div class="input-field">
34
+ <label for="number-input">number</label>
35
+ <input id="number-input" type="number" />
36
+ </div>
37
+ <div class="input-field">
38
+ <label for="search-input">search</label>
39
+ <input id="search-input" type="search" />
40
+ </div>
41
+ <div class="input-field">
42
+ <label for="date-input">date</label>
43
+ <input id="date-input" type="date" />
44
+ </div>
45
+ <div class="input-field">
46
+ <label for="time-input">time</label>
47
+ <input id="time-input" type="time" />
48
+ </div>
49
+ <div class="input-field">
50
+ <label for="month-input">month</label>
51
+ <input id="month-input" type="month" />
52
+ </div>
53
+ <div class="input-field">
54
+ <label for="datetime-input">datetime</label>
55
+ <input id="datetime-input" type="datetime-local" />
56
+ </div>
57
+ <div class="input-field">
58
+ <textarea id="textarea" class="materialize-textarea"></textarea>
59
+ <label for="textarea">Textarea</label>
60
+ </div>
61
+ `;
62
+
63
+ beforeEach(() => {
64
+ XloadHtml(fixture);
65
+ M.CharacterCounter.init(document.querySelector('#character-counter'));
66
+ const inputs = document.querySelectorAll('input');
67
+ inputs.forEach((input) => {
68
+ //input.dispatchEvent(new Event('focus'));
69
+ focus(input);
70
+ //input.focus();
71
+ //input.blur();
72
+ });
73
+ });
74
+ afterEach(() => XunloadFixtures());
75
+
76
+ describe('CharacterCounter', () => {
77
+ it('Should initialize', () => {
78
+ const el = document.querySelector('#character-counter');
79
+ expect(() => M.CharacterCounter.getInstance(el)).not.toThrow();
80
+ expect(M.CharacterCounter.getInstance(el)).toBeTruthy();
81
+ });
82
+
83
+ it('Should exhibit counter', () => {
84
+ const counter = document.querySelector('#character-counter ~ .character-counter');
85
+ expect(counter.textContent).toBe('0/10');
86
+ });
87
+ });
88
+
89
+ describe('TextArea Resize', () => {
90
+ it('Should resize', () => {
91
+ const el = document.querySelector('#textarea');
92
+ const pHeight = el.clientHeight;
93
+ el.value = `
94
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin eleifend urna orci, vitae sagittis ligula maximus quis. Duis eleifend ipsum vitae facilisis tincidunt. Aliquam condimentum consequat ex, ut commodo purus tristique at. Donec malesuada fringilla libero vel sodales. Nulla finibus volutpat lectus a varius. Praesent consequat ornare pulvinar. Quisque nec massa diam.
95
+ Nunc commodo tempus suscipit. Phasellus iaculis at lorem sit amet venenatis. Curabitur quis felis elementum enim fermentum dapibus. In pretium finibus mollis. Nam aliquet tristique diam sit amet ullamcorper. Suspendisse interdum, est sed aliquam dignissim, dolor augue tristique dui, non luctus felis dolor a dui. Suspendisse lacinia lorem nec enim ultricies maximus. Aenean quam erat, finibus non aliquam nec, pharetra vel metus. Nulla dignissim maximus cursus.
96
+ Integer massa est, semper eget sem quis, bibendum scelerisque odio. Nam sit amet urna auctor, luctus odio in, semper dui. Sed ut gravida libero, ac consectetur sem. Etiam pharetra pulvinar leo, eget imperdiet purus faucibus in. Cras blandit mi ullamcorper nulla viverra posuere. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec pretium euismod tortor a lacinia. Vivamus ultrices vulputate purus et blandit. Fusce mi quam, consequat vitae pretium sed, tempus at ligula.
97
+ Suspendisse sodales et dolor vitae sollicitudin. Curabitur sed vestibulum sapien. Integer porttitor pulvinar ullamcorper. Sed ultrices varius augue, at bibendum magna congue sit amet. Nam enim purus, fermentum sed feugiat viverra, accumsan nec diam. Donec a auctor est. Aenean non ante metus. Pellentesque ante ligula, varius vel dignissim in, euismod vel diam. Donec est ante, rhoncus at eros sed, cursus pulvinar enim. In pellentesque, erat eu egestas tempor, ipsum turpis ornare dui, sed fringilla sem lorem in ligula.
98
+ Integer facilisis arcu eu posuere placerat. Nam vel leo magna. Proin mattis feugiat nisi, quis tincidunt magna pulvinar tincidunt. Aliquam eget nunc sapien. Maecenas vitae orci nunc. Nulla condimentum sapien quis sapien varius suscipit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus non finibus nisl, et venenatis massa.
99
+ `.trim();
100
+ M.Forms.textareaAutoResize(el);
101
+ expect(el.clientHeight).toBeGreaterThan(pHeight);
102
+ });
103
+
104
+ it('Programmatically initialized textarea resize', (done) => {
105
+ const element = document.querySelector('#textarea');
106
+ M.Forms.InitTextarea(element);
107
+ const textareaHeight = element.clientHeight;
108
+ element.value = MULTILINE_TEXT;
109
+ keydown(element, 13);
110
+ setTimeout(() => {
111
+ expect(element.clientHeight).toBeGreaterThan(textareaHeight);
112
+ done();
113
+ }, 10);
114
+ });
115
+
116
+ it('Automatically initialized textarea resize', (done) => {
117
+ const event = new Event('DOMContentLoaded');
118
+ document.dispatchEvent(event);
119
+ const element = document.querySelector('#textarea');
120
+ const textareaHeight = element.clientHeight;
121
+ element.value = MULTILINE_TEXT;
122
+ keydown(element, 13);
123
+ setTimeout(() => {
124
+ expect(element.clientHeight).toBeGreaterThan(textareaHeight);
125
+ done();
126
+ }, 10);
127
+ });
128
+ });
129
+
130
+ // No active class added, because it is now a css feature only
131
+ /*
132
+ it("should keep label active while focusing on input", () => {
133
+ inputs.forEach(input => {
134
+ expect(input.labels[0]).not.toHaveClass('active')
135
+ input.focus()
136
+ expect(input.labels[0]).toHaveClass('active')
137
+ input.blur()
138
+ expect(input.labels[0]).not.toHaveClass('active')
139
+ })
140
+ });
141
+ */
142
+ });