material-inspired-component-library 7.0.2 → 8.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.
Files changed (104) hide show
  1. package/.claude/settings.local.json +14 -0
  2. package/CLAUDE.md +53 -0
  3. package/README.md +6 -0
  4. package/components/accordion/README.md +6 -3
  5. package/components/alert/index.scss +5 -0
  6. package/components/appbar/index.scss +12 -0
  7. package/components/badge/index.scss +2 -0
  8. package/components/bottomsheet/index.scss +9 -0
  9. package/components/button/index.scss +33 -6
  10. package/components/card/README.md +4 -0
  11. package/components/card/index.scss +182 -150
  12. package/components/checkbox/index.scss +28 -6
  13. package/components/datepicker/index.scss +13 -0
  14. package/components/datepicker/index.ts +9 -9
  15. package/components/dialog/index.scss +21 -6
  16. package/components/iconbutton/index.scss +28 -6
  17. package/components/list/README.md +191 -32
  18. package/components/list/index.scss +281 -190
  19. package/components/list/index.ts +100 -100
  20. package/components/menu/README.md +199 -10
  21. package/components/menu/index.scss +242 -47
  22. package/components/menu/index.ts +74 -37
  23. package/components/navigationrail/index.scss +91 -68
  24. package/components/progressindicator/README.md +88 -0
  25. package/components/progressindicator/index.scss +225 -0
  26. package/components/progressindicator/index.ts +77 -0
  27. package/components/radio/index.scss +24 -6
  28. package/components/select/README.md +42 -5
  29. package/components/select/index.scss +45 -79
  30. package/components/shape/README.md +103 -0
  31. package/components/shape/_paths.generated.scss +64 -0
  32. package/components/shape/index.scss +66 -0
  33. package/components/shape/master.scss +28 -0
  34. package/components/sidesheet/index.scss +11 -0
  35. package/components/slider/index.scss +13 -0
  36. package/components/snackbar/index.scss +12 -0
  37. package/components/stepper/index.scss +3 -5
  38. package/components/switch/index.scss +9 -0
  39. package/components/textfield/index.scss +10 -1
  40. package/components/textfield/index.ts +2 -2
  41. package/components/timepicker/index.scss +16 -0
  42. package/dist/alert.css +1 -1
  43. package/dist/appbar.css +1 -1
  44. package/dist/badge.css +1 -1
  45. package/dist/bottomsheet.css +1 -1
  46. package/dist/button.css +1 -1
  47. package/dist/card.css +1 -1
  48. package/dist/checkbox.css +1 -1
  49. package/dist/components/list/index.d.ts +2 -2
  50. package/dist/components/progressindicator/index.d.ts +6 -0
  51. package/dist/datepicker.css +1 -1
  52. package/dist/dialog.css +1 -1
  53. package/dist/divider.css +1 -1
  54. package/dist/foundations/form/index.js +1 -0
  55. package/dist/foundations.css +1 -1
  56. package/dist/iconbutton.css +1 -1
  57. package/dist/layout.css +1 -1
  58. package/dist/list.css +1 -1
  59. package/dist/menu.css +1 -1
  60. package/dist/micl.css +1 -1
  61. package/dist/micl.js +1 -1
  62. package/dist/navigationrail.css +1 -1
  63. package/dist/progressindicator.css +1 -0
  64. package/dist/progressindicator.js +1 -0
  65. package/dist/radio.css +1 -1
  66. package/dist/select.css +1 -1
  67. package/dist/shape.css +1 -0
  68. package/dist/shape.js +1 -0
  69. package/dist/sidesheet.css +1 -1
  70. package/dist/slider.css +1 -1
  71. package/dist/snackbar.css +1 -1
  72. package/dist/stepper.css +1 -1
  73. package/dist/switch.css +1 -1
  74. package/dist/textfield.css +1 -1
  75. package/dist/timepicker.css +1 -1
  76. package/docs/accordion.html +24 -24
  77. package/docs/bottomsheet.html +1 -4
  78. package/docs/datepicker.html +21 -21
  79. package/docs/dialog.html +1 -1
  80. package/docs/index.html +5 -4
  81. package/docs/list.html +38 -22
  82. package/docs/menu.html +246 -41
  83. package/docs/micl.css +1 -1
  84. package/docs/micl.js +1 -1
  85. package/docs/progressindicator.html +288 -0
  86. package/docs/select.html +68 -19
  87. package/docs/shape.css +1 -0
  88. package/docs/shape.js +1 -0
  89. package/docs/shapes.html +150 -0
  90. package/foundations/index.scss +0 -1
  91. package/foundations/layout/README.md +1 -1
  92. package/foundations/layout/index.scss +3 -0
  93. package/micl.ts +8 -1
  94. package/package.json +6 -4
  95. package/styles/README.md +90 -12
  96. package/styles/elevation.scss +46 -13
  97. package/styles/motion.scss +51 -47
  98. package/styles/shapes.scss +41 -26
  99. package/styles/statelayer.scss +93 -36
  100. package/styles/typography.scss +120 -322
  101. package/styles.scss +10 -6
  102. package/tools/shapes/check.mjs +42 -0
  103. package/tools/shapes/generate.mjs +834 -0
  104. package/webpack.config.js +16 -1
@@ -0,0 +1,77 @@
1
+ //
2
+ // Copyright © 2025 Hermana AS
3
+ //
4
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ // of this software and associated documentation files (the "Software"), to deal
6
+ // in the Software without restriction, including without limitation the rights
7
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ // copies of the Software, and to permit persons to whom the Software is
9
+ // furnished to do so, subject to the following conditions:
10
+ //
11
+ // The above copyright notice and this permission notice shall be included in all
12
+ // copies or substantial portions of the Software.
13
+ //
14
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ // SOFTWARE.
21
+
22
+ export const progressindicatorSelector = 'progress.micl-progress-linear,progress.micl-progress-circular';
23
+
24
+ export default (() =>
25
+ {
26
+ // <progress> emits no input/change events when its value/max change, so a
27
+ // per-instance MutationObserver mirrors the determinate attributes into the
28
+ // CSS custom properties the SCSS reads. Indeterminate progress (no value
29
+ // attribute) is handled entirely in CSS via the :indeterminate pseudo-class.
30
+ const observers = new WeakMap<HTMLProgressElement, MutationObserver>();
31
+
32
+ const setVars = (element: HTMLProgressElement): void =>
33
+ {
34
+ // position is value/max for determinate, or -1 when indeterminate.
35
+ const fraction = element.position;
36
+
37
+ if (fraction < 0) {
38
+ element.style.removeProperty('--md-comp-progress-value');
39
+ element.style.removeProperty('--md-comp-progress-max');
40
+ element.style.removeProperty('--md-comp-progress-fraction');
41
+ element.style.removeProperty('--md-comp-progress-amplitude-scale');
42
+ return;
43
+ }
44
+
45
+ // The Expressive wave amplitude eases to zero over the final 10% so the
46
+ // active indicator settles into a straight line as it completes.
47
+ const scale = Math.max(0, Math.min(1, (1 - fraction) / 0.1));
48
+
49
+ element.style.setProperty('--md-comp-progress-value', String(element.value));
50
+ element.style.setProperty('--md-comp-progress-max', String(element.max || 1));
51
+ element.style.setProperty('--md-comp-progress-fraction', String(fraction));
52
+ element.style.setProperty('--md-comp-progress-amplitude-scale', String(scale));
53
+ };
54
+
55
+ return {
56
+ initialize: (element: HTMLProgressElement): void =>
57
+ {
58
+ if (!element.matches(progressindicatorSelector)) {
59
+ return;
60
+ }
61
+
62
+ setVars(element);
63
+
64
+ const observer = new MutationObserver(() => setVars(element));
65
+ observer.observe(element, { attributes: true, attributeFilter: ['value', 'max'] });
66
+ observers.set(element, observer);
67
+ },
68
+ cleanup: (element: HTMLProgressElement): void =>
69
+ {
70
+ const observer = observers.get(element);
71
+ if (observer) {
72
+ observer.disconnect();
73
+ observers.delete(element);
74
+ }
75
+ }
76
+ };
77
+ })();
@@ -24,6 +24,19 @@
24
24
  @use '../../styles/shapes';
25
25
  @use '../../styles/statelayer';
26
26
 
27
+ @include shapes.corner('full');
28
+
29
+ @include statelayer.token('layer-size');
30
+ @include statelayer.token('hover-state-layer-opacity');
31
+ @include statelayer.token('focus-state-layer-opacity');
32
+ @include statelayer.token('pressed-state-layer-opacity');
33
+ @include statelayer.token('disabled-state-layer-opacity');
34
+ @include statelayer.token('focus-indicator-thickness');
35
+ @include statelayer.token('ripple-opacity-factor');
36
+ @include statelayer.token('ripple-duration');
37
+ @include statelayer.property;
38
+ @include statelayer.keyframes;
39
+
27
40
  :root {
28
41
  --md-sys-radio-border-width: 2px;
29
42
  --md-sys-radio-container-size: 20px;
@@ -77,13 +90,18 @@ input[type=radio].micl-radio {
77
90
  --micl-ripple: 1;
78
91
 
79
92
  background-image:
80
- 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%),
93
+ radial-gradient(
94
+ circle at var(--micl-x, center) var(--micl-y, center),
95
+ transparent 0%,
96
+ rgb(from var(--statelayer-color) r g b / calc(var(--statelayer-opacity) * var(--md-sys-state-ripple-opacity-factor))) 10%,
97
+ transparent 10%
98
+ ),
81
99
  linear-gradient(rgb(from var(--statelayer-color) r g b / var(--statelayer-opacity)));
82
100
  background-repeat: no-repeat;
83
- background-size: 10000%, 100%;
101
+ background-size: 0%, 100%;
84
102
  cursor: pointer;
85
103
  transition:
86
- background-size 3000ms,
104
+ background-size 0ms,
87
105
  --statelayer-opacity var(--md-sys-radio-motion-duration) linear;
88
106
 
89
107
  &:hover,
@@ -111,9 +129,9 @@ input[type=radio].micl-radio {
111
129
  }
112
130
  &:active {
113
131
  --statelayer-opacity: var(--md-sys-state-pressed-state-layer-opacity, 10%);
114
-
115
- background-size: 0%, 100%;
116
- transition: background-size 0ms;
132
+ }
133
+ &.micl-rippling {
134
+ animation: micl-ripple var(--md-sys-state-ripple-duration) motion.$md-sys-motion-easing-standard;
117
135
  }
118
136
  }
119
137
  &:disabled {
@@ -1,10 +1,10 @@
1
1
  # Select
2
- This component implements 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.
2
+ This component implements 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 present the user with a set of options from which one can be chosen.
3
3
 
4
4
  ## Basic Usage
5
5
 
6
6
  ### HTML
7
- The Select component is an extension of the [Text field](../textfield/README.md) and the [List](../list/README.md). It can be either `filled` or `outlined`. To create a basic select, use the following HTML and swap the class name to change the style.
7
+ The Select component is an extension of the [Text field](../textfield/README.md) and the [Menu](../menu/README.md) components. It can be either `filled` or `outlined`. To create a basic select, use the following HTML and swap the class name to change the style.
8
8
 
9
9
  ```HTML
10
10
  <div class="micl-textfield-filled">
@@ -21,10 +21,11 @@ The Select component is an extension of the [Text field](../textfield/README.md)
21
21
  ```
22
22
 
23
23
  ### CSS
24
- The Select component relies on styles from the text field and list components. Be sure to import all three styles into your project.
24
+ The Select component relies on styles from the text field, menu and list components. Be sure to import all four styles into your project.
25
25
 
26
26
  ```CSS
27
27
  @use "material-inspired-component-library/dist/list";
28
+ @use "material-inspired-component-library/dist/menu";
28
29
  @use "material-inspired-component-library/dist/textfield";
29
30
  @use "material-inspired-component-library/dist/select";
30
31
  ```
@@ -61,7 +62,7 @@ You can add [Dividers](../divider/README.md) into the list of options and they w
61
62
  <option class="micl-list-item-two" value="AR">
62
63
  <span class="micl-list-item__text">Argentina</span>
63
64
  </option>
64
- <hr class="micl-divider">
65
+ <hr class="micl-divider-inset">
65
66
  <option class="micl-list-item-two" value="BO">
66
67
  <span class="micl-list-item__text">Bolivia</span>
67
68
  </option>
@@ -97,7 +98,7 @@ The text content of an option can be preceded by various media elements:
97
98
  </option>
98
99
  ```
99
100
 
100
- - **Thumbnail**: Use `micl-list-item__thumbnail` for video previews with a background-image.
101
+ - **Thumbnail**: Use `micl-list-item__thumbnail` for thumbnail imagery (e.g. video previews or photos).
101
102
  ```HTML
102
103
  <option class="micl-list-item-two" value="AR">
103
104
  <span class="micl-list-item__thumbnail" style="background-image:url(https://upload.wikimedia.org/wikipedia/commons/thumb/1/1a/Flag_of_Argentina.svg/330px-Flag_of_Argentina.svg.png)"></span>
@@ -105,5 +106,41 @@ The text content of an option can be preceded by various media elements:
105
106
  </option>
106
107
  ```
107
108
 
109
+ **Example: Grouping options**
110
+
111
+ Options can be grouped by using the `<optgroup>` element. Add a `<legend>` element with the `micl-menu__section` class to provide a label for the option group.
112
+
113
+ ```HTML
114
+ <div class="micl-textfield-outlined">
115
+ <label for="myselect">Country</label>
116
+ <select id="myselect">
117
+ <option class="micl-list-item-one" value=""></option>
118
+ <optgroup>
119
+ <legend class="micl-menu__section">North American Countries</legend>
120
+ <option class="micl-list-item-one" value="CA">
121
+ <span class="micl-list-item__text">Canada</span>
122
+ </option>
123
+ </optgroup>
124
+ <hr class="micl-divider-inset">
125
+ <optgroup>
126
+ <legend class="micl-menu__section">South American Countries</legend>
127
+ <option class="micl-list-item-two" value="CL">
128
+ <span class="micl-list-item__text">Chile</span>
129
+ </option>
130
+ </optgroup>
131
+ </select>
132
+ </div>
133
+ ```
134
+
135
+ ## Customizations
136
+ You can customize the appearance of the Select 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 selects.
137
+
138
+ | Variable name | Default Value | Description |
139
+ | ------------------------------ | ------------- | ----------- |
140
+ | --md-comp-select-line-height | | The vertical line-height applied to the closed `<select>` element |
141
+ | --md-comp-select-picker-origin | left top | The transform-origin used for the open/close scale animation of the option pick-list |
142
+
143
+ The Select component supports the CSS variables listed for the [Menu](../menu/README.md) component.
144
+
108
145
  ## Compatibility
109
146
  This component uses modern browser features to style the `<select>` element, which may not be fully supported in all browsers. Browsers that do not support these features will display a default select menu. Please check [Browser compatibility](https://developer.mozilla.org/en-US/docs/Web/CSS/::picker#browser_compatibility) for details.
@@ -26,28 +26,31 @@
26
26
  @use '../../styles/statelayer';
27
27
  @use '../../styles/typography';
28
28
 
29
+ @include elevation.level(2);
30
+
31
+ @include shapes.corner('large');
32
+
33
+ @include statelayer.token('disabled-state-layer-opacity');
34
+
29
35
  .micl-textfield-filled > select {
30
- --md-sys-select-line-height: calc(var(--md-sys-textfield-height) - 18px - 3px);
36
+ --md-comp-select-line-height: calc(var(--md-sys-textfield-height) - 18px - 3px);
31
37
  }
32
38
  .micl-textfield-outlined > select {
33
- --md-sys-select-line-height: var(--md-sys-textfield-height);
39
+ --md-comp-select-line-height: var(--md-sys-textfield-height);
34
40
  }
35
41
  .micl-textfield-filled > select,
36
42
  .micl-textfield-outlined > select {
37
43
  --md-sys-divider-space: 8px;
38
- --md-sys-list-motion-duration: #{motion.$md-sys-motion-expressive-default-effects-duration};
39
- --md-sys-select-motion-spatial: #{motion.$md-sys-motion-expressive-default-spatial};
40
- --md-sys-select-motion-duration: #{motion.$md-sys-motion-expressive-default-spatial-duration};
41
- --md-sys-select-motion-duration-reverse: #{motion.$md-sys-motion-expressive-fast-spatial-duration};
42
- --md-sys-select-picker-origin: left top;
44
+ --md-comp-list-motion-duration: #{motion.$md-sys-motion-expressive-default-effects-duration};
45
+ --md-comp-select-picker-origin: left top;
43
46
 
44
47
  appearance: base-select;
45
- line-height: var(--md-sys-select-line-height);
48
+ line-height: var(--md-comp-select-line-height);
46
49
 
47
50
  &::picker-icon {
48
51
  color: var(--md-sys-color-on-surface-variant);
49
52
  transition: motion.$md-sys-motion-duration-medium4 rotate;
50
- transform-origin: 50% calc((var(--md-sys-select-line-height) / 2) - 1px);
53
+ transform-origin: 50% calc((var(--md-comp-select-line-height) / 2) - 1px);
51
54
  }
52
55
  &:disabled::picker-icon {
53
56
  color: rgb(from var(--md-sys-color-on-surface-variant) r g b/var(--md-sys-state-disabled-state-layer-opacity, 38%));
@@ -55,35 +58,48 @@
55
58
  &:open::picker-icon {
56
59
  rotate: 180deg;
57
60
  }
61
+
58
62
  &::picker(select) {
63
+ --md-comp-list-motion-effects: #{motion.$md-sys-motion-expressive-fast-spatial};
64
+ --md-comp-list-motion-duration: #{motion.$md-sys-motion-expressive-default-effects-duration};
65
+ --md-sys-divider-space: 0.5px;
66
+ --_list-shape: var(--md-comp-list-container-shape, var(--md-sys-shape-corner-large, 16px));
67
+ --_list-item-background-color: var(--md-comp-list-item-container-color, transparent);
68
+ --_list-item-background-opacity: 0%;
69
+
59
70
  appearance: base-select;
60
- min-inline-size: max(anchor-size(self-inline), 112px);
61
- max-inline-size: 280px;
62
- position-try: most-block-size flip-block;
63
- padding: var(--md-sys-list-padding, 8px) 0;
71
+ display: flex;
72
+ flex-direction: column;
73
+ position-try-order: most-block-size;
74
+ position-try-fallbacks: flip-block, flip-inline;
75
+ min-inline-size: max(anchor-size(self-inline), var(--md-comp-menu-width-min, 112px));
76
+ max-inline-size: var(--md-comp-menu-width-max, 320px);
77
+ gap: var(--md-comp-menu-gap, 2px);
78
+ padding: 4px;
79
+ border-radius: var(--_list-shape);
64
80
  border: none;
65
- border-radius: var(--md-sys-shape-corner-extra-small, 4px);
66
- background-color: var(--md-sys-color-surface-container);
67
- box-shadow: var(--md-sys-elevation-level2);
81
+ outline: none;
82
+ background-color: var(--md-comp-menu-standard-container-color, var(--md-sys-color-surface-container-low));
83
+ box-shadow: var(--md-comp-menu-container-elevation, var(--md-sys-elevation-level2));
68
84
  opacity: 0;
69
85
  overflow-x: hidden;
70
86
  overflow-y: auto;
71
87
  transform: scaleY(0);
72
- transform-origin: var(--md-sys-select-picker-origin);
88
+ transform-origin: var(--md-comp-select-picker-origin, left top);
73
89
  transition:
74
- opacity var(--md-sys-select-motion-duration-reverse) linear,
75
- transform var(--md-sys-select-motion-duration-reverse) var(--md-sys-select-motion-spatial),
76
- overlay var(--md-sys-select-motion-duration-reverse) linear allow-discrete,
77
- display var(--md-sys-select-motion-duration-reverse) linear allow-discrete;
90
+ opacity var(--md-comp-menu-motion-spatial-duration-reverse) linear,
91
+ transform var(--md-comp-menu-motion-spatial-duration-reverse) var(--md-comp-menu-motion-spatial),
92
+ overlay var(--md-comp-menu-motion-spatial-duration-reverse) linear allow-discrete,
93
+ display var(--md-comp-menu-motion-spatial-duration-reverse) linear allow-discrete;
78
94
 
79
95
  &:popover-open {
80
96
  opacity: 1;
81
97
  transform: scaleY(1);
82
98
  transition:
83
- opacity var(--md-sys-select-motion-duration) motion.$md-sys-motion-easing-emphasized-decelerate,
84
- transform var(--md-sys-select-motion-duration) var(--md-sys-select-motion-spatial),
85
- overlay var(--md-sys-select-motion-duration) linear allow-discrete,
86
- display var(--md-sys-select-motion-duration) linear allow-discrete;
99
+ opacity var(--md-comp-menu-motion-spatial-duration) motion.$md-sys-motion-easing-emphasized-decelerate,
100
+ transform var(--md-comp-menu-motion-spatial-duration) var(--md-comp-menu-motion-spatial),
101
+ overlay var(--md-comp-menu-motion-spatial-duration) linear allow-discrete,
102
+ display var(--md-comp-menu-motion-spatial-duration) linear allow-discrete;
87
103
 
88
104
  @starting-style {
89
105
  opacity: 0;
@@ -93,50 +109,10 @@
93
109
  }
94
110
 
95
111
  option {
96
- --md-sys-list-item-one-height: 48px;
97
- --md-sys-list-item-two-height: 64px;
98
- --md-sys-list-item-one-padding: 0;
99
- --md-sys-list-item-two-padding: 0;
100
- --md-sys-list-item-space: 12px;
101
- --md-sys-list-item-container-color: var(--md-sys-color-surface-container);
102
-
103
112
  line-height: normal;
104
- background-color: transparent;
105
-
106
- &:not(:disabled) {
107
- cursor: pointer;
108
- }
109
- &:checked {
110
- background-color: var(--md-sys-color-secondary-container);
111
113
 
112
- .micl-list-item__text {
113
- color: var(--md-sys-color-on-secondary-container);
114
-
115
- &::after {
116
- color: var(--md-sys-color-on-surface);
117
- }
118
- }
119
- }
120
- &:focus-visible {
121
- outline-offset: calc(-1 * var(--md-sys-state-focus-indicator-thickness, 3px));
122
- z-index: 1;
123
- }
124
-
125
- .micl-list-item__text {
126
- @include typography.body-large;
127
-
128
- color: var(--md-sys-color-on-surface);
129
- white-space: normal;
130
- }
131
114
  .micl-list-item__text::after {
132
- @include typography.body-medium;
133
-
134
115
  content: attr(aria-description);
135
- display: block;
136
- color: var(--md-sys-color-on-surface-variant);
137
- overflow-x: hidden;
138
- text-overflow: ellipsis;
139
- white-space: nowrap;
140
116
  }
141
117
  &::checkmark {
142
118
  color: var(--md-sys-color-on-surface-variant);
@@ -144,20 +120,10 @@
144
120
  }
145
121
  }
146
122
 
147
- /* dialog.micl-dialog:has(.micl-textfield-filled > select), */
148
- /* dialog.micl-dialog:has(.micl-textfield-outlined > select), */
149
- /* dialog.micl-dialog-fullscreen:has(.micl-textfield-filled > select), */
150
- /* dialog.micl-dialog-fullscreen:has(.micl-textfield-outlined > select) { */
151
- /* inset-block-start: 0; */
152
- /* inset-inline-start: 0; */
153
- /* margin: auto; */
154
- /* transform: scale(50%); */
155
-
156
- /* &:popover-open, */
157
- /* &[open] { */
158
- /* transform: scale(100%); */
159
- /* } */
160
- /* } */
123
+ [inert] .micl-textfield-filled > select::picker-icon,
124
+ [inert] .micl-textfield-outlined > select::picker-icon {
125
+ display: none;
126
+ }
161
127
 
162
128
  [dir=rtl] {
163
129
  .micl-textfield-filled > select,
@@ -0,0 +1,103 @@
1
+ # Shape
2
+ The Shape component renders Material Design 3 [Expressive Shapes](https://m3.material.io/styles/shape/overview-principles) — circle, square, pill, oval, heart, cookie, clover, sunny, and so on — as inline SVGs whose `d` attribute is supplied by CSS. Because the path data is set with `d:` rather than baked into the SVG markup, swapping a shape's class triggers a smooth `transition: d` morph between the old and new outline.
3
+
4
+ ## Basic Usage
5
+
6
+ ### HTML
7
+ A shape is an empty `<svg>` with the base class `micl-shape` plus one of the shape modifier classes:
8
+
9
+ ```HTML
10
+ <svg class="micl-shape micl-shape-heart" viewBox="0 0 100 100"><path /></svg>
11
+ ```
12
+
13
+ Optional modifier classes:
14
+
15
+ | Class | Effect |
16
+ | --- | --- |
17
+ | `micl-shape--outlined` | Renders the shape as a stroked outline instead of a filled fill |
18
+ | `micl-shape--shadowed` | Adds a soft drop-shadow filter |
19
+
20
+ ### CSS
21
+
22
+ The Shape component is **opt-in** — it is not included in the master `micl.css` bundle, because most apps don't need 35 decorative shapes. Pick one of three integration paths:
23
+
24
+ **1. Import only the shapes you actually use (recommended for production):**
25
+
26
+ ```SCSS
27
+ @use "material-inspired-component-library/components/shape" as shape;
28
+
29
+ @include shape.base;
30
+ @include shape.use("circle", "heart", "pill");
31
+ ```
32
+
33
+ `shape.base` emits the shared `.micl-shape`, `.micl-shape--outlined`, and `.micl-shape--shadowed` rules. `shape.use(<names>...)` emits one `.micl-shape-<name> > path { d: … }` rule per name. Unknown names raise a Sass error at compile time.
34
+
35
+ **2. Import the whole gallery via Sass:**
36
+
37
+ ```SCSS
38
+ @use "material-inspired-component-library/components/shape" with ($master: true);
39
+ ```
40
+
41
+ Equivalent to calling `shape.base` plus `shape.use(…)` with every shape.
42
+
43
+ **3. Drop in the prebuilt CSS:**
44
+
45
+ ```HTML
46
+ <link rel="stylesheet" href="material-inspired-component-library/dist/shape.css">
47
+ ```
48
+
49
+ The prebuilt bundle contains all 35 shapes plus the base styles.
50
+
51
+ ### JavaScript
52
+ No JavaScript is required. Morphing between shapes is a pure CSS animation: when you replace `micl-shape-heart` with `micl-shape-pill` on the element, the browser interpolates the `d:` value automatically. The morph timing can be customised via two CSS custom properties on the element:
53
+
54
+ | Custom property | Default | Description |
55
+ | --- | --- | --- |
56
+ | `--morph-duration` | `0ms` | Length of the morph transition |
57
+ | `--morph-easing` | `ease-in-out` | Easing curve of the transition |
58
+
59
+ ### Live Demo
60
+ A live example of the [Shape component](https://henkpb.github.io/micl/shapes.html) is available, with a button per shape that morphs the demo SVG.
61
+
62
+ ## Variants
63
+ The available shape names (use these as the `micl-shape-<name>` class and as arguments to `shape.use(...)`):
64
+
65
+ ```
66
+ circle, square, slanted, arch, semicircle, oval, pill,
67
+ triangle, arrow, fan, diamond, clamshell, pentagon, gem,
68
+ very-sunny, sunny, cookie-4, cookie-6, cookie-7, cookie-9,
69
+ cookie-12, clover-4, clover-8, burst, soft-burst, boom,
70
+ soft-boom, flower, puffy, puffy-diamond, ghost-ish,
71
+ pixel-circle, pixel-triangle, bun, heart
72
+ ```
73
+
74
+ ## Customizations
75
+ The base styles size the SVG to 100 × 100 px, fill it with `green`, and let it overflow its viewBox horizontally (so wide shapes like *pill* and *fan* are not clipped). Override these on the element or on a parent:
76
+
77
+ ```HTML
78
+ <svg class="micl-shape micl-shape-heart"
79
+ viewBox="0 0 100 100"
80
+ style="inline-size:64px;block-size:64px;fill:var(--md-sys-color-primary)">
81
+ <path />
82
+ </svg>
83
+ ```
84
+
85
+ For `micl-shape--outlined`, the stroke colour and width are controlled by the standard SVG `stroke` and `stroke-width` properties:
86
+
87
+ ```HTML
88
+ <svg class="micl-shape micl-shape--outlined micl-shape-pill"
89
+ viewBox="0 0 100 100"
90
+ style="stroke:var(--md-sys-color-outline);stroke-width:3"><path /></svg>
91
+ ```
92
+
93
+ ## Contributing — regenerating the path data
94
+ The 35 SVG path strings live in [`_paths.generated.scss`](./_paths.generated.scss) and are produced by [`tools/shapes/generate.mjs`](../../tools/shapes/generate.mjs). The Sass partial does no math at compile time — it only looks shapes up by name in the generated map. **Do not edit `_paths.generated.scss` by hand.**
95
+
96
+ When you change a shape's vertex coordinates, repeat count, mirror flag, vertex count, or any of the underlying math:
97
+
98
+ ```bash
99
+ npm run gen:shapes # regenerate components/shape/_paths.generated.scss
100
+ npm run check:shapes # verify the file is up to date (CI runs this too)
101
+ ```
102
+
103
+ Commit the regenerated `_paths.generated.scss` together with the change to the generator. CI fails if a PR modifies the generator without also updating the committed paths.