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.
- package/.claude/settings.local.json +14 -0
- package/CLAUDE.md +53 -0
- package/README.md +6 -0
- package/components/accordion/README.md +6 -3
- package/components/alert/index.scss +5 -0
- package/components/appbar/index.scss +12 -0
- package/components/badge/index.scss +2 -0
- package/components/bottomsheet/index.scss +9 -0
- package/components/button/index.scss +33 -6
- package/components/card/README.md +4 -0
- package/components/card/index.scss +182 -150
- package/components/checkbox/index.scss +28 -6
- package/components/datepicker/index.scss +13 -0
- package/components/datepicker/index.ts +9 -9
- package/components/dialog/index.scss +21 -6
- package/components/iconbutton/index.scss +28 -6
- package/components/list/README.md +191 -32
- package/components/list/index.scss +281 -190
- package/components/list/index.ts +100 -100
- package/components/menu/README.md +199 -10
- package/components/menu/index.scss +242 -47
- package/components/menu/index.ts +74 -37
- package/components/navigationrail/index.scss +91 -68
- package/components/progressindicator/README.md +88 -0
- package/components/progressindicator/index.scss +225 -0
- package/components/progressindicator/index.ts +77 -0
- package/components/radio/index.scss +24 -6
- package/components/select/README.md +42 -5
- package/components/select/index.scss +45 -79
- package/components/shape/README.md +103 -0
- package/components/shape/_paths.generated.scss +64 -0
- package/components/shape/index.scss +66 -0
- package/components/shape/master.scss +28 -0
- package/components/sidesheet/index.scss +11 -0
- package/components/slider/index.scss +13 -0
- package/components/snackbar/index.scss +12 -0
- package/components/stepper/index.scss +3 -5
- package/components/switch/index.scss +9 -0
- package/components/textfield/index.scss +10 -1
- package/components/textfield/index.ts +2 -2
- package/components/timepicker/index.scss +16 -0
- package/dist/alert.css +1 -1
- package/dist/appbar.css +1 -1
- package/dist/badge.css +1 -1
- package/dist/bottomsheet.css +1 -1
- package/dist/button.css +1 -1
- package/dist/card.css +1 -1
- package/dist/checkbox.css +1 -1
- package/dist/components/list/index.d.ts +2 -2
- package/dist/components/progressindicator/index.d.ts +6 -0
- package/dist/datepicker.css +1 -1
- package/dist/dialog.css +1 -1
- package/dist/divider.css +1 -1
- package/dist/foundations/form/index.js +1 -0
- package/dist/foundations.css +1 -1
- package/dist/iconbutton.css +1 -1
- package/dist/layout.css +1 -1
- package/dist/list.css +1 -1
- package/dist/menu.css +1 -1
- package/dist/micl.css +1 -1
- package/dist/micl.js +1 -1
- package/dist/navigationrail.css +1 -1
- package/dist/progressindicator.css +1 -0
- package/dist/progressindicator.js +1 -0
- package/dist/radio.css +1 -1
- package/dist/select.css +1 -1
- package/dist/shape.css +1 -0
- package/dist/shape.js +1 -0
- package/dist/sidesheet.css +1 -1
- package/dist/slider.css +1 -1
- package/dist/snackbar.css +1 -1
- package/dist/stepper.css +1 -1
- package/dist/switch.css +1 -1
- package/dist/textfield.css +1 -1
- package/dist/timepicker.css +1 -1
- package/docs/accordion.html +24 -24
- package/docs/bottomsheet.html +1 -4
- package/docs/datepicker.html +21 -21
- package/docs/dialog.html +1 -1
- package/docs/index.html +5 -4
- package/docs/list.html +38 -22
- package/docs/menu.html +246 -41
- package/docs/micl.css +1 -1
- package/docs/micl.js +1 -1
- package/docs/progressindicator.html +288 -0
- package/docs/select.html +68 -19
- package/docs/shape.css +1 -0
- package/docs/shape.js +1 -0
- package/docs/shapes.html +150 -0
- package/foundations/index.scss +0 -1
- package/foundations/layout/README.md +1 -1
- package/foundations/layout/index.scss +3 -0
- package/micl.ts +8 -1
- package/package.json +6 -4
- package/styles/README.md +90 -12
- package/styles/elevation.scss +46 -13
- package/styles/motion.scss +51 -47
- package/styles/shapes.scss +41 -26
- package/styles/statelayer.scss +93 -36
- package/styles/typography.scss +120 -322
- package/styles.scss +10 -6
- package/tools/shapes/check.mjs +42 -0
- package/tools/shapes/generate.mjs +834 -0
- 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(
|
|
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:
|
|
101
|
+
background-size: 0%, 100%;
|
|
84
102
|
cursor: pointer;
|
|
85
103
|
transition:
|
|
86
|
-
background-size
|
|
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
|
-
|
|
116
|
-
|
|
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
|
|
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 [
|
|
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
|
|
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
|
|
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-
|
|
36
|
+
--md-comp-select-line-height: calc(var(--md-sys-textfield-height) - 18px - 3px);
|
|
31
37
|
}
|
|
32
38
|
.micl-textfield-outlined > select {
|
|
33
|
-
--md-
|
|
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-
|
|
39
|
-
--md-
|
|
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-
|
|
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-
|
|
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
|
-
|
|
61
|
-
|
|
62
|
-
position-try: most-block-size
|
|
63
|
-
|
|
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
|
-
|
|
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-
|
|
88
|
+
transform-origin: var(--md-comp-select-picker-origin, left top);
|
|
73
89
|
transition:
|
|
74
|
-
opacity var(--md-
|
|
75
|
-
transform var(--md-
|
|
76
|
-
overlay var(--md-
|
|
77
|
-
display var(--md-
|
|
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-
|
|
84
|
-
transform var(--md-
|
|
85
|
-
overlay var(--md-
|
|
86
|
-
display var(--md-
|
|
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
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
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.
|