@med-o/ui 0.0.0-stage → 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.
Files changed (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +38 -2
  3. package/dist/index.d.ts +2237 -0
  4. package/dist/index.js +5119 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/styles.css +1 -0
  7. package/package.json +77 -4
  8. package/src/accordion/accordion.css +184 -0
  9. package/src/alert/alert.css +147 -0
  10. package/src/avatar/avatar.css +221 -0
  11. package/src/badge/badge.css +153 -0
  12. package/src/bottom-sheet/bottom-sheet.css +202 -0
  13. package/src/breadcrumbs/breadcrumbs.css +147 -0
  14. package/src/bulk-action-bar/bulk-action-bar.css +98 -0
  15. package/src/button/button.css +319 -0
  16. package/src/card/card.css +217 -0
  17. package/src/checkbox/choice.css +196 -0
  18. package/src/combobox/combobox.css +125 -0
  19. package/src/date-time/date-time.css +474 -0
  20. package/src/dialog/dialog.css +319 -0
  21. package/src/drawer/drawer.css +156 -0
  22. package/src/empty-state/empty-state.css +161 -0
  23. package/src/field/field.css +115 -0
  24. package/src/link/link.css +103 -0
  25. package/src/list/list.css +172 -0
  26. package/src/list-view/list-view.css +473 -0
  27. package/src/listbox/listbox.css +203 -0
  28. package/src/media/media.css +298 -0
  29. package/src/menu/menu.css +183 -0
  30. package/src/navigation/navigation.css +625 -0
  31. package/src/pagination/pagination.css +132 -0
  32. package/src/popover/popover.css +166 -0
  33. package/src/progress/progress.css +225 -0
  34. package/src/search/search.css +309 -0
  35. package/src/select/select.css +229 -0
  36. package/src/slider/slider.css +212 -0
  37. package/src/styles.css +48 -0
  38. package/src/switch/switch.css +160 -0
  39. package/src/table/table.css +286 -0
  40. package/src/tabs/tabs.css +211 -0
  41. package/src/tag/tag.css +225 -0
  42. package/src/text-field/input.css +206 -0
  43. package/src/toast/toast.css +184 -0
  44. package/src/toggle-button/toggle-button.css +143 -0
  45. package/src/tooltip/tooltip.css +66 -0
  46. package/src/upload/upload.css +380 -0
  47. package/src/utils/utilities.css +14 -0
@@ -0,0 +1,217 @@
1
+ /**
2
+ * Card – med.o Design System
3
+ *
4
+ * Container for one topic. Media, header actions, body and footer are optional; the title is required.
5
+ * <article class="medo-card medo-card--outlined">
6
+ * <div class="medo-card__media">…</div>
7
+ * <div class="medo-card__main">
8
+ * <div class="medo-card__header">
9
+ * <div class="medo-card__heading"><h3 class="medo-card__title">…</h3><p class="medo-card__subtitle">…</p></div>
10
+ * <div class="medo-card__header-actions">…</div>
11
+ * </div>
12
+ * <div class="medo-card__body">…</div>
13
+ * <div class="medo-card__footer">…</div>
14
+ * </div>
15
+ * </article>
16
+ *
17
+ * Variants: outlined (default) · elevated · filled · brand · plain. Density: standard (24) · compact (16).
18
+ * Interactive: the title link is stretched over the card (one click target); buttons stay above it.
19
+ */
20
+
21
+ .medo-card {
22
+ --_pad: var(--medo-space-6);
23
+ --_bg: var(--medo-color-surface-default);
24
+ --_border: var(--medo-color-border-default);
25
+
26
+ position: relative;
27
+ box-sizing: border-box;
28
+ display: flex;
29
+ flex-direction: column;
30
+ border: var(--medo-border-width-thin) solid var(--_border);
31
+ border-radius: var(--medo-radius-lg);
32
+ background-color: var(--_bg);
33
+ color: var(--medo-color-text-primary);
34
+ overflow: hidden;
35
+ isolation: isolate;
36
+ }
37
+
38
+ .medo-card--compact {
39
+ --_pad: var(--medo-space-4);
40
+ }
41
+
42
+ .medo-card--elevated {
43
+ box-shadow: var(--medo-shadow-elevation-1);
44
+ }
45
+ .medo-card--filled {
46
+ --_bg: var(--medo-color-surface-subtle);
47
+ --_border: transparent;
48
+ }
49
+ .medo-card--brand {
50
+ --_bg: var(--medo-color-surface-brand-subtle);
51
+ --_border: var(--medo-color-border-brand);
52
+ }
53
+ .medo-card--plain {
54
+ --_bg: transparent;
55
+ --_border: transparent;
56
+ --_pad: 0;
57
+ overflow: visible;
58
+ }
59
+
60
+ /* ---------- Parts ---------- */
61
+
62
+ .medo-card__media {
63
+ aspect-ratio: 16 / 9;
64
+ overflow: hidden;
65
+ background-color: var(--medo-color-surface-subtle);
66
+ }
67
+
68
+ .medo-card__media > :is(img, video, picture, .medo-image) {
69
+ display: block;
70
+ inline-size: 100%;
71
+ block-size: 100%;
72
+ object-fit: cover;
73
+ }
74
+
75
+ .medo-card--plain .medo-card__media {
76
+ border-radius: var(--medo-radius-lg);
77
+ margin-block-end: var(--medo-space-4);
78
+ }
79
+
80
+ .medo-card__main {
81
+ display: flex;
82
+ flex-direction: column;
83
+ gap: var(--medo-space-4);
84
+ flex: 1;
85
+ padding: var(--_pad);
86
+ }
87
+
88
+ .medo-card__header {
89
+ display: flex;
90
+ align-items: flex-start;
91
+ justify-content: space-between;
92
+ gap: var(--medo-space-4);
93
+ }
94
+
95
+ .medo-card__heading {
96
+ display: grid;
97
+ gap: var(--medo-space-1);
98
+ min-inline-size: 0;
99
+ }
100
+
101
+ .medo-card__title {
102
+ margin: 0;
103
+ font: var(--medo-typography-heading-sm);
104
+ color: var(--medo-color-text-primary);
105
+ }
106
+
107
+ .medo-card__subtitle {
108
+ margin: 0;
109
+ font: var(--medo-typography-body-sm);
110
+ color: var(--medo-color-text-secondary);
111
+ }
112
+
113
+ .medo-card__body {
114
+ font: var(--medo-typography-body-sm);
115
+ color: var(--medo-color-text-secondary);
116
+ }
117
+
118
+ .medo-card__body > :first-child {
119
+ margin-block-start: 0;
120
+ }
121
+ .medo-card__body > :last-child {
122
+ margin-block-end: 0;
123
+ }
124
+
125
+ /* Footer at the bottom, so cards in a row align. */
126
+ .medo-card__footer {
127
+ margin-block-start: auto;
128
+ }
129
+
130
+ /* ---------- Horizontal (lists): media 180 px wide on the left ---------- */
131
+
132
+ .medo-card--horizontal {
133
+ flex-direction: row;
134
+ }
135
+
136
+ .medo-card--horizontal .medo-card__media {
137
+ flex: 0 0 11.25rem; /* 180 px */
138
+ aspect-ratio: auto;
139
+ }
140
+
141
+ /* ---------- Interactive: stretched title link ---------- */
142
+
143
+ .medo-card__link {
144
+ color: inherit;
145
+ text-decoration: none;
146
+ outline: none;
147
+ }
148
+
149
+ /* The link covers the whole card. */
150
+ .medo-card__link::after {
151
+ content: '';
152
+ position: absolute;
153
+ inset: 0;
154
+ z-index: 0;
155
+ }
156
+
157
+ /* Buttons and other controls stay clickable above the link. */
158
+ .medo-card :is(.medo-card__header-actions, .medo-card__footer, .medo-card__body) :is(a, button, input, select, textarea, [tabindex]) {
159
+ position: relative;
160
+ z-index: 1;
161
+ }
162
+
163
+ .medo-card--interactive {
164
+ cursor: pointer;
165
+ }
166
+
167
+ .medo-card--interactive::before {
168
+ content: '';
169
+ position: absolute;
170
+ inset: 0;
171
+ border-radius: inherit;
172
+ background-color: transparent;
173
+ pointer-events: none;
174
+ z-index: 0;
175
+ transition: background-color var(--medo-motion-duration-fast) var(--medo-motion-easing-standard);
176
+ }
177
+
178
+ .medo-card--interactive:has(.medo-card__link[data-hovered])::before {
179
+ background-color: var(--medo-color-state-hover);
180
+ }
181
+
182
+ .medo-card--interactive:has(.medo-card__link[data-pressed])::before {
183
+ background-color: var(--medo-color-state-pressed);
184
+ }
185
+
186
+ .medo-card--interactive:has(.medo-card__link[data-focus-visible]) {
187
+ box-shadow: var(--medo-shadow-focus-ring);
188
+ }
189
+
190
+ .medo-card--interactive.medo-card--elevated:has(.medo-card__link[data-focus-visible]) {
191
+ box-shadow: var(--medo-shadow-focus-ring), var(--medo-shadow-elevation-1);
192
+ }
193
+
194
+ @media (forced-colors: active) {
195
+ .medo-card {
196
+ border-color: CanvasText;
197
+ }
198
+ .medo-card--interactive:has(.medo-card__link[data-focus-visible]) {
199
+ outline: var(--medo-focus-ring-width) solid Highlight;
200
+ outline-offset: 2px;
201
+ }
202
+ }
203
+
204
+ /* Interactive cards give way a little while pressed and spring back. */
205
+ .medo-card--interactive {
206
+ transition: scale var(--medo-motion-spring-snappy-duration) var(--medo-motion-spring-snappy);
207
+ }
208
+ .medo-card--interactive:has(.medo-card__link[data-pressed]) {
209
+ scale: 0.98;
210
+ transition-duration: var(--medo-motion-duration-fast);
211
+ }
212
+
213
+ @media (prefers-reduced-motion: reduce) {
214
+ .medo-card--interactive:has(.medo-card__link[data-pressed]) {
215
+ scale: none;
216
+ }
217
+ }
@@ -0,0 +1,196 @@
1
+ /**
2
+ * Checkbox + Radio – med.o Design System
3
+ *
4
+ * <div class="medo-choice medo-checkbox medo-choice--md" data-selected …>
5
+ * <label class="medo-choice__button" data-hovered data-focus-visible …>
6
+ * <span class="medo-choice__control">✓</span>
7
+ * <span class="medo-choice__label">Label</span>
8
+ * </label>
9
+ * <span class="medo-choice__description">Description</span>
10
+ * </div>
11
+ *
12
+ * State contract: [data-selected] [data-indeterminate] [data-hovered] [data-pressed]
13
+ * [data-focus-visible] [data-invalid] [data-disabled] [data-readonly]
14
+ * The whole row incl. label is clickable. Focus ring around the box.
15
+ */
16
+
17
+ .medo-choice {
18
+ --_box: var(--medo-size-icon-sm);
19
+ --_gap: var(--medo-space-2);
20
+ --_border: var(--medo-color-border-strong);
21
+ --_accent: var(--medo-color-action-primary);
22
+
23
+ display: flex;
24
+ flex-direction: column;
25
+ font: var(--medo-typography-body-sm);
26
+ color: var(--medo-color-text-primary);
27
+ }
28
+
29
+ .medo-choice--lg {
30
+ --_box: var(--medo-size-icon-md);
31
+ font: var(--medo-typography-body-md);
32
+ }
33
+
34
+ .medo-choice__button {
35
+ display: inline-flex;
36
+ align-items: flex-start;
37
+ gap: var(--_gap);
38
+ inline-size: fit-content;
39
+ cursor: pointer;
40
+ }
41
+
42
+ .medo-choice__control {
43
+ box-sizing: border-box;
44
+ display: inline-grid;
45
+ place-items: center;
46
+ flex-shrink: 0;
47
+ inline-size: var(--_box);
48
+ block-size: var(--_box);
49
+ /* Aligns the box with the first line of the label (20 px line, 16 px box). */
50
+ margin-block-start: var(--medo-space-0-5);
51
+ border: var(--medo-border-width-thin) solid var(--_border);
52
+ background-color: var(--medo-color-surface-default);
53
+ color: var(--medo-color-text-on-action);
54
+ transition:
55
+ background-color var(--medo-motion-duration-fast) var(--medo-motion-easing-standard),
56
+ border-color var(--medo-motion-duration-fast) var(--medo-motion-easing-standard);
57
+ }
58
+
59
+ .medo-checkbox .medo-choice__control {
60
+ border-radius: var(--medo-radius-sm);
61
+ }
62
+
63
+ .medo-checkbox .medo-choice__control > svg {
64
+ /* 2 px inset (md 16 → 12, lg 20 → 16). 75 % gave 15 px in lg:
65
+ odd size, half-pixel offset, so the mark looked off-centre. */
66
+ inline-size: calc(var(--_box) - 2 * var(--medo-space-0-5));
67
+ block-size: calc(var(--_box) - 2 * var(--medo-space-0-5));
68
+ stroke-width: 3;
69
+ }
70
+
71
+ .medo-radio .medo-choice__control {
72
+ border-radius: var(--medo-radius-full);
73
+ }
74
+
75
+ .medo-radio .medo-choice__control::after {
76
+ content: '';
77
+ /* Half of the outer size (md 16 → 8, lg 20 → 10). A % of the inner box
78
+ gives odd sizes (7 px) and a half-pixel offset, so the dot looks off-centre. */
79
+ inline-size: calc(var(--_box) / 2);
80
+ block-size: calc(var(--_box) / 2);
81
+ border-radius: var(--medo-radius-full);
82
+ background-color: var(--_accent);
83
+ transform: scale(0);
84
+ transition: transform var(--medo-motion-spring-snappy-duration) var(--medo-motion-spring-snappy);
85
+ }
86
+
87
+ /* The check pops in with a snappy spring. */
88
+ .medo-checkbox .medo-choice__control > svg {
89
+ transition:
90
+ scale var(--medo-motion-spring-snappy-duration) var(--medo-motion-spring-snappy),
91
+ opacity var(--medo-motion-duration-fast) var(--medo-motion-easing-standard);
92
+ }
93
+ @starting-style {
94
+ .medo-checkbox .medo-choice__control > svg {
95
+ scale: 0.4;
96
+ opacity: 0;
97
+ }
98
+ }
99
+
100
+ .medo-choice__description {
101
+ margin-inline-start: calc(var(--_box) + var(--_gap));
102
+ font: var(--medo-typography-body-sm);
103
+ color: var(--medo-color-text-secondary);
104
+ }
105
+
106
+ /* ---------- States ---------- */
107
+
108
+ .medo-choice__button[data-hovered] {
109
+ --_border: var(--medo-color-border-strong-hover);
110
+ --_accent: var(--medo-color-action-primary-hover);
111
+ }
112
+
113
+ .medo-choice[data-invalid] {
114
+ --_border: var(--medo-color-border-danger);
115
+ }
116
+
117
+ /* Checkbox checked / indeterminate: filled box */
118
+ .medo-checkbox:is([data-selected], [data-indeterminate]) .medo-choice__control {
119
+ border-color: var(--_accent);
120
+ background-color: var(--_accent);
121
+ }
122
+
123
+ /* Radio selected: outline + dot */
124
+ .medo-radio[data-selected] .medo-choice__control {
125
+ border-color: var(--_accent);
126
+ }
127
+
128
+ .medo-radio[data-selected] .medo-choice__control::after {
129
+ transform: scale(1);
130
+ }
131
+
132
+ .medo-choice__button[data-focus-visible] .medo-choice__control {
133
+ box-shadow: var(--medo-shadow-focus-ring);
134
+ }
135
+
136
+ .medo-choice[data-readonly] .medo-choice__button {
137
+ cursor: default;
138
+ }
139
+
140
+ .medo-choice[data-disabled] {
141
+ --_border: var(--medo-color-border-default);
142
+ --_accent: var(--medo-color-border-default);
143
+ color: var(--medo-color-text-disabled);
144
+ }
145
+
146
+ .medo-choice[data-disabled] .medo-choice__button {
147
+ cursor: not-allowed;
148
+ }
149
+
150
+ .medo-choice[data-disabled] .medo-choice__control {
151
+ background-color: var(--medo-color-action-disabled);
152
+ color: var(--medo-color-text-disabled);
153
+ }
154
+
155
+ .medo-checkbox[data-disabled]:is([data-selected], [data-indeterminate]) .medo-choice__control {
156
+ background-color: var(--medo-color-action-disabled);
157
+ }
158
+
159
+ .medo-radio[data-disabled] .medo-choice__control::after {
160
+ background-color: var(--medo-color-text-disabled);
161
+ }
162
+
163
+ @media (forced-colors: active) {
164
+ .medo-choice__control {
165
+ border-color: CanvasText;
166
+ }
167
+ .medo-checkbox:is([data-selected], [data-indeterminate]) .medo-choice__control,
168
+ .medo-radio[data-selected] .medo-choice__control::after {
169
+ background-color: Highlight;
170
+ border-color: Highlight;
171
+ }
172
+ .medo-choice__button[data-focus-visible] .medo-choice__control {
173
+ outline: var(--medo-focus-ring-width) solid Highlight;
174
+ outline-offset: 2px;
175
+ }
176
+ }
177
+
178
+ @media (prefers-reduced-motion: reduce) {
179
+ /* Reduced motion: marks fade in, nothing grows. */
180
+ .medo-radio .medo-choice__control::after {
181
+ transform: none;
182
+ opacity: 0;
183
+ transition: opacity var(--medo-motion-duration-fast) var(--medo-motion-easing-standard);
184
+ }
185
+ .medo-radio[data-selected] .medo-choice__control::after {
186
+ opacity: 1;
187
+ }
188
+ .medo-checkbox .medo-choice__control > svg {
189
+ transition: opacity var(--medo-motion-duration-fast) var(--medo-motion-easing-standard);
190
+ }
191
+ @starting-style {
192
+ .medo-checkbox .medo-choice__control > svg {
193
+ scale: none;
194
+ }
195
+ }
196
+ }
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Combobox – med.o Design System
3
+ *
4
+ * A Select you can type into. Input anatomy; clear and chevron are separate buttons (_Input action).
5
+ * <div class="medo-field medo-combobox" data-open data-invalid data-disabled data-readonly>
6
+ * <label class="medo-field__label">Assignee</label>
7
+ * <div class="medo-input medo-input--md medo-combobox__field" role="group">
8
+ * <span class="medo-input__icon">…</span>
9
+ * <span class="medo-combobox__tags-row">tags · “+N”</span> (multi)
10
+ * <input class="medo-input__control medo-combobox__input" role="combobox">
11
+ * <button class="medo-input__action" aria-label="Clear">×</button>
12
+ * <button class="medo-input__action medo-combobox__toggle">⌄</button>
13
+ * </div>
14
+ * </div>
15
+ * The list is the shared Listbox (medo-listbox) in a popover anchored to the whole field.
16
+ */
17
+
18
+ /* Multi with values: tags start closer to the edge (sm 4 · md/lg 8). */
19
+ .medo-combobox__field:has(.medo-combobox__tags-row) {
20
+ padding-inline-start: var(--medo-space-2);
21
+ }
22
+ .medo-combobox__field.medo-input--sm:has(.medo-combobox__tags-row) {
23
+ padding-inline-start: var(--medo-space-1);
24
+ }
25
+
26
+ /* Clear and toggle: 8 px apart, flush with the field padding. */
27
+ .medo-combobox__field > .medo-input__action {
28
+ margin-inline-end: 0;
29
+ }
30
+
31
+ .medo-combobox__toggle > svg {
32
+ transition: transform var(--medo-motion-spring-snappy-duration) var(--medo-motion-spring-snappy);
33
+ }
34
+
35
+ .medo-combobox__toggle[data-pressed]:not([data-hovered]) {
36
+ /* React Aria marks the toggle as pressed while the list is open: only the chevron flips. */
37
+ background: transparent;
38
+ }
39
+
40
+ .medo-combobox[data-open] .medo-combobox__toggle > svg {
41
+ transform: rotate(180deg);
42
+ }
43
+
44
+ .medo-combobox__input {
45
+ min-inline-size: 4rem;
46
+ }
47
+
48
+ /* ---------- Tags (multi) ---------- */
49
+
50
+ .medo-combobox__entry {
51
+ position: relative;
52
+ display: flex;
53
+ flex: 1;
54
+ align-items: center;
55
+ gap: var(--medo-space-1);
56
+ min-inline-size: 0;
57
+ block-size: 100%;
58
+ }
59
+
60
+ .medo-combobox__tags-row {
61
+ display: flex;
62
+ flex: 0 1 auto;
63
+ align-items: center;
64
+ gap: var(--medo-space-1);
65
+ min-inline-size: 0;
66
+ overflow: hidden;
67
+ }
68
+
69
+ /* The tag group behaves like a plain row inside the field. */
70
+ .medo-combobox__tags {
71
+ flex-direction: row;
72
+ gap: 0;
73
+ min-inline-size: 0;
74
+ }
75
+
76
+ .medo-combobox__tags .medo-tag-list {
77
+ flex-wrap: nowrap;
78
+ gap: var(--medo-space-1);
79
+ min-inline-size: 0;
80
+ }
81
+
82
+ .medo-combobox__tags .medo-tag:first-child {
83
+ flex-shrink: 1;
84
+ min-inline-size: 0;
85
+ }
86
+
87
+ .medo-combobox__more {
88
+ flex: none;
89
+ }
90
+
91
+ /* Hidden copy that measures every tag, so the visible row knows how many fit. */
92
+ .medo-combobox__measure {
93
+ position: absolute;
94
+ inset-inline-start: 0;
95
+ display: flex;
96
+ gap: var(--medo-space-1);
97
+ visibility: hidden;
98
+ pointer-events: none;
99
+ }
100
+
101
+ /* ---------- States ---------- */
102
+
103
+ .medo-combobox[data-open] .medo-combobox__field {
104
+ --_border: var(--medo-color-focus-ring);
105
+ box-shadow: inset 0 0 0 var(--medo-border-width-thin) var(--medo-color-focus-ring);
106
+ }
107
+
108
+ .medo-combobox[data-invalid] .medo-combobox__field {
109
+ --_border: var(--medo-color-border-danger);
110
+ }
111
+
112
+ .medo-combobox[data-invalid]:is([data-open], :focus-within) .medo-combobox__field {
113
+ --_border: var(--medo-color-focus-ring);
114
+ }
115
+
116
+ .medo-combobox[data-disabled] .medo-tag {
117
+ --_bg: transparent;
118
+ --_fg: var(--medo-color-text-disabled);
119
+ }
120
+
121
+ @media (prefers-reduced-motion: reduce) {
122
+ .medo-combobox__toggle > svg {
123
+ transition: transform var(--medo-motion-duration-fast) var(--medo-motion-easing-standard);
124
+ }
125
+ }