opui-css 1.2.4

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 (40) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +59 -0
  3. package/dist/ui.css +4417 -0
  4. package/package.json +33 -0
  5. package/src/components/accordion.css +172 -0
  6. package/src/components/alert.css +85 -0
  7. package/src/components/avatar.css +68 -0
  8. package/src/components/badge.css +101 -0
  9. package/src/components/button-group.css +69 -0
  10. package/src/components/button.css +272 -0
  11. package/src/components/card.css +82 -0
  12. package/src/components/checkbox-radio.css +123 -0
  13. package/src/components/chip.css +135 -0
  14. package/src/components/definition-list.css +65 -0
  15. package/src/components/description-list.css +0 -0
  16. package/src/components/dialog.css +61 -0
  17. package/src/components/divider.css +7 -0
  18. package/src/components/field-group.css +83 -0
  19. package/src/components/field.css +500 -0
  20. package/src/components/icon-button.css +40 -0
  21. package/src/components/link.css +21 -0
  22. package/src/components/list.css +317 -0
  23. package/src/components/progress.css +80 -0
  24. package/src/components/range.css +121 -0
  25. package/src/components/rich-text.css +210 -0
  26. package/src/components/select.css +166 -0
  27. package/src/components/snackbar.css +152 -0
  28. package/src/components/spinner.css +38 -0
  29. package/src/components/switch.css +189 -0
  30. package/src/components/tab-buttons.css +124 -0
  31. package/src/components/table.css +107 -0
  32. package/src/components/text-field.css +57 -0
  33. package/src/components/textarea.css +25 -0
  34. package/src/components/toggle-button-group.css +142 -0
  35. package/src/components/tooltip.css +94 -0
  36. package/src/components/typography.css +209 -0
  37. package/src/main.css +59 -0
  38. package/src/normalize.css +194 -0
  39. package/src/theme.css +160 -0
  40. package/src/utils.css +60 -0
@@ -0,0 +1,166 @@
1
+ @layer components.has-deps {
2
+ :where(.field > select) {
3
+ position: relative;
4
+
5
+ /* Default arrow */
6
+ &::picker-icon {
7
+ block-size: 0;
8
+ border-block-start: 5px solid;
9
+ border-inline: 5px solid transparent;
10
+ color: currentColor;
11
+ content: "";
12
+ inline-size: 0;
13
+ inset: 50% var(--size-3) auto auto;
14
+ pointer-events: none;
15
+ position: absolute;
16
+ translate: 0 -50%;
17
+ }
18
+
19
+ &:open {
20
+ &::picker-icon {
21
+ rotate: 180deg;
22
+ }
23
+ }
24
+
25
+ /* Select popover */
26
+ &::picker(select) {
27
+ /* Animation on-stage styles */
28
+ border: 0;
29
+ box-shadow: var(--shadow-2);
30
+ opacity: 1;
31
+ padding: 0;
32
+ scale: 1;
33
+
34
+ /* Animation starting styles */
35
+ @starting-style {
36
+ opacity: 0;
37
+ transform: scale(0.9);
38
+ }
39
+
40
+ @media (prefers-reduced-motion: no-preference) {
41
+ transition:
42
+ display 0.2s allow-discrete,
43
+ opacity 0.2s var(--ease-3),
44
+ overlay 0.2s allow-discrete,
45
+ scale 0.2s var(--ease-3);
46
+ }
47
+ }
48
+
49
+ /* Animation off-stage styles */
50
+ &:not(:open)::picker(select) {
51
+ opacity: 0;
52
+ scale: 0.9;
53
+ }
54
+
55
+ button {
56
+ background-color: transparent;
57
+ display: flex;
58
+ inline-size: 100%;
59
+ margin: 0;
60
+ position: relative;
61
+
62
+ selectedcontent {
63
+ overflow: hidden;
64
+ text-overflow: ellipsis;
65
+ white-space: nowrap;
66
+ }
67
+ }
68
+
69
+ .list {
70
+ /* Groups */
71
+ [role="group"] {
72
+ label {
73
+ background-color: light-dark(var(--gray-3), var(--gray-13));
74
+ color: light-dark(
75
+ oklch(from var(--text-color-1) calc(l * 0.75) c h),
76
+ oklch(from var(--text-color-1) calc(l * 1.25) c h)
77
+ );
78
+ font-weight: 500;
79
+ overflow: hidden;
80
+ padding-inline: var(--size-2);
81
+ text-overflow: ellipsis;
82
+ white-space: nowrap;
83
+ }
84
+
85
+ &:not(:first-child),
86
+ option:first-of-type {
87
+ margin-block-start: var(--size-2);
88
+ }
89
+
90
+ option:last-of-type,
91
+ &:last-child {
92
+ option:last-of-type {
93
+ margin-block-end: 0;
94
+ }
95
+ }
96
+ }
97
+
98
+ /* Option */
99
+ option {
100
+ /* Checkmark */
101
+ /* TODO - checkmark should be the final version of the checkmark API. Follow the development of this and remove redundant psuedo stuff. */
102
+ &::check {
103
+ display: none;
104
+ }
105
+ &::checkmark {
106
+ display: none;
107
+ }
108
+ &::before {
109
+ display: none;
110
+ }
111
+
112
+ &:focus-visible {
113
+ outline-offset: -1px;
114
+ }
115
+ }
116
+ }
117
+ }
118
+
119
+ :where(.field:has(> select)) {
120
+ /* Size */
121
+ &.small {
122
+ button {
123
+ padding-block: var(--size-1);
124
+ padding-inline: var(--size-2) var(--size-7);
125
+
126
+ &::after {
127
+ inset-inline-end: var(--size-2);
128
+ }
129
+ }
130
+ }
131
+
132
+ /*
133
+ * Non-experimental Select
134
+ *
135
+ * Hack to get the arrow working. Pseudo elements aren't allowed on the `<select>` element, so need to add it on the `.field` class instead. Noting this down if an `:after` element would be needed on a `.field`.
136
+ */
137
+ &:not(:has(button)) {
138
+ select {
139
+ appearance: none;
140
+ }
141
+
142
+ /* Arrow */
143
+ &::after {
144
+ align-self: center;
145
+ block-size: 0;
146
+ border-block-start: 5px solid;
147
+ border-inline: 5px solid transparent;
148
+ content: "";
149
+ display: inline-block;
150
+ flex-shrink: 0;
151
+ grid-column: 1/-1;
152
+ grid-row: 1;
153
+ inline-size: 0;
154
+ inset-inline-end: var(--size-3);
155
+ justify-self: end;
156
+ pointer-events: none;
157
+ position: relative;
158
+ }
159
+ }
160
+ }
161
+
162
+ select:has(button),
163
+ ::picker(select) {
164
+ appearance: base-select;
165
+ }
166
+ }
@@ -0,0 +1,152 @@
1
+ @layer components.has-deps {
2
+ :where(.snackbar) {
3
+ align-items: center;
4
+ /* Inverse surface-filled */
5
+ background-color: light-dark(var(--gray-15), var(--gray-2));
6
+ border-radius: var(--border-radius);
7
+ box-shadow: var(--shadow-2);
8
+ color: var(--text-color-1-contrast);
9
+ display: flex;
10
+ font-size: var(--font-size-sm);
11
+ gap: var(--size-3);
12
+ inset-block: auto var(--size-3);
13
+ inset-inline: var(--size-3) auto;
14
+ justify-content: space-between;
15
+ min-inline-size: min(100%, 37ch);
16
+ padding: var(--size-2) var(--size-3);
17
+ position: fixed;
18
+ inline-size: calc(100% - var(--size-6, 1.75rem));
19
+ z-index: 100;
20
+
21
+ &::backdrop {
22
+ display: none;
23
+ }
24
+
25
+ * {
26
+ word-break: break-word;
27
+ }
28
+
29
+ /* Global positioning (in relation to the window) */
30
+ /*** Default (end-start) */
31
+ inset-block: auto var(--size-3);
32
+ inset-inline: 50% 0;
33
+ translate: -50% 0;
34
+
35
+ &.start-start,
36
+ &.start-center,
37
+ &.start-end {
38
+ inset-block: var(--size-3) auto;
39
+ }
40
+
41
+ /* TODO use @custom-media instead? */
42
+ @container (width > 480px) {
43
+ /* Default (end-start) */
44
+ inset-block: auto var(--size-7, 2rem);
45
+ inset-inline: var(--size-7, 2rem) auto;
46
+ translate: revert;
47
+ inline-size: fit-content;
48
+
49
+ &.end-start,
50
+ &.end-end,
51
+ &.start-start,
52
+ &.start-end {
53
+ translate: revert;
54
+ }
55
+
56
+ &.start-start {
57
+ inset-block: var(--size-7, 2rem) auto;
58
+ inset-inline: var(--size-7, 2rem) auto;
59
+ }
60
+ &.start-center {
61
+ inset-block: var(--size-7, 2rem) auto;
62
+ inset-inline: 50% 0;
63
+ translate: -50% 0;
64
+ }
65
+ &.start-end {
66
+ inset-block: var(--size-7, 2rem) auto;
67
+ inset-inline: auto var(--size-7, 2rem);
68
+ }
69
+ &.end-start {
70
+ inset-block-end: var(--size-7, 2rem);
71
+ inset-inline: var(--size-7, 2rem) auto;
72
+ }
73
+ &.end-center {
74
+ inset-block: auto var(--size-7, 2rem);
75
+ inset-inline: 50% 0;
76
+ translate: -50% 0;
77
+ }
78
+ &.end-end {
79
+ inset-block: auto var(--size-7, 2rem);
80
+ inset-inline: auto var(--size-7, 2rem);
81
+ }
82
+ }
83
+
84
+ /* Absolute positioning */
85
+ &.absolute {
86
+ position: absolute;
87
+ }
88
+
89
+ /* Actions */
90
+ .actions {
91
+ align-items: center;
92
+ display: flex;
93
+ flex-shrink: 0;
94
+ gap: var(--size-3);
95
+ padding-inline: 0;
96
+
97
+ button {
98
+ /* Inverse hover and active backgrounds */
99
+ &:where(:not([disabled])) {
100
+ &:where(:not(:active):hover) {
101
+ --_bg-color: light-dark(
102
+ color-mix(in oklch, white 40%, black),
103
+ color-mix(in oklch, white 85%, black)
104
+ );
105
+ }
106
+
107
+ &:where(:hover:active) {
108
+ --_bg-color: light-dark(
109
+ color-mix(in oklch, white 45%, black),
110
+ color-mix(in oklch, white 80%, black)
111
+ );
112
+ }
113
+ }
114
+ }
115
+
116
+ button:not(:has(svg)) {
117
+ border-radius: var(--border-radius);
118
+ font-size: inherit;
119
+ max-block-size: var(--size-6, 1.5rem);
120
+ padding: 1ex;
121
+ }
122
+
123
+ button:has(svg) {
124
+ color: inherit;
125
+ max-inline-size: var(--size-6, 1.75rem);
126
+ margin: var(--size-00);
127
+ padding: var(--size-1);
128
+ }
129
+ }
130
+
131
+ /* Animations */
132
+ opacity: 0;
133
+ transition:
134
+ display 0.075s allow-discrete,
135
+ overlay 0.075s allow-discrete,
136
+ opacity 0.075s var(--ease-out-1);
137
+
138
+ &:popover-open,
139
+ &:popover-open::backdrop,
140
+ &.visible {
141
+ opacity: 1;
142
+ transition:
143
+ display 0.25s allow-discrete,
144
+ overlay 0.25s allow-discrete,
145
+ opacity 0.25s var(--ease-out-1);
146
+
147
+ @starting-style {
148
+ opacity: 0;
149
+ }
150
+ }
151
+ }
152
+ }
@@ -0,0 +1,38 @@
1
+ @layer components.base {
2
+ [aria-busy="true"]:not(
3
+ input,
4
+ select,
5
+ textarea,
6
+ html,
7
+ progress,
8
+ [aria-describedby]
9
+ ) {
10
+ position: relative;
11
+
12
+ &::before {
13
+ animation: spin 0.7s linear infinite;
14
+ border-color: transparent currentColor currentColor;
15
+ border-radius: 50%;
16
+ border-style: solid;
17
+ border-width: 3px;
18
+ content: "";
19
+ display: inline-block;
20
+ block-size: 1em;
21
+ opacity: 0.5;
22
+ vertical-align: -0.14em;
23
+ inline-size: 1em;
24
+ }
25
+
26
+ &:not(button.button):not(:empty) {
27
+ &::before {
28
+ margin-inline-end: 0.5em;
29
+ }
30
+ }
31
+ }
32
+
33
+ @keyframes spin {
34
+ to {
35
+ transform: rotate(1turn);
36
+ }
37
+ }
38
+ }
@@ -0,0 +1,189 @@
1
+ @layer components.base {
2
+ :where(.switch) {
3
+ --_accent-color: var(--primary);
4
+ --_accent-contrast: var(--primary-contrast);
5
+
6
+ --_dot-bg-color: light-dark(var(--gray-11), var(--gray-14));
7
+ --_dot-inset: var(--size-1) auto auto var(--size-1);
8
+ --_dot-outline-size: 0;
9
+ --_dot-size: var(--size-3);
10
+
11
+ --_track-bg-color: light-dark(var(--gray-3), var(--gray-8));
12
+ --_track-height: var(--size-5);
13
+ --_track-width: var(--size-8);
14
+ --_transition-tf: var(--ease-4);
15
+ --_transition-time: 0.2s;
16
+
17
+ align-items: center;
18
+ color: var(--text-color-1);
19
+ display: inline-grid;
20
+ gap: 0 var(--size-2);
21
+ grid-auto-columns: auto;
22
+ grid-auto-flow: column;
23
+ inline-size: fit-content;
24
+
25
+ input[type="checkbox"][role="switch"] {
26
+ appearance: none;
27
+ block-size: var(--_track-height);
28
+ cursor: pointer;
29
+ inline-size: var(--_track-width);
30
+ margin: 0;
31
+ position: relative;
32
+
33
+ /* Track */
34
+ &::before {
35
+ background-color: var(--_track-bg-color);
36
+ block-size: var(--_track-height);
37
+ border: 1px solid var(--_dot-bg-color);
38
+ border-radius: 100vmax;
39
+ content: "";
40
+ inline-size: var(--_track-width);
41
+ inset: 0;
42
+ position: absolute;
43
+ }
44
+
45
+ &:focus-visible {
46
+ outline-offset: 2px;
47
+ outline: 2px solid currentColor;
48
+ }
49
+
50
+ /* Dot */
51
+ &::after {
52
+ background-color: var(--_dot-bg-color);
53
+ block-size: var(--_dot-size);
54
+ border-radius: 100vmax;
55
+ content: "";
56
+ inline-size: var(--_dot-size);
57
+ inset: var(--_dot-inset);
58
+ outline-offset: -1px;
59
+ outline: var(--_dot-outline-size) solid var(--_dot-bg-color);
60
+ position: absolute;
61
+ }
62
+
63
+ /* Checked */
64
+ &:checked {
65
+ &::before {
66
+ background-color: var(--_accent-color);
67
+ border-color: var(--_accent-color);
68
+ transition:
69
+ background-color var(--_transition-time) var(--_transition-tf),
70
+ border-color var(--_transition-time) var(--_transition-tf);
71
+ }
72
+
73
+ /* Dot */
74
+ &::after {
75
+ --_dot-bg-color: var(--_accent-contrast);
76
+ --_dot-outline-size: calc(var(--size-1) - 1px);
77
+
78
+ inset-inline-start: calc(
79
+ var(--_track-width) - var(--_dot-size) - var(--size-1)
80
+ );
81
+ }
82
+ }
83
+
84
+ /* Animation */
85
+ @media (prefers-reduced-motion: no-preference) {
86
+ /* Track */
87
+ &::before {
88
+ transition:
89
+ background-color var(--_transition-time) var(--_transition-tf),
90
+ border-color var(--_transition-time) var(--_transition-tf);
91
+ }
92
+
93
+ /* Dot */
94
+ &::after {
95
+ transition: all var(--_transition-time) var(--_transition-tf);
96
+ }
97
+
98
+ &:active:after {
99
+ --_dot-outline-size: calc(var(--size-1) + 1px);
100
+ }
101
+
102
+ &:checked {
103
+ &:active:after {
104
+ --_dot-outline-size: calc(var(--size-1) + 1px);
105
+ }
106
+ }
107
+ }
108
+ }
109
+
110
+ /* Required dot */
111
+ &:has([required]:not(:checked)) {
112
+ .label:after {
113
+ color: var(--red);
114
+ content: "*";
115
+ inset: 0 -0.25ex auto auto;
116
+ position: absolute;
117
+ }
118
+ }
119
+
120
+ /* Disabled */
121
+ &:has([disabled]) {
122
+ cursor: not-allowed;
123
+ opacity: 0.64;
124
+ user-select: none;
125
+
126
+ input {
127
+ cursor: not-allowed;
128
+ }
129
+ }
130
+
131
+ /* Label */
132
+ .label {
133
+ grid-column: 2;
134
+ grid-row: 1;
135
+ min-width: 0;
136
+ padding-inline: 0 1ex;
137
+ position: relative;
138
+ user-select: none;
139
+ }
140
+
141
+ /* Supporting text */
142
+ .supporting-text {
143
+ color: var(--text-color-2);
144
+ font-size: var(--font-size-xs);
145
+ grid-column: 2;
146
+ grid-row: 2;
147
+ line-height: 1.5;
148
+ z-index: 1;
149
+ }
150
+
151
+ /* Size */
152
+ &.small {
153
+ --_dot-size: 0.75rem;
154
+ --_track-height: var(--size-4);
155
+ --_track-width: 2.5rem;
156
+ }
157
+
158
+ /* Stacked layout */
159
+ &.stack {
160
+ justify-items: center;
161
+ grid-auto-columns: unset;
162
+
163
+ .label {
164
+ grid-column: 1/-1;
165
+ grid-row: 2;
166
+ margin-block-start: var(--size-1);
167
+ padding-inline: 1ex;
168
+ }
169
+
170
+ .supporting-text {
171
+ grid-column: 1/-1;
172
+ grid-row: 3;
173
+ }
174
+ }
175
+
176
+ /* Validation */
177
+ &.error {
178
+ input {
179
+ outline: 2px solid var(--color-9);
180
+ border-radius: var(--radius-round);
181
+ }
182
+
183
+ .label,
184
+ .supporting-text {
185
+ color: var(--color-9);
186
+ }
187
+ }
188
+ }
189
+ }
@@ -0,0 +1,124 @@
1
+ @layer components.base {
2
+ :where(nav.tabs) {
3
+ --_bg-color: transparent;
4
+
5
+ & > [role="tablist"] {
6
+ button {
7
+ outline-color: transparent;
8
+ outline-offset: -4px;
9
+
10
+ &[aria-selected="true"] {
11
+ &:focus-visible {
12
+ outline: 2px solid var(--text-color-1);
13
+ }
14
+ }
15
+ }
16
+ }
17
+
18
+ /* Underlined */
19
+ &.underlined {
20
+ /* Tab list */
21
+ & > [role="tablist"] {
22
+ border-bottom: 1px solid var(--border-color);
23
+
24
+ button {
25
+ --_ripple-color: light-dark(
26
+ color-mix(in oklch, var(--gray-2) 80%, var(--color-8)),
27
+ color-mix(in oklch, var(--gray-13) 80%, var(--color-8))
28
+ );
29
+
30
+ background: var(--_bg-color) var(--ripple, none);
31
+ font-weight: 500;
32
+ line-height: var(--font-lineheight-4);
33
+ padding: var(--size-2) var(--size-3);
34
+
35
+ &:focus-visible {
36
+ border-radius: 0;
37
+ }
38
+
39
+ &[aria-selected="true"] {
40
+ border-block-end: 2px solid var(--primary);
41
+ color: var(--primary);
42
+ }
43
+
44
+ @media (prefers-reduced-motion: no-preference) {
45
+ transition:
46
+ background-color 0.2s var(--ease-out-3),
47
+ border-color 0.2s var(--ease-out-3),
48
+ color 0.2s var(--ease-out-3),
49
+ outline-offset 0.05s var(--ease-1);
50
+
51
+ /*** Ripple effect */
52
+ background-position: center;
53
+ transition: background var(--button-ripple-duration);
54
+ &:where(:not(:active):hover) {
55
+ --ripple: radial-gradient(
56
+ circle,
57
+ transparent 1%,
58
+ var(--_ripple-color) 1%
59
+ )
60
+ center/15000%;
61
+ }
62
+
63
+ &:where(:hover:active) {
64
+ background-size: var(--button-ripple-size);
65
+ transition: background 0s;
66
+ }
67
+
68
+ &:hover {
69
+ background-color: light-dark(
70
+ oklch(from var(--primary) calc(l * 0.75) none h / 5%),
71
+ oklch(from var(--primary) calc(l * 1.25) none h / 5%)
72
+ );
73
+ }
74
+ }
75
+ }
76
+ }
77
+ }
78
+
79
+ /* Filled */
80
+ &.filled {
81
+ --_bg-color: var(--surface-default);
82
+ --_radius: var(--border-radius);
83
+ --_selected-bg: var(--surface-filled);
84
+
85
+ & > [role="tablist"] {
86
+ background-color: var(--_bg-color);
87
+ border: var(--border-width) solid var(--border-color);
88
+ border-radius: var(--_radius);
89
+ overflow: hidden;
90
+ padding: 0.792ex;
91
+ width: fit-content;
92
+
93
+ button {
94
+ background-color: var(--_bg-color);
95
+ border-radius: var(--_radius);
96
+ line-height: var(--font-lineheight-4);
97
+ padding-inline: var(--size-3);
98
+
99
+ &:hover {
100
+ background-color: oklch(from var(--_bg-color) calc(l * 1.25) c h);
101
+ }
102
+
103
+ &[aria-selected="true"] {
104
+ background-color: var(--_selected-bg);
105
+
106
+ &:hover {
107
+ background-color: oklch(
108
+ from var(--_selected-bg) calc(l * 1.25) c h
109
+ );
110
+ }
111
+ }
112
+
113
+ @media (prefers-reduced-motion: no-preference) {
114
+ transition:
115
+ background-color 0.2s var(--ease-out-3),
116
+ border-color 0.2s var(--ease-out-3),
117
+ color 0.2s var(--ease-out-3),
118
+ outline-offset 0.05s var(--ease-1);
119
+ }
120
+ }
121
+ }
122
+ }
123
+ }
124
+ }