material-inspired-component-library 3.0.0 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -56,5 +56,14 @@ You can customize the appearance of the Checkbox component by overriding its glo
56
56
  </div>
57
57
  ```
58
58
 
59
+ To vertically align a checkbox with its label, wrap both in an element that has the `micl-flex--vcenter` class.
60
+
61
+ ```HTML
62
+ <div class="micl-flex--vcenter">
63
+ <input type="checkbox" id="mycheckbox" class="micl-checkbox">
64
+ <label for="mycheckbox">Checkbox</label>
65
+ </div>
66
+ ```
67
+
59
68
  ## Compatibility
60
69
  This component utilizes relative RGB color values, which may not be fully supported in your browser. Please check [Browser compatibility](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value#browser_compatibility) for details.
@@ -31,44 +31,44 @@ body {
31
31
  .micl-divider {
32
32
  width: 100%;
33
33
  height: 0;
34
- margin-block: var(--md-sys-divider-space);
34
+ margin-block: calc(var(--md-sys-divider-space, 4px) - 1px) var(--md-sys-divider-space, 4px);
35
35
  margin-inline: 0;
36
36
  border: 0;
37
- border-block-start: var(--md-sys-divider-thickness) solid var(--md-sys-divider-color);
37
+ border-block-start: var(--md-sys-divider-thickness, 1px) solid var(--md-sys-divider-color);
38
38
  }
39
39
 
40
40
  .micl-divider-inset {
41
41
  width: calc(100% - 2 * var(--md-sys-divider-inset-margin));
42
42
  height: 0;
43
- margin-block: var(--md-sys-divider-space);
43
+ margin-block: calc(var(--md-sys-divider-space, 4px) - 1px) var(--md-sys-divider-space, 4px);
44
44
  margin-inline: var(--md-sys-divider-inset-margin);
45
45
  border: 0;
46
- border-block-start: var(--md-sys-divider-thickness) solid var(--md-sys-divider-color);
46
+ border-block-start: var(--md-sys-divider-thickness, 1px) solid var(--md-sys-divider-color);
47
47
  }
48
48
 
49
49
  .micl-divider-inset--start {
50
50
  width: calc(100% - var(--md-sys-divider-inset-margin));
51
51
  height: 0;
52
- margin-block: var(--md-sys-divider-space);
52
+ margin-block: calc(var(--md-sys-divider-space, 4px) - 1px) var(--md-sys-divider-space, 4px);
53
53
  margin-inline: var(--md-sys-divider-inset-margin) 0;
54
54
  border: 0;
55
- border-block-start: var(--md-sys-divider-thickness) solid var(--md-sys-divider-color);
55
+ border-block-start: var(--md-sys-divider-thickness, 1px) solid var(--md-sys-divider-color);
56
56
  }
57
57
 
58
58
  .micl-divider-inset--end {
59
59
  width: calc(100% - var(--md-sys-divider-inset-margin));
60
60
  height: 0;
61
- margin-block: var(--md-sys-divider-space);
61
+ margin-block: calc(var(--md-sys-divider-space, 4px) - 1px) var(--md-sys-divider-space, 4px);
62
62
  margin-inline: 0 var(--md-sys-divider-inset-margin);
63
63
  border: 0;
64
- border-block-start: var(--md-sys-divider-thickness) solid var(--md-sys-divider-color);
64
+ border-block-start: var(--md-sys-divider-thickness, 1px) solid var(--md-sys-divider-color);
65
65
  }
66
66
 
67
67
  .micl-divider-vertical {
68
68
  min-height: 100%;
69
69
  width: 0;
70
70
  margin-block: 0;
71
- margin-inline: calc(2 * var(--md-sys-divider-space));
71
+ margin-inline: calc(2 * var(--md-sys-divider-space, 4px));
72
72
  border: 0;
73
- border-inline-start: var(--md-sys-divider-thickness) solid var(--md-sys-divider-color);
73
+ border-inline-start: var(--md-sys-divider-thickness, 1px) solid var(--md-sys-divider-color);
74
74
  }
@@ -156,19 +156,19 @@ To enable selection of list items, integrate a checkbox or switch component with
156
156
  <li class="micl-list-item-two" tabindex="0">
157
157
  <label>
158
158
  <span class="micl-list-item__text">
159
- <span class="micl-list-item__headline">Blue car</span>
159
+ <span id="hd1" class="micl-list-item__headline">Blue car</span>
160
160
  <span class="micl-list-item__supporting-text">A blue car with four wheels.</span>
161
161
  </label>
162
- <input type="checkbox" id="mycheckbox" class="micl-checkbox" value="cb1" tabindex="-1">
162
+ <input type="checkbox" id="mycheckbox" class="micl-checkbox" value="cb1" tabindex="-1" aria-labelledby="hd1">
163
163
  </span>
164
164
  </li>
165
165
  <li class="micl-list-item-two" tabindex="0">
166
166
  <label>
167
167
  <span class="micl-list-item__text">
168
- <span class="micl-list-item__headline">Red car</span>
168
+ <span id="hd2" class="micl-list-item__headline">Red car</span>
169
169
  <span class="micl-list-item__supporting-text">A red car with tinted windows.</span>
170
170
  </label>
171
- <input type="checkbox" id="checkbox2" class="micl-switch" value="cb2" tabindex="-1">
171
+ <input type="checkbox" id="checkbox2" class="micl-switch" value="cb2" tabindex="-1" aria-labelledby="hd2">
172
172
  </label>
173
173
  </li>
174
174
  </ul>
@@ -104,7 +104,7 @@
104
104
  column-gap: var(--md-sys-list-item-space);
105
105
  padding-inline: var(--md-sys-list-item-space);
106
106
  border: none;
107
- border-radius: var(--md-sys-shape-corner-none);
107
+ border-radius: var(--md-sys-shape-corner-none, 0px);
108
108
  background-color: var(--md-sys-list-item-container-color);
109
109
  background-image:
110
110
  radial-gradient(circle at var(--micl-x, center) var(--micl-y, center), transparent 0%, rgb(from var(--statelayer-color) r g b / var(--statelayer-opacity)) 10%, transparent 10%),
@@ -330,7 +330,7 @@
330
330
  display: inline-block;
331
331
  height: 56px;
332
332
  min-width: 56px;
333
- border-radius: var(--md-sys-shape-corner-none);
333
+ border-radius: var(--md-sys-shape-corner-none, 0px);
334
334
  background-position: center;
335
335
  background-repeat: no-repeat;
336
336
  background-size: cover;
@@ -339,7 +339,7 @@
339
339
  display: inline-block;
340
340
  height: 64px;
341
341
  min-width: calc(64px * var(--md-sys-list-item-thumbnail-aspect-ratio));
342
- border-radius: var(--md-sys-shape-corner-none);
342
+ border-radius: var(--md-sys-shape-corner-none, 0px);
343
343
  background-position: center;
344
344
  background-repeat: no-repeat;
345
345
  background-size: contain;
@@ -1,5 +1,5 @@
1
1
  # Radio button
2
- This component implements the the [Material Design 3 Expressive Radio button](https://m3.material.io/components/radio-button/overview) design.
2
+ This component implements the the [Material Design 3 Expressive Radio button](https://m3.material.io/components/radio-button/overview) design. A radio button allows a user to select only one option from a group of mutually exclusive choices.
3
3
 
4
4
  ## Basic Usage
5
5
 
@@ -29,7 +29,7 @@ A radio button can be disabled by adding the `disabled` attribute to the `<input
29
29
 
30
30
  The Radio Button component respects the `dir` global attribute, automatically adjusting its layout for right-to-left (RTL) languages when `dir="rtl"` is applied to an ancestor element.
31
31
 
32
- By default, the component applies a specific color and `cursor: pointer` to `<label>` elements immediately preceding or following an `<input type="radio">` with the `micl-radio` class. You are encouraged to customize these CSS settings to match your design system.
32
+ By default, the component applies `cursor: pointer` and the color role **on surface** to the `<label>` element immediately preceding or following an `<input type="radio">` with the `micl-radio` class. You are encouraged to customize these CSS settings to match your design system.
33
33
 
34
34
  ## Customizations
35
35
  You can customize the appearance of the Radio Button component by overriding its global CSS variables. These variables are declared on the `:root` pseudo-class and can be changed on any appropriate parent element to affect its child radio buttons.
@@ -44,8 +44,17 @@ You can customize the appearance of the Radio Button component by overriding its
44
44
 
45
45
  ```HTML
46
46
  <div style="--md-sys-radio-container-size:28px">
47
- <input type="radio" id="myradio" class="micl-radio">
48
- <label for="myradio">Large radio button</label>
47
+ <input type="radio" id="myradio" class="micl-radio">
48
+ <label for="myradio">Large radio button</label>
49
+ </div>
50
+ ```
51
+
52
+ To vertically align a radio button with its label, wrap both in an element that has the `micl-flex--vcenter` class.
53
+
54
+ ```HTML
55
+ <div class="micl-flex--vcenter">
56
+ <input type="radio" id="myradio" class="micl-radio">
57
+ <label for="myradio">Large radio button</label>
49
58
  </div>
50
59
  ```
51
60
 
@@ -37,8 +37,10 @@ input[type=radio].micl-radio {
37
37
  appearance: none;
38
38
  box-sizing: border-box;
39
39
  position: relative;
40
- width: var(--md-sys-target-size);
41
- height: var(--md-sys-target-size);
40
+ inline-size: var(--md-sys-target-size);
41
+ min-inline-size: var(--md-sys-target-size);
42
+ block-size: var(--md-sys-target-size);
43
+ min-block-size: var(--md-sys-target-size);
42
44
  margin: 0;
43
45
  border: calc((var(--md-sys-target-size) - var(--md-sys-radio-state-layer-size)) / 2) solid transparent;
44
46
  background-clip: content-box;
@@ -50,8 +52,8 @@ input[type=radio].micl-radio {
50
52
  content: "";
51
53
  box-sizing: border-box;
52
54
  position: absolute;
53
- width: var(--md-sys-radio-container-size);
54
- height: var(--md-sys-radio-container-size);
55
+ inline-size: var(--md-sys-radio-container-size);
56
+ block-size: var(--md-sys-radio-container-size);
55
57
  inset: 0;
56
58
  margin: auto;
57
59
  padding: calc((var(--md-sys-radio-container-size) / 2) - var(--md-sys-radio-border-width));
@@ -1,5 +1,5 @@
1
1
  # Select
2
- This component implements the the [Material Design 3 Expressive Select](https://m3.material.io/components/menus/guidelines#ee2f3664-c926-47ab-acbf-2ab675506932) design.
2
+ This component implements the the [Material Design 3 Expressive Select](https://m3.material.io/components/menus/guidelines#ee2f3664-c926-47ab-acbf-2ab675506932) design. A select component is used to offer the user with a set of options from which the user can select a single one.
3
3
 
4
4
  ## Basic Usage
5
5
 
@@ -11,10 +11,10 @@ The Select component is an extension of the [Text field](../textfield/README.md)
11
11
  <label for="myselect">Country</label>
12
12
  <select id="myselect">
13
13
  <option class="micl-list-item-one" value="AR">
14
- <span class="micl-list-item__text">Argentina</span>
14
+ <span class="micl-list-item__text">Argentina</span>
15
15
  </option>
16
16
  <option class="micl-list-item-one" value="BO">
17
- <span class="micl-list-item__text">Bolivia</span>
17
+ <span class="micl-list-item__text">Bolivia</span>
18
18
  </option>
19
19
  </select>
20
20
  </div>
@@ -42,7 +42,29 @@ This will initialize any Select component, including those that will be added to
42
42
  A live example of the [Select component](https://henkpb.github.io/micl/select.html) is available for you to interact with.
43
43
 
44
44
  ## Variants
45
- To display extra information for an option, add the `aria-description` attribute to the `<option>` element. In a two-line list item (`micl-list-item-two`), this displays the attribute's content as supporting text. Do not add a separate text element to the `<option>`, as this will change the text of the selected option.
45
+ A Select Component can be disabled by adding the `disabled` attribute to the `<select>` element. An option within the component can be disabled by adding the `disabled` attribute to the `<option>` element.
46
+
47
+ You can add [Dividers](../divider/README.md) into the list of options and they will appear as separators to help visually break up the options.
48
+
49
+ **Example: A select with a divider**
50
+
51
+ ```HTML
52
+ <div class="micl-textfield-outlined">
53
+ <label for="myselect">Country</label>
54
+ <select id="myselect">
55
+ <option class="micl-list-item-two" value=""></option>
56
+ <option class="micl-list-item-two" value="AR">
57
+ <span class="micl-list-item__text">Argentina</span>
58
+ </option>
59
+ <hr class="micl-divider">
60
+ <option class="micl-list-item-two" value="BO">
61
+ <span class="micl-list-item__text">Bolivia</span>
62
+ </option>
63
+ </select>
64
+ </div>
65
+ ```
66
+
67
+ To display extra information for an option, add the `aria-description` attribute to its `<span class="micl-list-item__text">` element. In a two-line list item (`micl-list-item-two`), this displays the attribute's content as supporting text. Do not add a separate text element to the `<option>`, as this will change the text of the selected option.
46
68
 
47
69
  **Example: A select with supporting text**
48
70
 
@@ -51,10 +73,10 @@ To display extra information for an option, add the `aria-description` attribute
51
73
  <label for="myselect">Country</label>
52
74
  <select id="myselect">
53
75
  <option class="micl-list-item-two" value="AR">
54
- <span class="micl-list-item__text" aria-description="Country code: AR">Argentina</span>
76
+ <span class="micl-list-item__text" aria-description="Country code: AR">Argentina</span>
55
77
  </option>
56
78
  <option class="micl-list-item-two" value="BO">
57
- <span class="micl-list-item__text" aria-description="Country code: BO">Bolivia</span>
79
+ <span class="micl-list-item__text" aria-description="Country code: BO">Bolivia</span>
58
80
  </option>
59
81
  </select>
60
82
  </div>
@@ -25,15 +25,28 @@
25
25
  @use '../../styles/statelayer';
26
26
  @use '../../styles/typography';
27
27
 
28
+ .micl-textfield-filled > select {
29
+ --md-sys-select-line-height: calc(var(--md-sys-textfield-height) - 18px - 3px);
30
+ }
31
+ .micl-textfield-outlined > select {
32
+ --md-sys-select-line-height: var(--md-sys-textfield-height);
33
+ }
28
34
  .micl-textfield-filled > select,
29
35
  .micl-textfield-outlined > select {
36
+ --md-sys-divider-space: 8px;
30
37
  --md-sys-list-motion-duration: #{motion.$md-sys-motion-expressive-default-effects-duration};
38
+ --md-sys-select-motion-spatial: #{motion.$md-sys-motion-expressive-default-spatial};
39
+ --md-sys-select-motion-duration: #{motion.$md-sys-motion-expressive-default-spatial-duration};
40
+ --md-sys-select-motion-duration-reverse: #{motion.$md-sys-motion-expressive-fast-spatial-duration};
41
+ --md-sys-select-picker-origin: left top;
31
42
 
32
43
  appearance: base-select;
44
+ line-height: var(--md-sys-select-line-height);
33
45
 
34
46
  &::picker-icon {
35
47
  color: var(--md-sys-color-on-surface-variant);
36
- transition: 0.4s rotate;
48
+ transition: motion.$md-sys-motion-duration-medium4 rotate;
49
+ transform-origin: 50% calc((var(--md-sys-select-line-height) / 2) - 1px);
37
50
  }
38
51
  &:open::picker-icon {
39
52
  rotate: 180deg;
@@ -42,12 +55,36 @@
42
55
  appearance: base-select;
43
56
  min-inline-size: max(anchor-size(self-inline), 112px);
44
57
  max-inline-size: 280px;
45
- padding-block: 8px;
46
- padding-inline: 0;
58
+ position-try: most-block-size flip-block;
59
+ padding: 8px 0;
47
60
  border: none;
48
61
  border-radius: var(--md-sys-shape-corner-extra-small);
49
62
  background-color: var(--md-sys-color-surface-container);
50
63
  box-shadow: var(--md-sys-elevation-level2);
64
+ opacity: 0;
65
+ overflow: hidden;
66
+ transform: scaleY(0);
67
+ transform-origin: var(--md-sys-select-picker-origin);
68
+ transition:
69
+ opacity var(--md-sys-select-motion-duration-reverse) linear,
70
+ transform var(--md-sys-select-motion-duration-reverse) var(--md-sys-select-motion-spatial),
71
+ overlay var(--md-sys-select-motion-duration-reverse) linear allow-discrete,
72
+ display var(--md-sys-select-motion-duration-reverse) linear allow-discrete;
73
+
74
+ &:popover-open {
75
+ opacity: 1;
76
+ transform: scaleY(1);
77
+ transition:
78
+ opacity var(--md-sys-select-motion-duration) motion.$md-sys-motion-easing-emphasized-decelerate,
79
+ transform var(--md-sys-select-motion-duration) var(--md-sys-select-motion-spatial),
80
+ overlay var(--md-sys-select-motion-duration) linear allow-discrete,
81
+ display var(--md-sys-select-motion-duration) linear allow-discrete;
82
+
83
+ @starting-style {
84
+ opacity: 0;
85
+ transform: scaleY(0);
86
+ }
87
+ }
51
88
  }
52
89
 
53
90
  option {
@@ -59,7 +96,8 @@
59
96
  --md-sys-list-item-padding-inline: 16px;
60
97
  --md-sys-list-item-container-color: var(--md-sys-color-surface-container);
61
98
 
62
- border-radius: 0px;
99
+ line-height: normal;
100
+ background-color: transparent;
63
101
 
64
102
  &:not(:disabled) {
65
103
  cursor: pointer;
@@ -84,6 +122,7 @@
84
122
  @include typography.body-large;
85
123
 
86
124
  color: var(--md-sys-color-on-surface);
125
+ white-space: normal;
87
126
  }
88
127
  .micl-list-item__text::after {
89
128
  @include typography.body-medium;
@@ -94,7 +133,7 @@
94
133
  white-space: normal;
95
134
  }
96
135
  &::checkmark {
97
- color: var(--md-sys-color-on-surface);
136
+ color: var(--md-sys-color-on-surface-variant);
98
137
  }
99
138
  }
100
139
  }
@@ -107,10 +146,17 @@ dialog.micl-dialog-fullscreen:has(.micl-textfield-outlined > select) {
107
146
  inset-inline-start: 0;
108
147
  margin: auto;
109
148
  transform: scale(50%);
149
+
150
+ &:popover-open {
151
+ transform: scale(100%);
152
+ }
110
153
  }
111
- dialog.micl-dialog:has(.micl-textfield-filled > select):popover-open,
112
- dialog.micl-dialog:has(.micl-textfield-outlined > select):popover-open,
113
- dialog.micl-dialog-fullscreen:has(.micl-textfield-filled > select):popover-open,
114
- dialog.micl-dialog-fullscreen:has(.micl-textfield-outlined > select):popover-open {
115
- transform: scale(100%);
154
+
155
+ [dir=rtl] {
156
+ .micl-textfield-filled > select,
157
+ .micl-textfield-outlined > select {
158
+ &:open::picker-icon {
159
+ rotate: -180deg;
160
+ }
161
+ }
116
162
  }
@@ -284,9 +284,6 @@
284
284
  border-block-end-color: var(--md-sys-color-primary);
285
285
  }
286
286
  }
287
- &> select {
288
- line-height: 28px;
289
- }
290
287
  &> textarea {
291
288
  padding-block-start: 24px;
292
289
  }
@@ -300,7 +297,7 @@
300
297
  > input[type=time],
301
298
  > input[type=week],
302
299
  > select:focus,
303
- > select[value]:not([value='']):not([data-miclinitialized]),
300
+ > select:not([data-miclinitialized]) option:checked:not([value='']),
304
301
  > select[data-miclvalue],
305
302
  > textarea:focus,
306
303
  > textarea:not(:empty):not([data-miclinitialized]),
@@ -324,7 +321,7 @@
324
321
  }
325
322
  }
326
323
  .micl-textfield-outlined {
327
- margin-block-start: 0.375rem;
324
+ margin-block-start: calc(2px + var(--md-sys-typescale-body-small-line-height)/2);
328
325
 
329
326
  &:hover {
330
327
  &> label {
@@ -353,9 +350,6 @@
353
350
  outline-color: var(--md-sys-color-primary);
354
351
  }
355
352
  }
356
- &> select {
357
- line-height: var(--md-sys-textfield-height);
358
- }
359
353
  &:has(
360
354
  > input:focus,
361
355
  > input[value]:not([value='']):not([data-miclinitialized]),
@@ -366,7 +360,7 @@
366
360
  > input[type=time],
367
361
  > input[type=week],
368
362
  > select:focus,
369
- > select[value]:not([value='']):not([data-miclinitialized]),
363
+ > select:not([data-miclinitialized]) option:checked:not([value='']),
370
364
  > select[data-miclvalue],
371
365
  > textarea:focus,
372
366
  > textarea:not(:empty):not([data-miclinitialized]),
@@ -20,12 +20,25 @@
20
20
  // SOFTWARE.
21
21
 
22
22
  export const textfieldSelector = '.micl-textfield-outlined > input,.micl-textfield-filled > input';
23
- export const selectSelector = '.micl-textfield-outlined > select,.micl-textfield-filled > select';
24
23
  export const textareaSelector = '.micl-textfield-outlined > textarea,.micl-textfield-filled > textarea';
24
+ export const selectSelector = '.micl-textfield-filled > select,.micl-textfield-outlined > select';
25
25
 
26
26
  export default (() =>
27
27
  {
28
- const counterSelector = '.micl-textfield__character-counter';
28
+ const setCounter = (element: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement) =>
29
+ {
30
+ if (
31
+ !element.parentElement
32
+ || element instanceof HTMLSelectElement
33
+ || !element.maxLength
34
+ ) {
35
+ return;
36
+ }
37
+ const counter = element.parentElement.querySelector('.micl-textfield__character-counter');
38
+ if (counter) {
39
+ counter.textContent = `${element.value.length}/${element.maxLength}`;
40
+ }
41
+ };
29
42
 
30
43
  return {
31
44
  initialize: (element: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement): void =>
@@ -39,17 +52,21 @@ export default (() =>
39
52
  element.dataset.miclvalue = '1';
40
53
  }
41
54
 
42
- if (
43
- (element instanceof HTMLSelectElement)
44
- || !element.maxLength
45
- ) {
46
- return;
47
- }
55
+ if (element instanceof HTMLSelectElement) {
56
+ element.addEventListener('mousedown', event =>
57
+ {
58
+ const
59
+ rect = element.getBoundingClientRect(),
60
+ roomAbove = rect.top,
61
+ roomBelow = window.innerHeight - rect.bottom;
48
62
 
49
- const counter = element.parentElement?.querySelector(counterSelector);
50
- if (counter) {
51
- counter.textContent = `${element.value.length}/${element.maxLength}`;
63
+ !element.matches(':open') && element.style.setProperty(
64
+ '--md-sys-select-picker-origin',
65
+ roomAbove > roomBelow ? 'left bottom' : 'left top'
66
+ );
67
+ });
52
68
  }
69
+ setCounter(element);
53
70
  },
54
71
 
55
72
  input: (event: Event): void =>
@@ -72,17 +89,7 @@ export default (() =>
72
89
  delete event.target.dataset.miclvalue;
73
90
  }
74
91
 
75
- if (
76
- (event.target instanceof HTMLSelectElement)
77
- || !event.target.maxLength
78
- ) {
79
- return;
80
- }
81
-
82
- const counter = event.target.parentElement?.querySelector(counterSelector);
83
- if (counter) {
84
- counter.textContent = `${event.target.value.length}/${event.target.maxLength}`;
85
- }
92
+ setCounter(event.target);
86
93
  }
87
94
  };
88
95
  })();