@jrgermain/stylesheet 0.2.1 → 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.
Files changed (53) hide show
  1. package/dist/index.css +2519 -2579
  2. package/dist/index.css.map +1 -1
  3. package/dist/index.min.css +2 -2
  4. package/dist/index.min.css.map +1 -1
  5. package/package.json +12 -12
  6. package/src/styles/components/accordion.css +136 -0
  7. package/src/styles/components/alert.css +12 -0
  8. package/src/styles/components/{_app.scss → app.css} +108 -57
  9. package/src/styles/components/banner.css +33 -0
  10. package/src/styles/components/{_button.scss → button.css} +145 -24
  11. package/src/styles/components/{_card.scss → card.css} +15 -19
  12. package/src/styles/components/chip.css +217 -0
  13. package/src/styles/components/{_hr.scss → divider.css} +7 -6
  14. package/src/styles/components/drawer.css +111 -0
  15. package/src/styles/components/{_field.scss → field.css} +25 -29
  16. package/src/styles/components/{_layout.scss → flex.css} +5 -25
  17. package/src/styles/components/heading.css +60 -0
  18. package/src/styles/components/highlight.css +39 -0
  19. package/src/styles/components/link.css +41 -0
  20. package/src/styles/components/meter.css +80 -0
  21. package/src/styles/components/modal.css +39 -0
  22. package/src/styles/components/progress.css +73 -0
  23. package/src/styles/components/quote.css +27 -0
  24. package/src/styles/components/{_skeleton.scss → skeleton.css} +17 -18
  25. package/src/styles/components/skip-link.css +44 -0
  26. package/src/styles/components/slider.css +96 -0
  27. package/src/styles/components/{_switch.scss → switch.css} +27 -23
  28. package/src/styles/components/table.css +86 -0
  29. package/src/styles/components/text.css +119 -0
  30. package/src/styles/components/visually-hidden.css +13 -0
  31. package/src/styles/experimental/dialog-animations.css +6 -6
  32. package/src/styles/index.css +32 -0
  33. package/src/styles/shared/base-alert.css +108 -0
  34. package/src/styles/shared/base-dialog.css +85 -0
  35. package/src/styles/shared/dismiss-button.css +27 -0
  36. package/src/styles/utils/reset.css +29 -0
  37. package/src/styles/utils/variables.css +204 -0
  38. package/src/svg/dropdown-invert-thick.svg +4 -0
  39. package/src/svg/dropdown-invert.svg +4 -0
  40. package/src/svg/dropdown-thick.svg +4 -0
  41. package/src/svg/dropdown.svg +1 -1
  42. package/src/tokens.js +141 -0
  43. package/src/styles/_utils.scss +0 -87
  44. package/src/styles/_variables.scss +0 -331
  45. package/src/styles/components/_alert.scss +0 -178
  46. package/src/styles/components/_chip.scss +0 -151
  47. package/src/styles/components/_details.scss +0 -155
  48. package/src/styles/components/_dialog.scss +0 -234
  49. package/src/styles/components/_progress-meter.scss +0 -149
  50. package/src/styles/components/_range.scss +0 -96
  51. package/src/styles/components/_table.scss +0 -82
  52. package/src/styles/components/_text.scss +0 -295
  53. package/src/styles/index.scss +0 -47
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jrgermain/stylesheet",
3
- "version": "0.2.1",
3
+ "version": "0.4.0",
4
4
  "description": "A stylesheet for apps I build",
5
5
  "homepage": "https://stylesheet.jrgermain.dev",
6
6
  "author": {
@@ -16,30 +16,30 @@
16
16
  "type": "module",
17
17
  "scripts": {
18
18
  "build": "node scripts/build.cjs",
19
+ "watch": "node scripts/watch.cjs",
19
20
  "lint": "stylelint ./src/styles"
20
21
  },
21
22
  "devDependencies": {
22
- "@csstools/postcss-sass": "^5.0.1",
23
- "cssnano": "^6.0.1",
24
- "postcss": "^8.4.31",
25
- "postcss-cli": "^11.0.0",
26
- "postcss-load-config": "^5.0.0",
27
- "postcss-preset-env": "^9.2.0",
23
+ "browserslist": "^4.24.3",
24
+ "chokidar": "^4.0.3",
25
+ "lightningcss": "^1.28.2",
28
26
  "prettier": "^3.2.5",
29
27
  "rimraf": "^5.0.5",
30
- "sass": "^1.69.4",
31
28
  "stylelint": "^16.0.0",
32
- "stylelint-config-standard-scss": "^13.0.0"
29
+ "stylelint-config-standard": "^36.0.1"
33
30
  },
34
31
  "files": [
35
32
  "dist",
36
- "src"
33
+ "src",
34
+ "index.cjs",
35
+ "index.mjs"
37
36
  ],
38
37
  "exports": {
39
38
  ".": {
40
- "sass": "./src/styles/index.scss"
39
+ "browser": "./dist/index.css",
40
+ "unpkg": "./dist/index.css",
41
+ "default": "./dist/index.css"
41
42
  },
42
- "./index.scss": "./src/styles/index.scss",
43
43
  "./index.css": "./dist/index.css",
44
44
  "./index.min.css": "./dist/index.min.css"
45
45
  },
@@ -0,0 +1,136 @@
1
+ .accordion {
2
+ width: 100%;
3
+
4
+ details {
5
+ width: 100%;
6
+ background-color: var(--color-body-alt);
7
+ padding-block: 0;
8
+ padding-inline: var(--space-xs);
9
+ border-radius: var(--radius-m);
10
+ border: var(--border-s) solid var(--color-outline);
11
+ box-shadow: var(--shadow-s);
12
+ font-family: var(--font-family-body);
13
+ font-size: var(--font-size-m);
14
+ font-weight: var(--font-weight-normal);
15
+
16
+ @media (prefers-reduced-motion: no-preference) {
17
+ transition: 150ms padding ease;
18
+ }
19
+
20
+ & + details {
21
+ border-block-start: 0;
22
+ }
23
+
24
+ &:not(:first-of-type) {
25
+ border-start-start-radius: 0;
26
+ border-start-end-radius: 0;
27
+ }
28
+
29
+ &:not(:last-of-type) {
30
+ border-end-start-radius: 0;
31
+ border-end-end-radius: 0;
32
+ }
33
+
34
+ &[open] {
35
+ padding-block-end: var(--space-xs);
36
+
37
+ summary {
38
+ border-block-end-color: var(--color-outline);
39
+ margin-block-end: var(--space-xs);
40
+
41
+ &::before {
42
+ rotate: 0deg;
43
+ }
44
+
45
+ &:not(:active, .active, :hover, .hover) {
46
+ color: var(--color-brand-3);
47
+ }
48
+ }
49
+ }
50
+ }
51
+
52
+ summary {
53
+ font-family: var(--font-family-heading);
54
+ font-size: var(--font-size-m);
55
+ font-weight: var(--font-weight-bold);
56
+ line-height: 1;
57
+ cursor: pointer;
58
+ border-block-end: var(--border-s) dashed transparent;
59
+ padding: var(--space-xs);
60
+ padding-inline-start: calc(var(--space-xs) + 1em);
61
+ margin-block: 0;
62
+ margin-inline: calc(-1 * var(--space-xs));
63
+ transition-duration: 150ms;
64
+ transition-property: color, border-color;
65
+ transition-timing-function: ease;
66
+ position: relative;
67
+ list-style: none; /* Hides ::marker pseudo element in favor of ::before (better cross browser consistency) */
68
+ color: var(--color-body-text);
69
+ user-select: none;
70
+
71
+ @media (prefers-reduced-motion: no-preference) {
72
+ transition-property: color, border-color, padding, margin;
73
+ }
74
+
75
+ &:is(:hover, .hover) {
76
+ color: light-dark(var(--color-brand-4), var(--color-brand-2));
77
+ }
78
+
79
+ &:is(:active, .active) {
80
+ color: light-dark(var(--color-brand-2), var(--color-brand-4));
81
+ }
82
+
83
+ /* Hides ::-webkit-details-marker pseudo element in favor of ::before (better cross browser consistency) */
84
+ &::-webkit-details-marker {
85
+ display: none;
86
+ }
87
+
88
+ /* Replacement marker element */
89
+ &::before {
90
+ content: light-dark(
91
+ url("@/src/svg/dropdown-thick.svg"),
92
+ url("@/src/svg/dropdown-invert-thick.svg")
93
+ );
94
+ display: inline-block;
95
+ position: absolute;
96
+ inset-block: 0;
97
+ inset-inline-start: calc(var(--space-xs) / 2);
98
+ margin: auto;
99
+ width: 1em;
100
+ height: 1em;
101
+ rotate: -90deg;
102
+ transition: rotate 200ms ease;
103
+ }
104
+
105
+ &:dir(rtl)::before {
106
+ rotate: 90deg;
107
+ }
108
+
109
+ @media (prefers-reduced-motion) {
110
+ transition-property: color, border-color;
111
+
112
+ &::before {
113
+ transition: none;
114
+ }
115
+ }
116
+ }
117
+
118
+ &.subtle {
119
+ details {
120
+ box-shadow: none;
121
+ border: 0;
122
+ padding-inline: var(--space-2xs);
123
+ background-color: transparent;
124
+
125
+ &[open] summary {
126
+ margin-block-end: var(--space-2xs);
127
+ }
128
+ }
129
+
130
+ summary {
131
+ border-block-end: 0;
132
+ padding: var(--space-2xs);
133
+ padding-inline-start: calc(var(--space-2xs) + 1em);
134
+ }
135
+ }
136
+ }
@@ -0,0 +1,12 @@
1
+ .alert {
2
+ border-radius: var(--radius-s);
3
+ border-start-start-radius: calc(var(--space-2xs) + 2em);
4
+ border-end-start-radius: calc(var(--space-2xs) + 2em);
5
+ padding: var(--space-2xs);
6
+ padding-inline-start: calc(var(--space-2xs) + 2em);
7
+
8
+ &::before,
9
+ &::after {
10
+ inset-inline-start: calc(var(--space-2xs) * 0.5);
11
+ }
12
+ }
@@ -1,37 +1,39 @@
1
- @use "../utils";
2
- @use "./layout";
3
-
4
1
  .app {
5
- --app-width: 110rem;
2
+ /* The app is designed to take up the entire width of the page. However, we
3
+ * set a global limit on the overall width of its content for UX and aesthetic
4
+ * reasons. The wrapper elements of the page will always extend to the edge of
5
+ * the screen, but all content within them will be kept within this limit and
6
+ * centered.
7
+ */
8
+ --app-max-content-width: 110rem;
9
+ --app-header-height: clamp(50px, 3.5rem, 70px);
10
+ --app-sidebar-width: clamp(300px, 18rem, 400px);
6
11
 
7
12
  position: relative;
8
- width: min-content;
9
- min-width: 100%;
13
+ width: 100%;
10
14
  min-height: 100svh;
11
15
  display: flex;
12
16
  flex-direction: column;
17
+ font-family: var(--font-family-body);
18
+ font-size: var(--font-size-m);
13
19
  }
14
20
 
15
21
  .app-header {
16
- height: clamp(50px, 3.5rem, 70px);
17
- width: 100dvw;
18
- color: var(--color-brand-3);
22
+ height: var(--app-header-height);
23
+ width: 100%;
24
+ color: light-dark(var(--color-brand-3), var(--color-brand-2));
19
25
  background-color: var(--color-body-alt);
20
26
  border-bottom: var(--border-l) solid var(--color-brand-transparent);
21
27
  box-shadow: var(--shadow-s);
22
28
  flex: none;
23
29
  position: sticky;
24
30
  left: 0;
25
-
26
- @media (prefers-color-scheme: dark) {
27
- color: var(--color-brand-2);
28
- }
29
31
  }
30
32
 
31
33
  .app-header-content {
32
34
  height: 100%;
33
35
  width: 100%;
34
- max-width: var(--app-width);
36
+ max-width: var(--app-max-content-width);
35
37
  margin-inline: auto;
36
38
  padding-inline: var(--space-body);
37
39
  display: flex;
@@ -46,33 +48,37 @@
46
48
  display: flex;
47
49
  align-items: center;
48
50
 
49
- // If header only has 1 section, center it
51
+ /* If header only has 1 section, center it */
50
52
  &:only-child {
51
53
  margin-inline: auto;
52
54
  }
53
55
 
54
- // Otherwise, align the first to the left and the rest to the right
56
+ /* Otherwise, align the first to the left and the rest to the right */
55
57
  &:first-child {
56
58
  margin-inline-end: auto;
57
59
  }
58
60
 
59
- // The content of the first header item should be var(--space-body) from the
60
- // left edge of the app. Since there is var(--space-body) padding in the
61
- // header and var(--space-xs) padding in the header items, we just need to
62
- // move it back by var(--space-xs).
61
+ /*
62
+ * The content of the first header item should be var(--space-body) from the
63
+ * left edge of the app. Since there is var(--space-body) padding in the
64
+ * header and var(--space-xs) padding in the header items, we just need to
65
+ * move it back by var(--space-xs).
66
+ */
63
67
  &:first-child .app-header-item:first-child {
64
68
  margin-inline-start: calc(-1 * var(--space-xs));
65
69
  }
66
70
 
67
- // The content of the last header item should be var(--space-body) from the
68
- // right edge of the app. Since there is var(--space-body) padding in the
69
- // header and var(--space-xs) padding in the header items, we just need to
70
- // move it forward by var(--space-xs).
71
+ /*
72
+ * The content of the last header item should be var(--space-body) from the
73
+ * right edge of the app. Since there is var(--space-body) padding in the
74
+ * header and var(--space-xs) padding in the header items, we just need to
75
+ * move it forward by var(--space-xs).
76
+ */
71
77
  &:last-child .app-header-item:last-child {
72
78
  margin-inline-end: calc(-1 * var(--space-xs));
73
79
  }
74
80
 
75
- // Put a spacer between consecutive right-aligned sections (3rd onward)
81
+ /* Put a spacer between consecutive right-aligned sections (3rd onward) */
76
82
  &:nth-child(n + 3)::before {
77
83
  content: "";
78
84
  background-color: var(--color-outline);
@@ -84,12 +90,12 @@
84
90
  }
85
91
 
86
92
  .app-header-item {
87
- // TODO simplify
93
+ /* TODO simplify */
88
94
  height: 100%;
89
95
  cursor: pointer;
90
96
  text-decoration: none;
91
97
  color: inherit;
92
- transition-property: color;
98
+ transition-property: color, background-color;
93
99
  transition-duration: 200ms;
94
100
  transition-timing-function: ease;
95
101
  display: flex;
@@ -97,13 +103,20 @@
97
103
  position: relative;
98
104
  font-weight: var(--font-weight-semibold);
99
105
  padding-inline: var(--space-xs);
106
+ border-radius: var(--radius-m);
107
+ border: var(--border-m) solid var(--color-body-alt);
100
108
 
101
- &:focus-visible {
102
- outline-offset: calc(-1 * var(--border-m));
109
+ &:hover {
110
+ background-color: var(--color-brand-extra-transparent);
103
111
  }
104
112
 
105
- &:hover {
106
- color: var(--color-body-text);
113
+ &:active {
114
+ background-color: var(--color-brand-transparent);
115
+ }
116
+
117
+ &:focus-visible {
118
+ background-color: var(--color-brand-extra-transparent);
119
+ outline-offset: calc(-1 * var(--border-m));
107
120
  }
108
121
 
109
122
  &:is([aria-current], .current) {
@@ -119,7 +132,7 @@
119
132
  position: absolute;
120
133
  width: 100%;
121
134
  height: var(--border-l);
122
- bottom: calc(-1 * var(--border-l));
135
+ bottom: calc(-1 * (var(--border-l) + var(--border-m)));
123
136
  left: 0;
124
137
  background-color: currentcolor;
125
138
  opacity: 0;
@@ -130,7 +143,7 @@
130
143
  .app-body {
131
144
  position: relative;
132
145
  width: 100%;
133
- max-width: var(--app-width);
146
+ max-width: var(--app-max-content-width);
134
147
  margin-inline: auto;
135
148
  flex: none;
136
149
  display: flex;
@@ -141,7 +154,7 @@
141
154
  transition:
142
155
  opacity 150ms ease,
143
156
  display 150ms allow-discrete;
144
- width: clamp(300px, 18rem, 400px);
157
+ width: var(--app-sidebar-width);
145
158
  flex: none;
146
159
  opacity: 1;
147
160
  border-inline-end: var(--border-s) dashed var(--color-outline);
@@ -151,7 +164,6 @@
151
164
  position: sticky;
152
165
  top: 0;
153
166
  overflow: auto;
154
- height: auto;
155
167
  height: 100dvh;
156
168
  }
157
169
 
@@ -184,6 +196,7 @@
184
196
  text-decoration: none;
185
197
  font-weight: var(--font-weight-normal);
186
198
  font-size: 1rem;
199
+ user-select: none;
187
200
  transition-property: color, background-color, box-shadow;
188
201
  transition-duration: 200ms;
189
202
  transition-timing-function: ease;
@@ -207,30 +220,24 @@
207
220
 
208
221
  &:focus-visible {
209
222
  outline-offset: 0;
223
+ background-color: var(--color-brand-extra-transparent);
210
224
  }
211
225
  }
212
226
 
213
227
  .app-sidebar-toggle {
214
- // TODO simplify
215
- @include utils.transition(("color", "background-color"));
216
-
228
+ /* TODO simplify */
229
+ transition-property: color, background-color;
230
+ transition-duration: 200ms;
231
+ transition-timing-function: ease;
217
232
  display: none;
218
233
  width: 2.75rem;
219
234
  margin-inline-start: 1rem;
220
235
 
221
- &:hover {
222
- color: var(--color-body-text);
223
- }
224
-
225
236
  &:has(input:focus-visible) {
226
237
  outline: var(--border-m) solid var(--color-brand-5);
227
238
  outline-offset: calc(-1 * var(--border-m));
228
239
  }
229
240
 
230
- input[type="checkbox"] {
231
- @extend %visually-hidden;
232
- }
233
-
234
241
  &::before {
235
242
  content: "";
236
243
  position: absolute;
@@ -242,8 +249,9 @@
242
249
  }
243
250
 
244
251
  > div {
245
- @include utils.transition(("transform", "opacity"));
246
-
252
+ transition-property: transform, opacity;
253
+ transition-duration: 200ms;
254
+ transition-timing-function: ease;
247
255
  position: absolute;
248
256
  width: 1.75rem;
249
257
  height: 2px;
@@ -285,22 +293,34 @@
285
293
  .app-content {
286
294
  width: 100%;
287
295
  padding: var(--space-body);
296
+ position: relative;
288
297
  }
289
298
 
290
- .app:has(.app-sidebar) {
291
- --app-width: 125rem;
299
+ /* If there's a sidebar, shrink the content area to accommodate it */
300
+ .app-sidebar ~ .app-content {
301
+ width: calc(100% - var(--app-sidebar-width));
292
302
  }
293
303
 
294
304
  @media (width < 55rem) {
305
+ /*
306
+ * If there's a sidebar, DON'T factor its width into the content width since
307
+ * the sidebar now has `position: fixed`. This only applies to pages with a
308
+ * sidebar; without one, app-content's width is already 100%.
309
+ */
310
+ .app-sidebar ~ .app-content {
311
+ width: 100%;
312
+ }
313
+
295
314
  .app-sidebar {
296
- width: 100dvw;
315
+ position: fixed;
316
+ top: var(--app-header-height);
317
+ left: 0;
318
+ width: 100vw;
297
319
  opacity: 1;
298
- background-color: #fffc;
320
+ background-color: light-dark(#fffc, #000a);
299
321
  backdrop-filter: blur(24px) saturate(120%);
300
-
301
- @media (prefers-color-scheme: dark) {
302
- background-color: #000c;
303
- }
322
+ border-right: 0;
323
+ z-index: 9;
304
324
 
305
325
  &::after {
306
326
  content: initial;
@@ -311,8 +331,39 @@
311
331
  display: initial;
312
332
  }
313
333
 
314
- .app:has(.app-sidebar-toggle input:not(:checked)) .app-sidebar {
334
+ .app-sidebar-content {
335
+ height: calc(100dvh - var(--app-header-height));
336
+ }
337
+
338
+ .app:not(:has(.app-sidebar-toggle input:checked)) .app-sidebar {
315
339
  opacity: 0;
316
340
  display: none;
317
341
  }
342
+
343
+ /* If sidebar is open, temporarily hide the overflow and any site-wide banners */
344
+ .app:has(.app-sidebar-toggle input:checked) {
345
+ overflow: hidden;
346
+
347
+ > .banner {
348
+ display: none;
349
+ }
350
+
351
+ .app-header {
352
+ position: fixed;
353
+ top: 0;
354
+ z-index: 10;
355
+ }
356
+
357
+ .app-content {
358
+ top: var(--app-header-height);
359
+ }
360
+ }
361
+ }
362
+
363
+ .app:has(dialog:modal) {
364
+ /*
365
+ * If modal is open, hide the overflow. This prevents the user from scrolling
366
+ * the page down by dragging on the header, which they'd have no way to undo.
367
+ */
368
+ overflow: hidden;
318
369
  }
@@ -0,0 +1,33 @@
1
+ .banner {
2
+ border-inline-width: 0;
3
+ width: 100%;
4
+ padding: var(--space-xs);
5
+ padding-inline-start: calc(var(--space-xs) + 2em);
6
+
7
+ &:has(.button.dismiss) {
8
+ padding-inline-end: calc(var(--space-xs) + 2em);
9
+ }
10
+
11
+ &::before,
12
+ &::after {
13
+ inset-inline-start: calc(var(--space-xs) * 0.5);
14
+ }
15
+
16
+ & + & {
17
+ border-block-start-width: 0;
18
+ }
19
+
20
+ .button.dismiss {
21
+ --button-fg-color: var(--alert-dismiss-icon-color);
22
+ --button-hover-bg-color: var(--alert-dismiss-hover-bg);
23
+
24
+ position: absolute;
25
+ inset-block: 0;
26
+ inset-inline-end: var(--space-3xs);
27
+ margin: auto;
28
+
29
+ &:is(:focus-visible, .focus) {
30
+ --button-bg-color: var(--alert-dismiss-focus-bg);
31
+ }
32
+ }
33
+ }