@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,298 @@
1
+ /**
2
+ * Image & Media – med.o Design System
3
+ *
4
+ * <div class="medo-image medo-image--cover medo-image--radius-md" data-state="loading|loaded|error" style="aspect-ratio">
5
+ * preview (blur-up) | Skeleton · <img class="medo-image__img"> · error (image-off) · overlay · badge · play
6
+ * </div>
7
+ * Surface surface/subtle · radius/md · optional 1 px border/media inside · fade-in 250 ms (100 ms with reduced motion)
8
+ * Overlay: gradient transparent → overlay/media, 55 % (min 96), padding 16, title heading/sm + meta caption, text/on-media
9
+ * Badge inset 12 · Play md 48 / lg 64, overlay/media, icon 20 / 28, hover/pressed/focus from the surrounding link
10
+ * Figure gap space/2 · caption body/sm · credit caption · text/secondary
11
+ * Embed consent surface/subtle + border/default · radius/md · Default padding space/8 · Compact (< 480) padding space/4
12
+ */
13
+
14
+ /* ---------- Image ---------- */
15
+
16
+ .medo-image {
17
+ position: relative;
18
+ overflow: hidden;
19
+ inline-size: 100%;
20
+ min-inline-size: 0; /* no content-based minimum from the aspect ratio */
21
+ background-color: var(--medo-color-surface-subtle);
22
+ isolation: isolate;
23
+ }
24
+
25
+ .medo-image--radius-none {
26
+ border-radius: 0;
27
+ }
28
+ .medo-image--radius-sm {
29
+ border-radius: var(--medo-radius-sm);
30
+ }
31
+ .medo-image--radius-md {
32
+ border-radius: var(--medo-radius-md);
33
+ }
34
+ .medo-image--radius-lg {
35
+ border-radius: var(--medo-radius-lg);
36
+ }
37
+
38
+ .medo-image__img {
39
+ display: block;
40
+ inline-size: 100%;
41
+ block-size: 100%;
42
+ object-fit: cover;
43
+ opacity: 1;
44
+ transition: opacity var(--medo-motion-duration-normal) var(--medo-motion-easing-standard);
45
+ }
46
+
47
+ .medo-image--contain .medo-image__img {
48
+ object-fit: contain;
49
+ }
50
+
51
+ /* Hidden while loading, fades in once loaded. */
52
+ .medo-image[data-state='loading'] .medo-image__img {
53
+ opacity: 0;
54
+ }
55
+
56
+ .medo-image__skeleton,
57
+ .medo-image__preview,
58
+ .medo-image__error {
59
+ position: absolute;
60
+ inset: 0;
61
+ inline-size: 100%;
62
+ block-size: 100%;
63
+ }
64
+
65
+ .medo-image__skeleton {
66
+ border-radius: 0;
67
+ }
68
+
69
+ /* Blur-up: the tiny preview, larger than the frame so the soft blur edge is cut off. */
70
+ .medo-image__preview {
71
+ inset: calc(-2 * var(--medo-space-6));
72
+ inline-size: calc(100% + 4 * var(--medo-space-6));
73
+ block-size: calc(100% + 4 * var(--medo-space-6));
74
+ max-inline-size: none; /* global img resets cap it at 100 % */
75
+ object-fit: cover;
76
+ filter: blur(var(--medo-space-6));
77
+ }
78
+
79
+ .medo-image__error {
80
+ display: grid;
81
+ place-items: center;
82
+ color: var(--medo-color-text-secondary);
83
+ }
84
+
85
+ .medo-image__error > svg {
86
+ inline-size: var(--medo-size-icon-lg);
87
+ block-size: var(--medo-size-icon-lg);
88
+ }
89
+
90
+ /* 1 px border/media inside, above the image. */
91
+ .medo-image--bordered::after {
92
+ content: '';
93
+ position: absolute;
94
+ inset: 0;
95
+ z-index: 2;
96
+ border: var(--medo-border-width-thin) solid var(--medo-color-border-media);
97
+ border-radius: inherit;
98
+ pointer-events: none;
99
+ }
100
+
101
+ /* Text overlay on a gradient – white text keeps ≥ 4.5 : 1 even on white images. */
102
+ .medo-image__overlay {
103
+ position: absolute;
104
+ inset-inline: 0;
105
+ z-index: 1;
106
+ box-sizing: border-box;
107
+ display: flex;
108
+ flex-direction: column;
109
+ gap: var(--medo-space-0-5);
110
+ block-size: 55%;
111
+ min-block-size: var(--medo-space-24);
112
+ padding: var(--medo-space-4);
113
+ color: var(--medo-color-text-on-media);
114
+ }
115
+
116
+ .medo-image__overlay--bottom {
117
+ inset-block-end: 0;
118
+ justify-content: flex-end;
119
+ background-image: linear-gradient(to bottom, transparent, var(--medo-color-overlay-media));
120
+ }
121
+
122
+ .medo-image__overlay--top {
123
+ inset-block-start: 0;
124
+ justify-content: flex-start;
125
+ background-image: linear-gradient(to top, transparent, var(--medo-color-overlay-media));
126
+ }
127
+
128
+ .medo-image__title {
129
+ font: var(--medo-typography-heading-sm);
130
+ }
131
+
132
+ .medo-image__meta {
133
+ font: var(--medo-typography-caption);
134
+ }
135
+
136
+ .medo-image__badge {
137
+ position: absolute;
138
+ inset-block-start: var(--medo-space-3);
139
+ inset-inline-start: var(--medo-space-3);
140
+ z-index: 1;
141
+ display: flex;
142
+ }
143
+
144
+ .medo-image__play {
145
+ position: absolute;
146
+ inset: 50% auto auto 50%;
147
+ z-index: 1;
148
+ translate: -50% -50%;
149
+ }
150
+
151
+ /* Play button tint follows the thumbnail link. */
152
+ .medo-media-play {
153
+ transition:
154
+ background-color var(--medo-motion-duration-fast) var(--medo-motion-easing-standard),
155
+ box-shadow var(--medo-motion-duration-fast) var(--medo-motion-easing-standard);
156
+ }
157
+
158
+ @media (prefers-reduced-motion: reduce) {
159
+ .medo-image__img {
160
+ transition-duration: var(--medo-motion-duration-fast);
161
+ }
162
+ }
163
+
164
+ /* ---------- Media play button ---------- */
165
+
166
+ .medo-media-play {
167
+ --_tint: transparent;
168
+ display: inline-grid;
169
+ place-items: center;
170
+ inline-size: var(--medo-size-control-lg); /* 48 */
171
+ block-size: var(--medo-size-control-lg);
172
+ border-radius: var(--medo-radius-full);
173
+ background-color: var(--medo-color-overlay-media);
174
+ background-image: linear-gradient(var(--_tint), var(--_tint));
175
+ color: var(--medo-color-text-on-media);
176
+ }
177
+
178
+ .medo-media-play > svg {
179
+ inline-size: var(--medo-size-icon-md); /* 20 */
180
+ block-size: var(--medo-size-icon-md);
181
+ margin-inline-start: var(--medo-space-0-5); /* optical centre of the triangle */
182
+ }
183
+
184
+ .medo-media-play--lg {
185
+ inline-size: var(--medo-space-16); /* 64 */
186
+ block-size: var(--medo-space-16);
187
+ }
188
+
189
+ .medo-media-play--lg > svg {
190
+ inline-size: calc(var(--medo-size-icon-lg) + var(--medo-space-1)); /* 28 */
191
+ block-size: calc(var(--medo-size-icon-lg) + var(--medo-space-1));
192
+ }
193
+
194
+ /* States come from the thumbnail link or button around it. */
195
+ :is(a, button, [role='link'], [role='button']):is(:hover, [data-hovered]) .medo-media-play {
196
+ --_tint: var(--medo-color-state-hover-on-media);
197
+ }
198
+
199
+ :is(a, button, [role='link'], [role='button']):is(:active, [data-pressed]) .medo-media-play {
200
+ --_tint: var(--medo-color-state-pressed-on-media);
201
+ }
202
+
203
+ :is(a, button, [role='link'], [role='button']):is(:focus-visible, [data-focus-visible]) .medo-media-play {
204
+ box-shadow: var(--medo-shadow-focus-ring);
205
+ }
206
+
207
+ /* ---------- Figure ---------- */
208
+
209
+ .medo-figure {
210
+ display: grid;
211
+ gap: var(--medo-space-2);
212
+ margin: 0;
213
+ }
214
+
215
+ .medo-figure__caption {
216
+ display: grid;
217
+ gap: var(--medo-space-0-5);
218
+ font: var(--medo-typography-body-sm);
219
+ color: var(--medo-color-text-secondary);
220
+ }
221
+
222
+ .medo-figure__credit {
223
+ font: var(--medo-typography-caption);
224
+ }
225
+
226
+ /* ---------- Embed consent ---------- */
227
+
228
+ .medo-embed {
229
+ box-sizing: border-box;
230
+ display: flex;
231
+ flex-direction: column;
232
+ align-items: center;
233
+ justify-content: center;
234
+ gap: var(--medo-space-4);
235
+ inline-size: 100%;
236
+ min-inline-size: 0; /* no content-based minimum from the aspect ratio */
237
+ padding: var(--medo-space-8);
238
+ border: var(--medo-border-width-thin) solid var(--medo-color-border-default);
239
+ border-radius: var(--medo-radius-md);
240
+ background-color: var(--medo-color-surface-subtle);
241
+ text-align: center;
242
+ }
243
+
244
+ .medo-embed--compact {
245
+ gap: var(--medo-space-3);
246
+ padding: var(--medo-space-4);
247
+ }
248
+
249
+ .medo-embed__content {
250
+ display: grid;
251
+ gap: var(--medo-space-1);
252
+ max-inline-size: 27.5rem; /* 440 – readable line length */
253
+ }
254
+
255
+ .medo-embed__title,
256
+ .medo-embed__body {
257
+ margin: 0;
258
+ }
259
+
260
+ .medo-embed__title {
261
+ font: var(--medo-typography-label-lg);
262
+ color: var(--medo-color-text-primary);
263
+ }
264
+
265
+ .medo-embed--compact .medo-embed__title {
266
+ font: var(--medo-typography-label-md);
267
+ }
268
+
269
+ .medo-embed__body {
270
+ font: var(--medo-typography-body-sm);
271
+ color: var(--medo-color-text-secondary);
272
+ }
273
+
274
+ .medo-embed__actions {
275
+ display: flex;
276
+ flex-wrap: wrap;
277
+ align-items: center;
278
+ justify-content: center;
279
+ gap: var(--medo-space-2) var(--medo-space-4);
280
+ }
281
+
282
+ .medo-embed--loaded {
283
+ padding: 0;
284
+ overflow: hidden;
285
+ background-color: var(--medo-color-surface-subtle);
286
+ }
287
+
288
+ .medo-embed__frame {
289
+ display: block;
290
+ inline-size: 100%;
291
+ block-size: 100%;
292
+ border: 0;
293
+ }
294
+
295
+ .medo-embed__frame:focus-visible {
296
+ outline: var(--medo-focus-ring-width) solid var(--medo-color-focus-ring);
297
+ outline-offset: calc(-1 * var(--medo-focus-ring-width));
298
+ }
@@ -0,0 +1,183 @@
1
+ /**
2
+ * Menu – med.o Design System
3
+ *
4
+ * A list of actions that opens from a trigger. Popover on desktop, Bottom Sheet below 640 px.
5
+ * <div class="medo-menu-popover"> surface/raised, border, elevation/2, radius/md
6
+ * <div class="medo-menu medo-menu--md" role="menu"> padding + gap 4
7
+ * <section class="medo-menu__section">
8
+ * <header class="medo-listbox__header">Group</header>
9
+ * <div class="medo-menu-item [medo-menu-item--danger]" role="menuitem">
10
+ * <span class="medo-menu-item__icon">…</span>
11
+ * <span class="medo-menu-item__label">Duplicate</span>
12
+ * <kbd class="medo-menu-item__shortcut">⌘ D</kbd> (desktop)
13
+ * <span class="medo-menu-item__chevron">›</span> (submenu)
14
+ * </div>
15
+ * </section>
16
+ * </div>
17
+ * </div>
18
+ * State contract: [data-focused] [data-hovered] [data-pressed] [data-disabled] [data-has-submenu] [data-open]
19
+ */
20
+
21
+ .medo-menu-popover {
22
+ box-sizing: border-box;
23
+ min-inline-size: 11.25rem; /* 180 */
24
+ inline-size: 15rem; /* 240 */
25
+ max-inline-size: min(20rem, calc(100vw - 2 * var(--medo-space-4))); /* 320 */
26
+ border: var(--medo-border-width-thin) solid var(--medo-color-border-default);
27
+ border-radius: var(--medo-radius-md);
28
+ background-color: var(--medo-color-surface-raised);
29
+ box-shadow: var(--medo-shadow-elevation-2);
30
+ z-index: var(--medo-layer-dropdown);
31
+ outline: none;
32
+ overflow: auto;
33
+ }
34
+
35
+ /* Motion (iOS): grows from the trigger with a snappy spring and fades in; out: a quick fade. Transitions, so a fast open–close reverses smoothly. */
36
+ .medo-menu-popover {
37
+ transform-origin: var(--trigger-anchor-point, top);
38
+ transition:
39
+ opacity var(--medo-motion-duration-normal) var(--medo-motion-easing-enter),
40
+ scale var(--medo-motion-spring-snappy-duration) var(--medo-motion-spring-snappy);
41
+ }
42
+ .medo-menu-popover[data-entering] {
43
+ opacity: 0;
44
+ scale: 0.96;
45
+ }
46
+ .medo-menu-popover[data-exiting] {
47
+ opacity: 0;
48
+ scale: 0.98;
49
+ transition:
50
+ opacity var(--medo-motion-duration-fast) var(--medo-motion-easing-exit),
51
+ scale var(--medo-motion-duration-fast) var(--medo-motion-easing-exit);
52
+ }
53
+
54
+ .medo-menu {
55
+ --_pad: var(--medo-space-2);
56
+ --_label: var(--medo-typography-body-sm);
57
+ --_icon: var(--medo-size-icon-sm);
58
+
59
+ display: flex;
60
+ flex-direction: column;
61
+ gap: var(--medo-space-1);
62
+ padding: var(--medo-space-1);
63
+ outline: none;
64
+ }
65
+
66
+ .medo-menu--lg {
67
+ --_pad: var(--medo-space-3);
68
+ --_label: var(--medo-typography-body-md);
69
+ --_icon: var(--medo-size-icon-md);
70
+ }
71
+
72
+ .medo-menu__section {
73
+ display: flex;
74
+ flex-direction: column;
75
+ gap: var(--medo-space-1);
76
+ }
77
+
78
+ /* Divider between groups (same as the Listbox). */
79
+ .medo-menu__section + .medo-menu__section,
80
+ .medo-menu__section + .medo-menu-item,
81
+ .medo-menu-item + .medo-menu__section {
82
+ margin-block-start: var(--medo-space-1);
83
+ padding-block-start: var(--medo-space-1);
84
+ border-block-start: var(--medo-border-width-thin) solid var(--medo-color-border-default);
85
+ }
86
+
87
+ /* ---------- Item ---------- */
88
+
89
+ .medo-menu-item {
90
+ --_fg: var(--medo-color-text-primary);
91
+ --_icon-fg: var(--medo-color-text-secondary);
92
+ --_hover: var(--medo-color-state-hover);
93
+
94
+ box-sizing: border-box;
95
+ display: flex;
96
+ align-items: center;
97
+ gap: var(--medo-space-2);
98
+ padding: var(--_pad);
99
+ border-radius: var(--medo-radius-sm);
100
+ font: var(--_label);
101
+ color: var(--_fg);
102
+ cursor: pointer;
103
+ outline: none;
104
+ -webkit-tap-highlight-color: transparent;
105
+ }
106
+
107
+ /* Hover and keyboard focus look the same: the menu moves focus with the arrow keys. */
108
+ .medo-menu-item:is([data-focused], [data-hovered], [data-open]) {
109
+ background-color: var(--_hover);
110
+ }
111
+
112
+ .medo-menu-item[data-pressed] {
113
+ background-color: var(--medo-color-state-pressed);
114
+ }
115
+
116
+ .medo-menu-item--danger {
117
+ --_fg: var(--medo-color-feedback-danger-text);
118
+ --_icon-fg: var(--medo-color-feedback-danger-text);
119
+ --_hover: var(--medo-color-feedback-danger-surface);
120
+ }
121
+
122
+ .medo-menu-item--danger[data-pressed] {
123
+ background-image: linear-gradient(var(--medo-color-state-pressed), var(--medo-color-state-pressed));
124
+ background-color: var(--medo-color-feedback-danger-surface);
125
+ }
126
+
127
+ .medo-menu-item[data-disabled] {
128
+ --_fg: var(--medo-color-text-disabled);
129
+ --_icon-fg: var(--medo-color-text-disabled);
130
+ background: none;
131
+ cursor: not-allowed;
132
+ }
133
+
134
+ .medo-menu-item__icon,
135
+ .medo-menu-item__chevron {
136
+ display: inline-flex;
137
+ flex: none;
138
+ inline-size: var(--_icon);
139
+ block-size: var(--_icon);
140
+ color: var(--_icon-fg);
141
+ }
142
+
143
+ .medo-menu-item__icon > svg,
144
+ .medo-menu-item__chevron > svg {
145
+ inline-size: 100%;
146
+ block-size: 100%;
147
+ }
148
+
149
+ .medo-menu-item__label {
150
+ flex: 1;
151
+ min-inline-size: 0;
152
+ overflow: hidden;
153
+ text-overflow: ellipsis;
154
+ white-space: nowrap;
155
+ }
156
+
157
+ .medo-menu-item__shortcut {
158
+ flex: none;
159
+ font: var(--medo-typography-caption);
160
+ color: var(--medo-color-text-secondary);
161
+ }
162
+
163
+ .medo-menu-item[data-disabled] .medo-menu-item__shortcut {
164
+ color: var(--medo-color-text-disabled);
165
+ }
166
+
167
+ @media (forced-colors: active) {
168
+ .medo-menu-item:is([data-focused], [data-hovered]) {
169
+ forced-color-adjust: none;
170
+ background-color: Highlight;
171
+ color: HighlightText;
172
+ }
173
+ }
174
+
175
+ @media (prefers-reduced-motion: reduce) {
176
+ /* Reduced motion: a short cross-fade, no scaling. */
177
+ .medo-menu-popover {
178
+ transition: opacity var(--medo-motion-duration-fast) var(--medo-motion-easing-standard);
179
+ }
180
+ .medo-menu-popover:is([data-entering], [data-exiting]) {
181
+ scale: none;
182
+ }
183
+ }