@stackoverflow/stacks 1.7.1 → 1.9.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 (138) hide show
  1. package/README.md +1 -1
  2. package/dist/components/activity-indicator/activity-indicator.a11y.test.d.ts +1 -0
  3. package/dist/components/activity-indicator/activity-indicator.visual.test.d.ts +1 -0
  4. package/dist/components/avatar/avatar.a11y.test.d.ts +1 -0
  5. package/dist/components/avatar/avatar.visual.test.d.ts +1 -0
  6. package/dist/{controllers/s-banner.d.ts → components/banner/banner.d.ts} +1 -1
  7. package/dist/components/banner/banner.test.d.ts +1 -0
  8. package/dist/components/banner/banner.visual.test.d.ts +1 -0
  9. package/dist/components/button/button.a11y.test.d.ts +1 -0
  10. package/dist/components/button/button.visual.test.d.ts +1 -0
  11. package/dist/{controllers/s-expandable-control.d.ts → components/expandable/expandable.d.ts} +1 -1
  12. package/dist/components/expandable/expandable.test.d.ts +1 -0
  13. package/dist/{controllers/s-modal.d.ts → components/modal/modal.d.ts} +1 -1
  14. package/dist/{controllers/s-navigation-tablist.d.ts → components/navigation/navigation.d.ts} +1 -1
  15. package/dist/{controllers/s-popover.d.ts → components/popover/popover.d.ts} +1 -1
  16. package/dist/{controllers/s-tooltip.d.ts → components/popover/tooltip.d.ts} +1 -1
  17. package/dist/components/popover/tooltip.test.d.ts +1 -0
  18. package/dist/components/popover/tooltip.visual.test.d.ts +1 -0
  19. package/dist/{controllers/s-table.d.ts → components/table/table.d.ts} +1 -1
  20. package/dist/{controllers/s-toast.d.ts → components/toast/toast.d.ts} +1 -1
  21. package/dist/components/toast/toast.test.d.ts +1 -0
  22. package/dist/components/toast/toast.visual.test.d.ts +1 -0
  23. package/dist/{controllers/s-uploader.d.ts → components/uploader/uploader.d.ts} +1 -1
  24. package/dist/controllers.d.ts +9 -0
  25. package/dist/css/stacks.css +1351 -1171
  26. package/dist/css/stacks.min.css +1 -1
  27. package/dist/index.d.ts +1 -1
  28. package/dist/js/stacks.js +545 -545
  29. package/dist/js/stacks.min.js +1 -1
  30. package/dist/test/test-utils.d.ts +136 -0
  31. package/lib/{css/atomic/borders.less → atomic/border.less} +18 -0
  32. package/lib/base/fieldset.less +5 -0
  33. package/lib/{css/base/icons.less → base/icon.less} +0 -9
  34. package/lib/components/activity-indicator/activity-indicator.a11y.test.ts +21 -0
  35. package/lib/components/activity-indicator/activity-indicator.visual.test.ts +23 -0
  36. package/lib/components/avatar/avatar.a11y.test.ts +36 -0
  37. package/lib/components/avatar/avatar.visual.test.ts +54 -0
  38. package/lib/components/banner/banner.less +51 -0
  39. package/lib/{test/s-banner.test.ts → components/banner/banner.test.ts} +7 -3
  40. package/lib/{ts/controllers/s-banner.ts → components/banner/banner.ts} +1 -1
  41. package/lib/components/banner/banner.visual.test.ts +36 -0
  42. package/lib/components/button/button.a11y.test.ts +32 -0
  43. package/lib/{css/components/buttons.less → components/button/button.less} +7 -6
  44. package/lib/components/button/button.visual.test.ts +52 -0
  45. package/lib/{css/components/cards.less → components/card/card.less} +1 -1
  46. package/lib/components/check-control/check-control.less +17 -0
  47. package/lib/components/check-group/check-group.less +19 -0
  48. package/lib/components/checkbox_radio/checkbox_radio.less +158 -0
  49. package/lib/components/description/description.less +9 -0
  50. package/lib/{css/components → components/expandable}/expandable.less +3 -0
  51. package/lib/components/expandable/expandable.test.ts +53 -0
  52. package/lib/{ts/controllers/s-expandable-control.ts → components/expandable/expandable.ts} +1 -1
  53. package/lib/components/input-fill/input-fill.less +35 -0
  54. package/lib/components/input-icon/input-icon.less +45 -0
  55. package/lib/components/input-message/input-message.less +48 -0
  56. package/lib/components/input_textarea/input_textarea.less +166 -0
  57. package/lib/{css/components/labels.less → components/label/label.less} +4 -4
  58. package/lib/{css/components → components/link}/link.less +9 -2
  59. package/lib/{ts/controllers/s-modal.ts → components/modal/modal.ts} +1 -1
  60. package/lib/{ts/controllers/s-navigation-tablist.ts → components/navigation/navigation.ts} +1 -1
  61. package/lib/{css/components/notices.less → components/notice/notice.less} +0 -89
  62. package/lib/{css/components/popovers.less → components/popover/popover.less} +1 -0
  63. package/lib/{ts/controllers/s-popover.ts → components/popover/popover.ts} +1 -1
  64. package/lib/{test/s-tooltip.test.ts → components/popover/tooltip.test.ts} +6 -2
  65. package/lib/{ts/controllers/s-tooltip.ts → components/popover/tooltip.ts} +2 -2
  66. package/lib/{test/s-tooltip.visual.test.ts → components/popover/tooltip.visual.test.ts} +2 -2
  67. package/lib/{css/components → components/post-summary}/post-summary.less +6 -2
  68. package/lib/components/select/select.less +148 -0
  69. package/lib/{css/components/sidebar-widgets.less → components/sidebar-widget/sidebar-widget.less} +0 -1
  70. package/lib/{css/components → components/table}/table.less +0 -5
  71. package/lib/{ts/controllers/s-table.ts → components/table/table.ts} +1 -1
  72. package/lib/components/table-container/table-container.less +4 -0
  73. package/lib/{css/components/tags.less → components/tag/tag.less} +3 -3
  74. package/lib/components/toast/toast.less +35 -0
  75. package/lib/{test/s-toast.test.ts → components/toast/toast.test.ts} +7 -3
  76. package/lib/{ts/controllers/s-toast.ts → components/toast/toast.ts} +1 -1
  77. package/lib/components/toast/toast.visual.test.ts +27 -0
  78. package/lib/{css/components/toggle-switches.less → components/toggle-switch/toggle-switch.less} +8 -0
  79. package/lib/{ts/controllers/s-uploader.ts → components/uploader/uploader.ts} +1 -1
  80. package/lib/controllers.ts +33 -0
  81. package/lib/{css/exports → exports}/mixins.less +73 -11
  82. package/lib/{ts/index.ts → index.ts} +1 -1
  83. package/lib/input-utils.less +44 -0
  84. package/lib/{css/stacks-dynamic.less → stacks-dynamic.less} +1 -2
  85. package/lib/stacks-static.less +93 -0
  86. package/lib/test/test-utils.ts +444 -0
  87. package/lib/tsconfig.json +1 -1
  88. package/package.json +26 -25
  89. package/dist/controllers/index.d.ts +0 -9
  90. package/lib/css/components/inputs.less +0 -666
  91. package/lib/css/stacks-static.less +0 -97
  92. package/lib/test/s-avatar.test.ts +0 -74
  93. package/lib/test/s-banner.visual.test.ts +0 -61
  94. package/lib/test/s-button.visual.test.ts +0 -12
  95. package/lib/test/s-toast.visual.test.ts +0 -48
  96. package/lib/ts/controllers/index.ts +0 -17
  97. /package/lib/{css/atomic/colors.less → atomic/color.less} +0 -0
  98. /package/lib/{css/atomic → atomic}/flex.less +0 -0
  99. /package/lib/{css/atomic → atomic}/gap.less +0 -0
  100. /package/lib/{css/atomic → atomic}/grid.less +0 -0
  101. /package/lib/{css/atomic → atomic}/misc.less +0 -0
  102. /package/lib/{css/atomic → atomic}/spacing.less +0 -0
  103. /package/lib/{css/atomic → atomic}/typography.less +0 -0
  104. /package/lib/{css/atomic → atomic}/width-height.less +0 -0
  105. /package/lib/{css/base → base}/body.less +0 -0
  106. /package/lib/{css/base → base}/configuration-static.less +0 -0
  107. /package/lib/{css/base/internals.less → base/internal.less} +0 -0
  108. /package/lib/{css/base → base}/reset-meyer.less +0 -0
  109. /package/lib/{css/base → base}/reset-normalize.less +0 -0
  110. /package/lib/{css/base → base}/reset.less +0 -0
  111. /package/lib/{css/components → components/activity-indicator}/activity-indicator.less +0 -0
  112. /package/lib/{css/components/anchors.less → components/anchor/anchor.less} +0 -0
  113. /package/lib/{css/components/avatars.less → components/avatar/avatar.less} +0 -0
  114. /package/lib/{css/components → components/award-bling}/award-bling.less +0 -0
  115. /package/lib/{css/components/badges.less → components/badge/badge.less} +0 -0
  116. /package/lib/{css/components → components/block-link}/block-link.less +0 -0
  117. /package/lib/{css/components → components/breadcrumbs}/breadcrumbs.less +0 -0
  118. /package/lib/{css/components/button-groups.less → components/button-group/button-group.less} +0 -0
  119. /package/lib/{css/components/code-blocks.less → components/code-block/code-block.less} +0 -0
  120. /package/lib/{css/components/empty-states.less → components/empty-state/empty-state.less} +0 -0
  121. /package/lib/{css/components/link-previews.less → components/link-preview/link-preview.less} +0 -0
  122. /package/lib/{css/components → components/menu}/menu.less +0 -0
  123. /package/lib/{css/components/modals.less → components/modal/modal.less} +0 -0
  124. /package/lib/{css/components → components/navigation}/navigation.less +0 -0
  125. /package/lib/{css/components/page-titles.less → components/page-title/page-title.less} +0 -0
  126. /package/lib/{css/components → components/pagination}/pagination.less +0 -0
  127. /package/lib/{css/components/progress-bars.less → components/progress-bar/progress-bar.less} +0 -0
  128. /package/lib/{css/components → components/prose}/prose.less +0 -0
  129. /package/lib/{css/components → components/spinner}/spinner.less +0 -0
  130. /package/lib/{css/components → components/topbar}/topbar.less +0 -0
  131. /package/lib/{css/components → components/uploader}/uploader.less +0 -0
  132. /package/lib/{css/components/user-cards.less → components/user-card/user-card.less} +0 -0
  133. /package/lib/{css/exports → exports}/constants-colors.less +0 -0
  134. /package/lib/{css/exports → exports}/constants-helpers.less +0 -0
  135. /package/lib/{css/exports → exports}/constants-type.less +0 -0
  136. /package/lib/{css/exports → exports}/exports.less +0 -0
  137. /package/lib/{css/stacks.less → stacks.less} +0 -0
  138. /package/lib/{ts/stacks.ts → stacks.ts} +0 -0
@@ -335,6 +335,24 @@
335
335
  .bc-yellow-800 { border-color: var(--yellow-800) !important; }
336
336
  .bc-yellow-900 { border-color: var(--yellow-900) !important; }
337
337
 
338
+ // $$ GOLD
339
+ // ----------------------------------------------------------------------------
340
+ .bc-gold-lighter { border-color: var(--gold-lighter) !important; }
341
+ .bc-gold { border-color: var(--gold) !important; }
342
+ .bc-gold-darker { border-color: var(--gold-darker) !important; }
343
+
344
+ // $$ SILVER
345
+ // ----------------------------------------------------------------------------
346
+ .bc-silver-lighter { border-color: var(--silver-lighter) !important; }
347
+ .bc-silver { border-color: var(--silver) !important; }
348
+ .bc-silver-darker { border-color: var(--silver-darker) !important; }
349
+
350
+ // $$ BRONZE
351
+ // ----------------------------------------------------------------------------
352
+ .bc-bronze-lighter { border-color: var(--bronze-lighter) !important; }
353
+ .bc-bronze { border-color: var(--bronze) !important; }
354
+ .bc-bronze-darker { border-color: var(--bronze-darker) !important; }
355
+
338
356
  // $$ PRIMARY
339
357
  // ----------------------------------------------------------------------------
340
358
  .bc-theme-primary-025 { border-color: var(--theme-primary-025) !important; }
@@ -0,0 +1,5 @@
1
+ fieldset {
2
+ border: 0;
3
+ min-width: 0;
4
+ padding: 0;
5
+ }
@@ -1,12 +1,3 @@
1
- //
2
- // STACK OVERFLOW
3
- // ICON STYLES
4
- //
5
- // This CSS comes from Stacks, our CSS & Pattern library for rapidly building
6
- // Stack Overflow. For documentation of all these classes and how to contribute,
7
- // visit https://stackoverflow.design/
8
- //
9
-
10
1
  .svg-icon,
11
2
  .svg-spot {
12
3
  vertical-align: bottom; // Make SVG play nicely while inline with text by default
@@ -0,0 +1,21 @@
1
+ import { runComponentTests } from "../../test/test-utils";
2
+ import "../../index";
3
+
4
+ describe("activity-indicator", () => {
5
+ runComponentTests({
6
+ type: "a11y",
7
+ baseClass: "s-activity-indicator",
8
+ variants: ["danger", "success", "warning"],
9
+ children: {
10
+ default: `<div class="v-visible-sr">New activity</div>`,
11
+ new: `new<div class="v-visible-sr">New activity</div>`,
12
+ },
13
+ skippedTestids: [
14
+ "s-activity-indicator-dark-new", // TODO fix contrast issue
15
+ "s-activity-indicator-dark-success-new", // TODO fix contrast issue
16
+ "s-activity-indicator-dark-warning-new", // TODO fix contrast issue
17
+ "s-activity-indicator-light-success-new", // TODO fix contrast issue
18
+ "s-activity-indicator-light-warning-new", // TODO fix contrast issue
19
+ ],
20
+ });
21
+ });
@@ -0,0 +1,23 @@
1
+ import { html } from "@open-wc/testing";
2
+ import { runComponentTests } from "../../test/test-utils";
3
+ import "../../index";
4
+
5
+ describe("activity-indicator", () => {
6
+ runComponentTests({
7
+ type: "visual",
8
+ baseClass: "s-activity-indicator",
9
+ variants: ["danger", "success", "warning"],
10
+ children: {
11
+ default: `<div class="v-visible-sr">New activity</div>`,
12
+ new: `new<div class="v-visible-sr">New activity</div>`,
13
+ },
14
+ template: ({ component, testid }) => html`
15
+ <div
16
+ class="d-inline-flex ai-center jc-center hs1 ws1 p8"
17
+ data-testid="${testid}"
18
+ >
19
+ ${component}
20
+ </div>
21
+ `,
22
+ });
23
+ });
@@ -0,0 +1,36 @@
1
+ import { runComponentTests } from "../../test/test-utils";
2
+ import "../../index";
3
+
4
+ const getChild = (child?: string): string => {
5
+ const srEl = `<span class="v-visible-sr">Stack Overflow</span>`;
6
+ switch (child) {
7
+ case "image":
8
+ return `<img
9
+ class="s-avatar--image"
10
+ src="https://picsum.photos/id/1/48"
11
+ alt="team logo"
12
+ />${srEl}`;
13
+ case "letter":
14
+ return `<div
15
+ class="s-avatar--letter"
16
+ aria-hidden="true">
17
+ S
18
+ </div>${srEl}`;
19
+ default:
20
+ return srEl;
21
+ }
22
+ };
23
+
24
+ describe("avatar", () => {
25
+ runComponentTests({
26
+ type: "a11y",
27
+ baseClass: "s-avatar",
28
+ variants: ["24", "32", "48", "64", "96", "128"],
29
+ children: {
30
+ default: getChild(),
31
+ image: getChild("image"),
32
+ letter: getChild("letter"),
33
+ },
34
+ tag: "span",
35
+ });
36
+ });
@@ -0,0 +1,54 @@
1
+ import { html } from "@open-wc/testing";
2
+ import { runComponentTests } from "../../test/test-utils";
3
+ import "../../index";
4
+
5
+ const base64Image =
6
+ "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAATwAAAE8CAMAAABq2/00AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAABhQTFRF/3IA/////44y/8OS/+fU//Xs/6tn/9e2EhvbMQAABH9JREFUeNrs3e1y2ygAhWELJHH/d7zuJpN1XAnxoe408Ly/6xnnHXEOIEwfDwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/gbAGEhrZl2VloY20PIk8tAzZbfkXA7eeuHyysVfdFMsXiY66ptiWF8Re05BdxF7HkBV7PUNW7FVx4E7sVSwrDjBw2+pC7NWwHtkTe3ULM7En9v6O2ONF7Ik9sSf2IPbEntgTexB7t8feTsynniD2Oh6tXex1hFoUe02kaxVi72JMZs+Rib0LLdkXFGLvaECWjkOxdxVmUex1rB6S2Kss2lcytSH2LnVkakPsXQ7E8xwTe5fuMrUh9vKj8CP4xN7lNOXc3mnwib1M2X7Z28VeS93mg0/sFZTG6WCMVSE51fqsYL4s9jpqQ+yV1caxErHXUxtir6c2xF5HbYRF7LXXhtjrqQ2x11MbYu9tLG4VtSH2empD7BUNxpPaSGKvPPh2sdcxX45i78baEHs18+X32hB7NfPl99oQex21MVHsxViaR8W1MU3s/XpMSvWF0tqYJfY+BmMq01dcG+scP6/6enTK9BW+1J0j9l5aYN0rP5BzM0XsbSUnAlpqY4LYezexFeRSbpslH3uDXdF64OG6est258PohXE8BK+7o6g29rJTQsPt1F3qK9qdTwMP2Wz2X1Vv0UvdbeQ53nl2Xesr2Z0Pww7Zs5lsafWW1MY+6JDNxv5/+kLb5/fXfzLirRdhKSGnr6A2tkGvJoxLGZnqva6NkAbdgA+pUN9a+QuWYYPu+98ee/W1/PJgoMG7lek7nW3UHiEdbKpcqu+kO2L9b4aG0rcWjt5jfWf2Z7kCeE891XtSG/O86A5d+tbZj1h0VW+c/ja90FG9uxMCFdWb/+SkZ1Oaq/d1vjzvXfvF+tLp+aiZT5S1Vm90lrFj02B3bW1d9X7T92u+7Aq9qk2D+Fob/v/Myu7YostC76xe9K966evfr5+7ekuXHVy1V6+R275pEMd3kPbGB+Syeod/8D7Sf41NBvPdMf7a4uXpaTGY0zd+4r0vDlKtwdPqHf/BOzzf8zQYqvRtcz54mXfUNUVyUL0T7AhcrBbKY/C36p1geVEy1y00+F3fBA9eKFxnlRXJa/XOcKxnqeF6Pv1VvTPc7RuXai6K5LN6Z9hQSUsb2Rh86pviUultaScTg/sMD15YeqmcT8/bFx1Foi/umk9P3hcMfqTenrabBT5j8DGTwHivwelOCTwNrnfJm/Ol2U0GZ74WdE+dBn9+Z/z2J9UZ7IjB7dZv8gPl9RRJIq89BiN57QZ38trn04G8k62E6xjcHuQ1D+JEXrvBnbz2+XQgr30+/SCveT69ktceg4m8doOBvDG/CXnkkTezvOXPQB555JFHHnnkkUceeeSRRx555JFHHnnkkWcnmTzyyCOPPPLII4888sgjjzzfhDzyyCOPPPL+9Ff+eyCPPPLII4888sgjjzzyyCOPPPLII4888sgDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPy//CPAAPiZOI3BPDFQAAAAAElFTkSuQmCC";
7
+
8
+ const getChild = (child?: string): string => {
9
+ const srEl = `<span class="v-visible-sr">Stack Overflow</span>`;
10
+ switch (child) {
11
+ case "image":
12
+ return `<img
13
+ class="s-avatar--image"
14
+ src="${base64Image}"
15
+ alt="team logo"
16
+ />${srEl}`;
17
+ case "letter":
18
+ return `<div
19
+ class="s-avatar--letter"
20
+ aria-hidden="true">
21
+ S
22
+ </div>${srEl}`;
23
+ default:
24
+ return srEl;
25
+ }
26
+ };
27
+
28
+ describe("avatar", () => {
29
+ runComponentTests({
30
+ type: "visual",
31
+ baseClass: "s-avatar",
32
+ variants: ["24", "32", "48", "64", "96", "128"],
33
+ children: {
34
+ default: getChild(),
35
+ image: getChild("image"),
36
+ letter: getChild("letter"),
37
+ },
38
+ attributes: {
39
+ href: "#",
40
+ },
41
+ tag: "a",
42
+ template: ({ component, testid }) => html`
43
+ <div
44
+ data-testid="${testid}"
45
+ class="d-inline-flex ai-center jc-center hmn1 wmn1 p8"
46
+ >
47
+ ${component}
48
+ </div>
49
+ `,
50
+ skippedTestids: [
51
+ /-letter/, // TODO: resolve font-family thrashing issues
52
+ ],
53
+ });
54
+ });
@@ -0,0 +1,51 @@
1
+ // See also ./lib/components/notice/notice.less
2
+ // TODO deprecate .s-banner (by turning it into a modifier on .s-notice)
3
+ // This would reduce the amount of CSS we ship to the client and simplify our codebase
4
+ .s-banner {
5
+ --_no-x-offset: 0; // [1]
6
+ .construct-notice-component(s-banner);
7
+
8
+ &[aria-hidden="true"] { // If you want to hide and reveal the banner
9
+ --_no-x-offset: calc(var(--su48) + var(--su2) * -1); // -50px
10
+ opacity: 0;
11
+ visibility: hidden;
12
+ }
13
+
14
+ &[aria-hidden="false"] {
15
+ --_no-x-offset: calc(var(--su48) + var(--su1)); // 49px
16
+ opacity: 1;
17
+ visibility: visible;
18
+ }
19
+
20
+ &.is-pinned { // If you want to put the banner above the topbar
21
+ z-index: calc(var(--zi-navigation-fixed) + 1);
22
+ }
23
+
24
+ &__body-pt {
25
+ padding-top: 93px;
26
+ }
27
+
28
+ & &--container { // When we want to keep hero content capped
29
+ margin: 0 auto;
30
+ max-width: calc(var(--s-step) * 10);
31
+ position: relative;
32
+ width: 100%;
33
+ }
34
+
35
+ border-width: var(--su-static1) 0;
36
+ inset: 0 0 auto 0;
37
+ padding: var(--su12);
38
+ position: fixed;
39
+ -webkit-transform: translate3d(0, var(--_no-x-offset), 0);
40
+ transform: translate3d(0, var(--_no-x-offset), 0);
41
+ width: 100%;
42
+ z-index: calc(var(--zi-navigation-fixed) - 1); // Tuck below topbar
43
+ }
44
+
45
+ // [1] When we use .s-banner, we need to adjust the padding-top on
46
+ // the body tag. This class correctly adjusts the body padding ONLY if
47
+ // the notice is one line. If it wraps to multiple lines, more classes or
48
+ // (ideally) JS will need to be used to determine the notice's height
49
+ // at the time of render. The padding value is determined like so:
50
+ // 50px (top bar) + 44px (notice height) - 1px (bottom border)
51
+ // The borders subtraction are necessary to neatly tuck everything together.
@@ -1,12 +1,12 @@
1
1
  import { html, fixture, expect } from "@open-wc/testing";
2
2
  import { screen } from "@testing-library/dom";
3
3
  import userEvent from "@testing-library/user-event";
4
- import "../ts/index";
5
- import { showBanner, hideBanner } from "../ts/index";
4
+ import "../../index";
5
+ import { showBanner, hideBanner } from "../../controllers";
6
6
 
7
7
  const user = userEvent.setup();
8
8
 
9
- describe("s-banner", () => {
9
+ describe("banner", () => {
10
10
  it("trigger should make banner visible", async () => {
11
11
  await fixture(html`
12
12
  <button data-toggle="s-banner" data-target="#test-banner">
@@ -29,10 +29,12 @@ describe("s-banner", () => {
29
29
  const button = screen.getByRole("button");
30
30
  const banner = screen.getByTestId("test-banner");
31
31
 
32
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
32
33
  expect(banner).to.have.attribute("aria-hidden", "true");
33
34
  button.addEventListener("click", () => showBanner(banner));
34
35
 
35
36
  await user.click(button);
37
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
36
38
  expect(banner).to.have.attribute("aria-hidden", "false");
37
39
  });
38
40
 
@@ -64,10 +66,12 @@ describe("s-banner", () => {
64
66
  const button = screen.getByRole("button");
65
67
  const banner = screen.getByTestId("test-banner");
66
68
 
69
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
67
70
  expect(banner).to.have.attribute("aria-hidden", "false");
68
71
  button.addEventListener("click", () => hideBanner(banner));
69
72
 
70
73
  await user.click(button);
74
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
71
75
  expect(banner).to.have.attribute("aria-hidden", "true");
72
76
  });
73
77
  });
@@ -1,4 +1,4 @@
1
- import * as Stacks from "../stacks";
1
+ import * as Stacks from "../../stacks";
2
2
 
3
3
  export class BannerController extends Stacks.StacksController {
4
4
  static targets = ["banner"];
@@ -0,0 +1,36 @@
1
+ import { runComponentTests } from "../../test/test-utils";
2
+ import "../../index";
3
+
4
+ const bannerChild = `
5
+ <div
6
+ class="d-flex flex__center jc-space-between s-banner--container"
7
+ role="alertdialog"
8
+ aria-describedby="banner-message"
9
+ >
10
+ <div aria-label="banner message">
11
+ Test Banner
12
+ </div>
13
+ <div class="ml-auto myn8">
14
+ <span class="s-btn s-banner--btn">Close</span>
15
+ </div>
16
+ </div>
17
+ `;
18
+
19
+ describe("banner", () => {
20
+ runComponentTests({
21
+ type: "visual",
22
+ baseClass: "s-banner",
23
+ variants: ["info", "success", "warning", "danger"],
24
+ modifiers: {
25
+ primary: ["important"],
26
+ },
27
+ attributes: {
28
+ role: "alert",
29
+ ariaHidden: "false",
30
+ },
31
+ children: {
32
+ default: bannerChild,
33
+ },
34
+ tag: "aside",
35
+ });
36
+ });
@@ -0,0 +1,32 @@
1
+ import { runComponentTests } from "../../test/test-utils";
2
+ import "../../index";
3
+
4
+ describe("button", () => {
5
+ runComponentTests({
6
+ type: "a11y",
7
+ baseClass: "s-btn",
8
+ variants: ["danger", "muted", "primary"],
9
+ modifiers: {
10
+ primary: ["filled", "outlined"],
11
+ secondary: [...["xs", "sm", "md"], ...["dropdown", "icon"]],
12
+ global: ["is-loading"],
13
+ standalone: [
14
+ ...["link", "unset"],
15
+ ...["facebook", "github", "google"],
16
+ ],
17
+ },
18
+ attributes: {
19
+ type: "button",
20
+ },
21
+ children: {
22
+ default: "Ask question",
23
+ },
24
+ tag: "button",
25
+ excludedTestids: [
26
+ /primary-outlined/, // This combination is not supported
27
+ ],
28
+ skippedTestids: [
29
+ /s-btn-dark/, // TODO remove when contrast bugs are fixed
30
+ ],
31
+ });
32
+ });
@@ -57,6 +57,7 @@
57
57
  });
58
58
 
59
59
  // STATES
60
+ fieldset[disabled] &,
60
61
  &[disabled],
61
62
  &[aria-disabled="true"] {
62
63
  --_bu-bs: none !important;
@@ -141,8 +142,6 @@
141
142
  &:focus-visible {
142
143
  outline-style: auto;
143
144
  }
144
-
145
- outline: initial;
146
145
  }
147
146
 
148
147
  &&__link {
@@ -169,6 +168,7 @@
169
168
  .s-link();
170
169
  display: inline;
171
170
  font: inherit;
171
+ outline: revert;
172
172
  text-align: inherit;
173
173
  }
174
174
 
@@ -190,6 +190,8 @@
190
190
  font: unset;
191
191
  user-select: auto;
192
192
  }
193
+
194
+ outline: initial;
193
195
  }
194
196
 
195
197
  // Pseudo-elements and child-based modifiers
@@ -221,18 +223,17 @@
221
223
 
222
224
  // Size
223
225
  &&__xs {
226
+ .size-styles(xs; bu; @styles: fs);
224
227
  --_bu-dropdown-bw: calc(var(--su-static4) - var(--su-static1));
225
- --_bu-fs: var(--fs-fine);
226
228
  --_bu-p: 0.6em;
227
229
  }
228
230
 
229
231
  &&__sm {
230
- --_bu-fs: var(--fs-caption);
232
+ .size-styles(sm; bu; @styles: fs);
231
233
  }
232
234
 
233
235
  &&__md {
234
- --_bu-br: calc(var(--br-sm) + var(--su-static1));
235
- --_bu-fs: var(--fs-body3);
236
+ .size-styles(md; bu; @styles: br, fs);
236
237
  --_bu-p: 0.7em;
237
238
  }
238
239
 
@@ -0,0 +1,52 @@
1
+ import { html } from "@open-wc/testing";
2
+ import { runComponentTests } from "../../test/test-utils";
3
+ import "../../index";
4
+
5
+ const getChild = (child?: string): string => {
6
+ switch (child) {
7
+ case "badge":
8
+ return `Ask question
9
+ <span class="s-btn--badge">
10
+ <span class="s-btn--number">198</span>
11
+ </span>`;
12
+ default:
13
+ return "Ask question";
14
+ }
15
+ };
16
+
17
+ describe("button", () => {
18
+ // TODO test disabled states, interaction pseudo-classes
19
+ runComponentTests({
20
+ type: "visual",
21
+ baseClass: "s-btn",
22
+ variants: ["danger", "muted", "primary"],
23
+ modifiers: {
24
+ primary: ["filled", "outlined"],
25
+ secondary: [...["xs", "sm", "md"], ...["dropdown", "icon"]],
26
+ global: ["is-loading"],
27
+ standalone: [
28
+ ...["link", "unset"],
29
+ ...["facebook", "github", "google"],
30
+ ],
31
+ },
32
+ attributes: {
33
+ type: "button",
34
+ },
35
+ children: {
36
+ default: getChild(),
37
+ badge: getChild("badge"),
38
+ },
39
+ tag: "button",
40
+ template: ({ component, testid }) => html`
41
+ <div
42
+ class="bg-black-100 d-inline-flex ai-center jc-center hs1 ws2 p8"
43
+ data-testid="${testid}"
44
+ >
45
+ ${component}
46
+ </div>
47
+ `,
48
+ excludedTestids: [
49
+ /primary-outlined/, // This combination is not supported
50
+ ],
51
+ });
52
+ });
@@ -17,7 +17,7 @@
17
17
  }
18
18
 
19
19
  // CHILD ELEMENTS
20
- p:last-of-type {
20
+ > :last-child {
21
21
  margin-bottom: 0;
22
22
  }
23
23
 
@@ -0,0 +1,17 @@
1
+ .s-check-control { // TODO would _love_ to use .s-check instead, with no class on the input itself
2
+ --_cc-ai: center;
3
+
4
+ // CONTEXTUAL STYLES
5
+ .s-check-group & {
6
+ --_cc-ai: flex-start; // manually align the checkboxes and radios to the top of the group
7
+ }
8
+
9
+ // CHILD ELEMENTS
10
+ .s-label {
11
+ font-weight: normal;
12
+ }
13
+
14
+ align-items: var(--_cc-ai);
15
+ display: flex;
16
+ gap: var(--su8);
17
+ }
@@ -0,0 +1,19 @@
1
+ .s-check-group {
2
+ --_cg-fd: column;
3
+
4
+ // MODIFIERS
5
+ &&__horizontal {
6
+ --_cg-fd: row;
7
+ }
8
+
9
+ // CHILD ELEMENTS
10
+ // TODO HACK? <legend> isn't respecting gap...
11
+ legend.s-label {
12
+ margin-bottom: var(--su8);
13
+ }
14
+
15
+ flex-direction: var(--_cg-fd);
16
+
17
+ display: flex;
18
+ gap: var(--su8);
19
+ }
@@ -0,0 +1,158 @@
1
+ .s-checkbox,
2
+ .s-radio {
3
+ --_ch-baw: var(--su-static1);
4
+ --_ch-bc: var(--bc-darker);
5
+ --_ch-bc-focus: var(--theme-secondary-300);
6
+ --_ch-bg: var(--white);
7
+ --_ch-bg-image: unset;
8
+ --_ch-bs-focus: 0 0 0 var(--su-static4) var(--focus-ring);
9
+
10
+ // CONTEXTUAL STYLES
11
+ fieldset[disabled] &,
12
+ &[disabled] {
13
+ cursor: not-allowed;
14
+ opacity: var(--_o-disabled-static);
15
+ }
16
+
17
+ .s-check-control & {
18
+ &[disabled] + .s-label {
19
+ &:extend(.is-disabled .s-label);
20
+ }
21
+ }
22
+
23
+ .s-check-group & {
24
+ margin-top: calc(var(--su2) + var(--su1)); // 3px
25
+ }
26
+
27
+ input& {
28
+ flex-shrink: 0;
29
+ }
30
+
31
+ // INTERACTION
32
+ &:focus {
33
+ box-shadow: var(--_ch-bs-focus);
34
+ }
35
+
36
+ background-color: var(--_ch-bg);
37
+ border: var(--_ch-baw) solid var(--_ch-bc);
38
+
39
+ appearance: none;
40
+ cursor: pointer;
41
+ font-size: inherit;
42
+ height: 1em;
43
+ margin: 0; // A guard against Core's default margins
44
+ outline: 0;
45
+ vertical-align: middle;
46
+ width: 1em;
47
+ }
48
+
49
+ .s-checkbox {
50
+
51
+ // CONTEXTUAL STYLES
52
+ .highcontrast-dark-mode({
53
+ &:checked, &:indeterminate {
54
+ --_ch-bc: var(--blue-700) !important;
55
+ --_ch-bc-focus: var(--_ch-bc);
56
+ --_ch-bg: var(--blue-300);
57
+ }
58
+ });
59
+
60
+ // STATES
61
+ &:checked, &:indeterminate {
62
+ --_ch-bc: var(--theme-secondary-400) !important;
63
+ --_ch-bg: var(--theme-secondary-400);
64
+
65
+ &:focus {
66
+ --_ch-bc-focus: var(--theme-secondary-400);
67
+ }
68
+ }
69
+
70
+ &:checked {
71
+ --_ch-bg-image: url("data:image/svg+xml,%3Csvg width='11' height='11' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M10 3.41L8.59 2 4 6.59 2.41 5 1 6.41l3 3z' fill='%23fff'/%3E%3C/svg%3E");
72
+ }
73
+
74
+ &:indeterminate {
75
+ --_ch-bg-image: url("data:image/svg+xml,%3Csvg width='11' height='11' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M2 4.5 h7 v2 h-7 z' fill='%23fff'/%3E%3C/svg%3E");
76
+ }
77
+
78
+ // INTERACTION
79
+ &:focus {
80
+ border-color: var(--_ch-bc-focus);
81
+ }
82
+
83
+ background-image: var(--_ch-bg-image);
84
+
85
+ background-position: center center;
86
+ background-repeat: no-repeat;
87
+ background-size: contain;
88
+ border-radius: var(--br-sm);
89
+ }
90
+
91
+ .s-radio {
92
+
93
+ // CONTEXTUAL STYLES
94
+ .highcontrast-dark-mode({
95
+ &:checked {
96
+ --_ch-bc: var(--blue-300);
97
+ outline: var(--su-static1) solid var(--black);
98
+ }
99
+ });
100
+
101
+ .dark-mode({
102
+ &:checked {
103
+ --_ch-bg: var(--black);
104
+ }
105
+ });
106
+
107
+ // STATES
108
+ &:checked {
109
+ --_ch-baw: 0.30769231em;
110
+ --_ch-bc: var(--theme-secondary-400);
111
+ --_ch-bg: var(--white);
112
+ }
113
+
114
+ border-radius: var(--br-circle);
115
+ }
116
+
117
+ .s-checkbox,
118
+ .s-radio:not(:checked) {
119
+ .validation-states(ch);
120
+ }
121
+
122
+ .s-check-control { // TODO would _love_ to use .s-check instead, with no class on the input itself
123
+ --_cc-ai: center;
124
+
125
+ // CONTEXTUAL STYLES
126
+ .s-check-group & {
127
+ --_cc-ai: flex-start; // manually align the checkboxes and radios to the top of the group
128
+ }
129
+
130
+ // CHILD ELEMENTS
131
+ .s-label {
132
+ font-weight: normal;
133
+ }
134
+
135
+ align-items: var(--_cc-ai);
136
+ display: flex;
137
+ gap: var(--su8);
138
+ }
139
+
140
+ .s-check-group {
141
+ --_cg-fd: column;
142
+
143
+ // MODIFIERS
144
+ &&__horizontal {
145
+ --_cg-fd: row;
146
+ }
147
+
148
+ // CHILD ELEMENTS
149
+ // TODO HACK? <legend> isn't respecting gap...
150
+ legend.s-label {
151
+ margin-bottom: var(--su8);
152
+ }
153
+
154
+ flex-direction: var(--_cg-fd);
155
+
156
+ display: flex;
157
+ gap: var(--su8);
158
+ }
@@ -0,0 +1,9 @@
1
+ .s-description {
2
+ .is-disabled & {
3
+ opacity: var(--_o-disabled-static);
4
+ }
5
+
6
+ color: var(--fc-medium);
7
+ font-size: var(--fs-caption);
8
+ padding: 0 var(--su2); // Helps the label visually line up with inputs
9
+ }