@stackoverflow/stacks 1.2.0 → 1.3.2

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 (42) hide show
  1. package/dist/controllers/s-expandable-control.d.ts +1 -1
  2. package/dist/controllers/s-tooltip.d.ts +16 -1
  3. package/dist/css/stacks.css +974 -731
  4. package/dist/css/stacks.min.css +1 -1
  5. package/dist/js/stacks.js +174 -91
  6. package/dist/js/stacks.min.js +1 -1
  7. package/lib/css/atomic/borders.less +1 -0
  8. package/lib/css/atomic/colors.less +1 -0
  9. package/lib/css/atomic/misc.less +1 -1
  10. package/lib/css/atomic/typography.less +0 -6
  11. package/lib/css/atomic/width-height.less +1 -1
  12. package/lib/css/components/activity-indicator.less +18 -17
  13. package/lib/css/components/avatars.less +51 -131
  14. package/lib/css/components/badges.less +2 -0
  15. package/lib/css/components/breadcrumbs.less +4 -4
  16. package/lib/css/components/buttons.less +38 -54
  17. package/lib/css/components/empty-states.less +15 -0
  18. package/lib/css/components/{collapsible.less → expandable.less} +0 -0
  19. package/lib/css/components/inputs.less +44 -110
  20. package/lib/css/components/labels.less +98 -0
  21. package/lib/css/components/notices.less +190 -163
  22. package/lib/css/components/post-summary.less +117 -114
  23. package/lib/css/components/progress-bars.less +1 -1
  24. package/lib/css/components/prose.less +4 -4
  25. package/lib/css/components/spinner.less +39 -1
  26. package/lib/css/components/tables.less +1 -5
  27. package/lib/css/components/topbar.less +4 -1
  28. package/lib/css/components/uploader.less +70 -84
  29. package/lib/css/exports/constants-colors.less +68 -49
  30. package/lib/css/stacks-dynamic.less +0 -1
  31. package/lib/css/stacks-static.less +3 -2
  32. package/lib/ts/controllers/s-expandable-control.ts +23 -19
  33. package/lib/ts/controllers/s-modal.ts +16 -16
  34. package/lib/ts/controllers/s-navigation-tablist.ts +13 -13
  35. package/lib/ts/controllers/s-popover.ts +26 -18
  36. package/lib/ts/controllers/s-table.ts +31 -29
  37. package/lib/ts/controllers/s-tooltip.ts +62 -23
  38. package/lib/ts/controllers/s-uploader.ts +26 -12
  39. package/lib/ts/stacks.ts +8 -4
  40. package/package.json +23 -23
  41. package/lib/css/components/banners.less +0 -80
  42. package/lib/css/components/blank-states.less +0 -26
@@ -6,206 +6,224 @@
6
6
  // Stack Overflow. For documentation of all these classes and how to contribute,
7
7
  // visit https://stackoverflow.design/
8
8
  //
9
- // TABLE OF CONTENTS
10
- // • BASE STYLE
11
- // • LAYOUT TRANSITIONS
12
- //
13
- // ============================================================================
14
- // $ BASE STYLES
15
- // ----------------------------------------------------------------------------
16
- // $$ FILLED, MUTED
17
- .s-notice {
18
- padding: var(--su16);
19
- border: 1px solid transparent;
20
- border-radius: var(--br-sm);
21
- color: var(--fc-medium);
9
+ .construct-notice-component() {
10
+ background: var(--_bg, var(--black-050));
11
+ border-color: var(--_bc, var(--bc-medium));
12
+ border-style: solid;
13
+ color: var(--_fc, var(--fc-medium));
22
14
  font-size: var(--fs-body1);
23
15
 
24
- .s-toast & {
25
- max-width: 44rem;
26
- width: 100%;
27
- padding-top: var(--su8);
28
- padding-bottom: var(--su8);
29
- box-shadow: var(--bs-sm);
30
- pointer-events: all;
16
+ code {
17
+ background: var(--_code-bg, transparent);
31
18
  }
32
19
 
33
- .s-notice--btn {
34
- color: var(--fc-dark);
20
+ & &--btn {
21
+ color: inherit;
35
22
  padding: var(--su8);
36
- }
37
- }
38
-
39
- // ============================================================================
40
- // $ VISUAL STYLES
41
- // ============================================================================
42
- // $$ INFO
43
- // ----------------------------------------------------------------------------
44
- .s-notice__info,
45
- .s-banner__info {
46
- border-color: var(--theme-secondary-150);
47
- background-color: var(--theme-secondary-050);
48
23
 
49
- &.s-notice__important,
50
- &.s-banner__important {
51
- background-color: var(--theme-secondary-400);
52
- }
53
-
54
- // Improve the presentation of buttons
55
- .s-notice--btn {
56
24
  &:focus,
57
25
  &:hover {
58
- background-color: var(--theme-secondary-300);
26
+ background: var(--_btn-focus-bg, var(--black-100));
59
27
  }
60
28
 
61
29
  &:active {
62
- background-color: var(--theme-secondary-400);
30
+ background: var(--_btn-active-bg, var(--black-150));
63
31
  }
64
32
  }
65
33
 
66
- code {
67
- background-color: var(--theme-secondary-150);
34
+ &:not(&__important) {
35
+ .dark-mode({ --_bc: var(--_bg); });
36
+ .highcontrast-mode({ --_bc: currentColor; });
37
+ .highcontrast-dark-mode({ --_bc: currentColor; });
68
38
  }
69
- }
70
39
 
71
- // $$ SUCCESS
72
- // ----------------------------------------------------------------------------
73
- .s-notice__success,
74
- .s-banner__success {
75
- border-color: var(--green-200);
76
- background-color: var(--green-050);
77
-
78
- // Bump up the border contrast in high contrast mode
79
- .highcontrast-mode({
80
- background-color: var(--green-200);
81
- border-color: var(--green-400);
82
- });
83
-
84
- &.s-notice__important,
85
- &.s-banner__important {
86
- background-color: var(--green-400);
87
- color: var(--black-900);
88
-
89
- // Bump up the text in high contrast
40
+ &__important {
41
+ --_bc: var(--_bg);
42
+ --_bg: var(--black-700);
43
+ --_fc: var(--white);
44
+ --_btn-focus-bg: var(--black-800);
45
+ --_btn-active-bg: var(--black-900);
46
+
47
+ .highcontrast-mode({ --_bc: var(--_bg); });
48
+ }
49
+
50
+ &__danger {
51
+ --_bc: var(--red-200);
52
+ --_bg: var(--red-050);
53
+ --_btn-focus-bg: var(--red-100);
54
+ --_btn-active-bg: var(--red-200);
55
+ }
56
+ &__danger:not(&__important) {
90
57
  .highcontrast-mode({
91
- background-color: var(--green-500);
92
- color: var(--white);
93
- border-color: transparent;
58
+ --_bg: var(--red-200);
94
59
  });
95
60
  }
96
-
97
- // Improve the presentation of buttons
98
- .s-notice--btn {
99
- &:focus,
100
- &:hover {
101
- background-color: var(--green-100);
102
- }
103
-
104
- &:active {
105
- background-color: var(--green-200);
106
- }
61
+ &__danger&__important {
62
+ --_bc: var(--_bg);
63
+ --_bg: var(--red-500);
64
+ --_btn-focus-bg: var(--red-600);
65
+ --_btn-active-bg: var(--red-700);
66
+
67
+ .dark-mode({
68
+ --_bg: var(--red-400);
69
+ --_fc: var(--black-900);
70
+ });
71
+ .highcontrast-dark-mode({
72
+ --_bg: var(--red-500);
73
+ --_fc: var(--white);
74
+ });
107
75
  }
108
- }
109
76
 
110
- // $$ WARNING
111
- // ----------------------------------------------------------------------------
112
- .s-notice__warning,
113
- .s-banner__warning {
114
- border-color: var(--yellow-300);
115
- background-color: var(--yellow-050);
116
-
117
- // Bump up the border contrast in high contrast mode
118
- .highcontrast-mode({
119
- background-color: var(--yellow-200);
120
- border-color: var(--yellow-700);
121
- });
122
-
123
- &.s-notice__important,
124
- &.s-banner__important {
125
- background-color: var(--yellow-400);
126
- color: var(--black-900);
127
-
128
- // Bump up the text in high contrast
77
+ &__info {
78
+ --_bc: var(--theme-secondary-150);
79
+ --_bg: var(--theme-secondary-050);
80
+ --_btn-focus-bg: var(--theme-secondary-100);
81
+ --_btn-active-bg: var(--theme-secondary-150);
82
+ --_code-bg: var(--theme-secondary-150);
83
+ }
84
+ &__info:not(&__important) {
129
85
  .highcontrast-mode({
130
- background-color: var(--yellow-500);
131
- color: var(--white);
132
- border-color: transparent;
86
+ --_bg: var(--theme-secondary-100);
87
+ });
88
+ .highcontrast-dark-mode({
89
+ --_bg: var(--theme-secondary-100);
90
+ });
91
+ }
92
+ &__info&__important {
93
+ --_bc: var(--_bg);
94
+ --_bg: var(--theme-secondary-400);
95
+ --_btn-focus-bg: var(--theme-secondary-500);
96
+ --_btn-active-bg: var(--theme-secondary-600);
97
+
98
+ .dark-mode({
99
+ --_bg: var(--theme-secondary-300);
100
+ --_fc: var(--black-900);
101
+ });
102
+ .highcontrast-dark-mode({
103
+ --_bg: var(--theme-secondary-400);
104
+ --_fc: var(--white);
133
105
  });
134
106
  }
135
107
 
136
- // Improve the presentation of buttons
137
- .s-notice--btn {
138
- &:focus,
139
- &:hover {
140
- background-color: var(--yellow-200);
141
- }
142
-
143
- &:active {
144
- background-color: var(--yellow-300);
145
- }
108
+ &__success {
109
+ --_bc: var(--green-200);
110
+ --_bg: var(--green-050);
111
+ --_btn-focus-bg: var(--green-100);
112
+ --_btn-active-bg: var(--green-200);
113
+ }
114
+ &__success:not(&__important) {
115
+ .highcontrast-mode({
116
+ --_bg: var(--green-200);
117
+ });
118
+ }
119
+ &__success&__important {
120
+ --_bc: var(--_bg);
121
+ --_bg: var(--green-400);
122
+ --_fc: var(--black-900);
123
+ --_btn-focus-bg: var(--green-500);
124
+ --_btn-active-bg: var(--green-600);
125
+
126
+ .dark-mode({
127
+ --_bg: var(--green-500);
128
+ --_fc: var(--white);
129
+ });
130
+ .highcontrast-mode({
131
+ --_bg: var(--green-500);
132
+ --_fc: var(--white);
133
+ });
146
134
  }
147
135
 
148
- code {
149
- background-color: var(--yellow-200);
136
+ &__warning {
137
+ --_bc: var(--yellow-300);
138
+ --_bg: var(--yellow-050);
139
+ --_btn-focus-bg: var(--yellow-200);
140
+ --_btn-active-bg: var(--yellow-300);
141
+ --_code-bg: var(--yellow-200);
142
+ }
143
+ &__warning:not(&__important) {
144
+ .highcontrast-mode({
145
+ --_bg: var(--yellow-200);
146
+ });
147
+ }
148
+ &__warning&__important {
149
+ --_bc: var(--_bg);
150
+ --_bg: var(--yellow-400);
151
+ --_btn-focus-bg: var(--yellow-500);
152
+ --_btn-active-bg: var(--yellow-600);
153
+ --_fc: var(--black-900);
154
+
155
+ .dark-mode({
156
+ --_bg: var(--yellow-600);
157
+ --_fc: var(--white);
158
+ });
159
+ .highcontrast-mode({
160
+ --_bg: var(--yellow-700);
161
+ --_fc: var(--white);
162
+ });
150
163
  }
151
164
  }
152
165
 
153
- // $$ DANGER
154
- // ----------------------------------------------------------------------------
155
- .s-notice__danger,
156
- .s-banner__danger {
157
- border-color: var(--red-200);
158
- background-color: var(--red-050);
159
-
160
- // Bump up the border contrast in high contrast mode
161
- .highcontrast-mode({
162
- background-color: var(--red-200);
163
- border-color: var(--red-500);
164
-
165
- &.s-notice__important,
166
- &.s-banner__important {
167
- background-color: var(--red-500);
168
- }
169
- });
170
-
171
- &.s-notice__important,
172
- &.s-banner__important {
173
- background-color: var(--red-400);
166
+ // Banner
167
+ // TODO deprecate .s-banner (by turning it into a modifier on .s-notice)
168
+ // This would reduce the amount of CSS we ship to the client and simplify our codebase
169
+ .s-banner {
170
+ .construct-notice-component();
171
+ --_x-offset: 0;
172
+ // When we use .s-banner, we need to adjust the padding-top on
173
+ // the body tag. This class correctly adjusts the body padding ONLY if
174
+ // the notice is one line. If it wraps to multiple lines, more classes or
175
+ // (ideally) JS will need to be used to determine the notice's height
176
+ // at the time of render. The padding value is determined like so:
177
+ //
178
+ // 50px (top bar) + 44px (notice height) - 1px (bottom border)
179
+ //
180
+ // The borders subtraction are necessary to neatly tuck everything together.
181
+ // ----------------------------------------------------------------------------
182
+ &__body-pt {
183
+ padding-top: 93px;
174
184
  }
175
-
176
- // Improve the presentation of buttons
177
- .s-notice--btn {
178
- &:focus,
179
- &:hover {
180
- background-color: var(--red-100);
181
- }
182
-
183
- &:active {
184
- background-color: var(--red-200);
185
- }
185
+ // If you want to put the banner above the topbar
186
+ &.is-pinned {
187
+ z-index: calc(var(--zi-navigation-fixed) + 1);
188
+ }
189
+ // If you want to hide and reveal the banner
190
+ &[aria-hidden="true"] {
191
+ --_x-offset: -50px; // TODO convert to su vars
192
+ visibility: hidden;
193
+ opacity: 0;
194
+ }
195
+ &[aria-hidden="false"] {
196
+ --_x-offset: 49px; // TODO convert to su vars
197
+ visibility: visible;
198
+ opacity: 1;
199
+ }
200
+ // When we want to keep hero content capped
201
+ .s-banner--container {
202
+ position: relative;
203
+ width: 100%;
204
+ max-width: calc(var(--s-step) * 10);
205
+ margin: 0 auto;
186
206
  }
187
- }
188
207
 
189
- // $$ IMPORTANT
190
- // ----------------------------------------------------------------------------
191
- .s-notice__important {
192
- border-color: transparent;
193
- background-color: var(--black-700);
194
- color: var(--white);
208
+ border-width: var(--su-static1) 0;
209
+ inset: 0 0 auto 0;
210
+ padding: var(--su12);
211
+ position: fixed;
212
+ width: 100%;
213
+ z-index: calc(var(--zi-navigation-fixed) - 1); // Tuck below topbar
214
+ -webkit-transform: translate3d(0, var(--_x-offset), 0);
215
+ transform: translate3d(0, var(--_x-offset), 0);
195
216
  }
196
217
 
197
- .s-notice__info,
198
- .s-notice__success,
199
- .s-notice__warning,
200
- .s-notice__danger {
201
- .dark-mode({ border-color: transparent; });
202
- .highcontrast-mode({ border-color: currentColor; });
203
-
218
+ // Notice
219
+ .s-notice {
220
+ .construct-notice-component();
221
+ border-radius: var(--br-sm);
222
+ border-width: var(--su-static1);
223
+ padding: var(--su16);
204
224
  }
205
225
 
206
- // ============================================================================
207
- // $ TOASTS
208
- // ----------------------------------------------------------------------------
226
+ // Toast
209
227
  .s-toast {
210
228
  visibility: hidden;
211
229
  position: fixed;
@@ -230,4 +248,13 @@
230
248
  @media (prefers-reduced-motion) {
231
249
  transform: none;
232
250
  }
251
+
252
+ .s-notice {
253
+ max-width: 44rem;
254
+ width: 100%;
255
+ padding-top: var(--su8);
256
+ padding-bottom: var(--su8);
257
+ box-shadow: var(--bs-sm);
258
+ pointer-events: all;
259
+ }
233
260
  }
@@ -34,87 +34,6 @@
34
34
  width: 100%;
35
35
  }
36
36
  }
37
-
38
- &.s-post-summary__legacy {
39
- padding-left: 0; // Since stats have padding, we don't need it on the parent
40
-
41
- #stacks-internals #screen-md({
42
- padding-left: var(--su16);
43
- });
44
-
45
- .s-post-summary--stats {
46
- width: auto;
47
- flex-direction: row;
48
- align-items: center;
49
- gap: var(--su2);
50
-
51
- .s-post-summary--stats-item {
52
- min-width: var(--su64);
53
- height: var(--su48);
54
- flex-direction: column;
55
- gap: 0;
56
- font-size: var(--fs-caption);
57
-
58
- &.s-post-summary--stats-item__emphasized {
59
- color: inherit;
60
- }
61
-
62
- &.has-accepted-answer .svg-icon {
63
- display: none;
64
- }
65
-
66
- .s-post-summary--stats-item-number {
67
- font-weight: normal;
68
- font-size: var(--fs-body3);
69
- }
70
-
71
- &.is-deleted,
72
- &.is-published,
73
- &.is-draft,
74
- &.is-review,
75
- &.is-closed,
76
- &.is-archived,
77
- &.is-pinned {
78
- display: none;
79
- }
80
- }
81
-
82
- #stacks-internals #screen-md({
83
- flex-direction: row;
84
- align-items: center;
85
- gap: var(--su8);
86
-
87
- .s-post-summary--stats-item {
88
- min-width: auto;
89
- height: auto;
90
- flex-direction: row;
91
- gap: 3px; // HTML spacing
92
-
93
- .s-post-summary--stats-item-number {
94
- font-size: inherit;
95
- }
96
-
97
- &.s-post-summary--stats-item__emphasized {
98
- color: var(--fc-dark);
99
- }
100
-
101
- &.has-accepted-answer .svg-icon {
102
- display: block;
103
- }
104
-
105
- &.is-deleted,
106
- &.is-published,
107
- &.is-draft,
108
- &.is-review,
109
- &.is-closed,
110
- &.is-archived,
111
- &.is-pinned {
112
- display: block;
113
- }
114
- }
115
- });
116
- }
117
- }
118
37
  }
119
38
 
120
39
  // [1] To override .s-btn class attributes
@@ -181,17 +100,13 @@
181
100
  }
182
101
 
183
102
  &.has-answers {
184
- color: var(--green-600);
185
- border: 1px solid var(--green-600);
103
+ color: var(--green-700);
104
+ border: 1px solid var(--green-700);
186
105
 
187
106
  &.has-accepted-answer {
188
- color: @white;
189
- background-color: var(--green-500);
190
- border-color: var(--green-500);
191
-
192
- .highcontrast-mode({
193
- color: var(--white);
194
- });
107
+ color: var(--white);
108
+ background-color: var(--green-700);
109
+ border-color: var(--green-700);
195
110
  }
196
111
  }
197
112
 
@@ -202,15 +117,15 @@
202
117
  }
203
118
 
204
119
  &.is-warm {
205
- color: var(--orange-800);
120
+ color: var(--yellow-800);
206
121
  }
207
122
 
208
123
  &.is-hot {
209
- color: var(--orange-600);
124
+ color: var(--orange-800);
210
125
  }
211
126
 
212
127
  &.is-supernova {
213
- color: var(--orange-400);
128
+ color: var(--red-800);
214
129
  }
215
130
 
216
131
  &.is-published {
@@ -390,39 +305,107 @@
390
305
 
391
306
  .s-post-summary__watched {
392
307
  background-color: var(--yellow-050);
393
- }
394
308
 
395
- .s-post-summary__deleted {
396
- background-color: var(--red-050);
309
+ .s-post-summary--content-title > a {
310
+ color: var(--blue-700);
397
311
 
398
- .is-deleted {
399
- color: @white;
400
- background-color: var(--red-500);
312
+ &:hover,
313
+ &:active{
314
+ color: var(--blue-700);
315
+ }
316
+ &:visited {
317
+ color: var(--blue-800);
318
+ }
319
+ }
320
+
321
+ .s-post-summary--stats {
322
+ color: var(--black-500);
323
+ }
324
+
325
+ .s-user-card {
326
+ .s-user-card--link {
327
+ color: var(--blue-700);
328
+ }
329
+
330
+ .s-user-card--rep,
331
+ .s-user-card--time {
332
+ color: var(--black-600);
333
+ }
401
334
  }
402
335
  }
403
336
 
404
- .s-post-summary__ignored,
405
337
  .s-post-summary__deleted {
406
- .s-post-summary--content > *:not(.s-post-summary--content-menu-button) {
407
- opacity: 0.6;
408
- }
338
+ background-color: var(--red-025);
409
339
 
410
- // TODO DEPRECATED remove `:not(.is-deleted)`
411
- .s-post-summary--stats-item:not(.s-badge):not(.is-deleted) {
412
- opacity: 0.6;
413
- filter: grayscale(100%);
340
+ .s-badge__filled {
341
+ color: var(--white);
342
+
343
+ .dark-mode({
344
+ background-color: var(--red-800)
345
+ });
414
346
  }
415
347
 
416
- .s-post-summary--content-title a {
417
- color: var(--black-600);
348
+ .is-deleted {
349
+ color: var(--white);
350
+ background-color: var(--red-600);
351
+ }
418
352
 
353
+ .s-post-summary--meta-tags > .s-tag {
354
+ &,
419
355
  &:hover,
420
- &:active {
356
+ &:active,
357
+ &:focus {
358
+ background-color: var(--black-075);
359
+ }
360
+
361
+ }
362
+ }
363
+
364
+ .s-post-summary__ignored {
365
+
366
+ .s-post-summary--stats {
367
+ color: var(--black-500);
368
+
369
+ .s-post-summary--stats-item {
370
+
371
+ &.has-answers {
372
+ color: var(--black-600);
373
+ border: 1px solid var(--black-075);
374
+ background-color: var(--black-075);
375
+
376
+ .has-accepted-answer {
377
+ color: var(--black-600);
378
+ background-color: var(--black-075);
379
+ border-color: var(--black-075);
380
+ }
381
+ }
382
+ }
383
+
384
+ .s-post-summary--stats-item__emphasized {
421
385
  color: var(--black-500);
422
386
  }
387
+ }
388
+
389
+ .s-post-summary--meta-tags > .s-tag {
390
+ &,
391
+ &:hover,
392
+ &:active,
393
+ &:focus {
394
+ background-color: var(--black-050);
395
+ }
396
+ }
397
+ }
398
+
399
+ .s-post-summary__ignored,
400
+ .s-post-summary__deleted {
401
+
402
+ .s-post-summary--content-title > a {
403
+ color: var(--black-500);
423
404
 
405
+ &:hover,
406
+ &:active,
424
407
  &:visited {
425
- color: var(--black-700);
408
+ color: var(--black-500);
426
409
  }
427
410
  }
428
411
 
@@ -430,7 +413,27 @@
430
413
  color: var(--black-500);
431
414
  }
432
415
 
433
- .s-post-summary--meta {
434
- filter: grayscale(100%);
416
+ .s-post-summary--meta > *:not(.s-post-summary--meta-tags) {
417
+ color: var(--black-600);
435
418
  }
436
- }
419
+
420
+ .s-post-summary--meta-tags > .s-tag {
421
+ &,
422
+ &:hover,
423
+ &:active,
424
+ &:focus {
425
+ color: var(--black-600);
426
+ }
427
+ }
428
+
429
+ .s-user-card {
430
+ .s-user-card--link {
431
+ color: var(--black-500);
432
+ }
433
+
434
+ .s-user-card--rep,
435
+ .s-user-card--time {
436
+ color: var(--black-500);
437
+ }
438
+ }
439
+ }
@@ -209,7 +209,7 @@
209
209
  border-radius: 0;
210
210
  padding: var(--su12) var(--su6) 0 var(--su6);
211
211
  text-align: center;
212
- color: var(--black-300);
212
+ color: var(--black-500);
213
213
  z-index: var(--zi-base);
214
214
  }
215
215