material-inspired-component-library 3.0.2 → 4.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 (90) hide show
  1. package/README.md +16 -14
  2. package/components/README.md +1 -1
  3. package/components/accordion/README.md +8 -3
  4. package/components/alert/README.md +76 -0
  5. package/components/alert/index.scss +121 -0
  6. package/components/appbar/README.md +9 -4
  7. package/components/appbar/index.scss +1 -1
  8. package/components/badge/README.md +8 -3
  9. package/components/badge/index.scss +1 -0
  10. package/components/bottomsheet/README.md +8 -3
  11. package/components/button/README.md +8 -3
  12. package/components/button/index.scss +7 -0
  13. package/components/card/README.md +10 -4
  14. package/components/card/index.scss +1 -1
  15. package/components/checkbox/README.md +56 -13
  16. package/components/checkbox/index.scss +148 -183
  17. package/components/checkbox/index.ts +148 -0
  18. package/components/dialog/README.md +8 -3
  19. package/components/dialog/index.scss +1 -0
  20. package/components/divider/README.md +8 -3
  21. package/components/iconbutton/README.md +8 -3
  22. package/components/iconbutton/index.scss +3 -1
  23. package/components/list/README.md +8 -3
  24. package/components/list/index.scss +2 -0
  25. package/components/list/index.ts +2 -3
  26. package/components/menu/README.md +7 -2
  27. package/components/menu/index.ts +2 -2
  28. package/components/navigationrail/README.md +8 -3
  29. package/components/navigationrail/index.scss +1 -0
  30. package/components/radio/README.md +8 -3
  31. package/components/radio/index.scss +8 -24
  32. package/components/select/README.md +3 -3
  33. package/components/sidesheet/README.md +8 -3
  34. package/components/slider/README.md +8 -3
  35. package/components/slider/index.scss +1 -0
  36. package/components/slider/index.ts +9 -10
  37. package/components/stepper/README.md +190 -0
  38. package/components/stepper/index.scss +93 -14
  39. package/components/stepper/index.ts +169 -88
  40. package/components/switch/README.md +8 -3
  41. package/components/switch/index.scss +2 -0
  42. package/components/textfield/README.md +8 -3
  43. package/components/textfield/index.ts +8 -41
  44. package/dist/alert.css +1 -0
  45. package/dist/alert.js +1 -0
  46. package/dist/badge.css +1 -1
  47. package/dist/button.css +1 -1
  48. package/dist/card.css +1 -1
  49. package/dist/checkbox.css +1 -1
  50. package/dist/components/checkbox/index.d.ts +5 -0
  51. package/dist/components/textfield/index.d.ts +0 -1
  52. package/dist/dialog.css +1 -1
  53. package/dist/foundations/form/index.d.ts +5 -0
  54. package/dist/iconbutton.css +1 -1
  55. package/dist/list.css +1 -1
  56. package/dist/micl.css +1 -1
  57. package/dist/micl.js +1 -1
  58. package/dist/navigationrail.css +1 -1
  59. package/dist/radio.css +1 -1
  60. package/dist/slider.css +1 -1
  61. package/dist/stepper.css +1 -1
  62. package/dist/switch.css +1 -1
  63. package/docs/accordion.html +1 -1
  64. package/docs/alert.html +176 -0
  65. package/docs/bottomsheet.html +2 -2
  66. package/docs/button.html +2 -2
  67. package/docs/card.html +7 -7
  68. package/docs/checkbox.html +33 -9
  69. package/docs/dialog.html +2 -2
  70. package/docs/divider.html +8 -8
  71. package/docs/iconbutton.html +2 -2
  72. package/docs/index.html +43 -32
  73. package/docs/list.html +2 -2
  74. package/docs/menu.html +2 -2
  75. package/docs/micl.css +1 -1
  76. package/docs/micl.js +1 -1
  77. package/docs/radio.html +2 -2
  78. package/docs/select.html +2 -2
  79. package/docs/sidesheet.html +2 -2
  80. package/docs/slider.html +2 -2
  81. package/docs/stepper.html +318 -0
  82. package/docs/switch.html +8 -4
  83. package/docs/textfield.html +2 -2
  84. package/foundations/form/index.ts +174 -0
  85. package/{layout → foundations/layout}/README.md +5 -0
  86. package/{layout → foundations/layout}/index.scss +1 -1
  87. package/micl.ts +3 -3
  88. package/package.json +3 -1
  89. package/styles.scss +2 -1
  90. package/webpack.config.js +1 -1
@@ -19,11 +19,15 @@
19
19
  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
20
  // SOFTWARE.
21
21
 
22
- @use '../../layout';
22
+ @use '../../foundations/layout';
23
23
  @use '../../styles/motion';
24
24
 
25
25
  :root {
26
- --md-sys-stepper-thickness: 1px;
26
+ --md-sys-stepper-counter-style: decimal;
27
+ --md-sys-stepper-dot-size: 12px;
28
+ }
29
+ body {
30
+ --md-sys-stepper-dot-done-color: var(--md-sys-color-tertiary-container, blue);
27
31
  }
28
32
 
29
33
  .micl-stepper {
@@ -35,8 +39,38 @@
35
39
  display: flex;
36
40
  flex-direction: column;
37
41
  row-gap: var(--md-sys-layout-padding-xl, 24px);
42
+ margin: 0;
38
43
  background-color: inherit;
39
44
 
45
+ .micl-stepper__header {
46
+ --md-sys-stepper-dot-size: 24px;
47
+
48
+ display: flex;
49
+ justify-content: space-between;
50
+ align-items: flex-start;
51
+ margin-inline: -10px;
52
+ background-color: inherit;
53
+ background-image: linear-gradient(90deg, var(--md-sys-divider-color), var(--md-sys-divider-color));
54
+ background-position: center;
55
+ background-repeat: no-repeat;
56
+ background-size: 100% 1px;
57
+ counter-reset: dotnumber;
58
+
59
+ button {
60
+ background-color: inherit;
61
+ pointer-events: none;
62
+
63
+ &.micl-stepper__progress--done {
64
+ pointer-events: inherit;
65
+ }
66
+ }
67
+ .micl-stepper__progress-dot::before {
68
+ content: counter(dotnumber, var(--md-sys-stepper-counter-style));
69
+ }
70
+ }
71
+ &.micl-stepper--nonlinear .micl-stepper__header button {
72
+ pointer-events: inherit;
73
+ }
40
74
  .micl-stepper__steps {
41
75
  display: grid;
42
76
  grid-template-areas: "stepper-steps";
@@ -48,7 +82,9 @@
48
82
  display: flex;
49
83
  visibility: hidden;
50
84
  flex-direction: column;
51
- justify-content: space-between;
85
+ margin: 0;
86
+ padding: 0;
87
+ border: none;
52
88
  opacity: 0%;
53
89
  background-color: inherit;
54
90
  transform: translateX(100%);
@@ -56,30 +92,73 @@
56
92
  opacity var(--md-sys-stepper-motion-duration) linear,
57
93
  transform var(--md-sys-stepper-motion-duration) var(--md-sys-stepper-motion-spatial);
58
94
 
59
- &:has(~ .micl-stepper__step--current) {
95
+ &:has(~ .micl-stepper__step[aria-current=step]) {
60
96
  transform: translateX(-100%);
61
97
  }
62
- &.micl-stepper__step--tocurrent {
98
+ &.micl-stepper__step--toselected {
63
99
  visibility: visible;
64
100
  }
65
- &.micl-stepper__step--current {
101
+ &[aria-current=step] {
66
102
  visibility: visible;
67
103
  opacity: 100%;
68
104
  transform: translateX(0%);
69
105
  }
70
- &.micl-stepper__step--fromcurrent {
106
+ &.micl-stepper__step--fromselected {
71
107
  visibility: visible;
72
108
  }
73
-
74
- .micl-stepper__content {
75
- box-sizing: border-box;
76
- padding-inline: var(--md-sys-stepper-padding-inline);
77
- background-color: inherit;
78
- }
79
109
  }
80
110
  }
81
111
  .micl-stepper__actions {
82
112
  display: flex;
83
- justify-content: space-between;
113
+ flex-direction: row;
114
+ justify-content: center;
115
+ inline-size: 100%;
116
+ align-items: center;
117
+
118
+ &>:first-child,
119
+ &>:last-child {
120
+ display: flex;
121
+ flex: 1 1 0;
122
+ column-gap: var(--md-sys-layout-padding-xs, 8px)
123
+ }
124
+ &>:last-child {
125
+ justify-content: flex-end;
126
+ }
127
+ }
128
+ .micl-stepper__progress-dots {
129
+ display: flex;
130
+ align-items: center;
131
+ column-gap: 4px;
132
+ }
133
+ .micl-stepper__progress-dot {
134
+ block-size: var(--md-sys-stepper-dot-size);
135
+ inline-size: var(--md-sys-stepper-dot-size);
136
+ min-inline-size: var(--md-sys-stepper-dot-size);
137
+ line-height: var(--md-sys-stepper-dot-size);
138
+ border-radius: calc(var(--md-sys-stepper-dot-size) / 2);
139
+ text-align: center;
140
+ background-color: var(--md-sys-color-on-surface);
141
+ color: var(--md-sys-color-surface);
142
+ opacity: 38%;
143
+ counter-increment: dotnumber 1;
144
+ }
145
+ .micl-stepper__progress--done.micl-stepper__progress-dot,
146
+ .micl-stepper__progress--done .micl-stepper__progress-dot {
147
+ background-color: var(--md-sys-stepper-dot-done-color);
148
+ color: var(--md-sys-color-on-tertiary-container);
149
+ opacity: 100%;
150
+ }
151
+ }
152
+
153
+ [dir=rtl] {
154
+ .micl-stepper .micl-stepper__steps .micl-stepper__step {
155
+ transform: translateX(-100%);
156
+
157
+ &:has(~ .micl-stepper__step[aria-current=step]) {
158
+ transform: translateX(100%);
159
+ }
160
+ &[aria-current=step] {
161
+ transform: translateX(0%);
162
+ }
84
163
  }
85
164
  }
@@ -19,145 +19,226 @@
19
19
  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
20
  // SOFTWARE.
21
21
 
22
+ import form from '../../foundations/form';
23
+
22
24
  export const stepperSelector = '.micl-stepper';
23
25
 
26
+ const ACTIONS_SELECTOR = '.micl-stepper__action-back,.micl-stepper__action-next';
27
+ const BUTTON_SELECTOR = '.micl-stepper__header button[role=tab][aria-controls]';
28
+ const STEP_CLASS = 'micl-stepper__step';
29
+ const STEP_SELECTOR = '.' + STEP_CLASS;
30
+
24
31
  export default (() =>
25
32
  {
26
- const getCurrentStep = (stepper: HTMLElement): HTMLElement | null =>
33
+ const getSelectedStep = (stepper: HTMLElement): HTMLElement | null =>
27
34
  {
28
- let step = stepper.querySelector('.micl-stepper__step--current') as HTMLElement;
35
+ let step = stepper.querySelector(`${STEP_SELECTOR}[aria-current=step]`);
29
36
  if (step) {
30
- return step;
37
+ return step as HTMLElement;
31
38
  }
32
- step = stepper.querySelector('.micl-stepper__step') as HTMLElement;
39
+ return setSelectedStep(stepper, stepper.querySelector(STEP_SELECTOR));
40
+ };
41
+
42
+ const getStepNumber = (stepper: HTMLElement, step: HTMLElement): number =>
43
+ {
44
+ const allSteps = Array.from(stepper.querySelectorAll(STEP_SELECTOR));
45
+ const index = allSteps.indexOf(step);
46
+
47
+ return index + 1;
48
+ };
49
+
50
+ const setSelectedStep = (stepper: HTMLElement, step: HTMLElement | null): HTMLElement | null =>
51
+ {
33
52
  if (!step) {
34
53
  return null;
35
54
  }
36
- step.classList.add('micl-stepper__step--current');
55
+ let index = 0;
56
+ stepper.querySelectorAll(STEP_SELECTOR).forEach((e, i) =>
57
+ {
58
+ e.setAttribute('aria-current', e === step ? 'step' : 'false');
59
+ if (e === step) {
60
+ index = i;
61
+ }
62
+ });
63
+ const button = stepper.querySelectorAll(BUTTON_SELECTOR).item(index);
64
+ stepper.querySelectorAll(BUTTON_SELECTOR).forEach((e, i) =>
65
+ {
66
+ e.setAttribute('aria-selected', e === button ? 'true' : 'false');
67
+ });
68
+ refresh(stepper, step);
69
+
37
70
  return step;
38
71
  };
39
72
 
40
- const endTransitionCurrent = (event: Event): void =>
73
+ const endTransitionSelected = (event: Event): void =>
41
74
  {
42
- if (!event.currentTarget || ((event as TransitionEvent).propertyName !== 'transform')) {
75
+ const target = event.currentTarget as Element;
76
+ if ((event as TransitionEvent).propertyName !== 'transform' || !target) {
43
77
  return;
44
78
  }
45
- (event.currentTarget as Element).classList.remove(
46
- 'micl-stepper__step--fromcurrent',
47
- 'micl-stepper__step--tocurrent'
79
+ target.classList.remove(
80
+ 'micl-stepper__step--fromselected',
81
+ 'micl-stepper__step--toselected'
48
82
  );
49
- event.currentTarget.removeEventListener('transitionend', endTransitionCurrent);
83
+ target.removeEventListener('transitionend', endTransitionSelected);
50
84
  };
51
85
 
52
- const showHideActions = (actions: HTMLElement[], step: HTMLElement | null): void =>
86
+ const goToSibling = (stepper: HTMLElement, selectedStep: HTMLElement, sibling: HTMLElement): void =>
87
+ {
88
+ selectedStep.addEventListener('transitionend', endTransitionSelected);
89
+ selectedStep.classList.add('micl-stepper__step--fromselected');
90
+ selectedStep.offsetHeight;
91
+
92
+ sibling.addEventListener('transitionend', endTransitionSelected);
93
+ sibling.classList.add('micl-stepper__step--toselected');
94
+ sibling.offsetHeight;
95
+
96
+ setSelectedStep(stepper, sibling);
97
+ };
98
+
99
+ const isBackAction = (action: HTMLElement): boolean =>
100
+ action.classList.contains('micl-stepper__action-back');
101
+
102
+ const showHideActions = (stepper: HTMLElement, step: HTMLElement): void =>
53
103
  {
54
- step && actions.forEach(action =>
104
+ Array.from(stepper.querySelectorAll<HTMLElement>(ACTIONS_SELECTOR)).forEach(action =>
55
105
  {
56
- action.classList.toggle('micl-hidden', !step[
57
- action.classList.contains('micl-stepper--gonext') ?
58
- 'nextElementSibling' : 'previousElementSibling'
59
- ]?.classList.contains('micl-stepper__step'));
106
+ const siblingKey = isBackAction(action) ? 'previousElementSibling' : 'nextElementSibling';
107
+ const hasSibling = (step[siblingKey] as Element)?.classList.contains(STEP_CLASS);
108
+
109
+ action.classList.toggle('micl-hidden', !hasSibling);
60
110
  });
61
111
  };
62
112
 
63
113
  const showHideElements = (stepper: HTMLElement, step: HTMLElement): void =>
64
114
  {
115
+ const selectedStep = getStepNumber(stepper, step);
116
+
65
117
  stepper.querySelectorAll<HTMLElement>('[data-step]').forEach(element =>
66
118
  {
67
- element.classList.toggle('micl-hidden', element.dataset.step !== step.dataset.miclstep);
119
+ const shouldHide = element.dataset.step != `${selectedStep}`;
120
+ element.classList.toggle('micl-hidden', shouldHide);
68
121
  });
69
122
  };
70
123
 
71
- const checkStepValidity = (stepper: HTMLElement): HTMLElement | null =>
124
+ const updateProgress = (stepper: HTMLElement, step: HTMLElement): void =>
72
125
  {
73
- let currentStep = getCurrentStep(stepper);
74
- if (currentStep) {
75
- currentStep.querySelectorAll<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>(
76
- 'input:required,select:required,textarea:required'
77
- ).forEach(input =>
78
- {
79
- if (!input.checkValidity()) {
80
- currentStep = null;
81
- }
82
- });
126
+ const index = getStepNumber(stepper, step);
127
+ const totalSteps = stepper.querySelectorAll(STEP_SELECTOR).length;
128
+ const linear = !stepper.classList.contains('micl-stepper--nonlinear');
129
+ const setText = (selector: string, content: string): void => {
130
+ stepper.querySelectorAll(selector).forEach(e => { e.textContent = content; });
131
+ };
83
132
 
84
- currentStep?.querySelectorAll<HTMLFieldSetElement>(
85
- 'fieldset.micl-checkbox-group[data-miclname]'
86
- ).forEach(fieldset =>
87
- {
88
- let nrChecked = 0;
89
- fieldset.querySelectorAll<HTMLInputElement>(
90
- `.micl-checkbox[name="${fieldset.dataset.miclname}"]`
91
- ).forEach(checkbox =>
92
- {
93
- if (checkbox.checked) {
94
- nrChecked++;
95
- }
96
- });
97
- if (nrChecked === 0) {
98
- console.log("NOT ENGOUGH CHECKS");
133
+ setText('.micl-stepper__progress-current', `${index}`);
134
+ setText('.micl-stepper__progress-total', `${totalSteps}`);
135
+
136
+ stepper.querySelectorAll('.micl-stepper__progress-dots').forEach(dots =>
137
+ {
138
+ const fragment = document.createDocumentFragment();
139
+
140
+ dots.innerHTML = '';
141
+ for (let i = 1; i <= totalSteps; i++) {
142
+ let dot = document.createElement('span');
143
+ dot.classList.add('micl-stepper__progress-dot');
144
+ if ((linear && (i <= index)) || (!linear && (i === index))) {
145
+ dot.classList.add('micl-stepper__progress--done');
99
146
  }
100
- });
101
- }
102
- return currentStep;
147
+ fragment.appendChild(dot);
148
+ }
149
+ dots.appendChild(fragment);
150
+ });
151
+ stepper.querySelectorAll(BUTTON_SELECTOR).forEach((button, i) =>
152
+ {
153
+ button.classList.toggle(
154
+ 'micl-stepper__progress--done',
155
+ linear ? i + 1 <= index : i + 1 === index
156
+ );
157
+ });
158
+ };
159
+
160
+ const refresh = (stepper: HTMLElement, step: HTMLElement): void =>
161
+ {
162
+ showHideActions(stepper, step);
163
+ showHideElements(stepper, step);
164
+ updateProgress(stepper, step);
103
165
  };
104
166
 
105
167
  return {
106
168
  initialize: (stepper: HTMLElement): void =>
107
169
  {
108
- if (
109
- !stepper.matches(stepperSelector)
110
- || stepper.dataset.miclinitialized
111
- ) {
170
+ if (!stepper.matches(stepperSelector) || stepper.dataset.miclinitialized) {
112
171
  return;
113
172
  }
114
173
  stepper.dataset.miclinitialized = '1';
115
174
 
116
- stepper.querySelectorAll<HTMLElement>('.micl-stepper__step').forEach((step, index) =>
117
- {
118
- step.dataset.miclstep = `${index + 1}`;
119
- });
175
+ const step = getSelectedStep(stepper);
176
+ const header = stepper.querySelector('.micl-stepper__header');
120
177
 
121
- const
122
- step = getCurrentStep(stepper),
123
- actions = stepper.querySelectorAll<HTMLButtonElement>(
124
- 'button.micl-stepper--goback,button.micl-stepper--gonext'
125
- );
126
- showHideActions([...actions], step);
127
- step && showHideElements(stepper, step);
178
+ if (step) {
179
+ refresh(stepper, step);
128
180
 
129
- actions.forEach(action =>
181
+ header?.querySelectorAll<HTMLButtonElement>(
182
+ 'button[role=tab][aria-controls]'
183
+ ).forEach(button =>
184
+ {
185
+ button.addEventListener('click', () =>
186
+ {
187
+ if (
188
+ ('ariaControlsElements' in Element.prototype)
189
+ && button.ariaControlsElements
190
+ ) {
191
+ setSelectedStep(stepper, button.ariaControlsElements[0] as HTMLElement);
192
+ }
193
+ else {
194
+ const id = button.getAttribute('aria-controls');
195
+ if (id) {
196
+ setSelectedStep(stepper, document.getElementById(id));
197
+ }
198
+ }
199
+ });
200
+ });
201
+ }
202
+
203
+ Array.from(stepper.querySelectorAll<HTMLElement>(ACTIONS_SELECTOR)).forEach(action =>
130
204
  {
131
- action.addEventListener('click', () =>
205
+ action.addEventListener('click', function(event: Event)
132
206
  {
133
- const currentStep = checkStepValidity(stepper);
134
- if (!currentStep) {
207
+ const back = isBackAction(this);
208
+ const selectedStep = getSelectedStep(stepper);
209
+
210
+ if (
211
+ !selectedStep
212
+ || (!back
213
+ && selectedStep instanceof HTMLFieldSetElement
214
+ && !form.validateFieldSet(selectedStep, true))
215
+ ) {
216
+ if (!back) {
217
+ event.stopImmediatePropagation();
218
+ }
135
219
  return;
136
220
  }
137
- const
138
- goNext = action.classList.contains('micl-stepper--gonext'),
139
- sibling = currentStep[
140
- goNext ? 'nextElementSibling' : 'previousElementSibling'
141
- ] as HTMLElement;
142
-
143
- if (sibling?.classList.contains('micl-stepper__step')) {
144
- currentStep.addEventListener('transitionend', endTransitionCurrent);
145
- currentStep.classList.add('micl-stepper__step--fromcurrent');
146
- currentStep.offsetHeight;
147
-
148
- sibling.addEventListener('transitionend', endTransitionCurrent);
149
- sibling.classList.add('micl-stepper__step--tocurrent');
150
- sibling.offsetHeight;
151
-
152
- sibling.classList.add('micl-stepper__step--current');
153
- currentStep.classList.remove('micl-stepper__step--current');
154
- currentStep.offsetHeight;
155
-
156
- showHideActions([...actions], sibling);
157
- showHideElements(stepper, sibling);
221
+ const sibling = selectedStep[
222
+ back ? 'previousElementSibling' : 'nextElementSibling'
223
+ ] as HTMLElement;
224
+
225
+ if (sibling?.classList.contains(STEP_CLASS)) {
226
+ goToSibling(stepper, selectedStep, sibling);
158
227
  }
159
- });
228
+ }, true);
160
229
  });
230
+
231
+ if (stepper instanceof HTMLFormElement) {
232
+ stepper.addEventListener('submit', (event: SubmitEvent) =>
233
+ {
234
+ if (!event.submitter?.classList.contains('micl-form--dosubmit')) {
235
+ event.preventDefault();
236
+ }
237
+ if (!form.validateForm(stepper, true)) {
238
+ event.stopImmediatePropagation();
239
+ }
240
+ }, true);
241
+ }
161
242
  }
162
243
  };
163
244
  })();
@@ -1,5 +1,5 @@
1
1
  # Switch
2
- This component implements the the [Material Design 3 Expressive Switch](https://m3.material.io/components/switch/overview) design. Switches toggle the state of a single setting on or off.
2
+ This component implements the [Material Design 3 Expressive Switch](https://m3.material.io/components/switch/overview) design. Switches toggle the state of a single setting on or off.
3
3
 
4
4
  ## Basic Usage
5
5
 
@@ -18,11 +18,16 @@ Import the switch styles into your project:
18
18
  @use "material-inspired-component-library/dist/switch";
19
19
  ```
20
20
 
21
+ Or import all MICL styles:
22
+ ```CSS
23
+ @use "material-inspired-component-library/styles";
24
+ ```
25
+
21
26
  ### JavaScript
22
27
  No custom JavaScript is required for the core functionality of this component.
23
28
 
24
- ### Demo
25
- A live example of the [Switch component](https://henkpb.github.io/micl/switch.html) is available for you to interact with.
29
+ ### Live Demo
30
+ A live example of the [Switch component](https://henkpb.github.io/micl/switch.html) is available to interact with.
26
31
 
27
32
  ## Variants
28
33
  By default, the component displays an icon on the switch handle in both the selected and unselected state. To remove the icon in the unselected state, assign an empty string to the following CSS variable:
@@ -48,6 +48,7 @@ input[type=checkbox].micl-switch {
48
48
  margin: 0;
49
49
  border-radius: calc(var(--md-sys-switch-target-height) / 2);
50
50
  outline: none;
51
+ -webkit-tap-highlight-color: transparent;
51
52
 
52
53
  &::before {
53
54
  content: "";
@@ -172,6 +173,7 @@ input[type=checkbox].micl-switch {
172
173
 
173
174
  input[type=checkbox].micl-switch:not(:disabled) + label,
174
175
  label:has(+ input[type=checkbox].micl-switch:not(:disabled)) {
176
+ -webkit-tap-highlight-color: transparent;
175
177
  cursor: pointer;
176
178
  }
177
179
  input[type=checkbox].micl-switch + label,
@@ -1,5 +1,5 @@
1
1
  # Text field
2
- This component implements the the [Material Design 3 Expressive Text field](https://m3.material.io/components/text-fields/overview) design.
2
+ This component implements the [Material Design 3 Expressive Text field](https://m3.material.io/components/text-fields/overview) design.
3
3
 
4
4
  ## Basic Usage
5
5
 
@@ -20,6 +20,11 @@ Import the text field styles into your project:
20
20
  @use "material-inspired-component-library/dist/textfield";
21
21
  ```
22
22
 
23
+ Or import all MICL styles:
24
+ ```CSS
25
+ @use "material-inspired-component-library/styles";
26
+ ```
27
+
23
28
  ### JavaScript
24
29
  This component requires JavaScript for interactive features like the **character counter**:
25
30
 
@@ -29,8 +34,8 @@ import micl from "material-inspired-component-library/dist/micl";
29
34
 
30
35
  This will initialize any Text field component, including those that will be added to the DOM later on.
31
36
 
32
- ### Demo
33
- A live example of the [Text field component](https://henkpb.github.io/micl/textfield.html) is available for you to interact with.
37
+ ### Live Demo
38
+ A live example of the [Text field component](https://henkpb.github.io/micl/textfield.html) is available to interact with.
34
39
 
35
40
  ## Variants
36
41
  The following example shows a text field with every available feature. You can include any combination of these elements. The order of elements inside the `<div>` does not change the layout.
@@ -25,14 +25,9 @@ export const selectSelector = '.micl-textfield-filled > select,.micl-textfield-o
25
25
 
26
26
  export default (() =>
27
27
  {
28
- const isRequiredType = (
29
- eventTarget: EventTarget | null
30
- ): eventTarget is HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement =>
31
- {
32
- return eventTarget instanceof HTMLInputElement ||
33
- eventTarget instanceof HTMLSelectElement ||
34
- eventTarget instanceof HTMLTextAreaElement;
35
- };
28
+ const isTextFieldElement = (target: EventTarget | null): target is
29
+ HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement =>
30
+ (target as Element).matches(`${textfieldSelector},${selectSelector},${textareaSelector}`);
36
31
 
37
32
  const setCounter = (input: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement): void =>
38
33
  {
@@ -49,26 +44,6 @@ export default (() =>
49
44
  }
50
45
  };
51
46
 
52
- const handleInvalid = (
53
- input: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement,
54
- isValid?: boolean
55
- ): void => {
56
- if (input.required) {
57
- input.parentElement?.classList.toggle('micl-textfield--error', !isValid);
58
-
59
- const supporting = input.parentElement?.querySelector(
60
- '.micl-textfield__supporting-text'
61
- ) as HTMLElement;
62
-
63
- if (supporting) {
64
- if (!isValid && !('micltext' in supporting.dataset)) {
65
- supporting.dataset.micltext = supporting.textContent;
66
- }
67
- supporting.textContent = input.validationMessage || supporting.dataset.micltext || '';
68
- }
69
- }
70
- };
71
-
72
47
  return {
73
48
  initialize: (input: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement): void =>
74
49
  {
@@ -84,14 +59,13 @@ export default (() =>
84
59
  if (input instanceof HTMLSelectElement) {
85
60
  input.addEventListener('mousedown', () =>
86
61
  {
87
- const
88
- rect = input.getBoundingClientRect(),
89
- roomAbove = rect.top,
90
- roomBelow = window.innerHeight - rect.bottom;
62
+ const rect = input.getBoundingClientRect();
63
+ const spaceAbove = rect.top;
64
+ const spaceBelow = window.innerHeight - rect.bottom;
91
65
 
92
66
  !input.matches(':open') && input.style.setProperty(
93
67
  '--md-sys-select-picker-origin',
94
- roomAbove > roomBelow ? 'left bottom' : 'left top'
68
+ spaceAbove > spaceBelow ? 'left bottom' : 'left top'
95
69
  );
96
70
  });
97
71
  }
@@ -102,8 +76,7 @@ export default (() =>
102
76
  input: (event: Event): void =>
103
77
  {
104
78
  if (
105
- !isRequiredType(event.target)
106
- || !event.target.matches(`${textfieldSelector},${selectSelector},${textareaSelector}`)
79
+ !isTextFieldElement(event.target)
107
80
  || !event.target.dataset.miclinitialized
108
81
  || event.target.disabled
109
82
  ) {
@@ -117,13 +90,7 @@ export default (() =>
117
90
  delete event.target.dataset.miclvalue;
118
91
  }
119
92
 
120
- handleInvalid(event.target, true);
121
93
  setCounter(event.target);
122
- },
123
-
124
- invalid: (event: Event): void =>
125
- {
126
- isRequiredType(event.target) && handleInvalid(event.target);
127
94
  }
128
95
  };
129
96
  })();