@rio-m3e/styles 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -9,4 +9,6 @@ import '@rio-m3e/styles/button.css';
9
9
  import '@rio-m3e/styles/base/ripple.css';
10
10
  ```
11
11
 
12
+ You can see the document page in [here](https://legenlee.github.io/rio/).
13
+
12
14
  Licensed under the Apache License 2.0.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rio-m3e/styles",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Framework-agnostic component styles for Rio",
5
5
  "license": "Apache-2.0",
6
6
  "author": "LegenLee",
@@ -0,0 +1,10 @@
1
+ /*
2
+ * Pairs with `attachAnchoredPosition` from `@rio-m3e/core`, which marks the element with
3
+ * `data-anchored` and writes `left` and `top` in viewport coordinates. The element is shown in the
4
+ * top layer, as a popover, which browsers center by default; this lets the coordinates apply.
5
+ */
6
+ :where([data-anchored]) {
7
+ position: fixed;
8
+ inset: auto;
9
+ margin: 0;
10
+ }
@@ -1,8 +1,7 @@
1
1
  /*
2
2
  * Reduced motion: when the user asks the OS to reduce motion, spatial motion (position, size,
3
3
  * rotation, corner radius) becomes instant. Effects motion (color, opacity) keeps its short fades,
4
- * which don't cause the discomfort reduced motion is meant to prevent. This is a Rio decision; the
5
- * M3 pages Rio has read don't define reduced-motion behavior.
4
+ * which don't cause the discomfort reduced motion is meant to prevent.
6
5
  *
7
6
  * Every element gets the override, with !important, so it beats the theme variables `applyTheme`
8
7
  * sets inline on the root, and any subtree that swaps motion schemes. Components that use the
@@ -41,6 +41,19 @@
41
41
  opacity: var(--rio-state-pressed-state-layer-opacity);
42
42
  }
43
43
 
44
+ /*
45
+ * A button that opened a menu stays pressed while the menu is open. Only a button that opens a
46
+ * popup: other buttons that expand something, such as an accordion's, keep their look. Disabled
47
+ * ones are left out here, since this selector outweighs the disabled rule below.
48
+ */
49
+ .rio-state-layer[aria-haspopup]:not(
50
+ [aria-haspopup='false'],
51
+ :disabled,
52
+ [aria-disabled='true']
53
+ )[aria-expanded='true']::before {
54
+ opacity: var(--rio-state-pressed-state-layer-opacity);
55
+ }
56
+
44
57
  /* `attachDrag` from `@rio-m3e/core` marks an element with `data-dragging` while it moves. */
45
58
  .rio-state-layer[data-dragging]::before {
46
59
  opacity: var(--rio-state-dragged-state-layer-opacity);
@@ -34,6 +34,9 @@
34
34
  * ends of the row keep the group's shape; the facing corners are smaller, tighten when pressed,
35
35
  * and open up fully when the button is selected. Each button springs its two sides separately
36
36
  * (see base/shape-morph.css).
37
+ *
38
+ * A button may sit in a tooltip's wrapper (`tooltip.css`), which has no box, so each rule also
39
+ * reaches a button one level down in one.
37
40
  */
38
41
 
39
42
  .rio-button-group:where([data-variant='connected']) {
@@ -42,7 +45,8 @@
42
45
  display: flex;
43
46
  }
44
47
 
45
- .rio-button-group[data-variant='connected'] > .rio-button {
48
+ .rio-button-group[data-variant='connected'] > .rio-button,
49
+ .rio-button-group[data-variant='connected'] > .rio-tooltip-trigger > .rio-button {
46
50
  /* Small, medium, and extra small */
47
51
  --_inner: var(--rio-shape-corner-small);
48
52
  --_inner-pressed: var(--rio-shape-corner-extra-small);
@@ -58,41 +62,59 @@
58
62
  --rio-shape-morph-end-target: var(--_end);
59
63
  }
60
64
 
61
- .rio-button-group[data-variant='connected'] > .rio-button:where([data-size='large']) {
65
+ .rio-button-group[data-variant='connected'] > .rio-button:where([data-size='large']),
66
+ .rio-button-group[data-variant='connected']
67
+ > .rio-tooltip-trigger
68
+ > .rio-button:where([data-size='large']) {
62
69
  --_inner: var(--rio-shape-corner-large);
63
70
  --_inner-pressed: var(--rio-shape-corner-medium);
64
71
  }
65
72
 
66
- .rio-button-group[data-variant='connected'] > .rio-button:where([data-size='xlarge']) {
73
+ .rio-button-group[data-variant='connected'] > .rio-button:where([data-size='xlarge']),
74
+ .rio-button-group[data-variant='connected']
75
+ > .rio-tooltip-trigger
76
+ > .rio-button:where([data-size='xlarge']) {
67
77
  --_inner: var(--rio-shape-corner-large-increased);
68
78
  --_inner-pressed: var(--rio-shape-corner-large);
69
79
  }
70
80
 
71
81
  /* A square group's ends use the same radius as its facing corners. */
72
- .rio-button-group[data-variant='connected'] > .rio-button[data-shape='square'] {
82
+ .rio-button-group[data-variant='connected'] > .rio-button[data-shape='square'],
83
+ .rio-button-group[data-variant='connected']
84
+ > .rio-tooltip-trigger
85
+ > .rio-button[data-shape='square'] {
73
86
  --_outer: var(--_inner);
74
87
  }
75
88
 
76
- .rio-button-group[data-variant='connected'] > .rio-button:first-child {
89
+ .rio-button-group[data-variant='connected'] > .rio-button:first-child,
90
+ .rio-button-group[data-variant='connected'] > .rio-tooltip-trigger:first-child > .rio-button {
77
91
  --_start: var(--_outer);
78
92
  }
79
93
 
80
- .rio-button-group[data-variant='connected'] > .rio-button:last-child {
94
+ .rio-button-group[data-variant='connected'] > .rio-button:last-child,
95
+ .rio-button-group[data-variant='connected'] > .rio-tooltip-trigger:last-child > .rio-button {
81
96
  --_end: var(--_outer);
82
97
  }
83
98
 
84
- .rio-button-group[data-variant='connected'] > .rio-button[data-selected='true'] {
99
+ .rio-button-group[data-variant='connected'] > .rio-button[data-selected='true'],
100
+ .rio-button-group[data-variant='connected']
101
+ > .rio-tooltip-trigger
102
+ > .rio-button[data-selected='true'] {
85
103
  --_inner-now: var(--_round);
86
104
  --_outer: var(--_round);
87
105
  }
88
106
 
89
107
  /* After selected, so a pressed selected button still tightens its facing corners */
90
- .rio-button-group[data-variant='connected'] > .rio-button[data-pressed] {
108
+ .rio-button-group[data-variant='connected'] > .rio-button[data-pressed],
109
+ .rio-button-group[data-variant='connected'] > .rio-tooltip-trigger > .rio-button[data-pressed] {
91
110
  --_inner-now: var(--_inner-pressed);
92
111
  }
93
112
 
94
113
  /* Extra small and small icon buttons keep a 48px minimum width, matching their target. */
95
114
  .rio-button-group[data-variant='connected']
115
+ > .rio-icon-button:where([data-size='xsmall'], [data-size='small']),
116
+ .rio-button-group[data-variant='connected']
117
+ > .rio-tooltip-trigger
96
118
  > .rio-icon-button:where([data-size='xsmall'], [data-size='small']) {
97
119
  min-inline-size: 48px;
98
120
  }
package/src/dialog.css ADDED
@@ -0,0 +1,201 @@
1
+ /*
2
+ * M3 basic dialogs. `attachDialog` from `@rio-m3e/core` shows the `<dialog>` with `showModal()`,
3
+ * in the top layer above its scrim, centered in the window.
4
+ *
5
+ * Values come from Material Web's component tokens (`_md-comp-dialog.scss`, Material 3 v34.0.21)
6
+ * and the spec page's measurements: 280px to 560px wide, 24px padding, 16px from the icon to the
7
+ * headline and from the headline to the content, 24px from the content to the buttons, 8px
8
+ * between buttons. The scrim's color and 32% opacity come from `_md-comp-scrim.scss`.
9
+ */
10
+
11
+ /* How much of the container shows, from the top: it expands as the dialog opens. */
12
+ @property --_dialog-reveal {
13
+ syntax: '<percentage>';
14
+ inherits: true;
15
+ initial-value: 100%;
16
+ }
17
+
18
+ .rio-dialog {
19
+ box-sizing: border-box;
20
+ flex-direction: column;
21
+ min-inline-size: 280px;
22
+ max-inline-size: min(560px, 100% - 48px);
23
+ max-block-size: calc(100% - 48px);
24
+ margin: auto;
25
+ padding: 24px 0;
26
+ border: 0;
27
+ border-radius: var(--rio-shape-corner-extra-large);
28
+ outline: none;
29
+ /* The container is drawn behind the content, so it can expand; its shadow reaches past the box. */
30
+ isolation: isolate;
31
+ overflow: visible;
32
+ background: transparent;
33
+ color: var(--rio-color-on-surface-variant);
34
+ font: var(--rio-typescale-body-medium);
35
+ letter-spacing: var(--rio-typescale-body-medium-tracking);
36
+ overflow-wrap: break-word;
37
+ /* Closing */
38
+ transition:
39
+ opacity var(--rio-motion-fast-effects),
40
+ --_dialog-reveal var(--rio-motion-fast-spatial),
41
+ overlay var(--rio-motion-fast-effects) allow-discrete,
42
+ display var(--rio-motion-fast-effects) allow-discrete;
43
+ }
44
+
45
+ .rio-dialog::before {
46
+ content: '';
47
+ position: absolute;
48
+ z-index: -1;
49
+ inset: 0 0 auto;
50
+ block-size: var(--_dialog-reveal);
51
+ border-radius: inherit;
52
+ background-color: var(--rio-color-surface-container-high);
53
+ box-shadow: var(--rio-elevation-level3);
54
+ }
55
+
56
+ /*
57
+ * Opening: the container expands downward from the top, and its content fades in once the
58
+ * container is under it. Closing fades it all out as the container collapses.
59
+ */
60
+ .rio-dialog[open] {
61
+ display: flex;
62
+ transition:
63
+ opacity var(--rio-motion-fast-effects),
64
+ --_dialog-reveal var(--rio-motion-default-spatial),
65
+ overlay var(--rio-motion-fast-effects) allow-discrete,
66
+ display var(--rio-motion-fast-effects) allow-discrete;
67
+ }
68
+
69
+ .rio-dialog:not([open]) {
70
+ --_dialog-reveal: 35%;
71
+
72
+ opacity: 0;
73
+ }
74
+
75
+ .rio-dialog > * {
76
+ transition: opacity var(--rio-motion-fast-effects);
77
+ }
78
+
79
+ .rio-dialog[open] > * {
80
+ transition-delay: var(--rio-motion-fast-effects-duration);
81
+ }
82
+
83
+ @starting-style {
84
+ .rio-dialog[open] {
85
+ --_dialog-reveal: 35%;
86
+
87
+ opacity: 0;
88
+ }
89
+
90
+ .rio-dialog[open] > * {
91
+ opacity: 0;
92
+ }
93
+ }
94
+
95
+ /* Without spatial motion the container doesn't collapse at once as it starts fading out. */
96
+ @media (prefers-reduced-motion: reduce) {
97
+ .rio-dialog:not([open]) {
98
+ --_dialog-reveal: 100%;
99
+ }
100
+ }
101
+
102
+ .rio-dialog::backdrop {
103
+ background-color: color-mix(in srgb, var(--rio-color-scrim) 32%, transparent);
104
+ transition:
105
+ opacity var(--rio-motion-fast-effects),
106
+ overlay var(--rio-motion-fast-effects) allow-discrete,
107
+ display var(--rio-motion-fast-effects) allow-discrete;
108
+ }
109
+
110
+ .rio-dialog[open]::backdrop {
111
+ transition:
112
+ opacity var(--rio-motion-default-effects),
113
+ overlay var(--rio-motion-fast-effects) allow-discrete,
114
+ display var(--rio-motion-fast-effects) allow-discrete;
115
+ }
116
+
117
+ .rio-dialog:not([open])::backdrop {
118
+ opacity: 0;
119
+ }
120
+
121
+ @starting-style {
122
+ .rio-dialog[open]::backdrop {
123
+ opacity: 0;
124
+ }
125
+ }
126
+
127
+ /* Parts */
128
+
129
+ .rio-dialog__icon {
130
+ display: inline-flex;
131
+ flex: none;
132
+ align-self: center;
133
+ inline-size: 24px;
134
+ block-size: 24px;
135
+ margin-block-end: 16px;
136
+ color: var(--rio-color-secondary);
137
+ }
138
+
139
+ .rio-dialog__icon > :is(svg, img) {
140
+ inline-size: 100%;
141
+ block-size: 100%;
142
+ }
143
+
144
+ .rio-dialog__headline {
145
+ flex: none;
146
+ margin: 0 0 16px;
147
+ padding-inline: 24px;
148
+ color: var(--rio-color-on-surface);
149
+ font: var(--rio-typescale-headline-small);
150
+ letter-spacing: var(--rio-typescale-headline-small-tracking);
151
+ }
152
+
153
+ .rio-dialog[data-icon] .rio-dialog__headline {
154
+ text-align: center;
155
+ }
156
+
157
+ /*
158
+ * The headline and the buttons stay put while the content scrolls. A divider shows at the edge
159
+ * the content scrolls past, where it meets the headline or the buttons.
160
+ */
161
+ .rio-dialog__content {
162
+ --_divider-top: transparent;
163
+ --_divider-bottom: transparent;
164
+
165
+ flex: 1 1 auto;
166
+ min-block-size: 0;
167
+ padding-inline: 24px;
168
+ overflow-y: auto;
169
+ overscroll-behavior: contain;
170
+ box-shadow:
171
+ 0 -1px var(--_divider-top),
172
+ 0 1px var(--_divider-bottom);
173
+ }
174
+
175
+ .rio-dialog__content[data-overflow-top]:not(:first-child) {
176
+ --_divider-top: var(--rio-color-outline);
177
+ }
178
+
179
+ .rio-dialog__content[data-overflow-bottom]:not(:last-child) {
180
+ --_divider-bottom: var(--rio-color-outline);
181
+ }
182
+
183
+ /*
184
+ * Buttons sit at the end, the confirming one last, nearest the edge. When they don't fit side by
185
+ * side, they stack with the confirming one on top.
186
+ */
187
+ .rio-dialog__actions {
188
+ display: flex;
189
+ flex: none;
190
+ flex-wrap: wrap-reverse;
191
+ justify-content: flex-end;
192
+ gap: 8px;
193
+ margin-block-start: 24px;
194
+ padding-inline: 24px;
195
+ }
196
+
197
+ @media (forced-colors: active) {
198
+ .rio-dialog {
199
+ outline: 2px solid CanvasText;
200
+ }
201
+ }
package/src/menu.css ADDED
@@ -0,0 +1,255 @@
1
+ /*
2
+ * M3E vertical menu. `attachMenu` from `@rio-m3e/core` shows the menu in the top layer as a
3
+ * popover and places it next to its anchor (`base/anchored-position.css`), which also says where
4
+ * it ended up (`data-side`, `data-align`) and how much room there is.
5
+ *
6
+ * Values come from Material Web's component tokens (`_md-comp-menus.scss`, `-standard`,
7
+ * `-vibrant`, Material 3 v34.0.21). The spacing around the items comes from the M3 Design Kit: a
8
+ * 48px row per item, with the 44px item inset 2px above and below and 4px at the sides, so items
9
+ * sit 4px apart and 4px from the container's edges.
10
+ */
11
+
12
+ .rio-menu {
13
+ --_container: var(--rio-color-surface-container-low);
14
+ --_content: var(--rio-color-on-surface);
15
+ --_icon: var(--rio-color-on-surface-variant);
16
+ --_supporting: var(--rio-color-on-surface-variant);
17
+ --_selected-container: var(--rio-color-tertiary-container);
18
+ --_selected-content: var(--rio-color-on-tertiary-container);
19
+
20
+ /* Only while open: a `display` here would override the browser's hiding of closed popovers. */
21
+ flex-direction: column;
22
+ box-sizing: border-box;
23
+ /* Not in the tokens: the baseline menu's limits */
24
+ min-inline-size: 112px;
25
+ max-inline-size: min(280px, var(--rio-anchored-available-width, 280px));
26
+ max-block-size: var(--rio-anchored-available-height, none);
27
+ padding: 2px 4px;
28
+ overflow-x: hidden;
29
+ overflow-y: auto;
30
+ border: 0;
31
+ border-radius: var(--rio-shape-corner-large);
32
+ background-color: var(--_container);
33
+ color: var(--_content);
34
+ box-shadow: var(--rio-elevation-level2);
35
+ }
36
+
37
+ .rio-menu:where([data-variant='vibrant']) {
38
+ --_container: var(--rio-color-tertiary-container);
39
+ --_content: var(--rio-color-on-tertiary-container);
40
+ --_icon: var(--rio-color-on-tertiary-container);
41
+ --_supporting: var(--rio-color-on-tertiary-container);
42
+ --_selected-container: var(--rio-color-tertiary);
43
+ --_selected-content: var(--rio-color-on-tertiary);
44
+ }
45
+
46
+ /*
47
+ * Opening: the menu expands from the side facing its anchor and fades in; closing reverses it.
48
+ * Without `transition-behavior: allow-discrete` support for `overlay`, closing is instant.
49
+ */
50
+ .rio-menu {
51
+ --_origin-block: top;
52
+ --_origin-inline: left;
53
+
54
+ transform-origin: var(--_origin-inline) var(--_origin-block);
55
+ transition:
56
+ opacity var(--rio-motion-fast-effects),
57
+ scale var(--rio-motion-fast-spatial),
58
+ border-radius var(--rio-motion-fast-spatial),
59
+ overlay var(--rio-motion-fast-effects) allow-discrete,
60
+ display var(--rio-motion-fast-effects) allow-discrete;
61
+ }
62
+
63
+ /*
64
+ * With a submenu open, the menu the pointer or the focus is in keeps the active container shape
65
+ * (corner large), and the others take the inactive one (corner small), on the `fast-spatial` curve.
66
+ * `attachMenu` marks them with `data-inactive`.
67
+ */
68
+ .rio-menu[data-inactive] {
69
+ border-radius: var(--rio-shape-corner-small);
70
+ }
71
+
72
+ .rio-menu:popover-open {
73
+ display: flex;
74
+ }
75
+
76
+ .rio-menu:not(:popover-open) {
77
+ opacity: 0;
78
+ scale: 1 0.8;
79
+ }
80
+
81
+ @starting-style {
82
+ .rio-menu:popover-open {
83
+ opacity: 0;
84
+ scale: 1 0.8;
85
+ }
86
+ }
87
+
88
+ .rio-menu[data-side='top'] {
89
+ --_origin-block: bottom;
90
+ }
91
+
92
+ .rio-menu:is([data-side='start'], [data-side='end']) {
93
+ --_origin-block: top;
94
+ }
95
+
96
+ .rio-menu:is([data-align='end'], [data-side='start']):dir(ltr),
97
+ .rio-menu:not([data-align='end'], [data-side='start']):dir(rtl) {
98
+ --_origin-inline: right;
99
+ }
100
+
101
+ .rio-menu[data-instant] {
102
+ transition: none;
103
+ }
104
+
105
+ /* Items */
106
+
107
+ .rio-menu-item {
108
+ --_item-content: var(--_content);
109
+ --_item-icon: var(--_icon);
110
+ --_item-supporting: var(--_supporting);
111
+ --_item-container: transparent;
112
+ --_corner-block-start: var(--rio-shape-corner-extra-small);
113
+ --_corner-block-end: var(--rio-shape-corner-extra-small);
114
+
115
+ display: flex;
116
+ flex: none;
117
+ align-items: center;
118
+ gap: 12px;
119
+ box-sizing: border-box;
120
+ inline-size: 100%;
121
+ min-block-size: 44px;
122
+ margin: 2px 0;
123
+ padding: 8px 12px;
124
+ border: 0;
125
+ border-start-start-radius: var(--_corner-block-start);
126
+ border-start-end-radius: var(--_corner-block-start);
127
+ border-end-start-radius: var(--_corner-block-end);
128
+ border-end-end-radius: var(--_corner-block-end);
129
+ background-color: var(--_item-container);
130
+ color: var(--_item-content);
131
+ font: var(--rio-typescale-label-large);
132
+ letter-spacing: var(--rio-typescale-label-large-tracking);
133
+ text-align: start;
134
+ cursor: pointer;
135
+ user-select: none;
136
+ transition:
137
+ background-color var(--rio-motion-fast-effects),
138
+ color var(--rio-motion-fast-effects),
139
+ border-radius var(--rio-motion-fast-spatial);
140
+ --rio-focus-ring-color: var(--rio-color-secondary);
141
+ }
142
+
143
+ /* The first and last items of a menu or group round their outer corners to sit inside the container. */
144
+ .rio-menu-item:nth-child(1 of .rio-menu-item) {
145
+ --_corner-block-start: var(--rio-shape-corner-medium);
146
+ }
147
+
148
+ .rio-menu-item:nth-last-child(1 of .rio-menu-item) {
149
+ --_corner-block-end: var(--rio-shape-corner-medium);
150
+ }
151
+
152
+ .rio-menu-item[data-selected='true'] {
153
+ --_item-content: var(--_selected-content);
154
+ --_item-icon: var(--_selected-content);
155
+ --_item-supporting: var(--_selected-content);
156
+ --_item-container: var(--_selected-container);
157
+ --_corner-block-start: var(--rio-shape-corner-medium);
158
+ --_corner-block-end: var(--rio-shape-corner-medium);
159
+ }
160
+
161
+ /*
162
+ * The item whose submenu is open is active, with the hovered state layer
163
+ * (`menu-item.active.state-layer`), where `base/state-layer.css` would show a menu button's open
164
+ * menu as pressed. With the focus on it, that pressed layer stays, of the same strength as focus.
165
+ */
166
+ .rio-menu-item.rio-state-layer[aria-haspopup][aria-expanded='true']:not(:focus-visible)::before {
167
+ opacity: var(--rio-state-hover-state-layer-opacity);
168
+ }
169
+
170
+ .rio-menu-item[aria-disabled='true'] {
171
+ cursor: default;
172
+ }
173
+
174
+ .rio-menu-item[aria-disabled='true'] > :not(.rio-menu-item__touch) {
175
+ opacity: 0.38;
176
+ }
177
+
178
+ .rio-menu-item[aria-disabled='true'][data-selected='true'] {
179
+ --_item-container: color-mix(in srgb, var(--_selected-container) 38%, transparent);
180
+ }
181
+
182
+ .rio-menu-item__touch {
183
+ position: absolute;
184
+ inset: -2px 0;
185
+ }
186
+
187
+ .rio-menu-item__icon,
188
+ .rio-menu-item__trailing-icon {
189
+ display: inline-flex;
190
+ flex: none;
191
+ inline-size: 20px;
192
+ block-size: 20px;
193
+ color: var(--_item-icon);
194
+ }
195
+
196
+ .rio-menu-item__icon > :is(svg, img),
197
+ .rio-menu-item__trailing-icon > :is(svg, img) {
198
+ inline-size: 100%;
199
+ block-size: 100%;
200
+ }
201
+
202
+ .rio-menu-item__text {
203
+ display: flex;
204
+ flex: 1;
205
+ flex-direction: column;
206
+ min-inline-size: 0;
207
+ }
208
+
209
+ .rio-menu-item__label {
210
+ overflow: hidden;
211
+ text-overflow: ellipsis;
212
+ white-space: nowrap;
213
+ }
214
+
215
+ .rio-menu-item__supporting-text {
216
+ color: var(--_item-supporting);
217
+ font: var(--rio-typescale-body-small);
218
+ letter-spacing: var(--rio-typescale-body-small-tracking);
219
+ }
220
+
221
+ .rio-menu-item__trailing-text {
222
+ flex: none;
223
+ color: var(--_item-supporting);
224
+ }
225
+
226
+ /* Groups and dividers */
227
+
228
+ .rio-menu-group__items {
229
+ display: flex;
230
+ flex-direction: column;
231
+ }
232
+
233
+ .rio-menu-group__label {
234
+ display: flex;
235
+ align-items: center;
236
+ min-block-size: 32px;
237
+ padding-inline: 12px;
238
+ color: var(--_supporting);
239
+ font: var(--rio-typescale-label-large);
240
+ letter-spacing: var(--rio-typescale-label-large-tracking);
241
+ }
242
+
243
+ /* Not in the vertical menu's tokens: the baseline menu's divider, 1px of surface variant */
244
+ .rio-menu-divider {
245
+ flex: none;
246
+ block-size: 1px;
247
+ margin: 4px 12px;
248
+ background-color: var(--rio-color-surface-variant);
249
+ }
250
+
251
+ @media (forced-colors: active) {
252
+ .rio-menu {
253
+ border: 1px solid CanvasText;
254
+ }
255
+ }
@@ -0,0 +1,93 @@
1
+ /*
2
+ * M3 tooltips, plain and rich. `attachTooltip` from `@rio-m3e/core` shows the tooltip in the top
3
+ * layer as a popover and places it next to its element (`base/anchored-position.css`).
4
+ *
5
+ * Values come from Material Web's component tokens (`_md-comp-plain-tooltip.scss`,
6
+ * `_md-comp-rich-tooltip.scss`, Material 3 v34.0.21) and the spec page. Sizes the tokens leave out
7
+ * come from the M3 Design Kit: a plain tooltip at most 200px wide, a rich one at most 312px, with
8
+ * 4px between subhead and text and 12px from the text to the actions.
9
+ */
10
+
11
+ /* Wraps the element and the tooltip without a box, so the element lays out as if unwrapped. */
12
+ .rio-tooltip-trigger {
13
+ display: contents;
14
+ }
15
+
16
+ .rio-tooltip {
17
+ box-sizing: border-box;
18
+ max-inline-size: var(--rio-anchored-available-width, none);
19
+ border: 0;
20
+ overflow-wrap: break-word;
21
+ transition:
22
+ opacity var(--rio-motion-fast-effects),
23
+ overlay var(--rio-motion-fast-effects) allow-discrete,
24
+ display var(--rio-motion-fast-effects) allow-discrete;
25
+ }
26
+
27
+ /* Only while open: a `display` here would override the browser's hiding of closed popovers. */
28
+ .rio-tooltip:popover-open {
29
+ display: block;
30
+ }
31
+
32
+ .rio-tooltip:not(:popover-open) {
33
+ opacity: 0;
34
+ }
35
+
36
+ @starting-style {
37
+ .rio-tooltip:popover-open {
38
+ opacity: 0;
39
+ }
40
+ }
41
+
42
+ /* Plain: a brief label on the inverse surface, one 24px line high */
43
+
44
+ .rio-tooltip[data-variant='plain'] {
45
+ max-inline-size: min(200px, var(--rio-anchored-available-width, 200px));
46
+ min-block-size: 24px;
47
+ padding: 4px 8px;
48
+ border-radius: var(--rio-shape-corner-extra-small);
49
+ background-color: var(--rio-color-inverse-surface);
50
+ color: var(--rio-color-inverse-on-surface);
51
+ font: var(--rio-typescale-body-small);
52
+ letter-spacing: var(--rio-typescale-body-small-tracking);
53
+ }
54
+
55
+ /* Rich: a card with an optional subhead, the text, and up to two text buttons */
56
+
57
+ .rio-tooltip[data-variant='rich'] {
58
+ max-inline-size: min(312px, var(--rio-anchored-available-width, 312px));
59
+ padding: 12px 16px 8px;
60
+ border-radius: var(--rio-shape-corner-medium);
61
+ background-color: var(--rio-color-surface-container);
62
+ color: var(--rio-color-on-surface-variant);
63
+ box-shadow: var(--rio-elevation-level2);
64
+ font: var(--rio-typescale-body-medium);
65
+ letter-spacing: var(--rio-typescale-body-medium-tracking);
66
+ }
67
+
68
+ .rio-tooltip__subhead {
69
+ display: block;
70
+ margin-block-end: 4px;
71
+ font: var(--rio-typescale-title-small);
72
+ letter-spacing: var(--rio-typescale-title-small-tracking);
73
+ }
74
+
75
+ .rio-tooltip[data-variant='rich'] .rio-tooltip__supporting-text {
76
+ display: block;
77
+ padding-block-end: 4px;
78
+ }
79
+
80
+ /* The buttons sit 4px in from the container's edge. */
81
+ .rio-tooltip__actions {
82
+ display: flex;
83
+ flex-wrap: wrap;
84
+ gap: 8px;
85
+ margin-block-start: 8px;
86
+ margin-inline: -12px;
87
+ }
88
+
89
+ @media (forced-colors: active) {
90
+ .rio-tooltip {
91
+ border: 1px solid CanvasText;
92
+ }
93
+ }