@knadh/oat 0.2.0 → 0.4.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
@@ -10,6 +10,8 @@ I wrote this to use in my own projects after getting sick of the ridiculous bloa
10
10
 
11
11
  See live demo and docs at [**oat.ink**](https://oat.ink)
12
12
 
13
+ **IMPORTANT:** The lib is currently sub v1 and is likely to have breaking changes until it hits v1.
14
+
13
15
  -------------
14
16
 
15
17
  <img width="739" height="735" alt="image" src="https://github.com/user-attachments/assets/b0a2f55c-659d-4aab-922c-b13d89eeab36" />
package/css/00-base.css CHANGED
@@ -3,6 +3,7 @@
3
3
  @layer base {
4
4
  *, *::before, *::after {
5
5
  box-sizing: border-box;
6
+ -webkit-tap-highlight-color: transparent;
6
7
  }
7
8
 
8
9
  * {
@@ -45,27 +46,27 @@
45
46
  }
46
47
 
47
48
  h1 {
48
- font-size: 2.25rem;
49
+ font-size: var(--text-1);
49
50
  margin: var(--space-10) 0 var(--space-6);
50
51
  }
51
52
 
52
53
  h2 {
53
- font-size: 1.875rem;
54
+ font-size: var(--text-2);
54
55
  margin: var(--space-8) 0 var(--space-5);
55
56
  }
56
57
 
57
58
  h3 {
58
- font-size: 1.5rem;
59
+ font-size: var(--text-3);
59
60
  margin: var(--space-6) 0 var(--space-4);
60
61
  }
61
62
 
62
63
  h4 {
63
- font-size: 1.25rem;
64
+ font-size: var(--text-4);
64
65
  margin: var(--space-5) 0 var(--space-3);
65
66
  }
66
67
 
67
68
  h5 {
68
- font-size: 1.125rem;
69
+ font-size: var(--text-5);
69
70
  margin: var(--space-4) 0 var(--space-2);
70
71
  }
71
72
 
@@ -108,7 +109,7 @@
108
109
  code {
109
110
  font-family: var(--font-mono);
110
111
  font-size: 0.875em;
111
- padding: 0.125rem 0.25rem;
112
+ padding: calc(var(--space-1) / 2) var(--space-1);
112
113
  background-color: var(--faint);
113
114
  border-radius: var(--radius-small);
114
115
  }
@@ -139,7 +140,7 @@
139
140
  hr {
140
141
  border: none;
141
142
  border-top: 1px solid var(--border);
142
- margin: var(--space-8) 0;
143
+ margin: var(--space-2) 0;
143
144
  }
144
145
 
145
146
  ul, ol {
@@ -161,10 +162,14 @@
161
162
 
162
163
  mark {
163
164
  background-color: rgb(from var(--warning) r g b / 0.3);
164
- padding: 0.125rem 0.25rem;
165
+ padding: calc(var(--space-1) / 2) var(--space-1);
165
166
  border-radius: var(--radius-small);
166
167
  }
167
168
 
169
+ [hidden] {
170
+ display: none;
171
+ }
172
+
168
173
  :focus-visible {
169
174
  outline: 2px solid var(--ring);
170
175
  outline-offset: 2px;
package/css/01-theme.css CHANGED
@@ -1,27 +1,29 @@
1
1
  @layer theme {
2
2
  :root {
3
- /* Default light theme variables */
4
- --background: #fff;
5
- --foreground: #09090b;
6
- --card: #fff;
7
- --card-foreground: #09090b;
8
- --primary: #574747;
9
- --primary-foreground: #fafafa;
10
- --secondary: #f4f4f5;
11
- --secondary-foreground: #574747;
12
- --muted: #f4f4f5;
13
- --muted-foreground: #71717a;
14
- --faint: #fafafa;
15
- --accent: #f4f4f5;
16
- --danger: #df514c;
17
- --danger-foreground: #fafafa;
18
- --success: #4caf50;
19
- --success-foreground: #fafafa;
20
- --warning: #ff8c00;
3
+ color-scheme: light dark;
4
+
5
+ --background: light-dark(#fff, #09090b);
6
+ --foreground: light-dark(#09090b, #fafafa);
7
+ --card: light-dark(#fff, #18181b);
8
+ --card-foreground: light-dark(#09090b, #fafafa);
9
+ --primary: light-dark(#574747, #fafafa);
10
+ --primary-foreground: light-dark(#fafafa, #18181b);
11
+ --secondary: light-dark(#f4f4f5, #27272a);
12
+ --secondary-foreground: light-dark(#574747, #fafafa);
13
+ --muted: light-dark(#f4f4f5, #27272a);
14
+ --muted-foreground: light-dark(#71717a, #a1a1aa);
15
+ --faint: light-dark(#fafafa, #1e1e21);
16
+ --faint-foreground: light-dark(#a1a1aa, #71717a);
17
+ --accent: light-dark(#f4f4f5, #27272a);
18
+ --danger: light-dark(#d32f2f, #f4807b);
19
+ --danger-foreground: light-dark(#fafafa, #18181b);
20
+ --success: light-dark(#008032, #6cc070);
21
+ --success-foreground: light-dark(#fafafa, #18181b);
22
+ --warning: light-dark(#a65b00, #f0a030);
21
23
  --warning-foreground: #09090b;
22
- --border: #d4d4d8;
23
- --input: #d4d4d8;
24
- --ring: #574747;
24
+ --border: light-dark(#d4d4d8, #52525b);
25
+ --input: light-dark(#d4d4d8, #52525b);
26
+ --ring: light-dark(#574747, #d4d4d8);
25
27
 
26
28
  /* ==================== */
27
29
  --space-1: 0.25rem;
@@ -47,11 +49,11 @@
47
49
  --font-sans: system-ui, sans-serif;
48
50
  --font-mono: ui-monospace, Consolas, monospace;
49
51
 
50
- --text-1: 3rem;
51
- --text-2: 2.25rem;
52
- --text-3: 1.875rem;
53
- --text-4: 1.5rem;
54
- --text-5: 1.25rem;
52
+ --text-1: clamp(1.75rem, 1.5rem + 1.1vw, 2.25rem);
53
+ --text-2: clamp(1.5rem, 1.3rem + 0.8vw, 1.875rem);
54
+ --text-3: clamp(1.25rem, 1.1rem + 0.5vw, 1.5rem);
55
+ --text-4: clamp(1.125rem, 1.05rem + 0.3vw, 1.25rem);
56
+ --text-5: 1.125rem;
55
57
  --text-6: 1rem;
56
58
  --text-7: 0.875rem;
57
59
  --text-8: 0.75rem;
@@ -74,26 +76,4 @@
74
76
  --z-dropdown: 50;
75
77
  --z-modal: 200;
76
78
  }
77
-
78
- [data-theme="dark"] {
79
- color-scheme: dark;
80
- --background: #09090b;
81
- --foreground: #fafafa;
82
- --card: #18181b;
83
- --card-foreground: #fafafa;
84
- --primary: #fafafa;
85
- --primary-foreground: #18181b;
86
- --secondary: #27272a;
87
- --secondary-foreground: #fafafa;
88
- --muted: #27272a;
89
- --muted-foreground: #a1a1aa;
90
- --faint: #1e1e21;
91
- --accent: #27272a;
92
- --danger-foreground: #fafafa;
93
- --success-foreground: #fafafa;
94
- --warning-foreground: #09090b;
95
- --border: #52525b;
96
- --input: #52525b;
97
- --ring: #d4d4d8;
98
- }
99
79
  }
package/css/alert.css CHANGED
@@ -3,7 +3,7 @@
3
3
  position: relative;
4
4
  display: flex;
5
5
  gap: var(--space-3);
6
- padding: var(--space-4);
6
+ padding: var(--space-4) var(--space-6);
7
7
  background-color: var(--background);
8
8
  border: 1px solid var(--border);
9
9
  border-radius: var(--radius-medium);
@@ -13,9 +13,13 @@
13
13
  border: none;
14
14
  }
15
15
 
16
- &[data-variant="error"], &[data-variant="danger"] {
16
+ &[data-variant="error"],
17
+ &[data-variant="danger"] {
17
18
  color: var(--danger);
18
- background-color: color-mix(in srgb, var(--danger) 8%, white);
19
+ background-color: light-dark(
20
+ color-mix(in srgb, var(--danger) 8%, transparent),
21
+ color-mix(in srgb, var(--danger) 20%, transparent)
22
+ );
19
23
 
20
24
  & a {
21
25
  color: var(--danger);
@@ -24,7 +28,10 @@
24
28
 
25
29
  &[data-variant="success"] {
26
30
  color: var(--success);
27
- background-color: color-mix(in srgb, var(--success) 8%, white);
31
+ background-color: light-dark(
32
+ color-mix(in srgb, var(--success) 8%, transparent),
33
+ color-mix(in srgb, var(--success) 20%, transparent)
34
+ );
28
35
 
29
36
  & a {
30
37
  color: var(--success);
@@ -33,25 +40,14 @@
33
40
 
34
41
  &[data-variant="warning"] {
35
42
  color: var(--warning);
36
- background-color: color-mix(in srgb, var(--warning) 8%, white);
43
+ background-color: light-dark(
44
+ color-mix(in srgb, var(--warning) 8%, transparent),
45
+ color-mix(in srgb, var(--warning) 20%, transparent)
46
+ );
37
47
 
38
48
  & a {
39
49
  color: var(--warning);
40
50
  }
41
51
  }
42
-
43
- [data-theme="dark"] & {
44
- &[data-variant="error"], &[data-variant="danger"] {
45
- background-color: color-mix(in srgb, var(--danger) 20%, black);
46
- }
47
-
48
- &[data-variant="success"] {
49
- background-color: color-mix(in srgb, var(--success) 20%, black);
50
- }
51
-
52
- &[data-variant="warning"] {
53
- background-color: color-mix(in srgb, var(--warning) 20%, black);
54
- }
55
- }
56
52
  }
57
53
  }
package/css/badge.css CHANGED
@@ -24,31 +24,26 @@
24
24
 
25
25
  &.success {
26
26
  color: var(--success);
27
- background-color: color-mix(in srgb, var(--success) 12%, white);
27
+ background-color: light-dark(
28
+ color-mix(in srgb, var(--success) 10%, transparent),
29
+ color-mix(in srgb, var(--success) 30%, transparent)
30
+ );
28
31
  }
29
32
 
30
33
  &.warning {
31
34
  color: var(--warning);
32
- background-color: color-mix(in srgb, var(--warning) 12%, white);
35
+ background-color: light-dark(
36
+ color-mix(in srgb, var(--warning) 10%, transparent),
37
+ color-mix(in srgb, var(--warning) 30%, transparent)
38
+ );
33
39
  }
34
40
 
35
41
  &.danger {
36
42
  color: var(--danger);
37
- background-color: color-mix(in srgb, var(--danger) 15%, white);
38
- }
39
-
40
- [data-theme="dark"] & {
41
- &.success {
42
- background-color: color-mix(in srgb, var(--success) 40%, black);
43
- }
44
-
45
- &.warning {
46
- background-color: color-mix(in srgb, var(--warning) 40%, black);
47
- }
48
-
49
- &.danger {
50
- background-color: color-mix(in srgb, var(--danger) 40%, black);
51
- }
43
+ background-color: light-dark(
44
+ color-mix(in srgb, var(--danger) 10%, transparent),
45
+ color-mix(in srgb, var(--danger) 30%, transparent)
46
+ );
52
47
  }
53
48
  }
54
49
  }
package/css/button.css CHANGED
@@ -1,10 +1,11 @@
1
1
  @layer base {
2
- :is(button, [type=submit], [type=reset], [type=button], a.button) {
2
+ :is(button, [type=submit], [type=reset], [type=button], a.button), ::file-selector-button {
3
+ --_hov: color-mix(in srgb, var(--primary), white 25%);
4
+
3
5
  display: inline-flex;
4
6
  align-items: center;
5
7
  justify-content: center;
6
8
  gap: var(--space-2);
7
- /* height: 2.5rem; */
8
9
  padding: var(--space-2) var(--space-4);
9
10
  font-size: var(--text-7);
10
11
  font-weight: var(--font-medium);
@@ -17,10 +18,13 @@
17
18
  border: 1px solid;
18
19
  border-color: rgb(from #fff r g b / 0.15) rgb(from #000 r g b / 0.2) rgb(from #000 r g b / 0.2) rgb(from #fff r g b / 0.15);
19
20
  transition: background-color var(--transition-fast), opacity var(--transition-fast), transform var(--transition-fast);
20
- cursor: pointer;
21
+
22
+ &:not(:disabled) {
23
+ cursor: pointer;
24
+ }
21
25
 
22
26
  &:hover:not(:disabled) {
23
- background-color: color-mix(in srgb, var(--primary), white 25%);
27
+ background-color: var(--_hov);
24
28
  }
25
29
 
26
30
  &:active:not(:disabled) {
@@ -28,74 +32,51 @@
28
32
  }
29
33
 
30
34
  &[data-variant="secondary"] {
35
+ --_hov: color-mix(in srgb, var(--secondary), black 10%);
31
36
  background-color: var(--secondary);
32
37
  color: var(--secondary-foreground);
33
38
  border-color: rgb(from #fff r g b / 0.5) rgb(from #000 r g b / 0.1) rgb(from #000 r g b / 0.1) rgb(from #fff r g b / 0.5);
34
-
35
- &:hover:not(:disabled) {
36
- background-color: color-mix(in srgb, var(--secondary), black 10%);
37
- }
38
39
  }
39
40
 
40
41
  &[data-variant="danger"] {
42
+ --_hov: color-mix(in srgb, var(--danger), black 15%);
41
43
  background-color: var(--danger);
42
44
  color: var(--danger-foreground);
43
-
44
- &:hover:not(:disabled) {
45
- background-color: color-mix(in srgb, var(--danger), black 15%);
46
- }
47
45
  }
48
46
 
49
- &.outline {
47
+ &:is(.outline, .ghost) {
48
+ --_hov: var(--accent);
50
49
  background-color: transparent;
51
- border-color: var(--border);
50
+ color: var(--foreground);
52
51
 
53
- &:not([data-variant]) {
54
- color: var(--foreground);
55
- }
56
52
  &[data-variant="danger"] {
53
+ --_hov: color-mix(in srgb, var(--danger), transparent 90%);
57
54
  color: var(--danger);
58
- border-color: var(--danger);
59
- &:hover:not(:disabled) {
60
- background-color: color-mix(in srgb, var(--danger), transparent 90%);
61
- }
62
55
  }
56
+
63
57
  &[data-variant="secondary"] {
58
+ --_hov: color-mix(in srgb, var(--secondary), transparent 80%);
64
59
  color: var(--secondary-foreground);
65
- border-color: var(--secondary);
66
- &:hover:not(:disabled) {
67
- background-color: color-mix(in srgb, var(--secondary), transparent 80%);
68
- }
69
- }
70
- &:hover:not(:disabled):not([data-variant]) {
71
- background-color: var(--accent);
72
60
  }
73
61
  }
74
62
 
75
- &.ghost {
76
- background-color: transparent;
77
- border-color: transparent;
63
+ &.outline {
64
+ border-color: var(--border);
78
65
 
79
- &:not([data-variant]) {
80
- color: var(--foreground);
81
- }
82
66
  &[data-variant="danger"] {
83
- color: var(--danger);
84
- &:hover:not(:disabled) {
85
- background-color: color-mix(in srgb, var(--danger), transparent 90%);
86
- }
67
+ border-color: var(--danger);
87
68
  }
69
+
88
70
  &[data-variant="secondary"] {
89
- color: var(--secondary-foreground);
90
- &:hover:not(:disabled) {
91
- background-color: color-mix(in srgb, var(--secondary), transparent 80%);
92
- }
93
- }
94
- &:hover:not(:disabled):not([data-variant]) {
95
- background-color: var(--accent);
71
+ border-color: var(--secondary);
96
72
  }
97
73
  }
98
74
 
75
+ &.ghost {
76
+ /* Same as .outline but no border. */
77
+ border-color: transparent;
78
+ }
79
+
99
80
  &.small {
100
81
  padding: var(--space-1) var(--space-3);
101
82
  font-size: var(--text-8);
@@ -120,27 +101,41 @@
120
101
  }
121
102
  }
122
103
  }
104
+
105
+ ::file-selector-button {
106
+ background-color: transparent;
107
+ color: var(--foreground);
108
+ border: 1px solid var(--border);
109
+ }
110
+ ::file-selector-button:hover {
111
+ /* pseudoelement:hover can't be nested and has to be a separate block. */
112
+ background-color: var(--accent);
113
+ }
123
114
  }
124
115
 
125
116
  @layer components {
126
117
  menu.buttons {
118
+ list-style-type: none;
127
119
  padding-inline-start: 0;
128
120
  display: inline-flex;
129
121
 
130
- & > :is(button, [type=button], [type=submit], [type=reset], a.button) {
131
- border-radius: 0;
132
-
133
- &:first-child {
122
+ /* In menu.buttons, <li> children are expected to have just one child, which is a button/or a.button */
123
+ & > li {
124
+ &:first-child > * {
134
125
  border-start-start-radius: var(--radius-medium);
135
126
  border-end-start-radius: var(--radius-medium);
136
127
  }
137
128
 
138
- &:last-child {
129
+ &:last-child > * {
139
130
  border-start-end-radius: var(--radius-medium);
140
131
  border-end-end-radius: var(--radius-medium);
141
132
  }
142
133
 
143
- &:not(:last-child) {
134
+ & > * {
135
+ border-radius: 0;
136
+ }
137
+
138
+ &:not(:last-child) > * {
144
139
  border-inline-end: 1px solid rgb(from var(--primary-foreground) r g b / 0.2);
145
140
  }
146
141
  }
package/css/dialog.css CHANGED
@@ -3,8 +3,7 @@
3
3
  position: fixed;
4
4
  inset: 0;
5
5
  z-index: var(--z-modal);
6
- width: 100%;
7
- max-width: 32rem;
6
+ width: min(100% - 2rem, 32rem);
8
7
  max-height: 85vh;
9
8
  margin: auto;
10
9
  padding: 0;
package/css/dropdown.css CHANGED
@@ -28,10 +28,6 @@
28
28
  transform: translateY(-4px);
29
29
  }
30
30
  }
31
-
32
- hr {
33
- margin: var(--space-1) 0;
34
- }
35
31
  }
36
32
 
37
33
  [role="menuitem"] {
package/css/form.css CHANGED
@@ -32,6 +32,7 @@
32
32
  outline: none;
33
33
  border-color: var(--ring);
34
34
  box-shadow: 0 0 0 2px rgb(from var(--ring) r g b / 0.2);
35
+ z-index: 1;
35
36
  }
36
37
 
37
38
  &:disabled {
@@ -67,6 +68,7 @@
67
68
  width: 1rem;
68
69
  height: 1rem;
69
70
  margin: 0;
71
+ position: relative;
70
72
  background-color: var(--background);
71
73
  border: 1px solid var(--input);
72
74
  transition: background-color var(--transition-fast), border-color var(--transition-fast);
@@ -74,22 +76,24 @@
74
76
  &:checked {
75
77
  background-color: var(--primary);
76
78
  border-color: var(--primary);
79
+
80
+ &::after {
81
+ content: "";
82
+ position: absolute;
83
+ inset: 0;
84
+ background-color: var(--primary-foreground);
85
+ mask-position: center;
86
+ mask-repeat: no-repeat;
87
+ mask-size: 100%;
88
+ }
77
89
  }
78
90
  }
79
91
 
80
92
  input[type=checkbox] {
81
93
  border-radius: var(--radius-small);
82
- position: relative;
83
94
 
84
95
  &:checked::after {
85
- content: "";
86
- position: absolute;
87
- inset: 0;
88
- background-color: var(--primary-foreground);
89
96
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='4'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E");
90
- mask-size: 90%;
91
- mask-position: center;
92
- mask-repeat: no-repeat;
93
97
  }
94
98
 
95
99
  &[role=switch] {
@@ -101,7 +105,6 @@
101
105
  height: var(--switch-height);
102
106
  border-radius: var(--radius-full);
103
107
  background-color: var(--input);
104
- position: relative;
105
108
 
106
109
  &::before {
107
110
  content: "";
@@ -133,17 +136,9 @@
133
136
 
134
137
  input[type=radio] {
135
138
  border-radius: var(--radius-full);
136
- position: relative;
137
139
 
138
140
  &:checked::after {
139
- content: "";
140
- position: absolute;
141
- inset: 0;
142
- background-color: var(--primary-foreground);
143
141
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='4' fill='currentColor'/%3E%3C/svg%3E");
144
- mask-size: 100%;
145
- mask-position: center;
146
- mask-repeat: no-repeat;
147
142
  }
148
143
  }
149
144
 
@@ -206,7 +201,10 @@
206
201
  & > :is(input, textarea, select) {
207
202
  flex: 1;
208
203
  margin-block-start: 0;
209
- border-inline-end: 0;
204
+
205
+ &:not(:focus) {
206
+ border-inline-end-color: transparent;
207
+ }
210
208
  }
211
209
 
212
210
  & > :is(input, textarea, select, button) {
package/css/grid.css CHANGED
@@ -51,7 +51,15 @@
51
51
 
52
52
  /* Responsive: stack on mobile */
53
53
  @media (max-width: 768px) {
54
- .row { --grid-cols: 4; --grid-gap: 1rem; }
55
- .col, [class*="col-"] { --span: 4; } /* full width */
54
+ .row {
55
+ --grid-cols: 4;
56
+ --grid-gap: 1rem;
57
+ }
58
+ .col, [class*="col-"] {
59
+ --span: 4;
60
+ }
61
+ [class*="offset-"] {
62
+ grid-column-start: auto;
63
+ }
56
64
  }
57
65
  }