@med-o/ui 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +38 -2
  3. package/dist/index.d.ts +2021 -0
  4. package/dist/index.js +4721 -0
  5. package/dist/index.js.map +1 -0
  6. package/package.json +78 -4
  7. package/src/accordion/accordion.css +184 -0
  8. package/src/alert/alert.css +147 -0
  9. package/src/avatar/avatar.css +221 -0
  10. package/src/badge/badge.css +153 -0
  11. package/src/bottom-sheet/bottom-sheet.css +202 -0
  12. package/src/breadcrumbs/breadcrumbs.css +147 -0
  13. package/src/bulk-action-bar/bulk-action-bar.css +98 -0
  14. package/src/button/button.css +319 -0
  15. package/src/card/card.css +217 -0
  16. package/src/checkbox/choice.css +196 -0
  17. package/src/combobox/combobox.css +125 -0
  18. package/src/date-time/date-time.css +474 -0
  19. package/src/dialog/dialog.css +319 -0
  20. package/src/drawer/drawer.css +156 -0
  21. package/src/empty-state/empty-state.css +161 -0
  22. package/src/field/field.css +115 -0
  23. package/src/link/link.css +103 -0
  24. package/src/list/list.css +172 -0
  25. package/src/list-view/list-view.css +473 -0
  26. package/src/listbox/listbox.css +203 -0
  27. package/src/media/media.css +298 -0
  28. package/src/menu/menu.css +183 -0
  29. package/src/navigation/navigation.css +626 -0
  30. package/src/pagination/pagination.css +132 -0
  31. package/src/popover/popover.css +166 -0
  32. package/src/progress/progress.css +225 -0
  33. package/src/search/search.css +309 -0
  34. package/src/select/select.css +229 -0
  35. package/src/slider/slider.css +212 -0
  36. package/src/styles.css +40 -0
  37. package/src/switch/switch.css +160 -0
  38. package/src/table/table.css +276 -0
  39. package/src/tabs/tabs.css +211 -0
  40. package/src/tag/tag.css +225 -0
  41. package/src/text-field/input.css +206 -0
  42. package/src/toast/toast.css +184 -0
  43. package/src/toggle-button/toggle-button.css +143 -0
  44. package/src/tooltip/tooltip.css +66 -0
  45. package/src/upload/upload.css +380 -0
  46. package/src/utils/utilities.css +14 -0
@@ -0,0 +1,212 @@
1
+ /**
2
+ * Slider – med.o Design System
3
+ *
4
+ * <div class="medo-slider" [data-disabled]>
5
+ * <div class="medo-slider__header"><label>Volume</label><output>40 %</output></div>
6
+ * <div class="medo-slider__track"> 20 high, 10 px inset on both ends
7
+ * rail (4, border/default) · ticks (2 × 6, border/strong) · fill (action/primary)
8
+ * <div class="medo-slider__thumb" [data-hovered] [data-dragging] [data-focus-visible]> 20 · hit area 44
9
+ * </div>
10
+ * <div class="medo-slider__limits">0 · 100</div>
11
+ * </div>
12
+ * Halo: hover 36 state/hover · pressed 40 state/pressed. Focus: 2 px focus/ring, 28 ring. Disabled 50 %.
13
+ */
14
+
15
+ .medo-slider {
16
+ display: grid;
17
+ gap: var(--medo-space-2);
18
+ inline-size: 100%;
19
+ min-inline-size: 0;
20
+ }
21
+
22
+ .medo-slider[data-disabled] {
23
+ opacity: 0.5;
24
+ }
25
+
26
+ .medo-slider__header {
27
+ display: flex;
28
+ align-items: baseline;
29
+ justify-content: space-between;
30
+ gap: var(--medo-space-3);
31
+ }
32
+
33
+ .medo-slider__label {
34
+ font: var(--medo-typography-label-md);
35
+ color: var(--medo-color-text-primary);
36
+ }
37
+
38
+ .medo-slider__value {
39
+ font: var(--medo-typography-body-sm);
40
+ font-variant-numeric: tabular-nums;
41
+ color: var(--medo-color-text-secondary);
42
+ white-space: nowrap;
43
+ }
44
+
45
+ /* The track is inset by 10 px, so the thumb never overflows the field; pointer positions map to it. */
46
+ .medo-slider__track {
47
+ position: relative;
48
+ block-size: var(--medo-space-5); /* 20 */
49
+ margin-inline: calc(var(--medo-space-2) + var(--medo-space-0-5)); /* 10 */
50
+ cursor: pointer;
51
+ }
52
+
53
+ .medo-slider[data-disabled] .medo-slider__track {
54
+ cursor: not-allowed;
55
+ }
56
+
57
+ .medo-slider__rail,
58
+ .medo-slider__fill {
59
+ position: absolute;
60
+ inset-block-start: 50%;
61
+ block-size: var(--medo-space-1); /* 4 */
62
+ border-radius: var(--medo-radius-full);
63
+ translate: 0 -50%;
64
+ }
65
+
66
+ .medo-slider__rail {
67
+ inset-inline: 0;
68
+ background-color: var(--medo-color-border-default);
69
+ }
70
+
71
+ .medo-slider__fill {
72
+ background-color: var(--medo-color-action-primary);
73
+ }
74
+
75
+ .medo-slider__ticks {
76
+ position: absolute;
77
+ inset-inline: 0;
78
+ inset-block-start: calc(var(--medo-space-4)); /* 16: below the track */
79
+ }
80
+
81
+ .medo-slider__tick {
82
+ position: absolute;
83
+ inline-size: var(--medo-space-0-5);
84
+ block-size: var(--medo-space-1-5);
85
+ border-radius: var(--medo-radius-full);
86
+ background-color: var(--medo-color-border-strong);
87
+ translate: -50% 0;
88
+ }
89
+
90
+ .medo-slider__thumb {
91
+ /* React Aria positions the thumb (left, top 50 %, translate -50 %). */
92
+ inset-block-start: 50%;
93
+ box-sizing: border-box;
94
+ inline-size: var(--medo-space-5); /* 20 */
95
+ block-size: var(--medo-space-5);
96
+ border: var(--medo-border-width-thick) solid var(--medo-color-action-primary);
97
+ border-radius: var(--medo-radius-full);
98
+ background-color: var(--medo-color-surface-default);
99
+ box-shadow: var(--medo-shadow-elevation-1);
100
+ transition:
101
+ box-shadow var(--medo-motion-duration-fast) var(--medo-motion-easing-standard),
102
+ left var(--medo-motion-spring-snappy-duration) var(--medo-motion-spring-snappy),
103
+ right var(--medo-motion-spring-snappy-duration) var(--medo-motion-spring-snappy);
104
+ }
105
+
106
+ /* 44 px hit area around the 20 px thumb. */
107
+ .medo-slider__thumb::before {
108
+ content: '';
109
+ position: absolute;
110
+ inset: calc(-1 * var(--medo-space-3));
111
+ border-radius: var(--medo-radius-full);
112
+ }
113
+
114
+ .medo-slider__thumb[data-hovered] {
115
+ box-shadow:
116
+ 0 0 0 var(--medo-space-2) var(--medo-color-state-hover),
117
+ var(--medo-shadow-elevation-1);
118
+ }
119
+
120
+ .medo-slider__thumb[data-dragging] {
121
+ box-shadow:
122
+ 0 0 0 calc(var(--medo-space-2) + var(--medo-space-0-5)) var(--medo-color-state-pressed),
123
+ var(--medo-shadow-elevation-1);
124
+ }
125
+
126
+ .medo-slider__thumb[data-focus-visible] {
127
+ outline: var(--medo-focus-ring-width) solid var(--medo-color-focus-ring);
128
+ outline-offset: var(--medo-space-0-5);
129
+ }
130
+
131
+ .medo-slider__thumb[data-disabled] {
132
+ cursor: not-allowed;
133
+ }
134
+
135
+ /* Value bubble while dragging – the Tooltip look, above the thumb. */
136
+ .medo-slider__bubble {
137
+ position: absolute;
138
+ inset-block-end: calc(100% + var(--medo-space-2));
139
+ inset-inline-start: 50%;
140
+ translate: -50% 0;
141
+ white-space: nowrap;
142
+ pointer-events: none;
143
+ }
144
+
145
+ .medo-slider__limits {
146
+ display: flex;
147
+ justify-content: space-between;
148
+ font: var(--medo-typography-caption);
149
+ font-variant-numeric: tabular-nums;
150
+ color: var(--medo-color-text-secondary);
151
+ }
152
+
153
+ /* ---------- Slider field ---------- */
154
+
155
+ .medo-slider-field {
156
+ display: grid;
157
+ gap: var(--medo-space-2);
158
+ }
159
+
160
+ /* Single: input 88 on the right, level with the track. */
161
+ .medo-slider-field--single {
162
+ grid-template-columns: 1fr 5.5rem;
163
+ align-items: end;
164
+ gap: var(--medo-space-4);
165
+ }
166
+
167
+ .medo-slider-field__inputs {
168
+ display: grid;
169
+ grid-template-columns: 1fr auto 1fr;
170
+ align-items: center;
171
+ gap: var(--medo-space-2);
172
+ }
173
+
174
+ .medo-slider-field__dash {
175
+ color: var(--medo-color-text-secondary);
176
+ }
177
+
178
+ /* Tabular figures, so digits do not jump while the value changes. */
179
+ .medo-number-field__control {
180
+ font-variant-numeric: tabular-nums;
181
+ }
182
+
183
+ /* A click on the track or a key moves thumb and fill with a snappy spring; while dragging they follow 1:1. */
184
+ .medo-slider__fill {
185
+ transition:
186
+ inset-inline-start var(--medo-motion-spring-snappy-duration) var(--medo-motion-spring-snappy),
187
+ inline-size var(--medo-motion-spring-snappy-duration) var(--medo-motion-spring-snappy);
188
+ }
189
+ .medo-slider__track:has(.medo-slider__thumb[data-dragging]) :is(.medo-slider__thumb, .medo-slider__fill) {
190
+ transition-property: box-shadow;
191
+ }
192
+
193
+ @media (prefers-reduced-motion: reduce) {
194
+ .medo-slider__thumb {
195
+ transition: box-shadow var(--medo-motion-duration-fast) var(--medo-motion-easing-standard);
196
+ }
197
+ .medo-slider__fill {
198
+ transition: none;
199
+ }
200
+ }
201
+
202
+ @media (forced-colors: active) {
203
+ .medo-slider__fill,
204
+ .medo-slider__thumb {
205
+ forced-color-adjust: none;
206
+ background-color: Highlight;
207
+ border-color: CanvasText;
208
+ }
209
+ .medo-slider__rail {
210
+ background-color: GrayText;
211
+ }
212
+ }
package/src/styles.css ADDED
@@ -0,0 +1,40 @@
1
+ /* All component styles of @med-o/ui. Needs the tokens: @import "@med-o/design-tokens/css"; */
2
+ @import './utils/utilities.css';
3
+ @import './button/button.css';
4
+ @import './field/field.css';
5
+ @import './text-field/input.css';
6
+ @import './checkbox/choice.css';
7
+ @import './switch/switch.css';
8
+ @import './badge/badge.css';
9
+ @import './tag/tag.css';
10
+ @import './avatar/avatar.css';
11
+ @import './tooltip/tooltip.css';
12
+ @import './progress/progress.css';
13
+ @import './list/list.css';
14
+ @import './list-view/list-view.css';
15
+ @import './bulk-action-bar/bulk-action-bar.css';
16
+ @import './empty-state/empty-state.css';
17
+ @import './pagination/pagination.css';
18
+ @import './search/search.css';
19
+ @import './breadcrumbs/breadcrumbs.css';
20
+ @import './accordion/accordion.css';
21
+ @import './slider/slider.css';
22
+ @import './toggle-button/toggle-button.css';
23
+ @import './listbox/listbox.css';
24
+ @import './select/select.css';
25
+ @import './combobox/combobox.css';
26
+ @import './bottom-sheet/bottom-sheet.css';
27
+ @import './menu/menu.css';
28
+ @import './dialog/dialog.css';
29
+ @import './drawer/drawer.css';
30
+ @import './link/link.css';
31
+ @import './alert/alert.css';
32
+ @import './toast/toast.css';
33
+ @import './tabs/tabs.css';
34
+ @import './popover/popover.css';
35
+ @import './navigation/navigation.css';
36
+ @import './card/card.css';
37
+ @import './table/table.css';
38
+ @import './upload/upload.css';
39
+ @import './date-time/date-time.css';
40
+ @import './media/media.css';
@@ -0,0 +1,160 @@
1
+ /**
2
+ * Switch – med.o Design System
3
+ * On / off that takes effect immediately (no submit). The label never changes with the state.
4
+ *
5
+ * State contract: [data-selected] [data-hovered] [data-focus-visible] [data-disabled] [data-readonly]
6
+ * Label position: start (settings lists, switch at the end) or end (forms, switch first).
7
+ */
8
+
9
+ .medo-switch {
10
+ --_track-w: calc(var(--medo-space-8) + var(--medo-space-1));
11
+ --_track-h: var(--medo-space-5);
12
+ --_thumb: var(--medo-space-4);
13
+ --_pad: var(--medo-space-0-5);
14
+ --_track: var(--medo-color-action-toggle-off);
15
+ --_gap: var(--medo-space-2);
16
+
17
+ display: flex;
18
+ flex-direction: column;
19
+ font: var(--medo-typography-body-sm);
20
+ color: var(--medo-color-text-primary);
21
+ }
22
+
23
+ .medo-switch--lg {
24
+ --_track-w: calc(var(--medo-space-10) + var(--medo-space-1));
25
+ --_track-h: var(--medo-space-6);
26
+ --_thumb: var(--medo-space-5);
27
+ font: var(--medo-typography-body-md);
28
+ }
29
+
30
+ .medo-switch__button {
31
+ display: inline-flex;
32
+ align-items: flex-start;
33
+ gap: var(--_gap);
34
+ inline-size: fit-content;
35
+ cursor: pointer;
36
+ }
37
+
38
+ .medo-switch--label-start .medo-switch__button {
39
+ --_gap: var(--medo-space-4);
40
+ flex-direction: row-reverse;
41
+ justify-content: space-between;
42
+ inline-size: 100%;
43
+ }
44
+
45
+ .medo-switch__track {
46
+ box-sizing: border-box;
47
+ display: flex;
48
+ align-items: center;
49
+ flex-shrink: 0;
50
+ inline-size: var(--_track-w);
51
+ block-size: var(--_track-h);
52
+ padding: var(--_pad);
53
+ border-radius: var(--medo-radius-full);
54
+ background-color: var(--_track);
55
+ transition: background-color var(--medo-motion-duration-fast) var(--medo-motion-easing-standard);
56
+ }
57
+
58
+ .medo-switch__thumb {
59
+ display: grid;
60
+ place-items: center;
61
+ inline-size: var(--_thumb);
62
+ block-size: var(--_thumb);
63
+ border-radius: var(--medo-radius-full);
64
+ background-color: var(--medo-color-text-on-action);
65
+ color: var(--_track);
66
+ /* The thumb moves with a snappy spring (iOS). */
67
+ transition:
68
+ transform var(--medo-motion-spring-snappy-duration) var(--medo-motion-spring-snappy),
69
+ color var(--medo-motion-duration-fast) var(--medo-motion-easing-standard);
70
+ }
71
+
72
+ .medo-switch__thumb > svg {
73
+ inline-size: 70%;
74
+ block-size: 70%;
75
+ stroke-width: 3;
76
+ }
77
+
78
+ .medo-switch__description {
79
+ font: var(--medo-typography-body-sm);
80
+ color: var(--medo-color-text-secondary);
81
+ }
82
+
83
+ .medo-switch--label-end .medo-switch__description {
84
+ margin-inline-start: calc(var(--_track-w) + var(--_gap));
85
+ }
86
+
87
+ /* ---------- States ---------- */
88
+
89
+ .medo-switch__button[data-hovered] {
90
+ --_track: var(--medo-color-action-toggle-off-hover);
91
+ }
92
+
93
+ .medo-switch[data-selected] {
94
+ --_track: var(--medo-color-action-primary);
95
+ }
96
+
97
+ .medo-switch[data-selected] .medo-switch__button[data-hovered] {
98
+ --_track: var(--medo-color-action-primary-hover);
99
+ }
100
+
101
+ .medo-switch[data-selected] .medo-switch__thumb {
102
+ transform: translateX(calc(var(--_track-w) - var(--_thumb) - 2 * var(--_pad)));
103
+ }
104
+
105
+ .medo-switch[data-selected]:dir(rtl) .medo-switch__thumb {
106
+ transform: translateX(calc(-1 * (var(--_track-w) - var(--_thumb) - 2 * var(--_pad))));
107
+ }
108
+
109
+ .medo-switch__button[data-focus-visible] .medo-switch__track {
110
+ box-shadow: var(--medo-shadow-focus-ring);
111
+ }
112
+
113
+ .medo-switch[data-disabled] {
114
+ --_track: var(--medo-color-border-default);
115
+ color: var(--medo-color-text-disabled);
116
+ }
117
+
118
+ .medo-switch[data-disabled] .medo-switch__button {
119
+ cursor: not-allowed;
120
+ }
121
+
122
+ .medo-switch[data-disabled] .medo-switch__thumb {
123
+ background-color: var(--medo-color-surface-default);
124
+ color: var(--medo-color-text-disabled);
125
+ }
126
+
127
+ .medo-switch[aria-busy='true'] .medo-switch__button {
128
+ cursor: progress;
129
+ }
130
+
131
+ .medo-switch__spinner {
132
+ animation: medo-switch-spin 0.8s linear infinite;
133
+ }
134
+
135
+ @keyframes medo-switch-spin {
136
+ to {
137
+ transform: rotate(1turn);
138
+ }
139
+ }
140
+
141
+ @media (forced-colors: active) {
142
+ .medo-switch__track {
143
+ border: var(--medo-border-width-thin) solid CanvasText;
144
+ }
145
+ .medo-switch[data-selected] .medo-switch__track {
146
+ background-color: Highlight;
147
+ }
148
+ }
149
+
150
+ @media (prefers-reduced-motion: reduce) {
151
+ /* Reduced motion: a short, plain move – the state change stays visible. */
152
+ .medo-switch__thumb {
153
+ transition:
154
+ transform var(--medo-motion-duration-fast) var(--medo-motion-easing-standard),
155
+ color var(--medo-motion-duration-fast) var(--medo-motion-easing-standard);
156
+ }
157
+ .medo-switch__spinner {
158
+ animation-duration: 3s;
159
+ }
160
+ }
@@ -0,0 +1,276 @@
1
+ /**
2
+ * Table – med.o Design System
3
+ *
4
+ * One look for two kinds of tables:
5
+ * Static (content, docs, simple data): a native <table> – read like a table, not navigable cell by cell.
6
+ * <div class="medo-table-container"><table class="medo-table">…</table></div>
7
+ * Interactive (sort, select): React Aria Table (role grid) with the same classes.
8
+ *
9
+ * Text left, numbers right with tabular figures (class medo-table__cell--number or align="end").
10
+ * Density: standard (rows 48, header 40) · compact (rows 40, header 36).
11
+ *
12
+ * State contract (interactive rows): [data-hovered] [data-pressed] [data-selected] [data-focus-visible] [data-disabled]
13
+ * Sortable header: [data-allows-sorting] [data-sort-direction] (aria-sort is set too).
14
+ */
15
+
16
+ .medo-table-container {
17
+ box-sizing: border-box;
18
+ inline-size: 100%;
19
+ overflow: auto;
20
+ border: var(--medo-border-width-thin) solid var(--medo-color-border-default);
21
+ border-radius: var(--medo-radius-lg);
22
+ background-color: var(--medo-color-surface-default);
23
+ }
24
+
25
+ /* Without the frame, e.g. inside a card or a documentation page. */
26
+ .medo-table-container--plain {
27
+ border: 0;
28
+ border-radius: 0;
29
+ background-color: transparent;
30
+ }
31
+
32
+ .medo-table {
33
+ --_row: var(--medo-space-12);
34
+ --_head: var(--medo-space-10);
35
+ --_pad: var(--medo-space-4);
36
+
37
+ inline-size: 100%;
38
+ border-collapse: separate;
39
+ border-spacing: 0;
40
+ font: var(--medo-typography-body-sm);
41
+ color: var(--medo-color-text-primary);
42
+ text-align: start;
43
+ }
44
+
45
+ .medo-table--compact {
46
+ --_row: var(--medo-space-10);
47
+ --_head: calc(var(--medo-space-8) + var(--medo-space-1)); /* 36 */
48
+ --_pad: var(--medo-space-3);
49
+ }
50
+
51
+ .medo-table caption {
52
+ padding: var(--medo-space-3) var(--_pad);
53
+ font: var(--medo-typography-label-md);
54
+ text-align: start;
55
+ }
56
+
57
+ /* ---------- Header ---------- */
58
+
59
+ .medo-table__column,
60
+ .medo-table thead th {
61
+ position: sticky;
62
+ inset-block-start: 0;
63
+ z-index: 1;
64
+ block-size: var(--_head);
65
+ padding: 0 var(--_pad);
66
+ border-block-end: var(--medo-border-width-thin) solid var(--medo-color-border-default);
67
+ background-color: var(--medo-color-surface-subtle);
68
+ font: var(--medo-typography-label-sm);
69
+ color: var(--medo-color-text-secondary);
70
+ text-align: start;
71
+ vertical-align: middle;
72
+ white-space: nowrap;
73
+ outline: none;
74
+ }
75
+
76
+ .medo-table__column[data-allows-sorting] {
77
+ cursor: pointer;
78
+ user-select: none;
79
+ }
80
+
81
+ .medo-table__column {
82
+ transition: color var(--medo-motion-duration-fast) var(--medo-motion-easing-standard);
83
+ }
84
+ .medo-table__column[data-hovered] {
85
+ color: var(--medo-color-text-primary);
86
+ }
87
+
88
+ .medo-table__column[data-focus-visible] {
89
+ box-shadow: var(--medo-shadow-focus-ring-inset);
90
+ }
91
+
92
+ .medo-table__column[aria-sort='ascending'],
93
+ .medo-table__column[aria-sort='descending'] {
94
+ font: var(--medo-typography-label-sm-strong);
95
+ color: var(--medo-color-text-primary);
96
+ }
97
+
98
+ .medo-table__column-inner {
99
+ display: inline-flex;
100
+ vertical-align: middle;
101
+ align-items: center;
102
+ gap: var(--medo-space-1);
103
+ }
104
+
105
+ .medo-table__sort {
106
+ inline-size: calc(var(--medo-space-3) + var(--medo-space-0-5)); /* 14 */
107
+ block-size: calc(var(--medo-space-3) + var(--medo-space-0-5));
108
+ stroke-width: 2.5;
109
+ }
110
+
111
+ /* Unsorted sortable columns show the arrow on hover and focus only. */
112
+ .medo-table__sort {
113
+ transition: opacity var(--medo-motion-duration-fast) var(--medo-motion-easing-standard);
114
+ }
115
+ .medo-table__column:not([aria-sort='ascending'], [aria-sort='descending']) .medo-table__sort {
116
+ opacity: 0;
117
+ }
118
+ .medo-table__column:is([data-hovered], [data-focus-visible]) .medo-table__sort {
119
+ opacity: 1;
120
+ }
121
+
122
+ /* ---------- Rows and cells ---------- */
123
+
124
+ .medo-table__row,
125
+ .medo-table tbody tr {
126
+ outline: none;
127
+ }
128
+
129
+ .medo-table__cell,
130
+ .medo-table tbody :is(td, th) {
131
+ block-size: var(--_row);
132
+ padding: var(--medo-space-2) var(--_pad);
133
+ border-block-end: var(--medo-border-width-thin) solid var(--medo-color-border-default);
134
+ vertical-align: middle;
135
+ text-align: start;
136
+ outline: none;
137
+ }
138
+
139
+ .medo-table tbody th {
140
+ font-weight: var(--medo-font-weight-medium);
141
+ }
142
+
143
+ .medo-table tbody tr:last-child > *,
144
+ .medo-table__row:last-child > .medo-table__cell {
145
+ border-block-end: 0;
146
+ }
147
+
148
+ /* Numbers: right, tabular, never truncated. */
149
+ .medo-table :is(th, td, .medo-table__column, .medo-table__cell):is(.medo-table__cell--number, [data-align='end']) {
150
+ text-align: end;
151
+ font-variant-numeric: tabular-nums;
152
+ white-space: nowrap;
153
+ }
154
+
155
+ .medo-table__column[data-align='end'] .medo-table__column-inner {
156
+ flex-direction: row-reverse;
157
+ }
158
+
159
+ /* Skeletons in number columns sit on the right, like the numbers will. */
160
+ .medo-table :is(.medo-table__cell--number, [data-align='end']) .medo-skeleton {
161
+ margin-inline-start: auto;
162
+ }
163
+
164
+ /* Utility columns (checkbox, actions, chevron) */
165
+ .medo-table :is(.medo-table__cell--utility, .medo-table__column--utility) {
166
+ inline-size: var(--medo-space-12);
167
+ padding-inline: var(--medo-space-4) 0;
168
+ }
169
+
170
+ /* Row feedback fades; pressed shows at once (iOS highlight). */
171
+ .medo-table__row > .medo-table__cell {
172
+ transition: background-color var(--medo-motion-duration-fast) var(--medo-motion-easing-standard);
173
+ }
174
+ .medo-table__row[data-pressed] > .medo-table__cell {
175
+ transition-duration: 0s;
176
+ }
177
+
178
+ .medo-table__row[data-hovered] > .medo-table__cell {
179
+ background-color: var(--medo-color-state-hover);
180
+ }
181
+
182
+ .medo-table__row[data-pressed] > .medo-table__cell {
183
+ background-color: var(--medo-color-state-pressed);
184
+ }
185
+
186
+ .medo-table__row[data-selected] > .medo-table__cell {
187
+ background-color: var(--medo-color-action-selected);
188
+ }
189
+
190
+ .medo-table__row[data-selected][data-hovered] > .medo-table__cell {
191
+ background-color: var(--medo-color-action-selected-hover);
192
+ }
193
+
194
+ .medo-table__row[data-focus-visible] > .medo-table__cell:first-child {
195
+ box-shadow: inset var(--medo-focus-ring-width) 0 0 var(--medo-color-focus-ring);
196
+ }
197
+
198
+ .medo-table__row[data-focus-visible] {
199
+ outline: var(--medo-focus-ring-width) solid var(--medo-color-focus-ring);
200
+ outline-offset: calc(-1 * var(--medo-focus-ring-width));
201
+ }
202
+
203
+ .medo-table__cell[data-focus-visible] {
204
+ box-shadow: var(--medo-shadow-focus-ring-inset);
205
+ }
206
+
207
+ .medo-table__row[data-disabled] {
208
+ color: var(--medo-color-text-disabled);
209
+ }
210
+
211
+ .medo-table__row[data-href],
212
+ .medo-table__row[data-selection-mode] {
213
+ cursor: pointer;
214
+ }
215
+
216
+ /* Optional zebra stripes for wide, dense data. */
217
+ .medo-table--striped tbody tr:nth-child(even) > *,
218
+ .medo-table--striped .medo-table__row:nth-child(even) > .medo-table__cell {
219
+ background-color: var(--medo-color-surface-subtle);
220
+ }
221
+
222
+ /* Empty and loading states fill the body; toolbar and header stay. */
223
+ .medo-table__empty {
224
+ padding: var(--medo-space-12) var(--_pad);
225
+ text-align: center;
226
+ color: var(--medo-color-text-secondary);
227
+ }
228
+
229
+ @media (forced-colors: active) {
230
+ .medo-table__row[data-selected] > .medo-table__cell {
231
+ forced-color-adjust: none;
232
+ background-color: Highlight;
233
+ color: HighlightText;
234
+ }
235
+ .medo-table__row[data-focus-visible] {
236
+ outline-color: Highlight;
237
+ }
238
+ }
239
+
240
+ /* ---------- Frame: toolbar – table – footer in one bordered surface ---------- */
241
+
242
+ .medo-table-frame {
243
+ box-sizing: border-box;
244
+ display: flex;
245
+ flex-direction: column;
246
+ inline-size: 100%;
247
+ overflow: hidden;
248
+ border: var(--medo-border-width-thin) solid var(--medo-color-border-default);
249
+ border-radius: var(--medo-radius-lg);
250
+ background-color: var(--medo-color-surface-default);
251
+ }
252
+
253
+ .medo-table-frame--plain {
254
+ border: 0;
255
+ border-radius: 0;
256
+ background-color: transparent;
257
+ }
258
+
259
+ /* Search, filter, columns – spacer – primary action. Wraps on narrow screens. */
260
+ .medo-table__toolbar {
261
+ display: flex;
262
+ flex-wrap: wrap;
263
+ align-items: center;
264
+ gap: var(--medo-space-2);
265
+ padding: var(--medo-space-3) var(--medo-space-4);
266
+ }
267
+
268
+ .medo-table__footer {
269
+ padding: var(--medo-space-3) var(--medo-space-4);
270
+ border-block-start: var(--medo-border-width-thin) solid var(--medo-color-border-default);
271
+ }
272
+
273
+ /* Rows above the footer keep their bottom divider only between rows. */
274
+ .medo-table-frame .medo-table__row:last-child > .medo-table__cell {
275
+ border-block-end: 0;
276
+ }