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.
- package/LICENSE +21 -21
- package/README.md +55 -91
- package/components/appbar/_navbar.old.scss +223 -0
- package/components/appbar/appbar.css +235 -0
- package/components/appbar/appbar.mjs +54 -0
- package/components/appbar/appbar.test.mjs +9 -0
- package/components/atomic/atomic.mjs +19 -0
- package/components/atomic/component.mjs +67 -0
- package/components/badge/_badges.scss +75 -0
- package/components/badge/badge.mjs +11 -0
- package/components/breadcrumb/_breadcrumb.scss +27 -0
- package/components/button/_buttons.scss +352 -0
- package/components/button/button.mjs +11 -0
- package/components/button/buttons.stories.ts +150 -0
- package/components/button/buttons.ts +282 -0
- package/components/button/examples.iso.js +18 -0
- package/components/button/fabSpec.js +65 -0
- package/components/button/test-button.mjs +16 -0
- package/components/card/_cards.scss +229 -0
- package/components/card/card.mjs +10 -0
- package/components/card/cards.ts +185 -0
- package/components/card/cardsSpec.js +269 -0
- package/components/carousel/_carousel.scss +93 -0
- package/components/carousel/_slider.scss +119 -0
- package/components/carousel/carousel.ts +693 -0
- package/components/carousel/carouselSpec.js +61 -0
- package/components/carousel/slider.ts +431 -0
- package/components/carousel/sliderSpec.js +99 -0
- package/components/checkbox/_checkboxes.scss +281 -0
- package/components/checkbox/checkbox.mdx +24 -0
- package/components/checkbox/checkbox.stories.ts +120 -0
- package/components/chip/chip.mjs +37 -0
- package/components/chip/chip.test.mjs +10 -0
- package/components/chip/chips.css +126 -0
- package/components/chip/chips.mdx +33 -0
- package/components/chip/chips.ts +440 -0
- package/components/chip/chipsSpec.js +165 -0
- package/components/chip/readme.md +323 -0
- package/components/collapsible/_collapsible.scss +82 -0
- package/components/collapsible/collapsible.ts +230 -0
- package/components/collapsible/collapsibleSpec.js +240 -0
- package/components/datepicker/_datepicker.scss +268 -0
- package/components/datepicker/datepicker.ts +1450 -0
- package/components/datepicker/datepickerSpec.js +162 -0
- package/components/dialog/_materialbox.scss +42 -0
- package/components/dialog/_modal.scss +79 -0
- package/components/dialog/materialbox.ts +446 -0
- package/components/dialog/materialboxSpec.js +37 -0
- package/components/dialog/modal.ts +111 -0
- package/components/dialog/modalSpec.js +83 -0
- package/components/dialog/readme.md +5 -0
- package/components/divider/readme.md +15 -0
- package/components/dropdown/_dropdown.scss +83 -0
- package/components/dropdown/dropdown.ts +653 -0
- package/components/dropdown/dropdownSpec.js +108 -0
- package/components/list/_collection.scss +114 -0
- package/components/list/_list.scss +6 -0
- package/components/list/list.mjs +58 -0
- package/components/list/list.test.mjs +16 -0
- package/components/loading/loading.mjs +26 -0
- package/components/loading/loading.test.mjs +10 -0
- package/components/navigation-bar/_old +582 -0
- package/components/navigation-bar/navigation-bar.mdx +20 -0
- package/components/navigation-bar/navigation-bar.stories.ts +39 -0
- package/components/navigation-drawer/_sidenav.scss +247 -0
- package/components/navigation-drawer/sidenav.ts +546 -0
- package/components/navigation-drawer/sidenavSpec.js +124 -0
- package/components/pagination/_pagination.scss +47 -0
- package/components/progress/_preloader.scss +416 -0
- package/components/radio-button/_radio-buttons.scss +112 -0
- package/components/radio-button/radio-buttons.mdx +28 -0
- package/components/radio-button/radio-buttons.stories.ts +51 -0
- package/components/search/autocomplete.ts +620 -0
- package/components/search/autocompleteSpec.js +321 -0
- package/components/slider/_range.scss +157 -0
- package/components/slider/range.ts +216 -0
- package/components/snackbar/_toast.scss +68 -0
- package/components/snackbar/toastSpec.js +132 -0
- package/components/snackbar/toasts.ts +312 -0
- package/components/switch/_switches.scss +121 -0
- package/components/tabs/_tabs.scss +171 -0
- package/components/tabs/tabs.mjs +31 -0
- package/components/tabs/tabs.ts +358 -0
- package/components/tabs/tabsSpec.js +180 -0
- package/components/textfield/_file-input.scss +41 -0
- package/components/textfield/_input-fields.scss +368 -0
- package/components/textfield/_select.scss +104 -0
- package/components/textfield/formfields.css +311 -0
- package/components/textfield/forms.ts +182 -0
- package/components/textfield/formsSpec.js +142 -0
- package/components/textfield/select.ts +472 -0
- package/components/textfield/selectSpec.js +390 -0
- package/components/textfield/textfield.mjs +29 -0
- package/components/textfield/textfield.test.mjs +10 -0
- package/components/timepicker/_timepicker.scss +362 -0
- package/components/timepicker/timepicker.ts +905 -0
- package/components/tooltip/_tooltip.scss +40 -0
- package/components/tooltip/tooltip.ts +380 -0
- package/components/tooltip/tooltipSpec.js +145 -0
- package/dist/css/materialize.colors.min.css +6 -0
- package/dist/css/materialize.css +7578 -6326
- package/dist/css/materialize.min.css +6 -13
- package/dist/css/materialize.min.css.map +1 -0
- package/dist/js/materialize.cjs.js +8410 -0
- package/dist/js/materialize.d.ts +2625 -0
- package/dist/js/materialize.js +8415 -12374
- package/dist/js/materialize.min.js +6 -6
- package/dist/js/materialize.mjs +8382 -0
- package/package.json +82 -47
- package/sass/_colors.scss +417 -0
- package/sass/_global.scss +490 -0
- package/sass/_grid.scss +172 -0
- package/sass/_table_of_contents.scss +28 -0
- package/sass/_tapTarget.scss +102 -0
- package/sass/_typography.scss +58 -0
- package/sass/_variables.scss +56 -0
- package/sass/materialize.scss +51 -0
- package/sass/mixins.module.scss +168 -0
- package/extras/noUiSlider/nouislider.css +0 -406
- package/extras/noUiSlider/nouislider.js +0 -2147
- package/extras/noUiSlider/nouislider.min.js +0 -1
- package/js/anime.min.js +0 -34
- package/js/autocomplete.js +0 -448
- package/js/buttons.js +0 -354
- package/js/cards.js +0 -40
- package/js/carousel.js +0 -717
- package/js/cash.js +0 -960
- package/js/characterCounter.js +0 -136
- package/js/chips.js +0 -481
- package/js/collapsible.js +0 -275
- package/js/component.js +0 -44
- package/js/datepicker.js +0 -975
- package/js/dropdown.js +0 -635
- package/js/forms.js +0 -275
- package/js/global.js +0 -444
- package/js/materialbox.js +0 -453
- package/js/modal.js +0 -382
- package/js/parallax.js +0 -138
- package/js/pushpin.js +0 -148
- package/js/range.js +0 -263
- package/js/scrollspy.js +0 -295
- package/js/select.js +0 -450
- package/js/sidenav.js +0 -580
- package/js/slider.js +0 -359
- package/js/tabs.js +0 -402
- package/js/tapTarget.js +0 -314
- package/js/timepicker.js +0 -647
- package/js/toasts.js +0 -310
- package/js/tooltip.js +0 -303
- 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
|
+
});
|