Skip to content

Commit

Permalink
chore: use component-based file structure (#1232)
Browse files Browse the repository at this point in the history
* chore: use component-based file structure

* move files from test/, ts/ dirs, delete dirs

* fix busted import for tooltip test

* fix ts linting

* Remove dupe icon.less import

* More linter and linting fixes

* use index.less filename for component styles

* Separate banner, notice, toast (best I can)

* Separate check_radio, check-group, check-control

* Separate input_textarea, input-* components

* Revert to previous css file structure for bundles

Partially addresses https://github.com/StackExchange/Stacks/pull/1232/files#r1129176446

* Update component file naming convention

Partially addresses #1232 (review)

* Update tooltip controller file name

* Update controllers.ts

* move some test files

* Cleanup avatar/activity-indicator tests

* Update visual baseline images

* Allow no arg to getChild tests

* Update tsconfig.json

addresses #1232 (comment)

* Remove `s-` from test titles

* consistent file names

* regen some visual test files

* naming tweak

* add encoded avatar image; update visual test images

* Bump test timeout

* Prettier!

* Skip visual avatar tests that include letter child

These tests are subject to failure based on the font stack available in a given environment and are therefore unreliable

* ci(test): split tests in separate steps

* ci(reporter): add a custom reporter to better visualise test output

* ci(reporter): small fix selecting failing session

* Use a template with min width/height for avatar tests

* prettier… again.

---------

Co-authored-by: Giamir Buoncristiani <[email protected]>
  • Loading branch information
dancormier and giamir authored Mar 23, 2023
1 parent 1b7cd6b commit c637b49
Show file tree
Hide file tree
Showing 280 changed files with 1,154 additions and 451 deletions.
15 changes: 11 additions & 4 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,17 @@ jobs:
npx playwright install --with-deps
npm run build
- name: ▶️ Lint and Test
run: |
npm run lint
npm run test -- --config web-test-runner.config.ci.mjs
- name: ▶️ Linting
run: npm run lint

- name: ▶️ Unit Tests
run: npm run test:unit -- --config web-test-runner.config.ci.mjs

- name: ▶️ A11y Tests
run: npm run test:a11y -- --config web-test-runner.config.ci.mjs

- name: ▶️ Visual Regression Tests
run: npm run test:visual -- --config web-test-runner.config.ci.mjs

- name: ⬆️ Upload Visual Regression Test Results
uses: actions/upload-artifact@v3
Expand Down
4 changes: 2 additions & 2 deletions docs/assets/js/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import "../../../lib/ts/index";
import "../../../lib/index";
import "../less/stacks-documentation.less";
import "./controllers/docs-resizer";
import * as Stacks from "../../../lib/ts/index";
import * as Stacks from "../../../lib/index";

// @ts-expect-error
global.Stacks = Stacks;
Expand Down
2 changes: 1 addition & 1 deletion docs/assets/js/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
"compilerOptions": {
"declaration": false,
},
"include": ["./js/index.ts", "./controllers/*.ts"]
"include": ["./js/index.ts", "./*.ts"]
}
2 changes: 1 addition & 1 deletion docs/assets/less/stacks-documentation.less
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
// ============================================================================
// $ IMPORTS
// ----------------------------------------------------------------------------
@import (reference) "../../../lib/css/stacks.less"; // These are actual styles used in SO projects
@import (reference) "../../../lib/stacks.less"; // These are actual styles used in SO projects

.stacks-section {
margin-top: var(--su48);
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
9 changes: 0 additions & 9 deletions lib/css/base/icons.less → lib/base/icon.less
Original file line number Diff line number Diff line change
@@ -1,12 +1,3 @@
//
// STACK OVERFLOW
// ICON STYLES
//
// This CSS comes from Stacks, our CSS & Pattern library for rapidly building
// Stack Overflow. For documentation of all these classes and how to contribute,
// visit https://stackoverflow.design/
//

.svg-icon,
.svg-spot {
vertical-align: bottom; // Make SVG play nicely while inline with text by default
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
21 changes: 21 additions & 0 deletions lib/components/activity-indicator/activity-indicator.a11y.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { runComponentTests } from "../../test/test-utils";
import "../../index";

describe("activity-indicator", () => {
runComponentTests({
type: "a11y",
baseClass: "s-activity-indicator",
variants: ["danger", "success", "warning"],
children: {
default: `<div class="v-visible-sr">New activity</div>`,
new: `new<div class="v-visible-sr">New activity</div>`,
},
skippedTestids: [
"s-activity-indicator-dark-new", // TODO fix contrast issue
"s-activity-indicator-dark-success-new", // TODO fix contrast issue
"s-activity-indicator-dark-warning-new", // TODO fix contrast issue
"s-activity-indicator-light-success-new", // TODO fix contrast issue
"s-activity-indicator-light-warning-new", // TODO fix contrast issue
],
});
});
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { html } from "@open-wc/testing";
import { runComponentTests } from "./test-utils";
import "../ts/index";
import { runComponentTests } from "../../test/test-utils";
import "../../index";

describe("s-activity-indicator", () => {
describe("activity-indicator", () => {
runComponentTests({
type: "visual",
baseClass: "s-activity-indicator",
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { runComponentTests } from "./test-utils";
import "../ts/index";
import { runComponentTests } from "../../test/test-utils";
import "../../index";

const getChild = (child) => {
const getChild = (child?: string): string => {
const srEl = `<span class="v-visible-sr">Stack Overflow</span>`;
switch (child) {
case "image":
return `<img
class="s-avatar--image"
src="https://picsum.photos/48"
src="https://picsum.photos/id/1/48"
alt="team logo"
/>${srEl}`;
case "letter":
Expand All @@ -21,13 +21,13 @@ const getChild = (child) => {
}
};

describe("s-avatar", () => {
describe("avatar", () => {
runComponentTests({
type: "a11y",
baseClass: "s-avatar",
variants: ["24", "32", "48", "64", "96", "128"],
children: {
default: getChild(""),
default: getChild(),
image: getChild("image"),
letter: getChild("letter"),
},
Expand Down
File renamed without changes.
54 changes: 54 additions & 0 deletions lib/components/avatar/avatar.visual.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { html } from "@open-wc/testing";
import { runComponentTests } from "../../test/test-utils";
import "../../index";

const base64Image =
"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";

const getChild = (child?: string): string => {
const srEl = `<span class="v-visible-sr">Stack Overflow</span>`;
switch (child) {
case "image":
return `<img
class="s-avatar--image"
src="${base64Image}"
alt="team logo"
/>${srEl}`;
case "letter":
return `<div
class="s-avatar--letter"
aria-hidden="true">
S
</div>${srEl}`;
default:
return srEl;
}
};

describe("avatar", () => {
runComponentTests({
type: "visual",
baseClass: "s-avatar",
variants: ["24", "32", "48", "64", "96", "128"],
children: {
default: getChild(),
image: getChild("image"),
letter: getChild("letter"),
},
attributes: {
href: "#",
},
tag: "a",
template: ({ component, testid }) => html`
<div
data-testid="${testid}"
class="d-inline-flex ai-center jc-center hmn1 wmn1 p8"
>
${component}
</div>
`,
skippedTestids: [
/-letter/, // TODO: resolve font-family thrashing issues
],
});
});
File renamed without changes.
File renamed without changes.
51 changes: 51 additions & 0 deletions lib/components/banner/banner.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// See also ./lib/components/notice/notice.less
// TODO deprecate .s-banner (by turning it into a modifier on .s-notice)
// This would reduce the amount of CSS we ship to the client and simplify our codebase
.s-banner {
--_no-x-offset: 0; // [1]
.construct-notice-component(s-banner);

&[aria-hidden="true"] { // If you want to hide and reveal the banner
--_no-x-offset: calc(var(--su48) + var(--su2) * -1); // -50px
opacity: 0;
visibility: hidden;
}

&[aria-hidden="false"] {
--_no-x-offset: calc(var(--su48) + var(--su1)); // 49px
opacity: 1;
visibility: visible;
}

&.is-pinned { // If you want to put the banner above the topbar
z-index: calc(var(--zi-navigation-fixed) + 1);
}

&__body-pt {
padding-top: 93px;
}

& &--container { // When we want to keep hero content capped
margin: 0 auto;
max-width: calc(var(--s-step) * 10);
position: relative;
width: 100%;
}

border-width: var(--su-static1) 0;
inset: 0 0 auto 0;
padding: var(--su12);
position: fixed;
-webkit-transform: translate3d(0, var(--_no-x-offset), 0);
transform: translate3d(0, var(--_no-x-offset), 0);
width: 100%;
z-index: calc(var(--zi-navigation-fixed) - 1); // Tuck below topbar
}

// [1] When we use .s-banner, we need to adjust the padding-top on
// the body tag. This class correctly adjusts the body padding ONLY if
// the notice is one line. If it wraps to multiple lines, more classes or
// (ideally) JS will need to be used to determine the notice's height
// at the time of render. The padding value is determined like so:
// 50px (top bar) + 44px (notice height) - 1px (bottom border)
// The borders subtraction are necessary to neatly tuck everything together.
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { html, fixture, expect } from "@open-wc/testing";
import { screen } from "@testing-library/dom";
import userEvent from "@testing-library/user-event";
import "../ts/index";
import { showBanner, hideBanner } from "../ts/index";
import "../../index";
import { showBanner, hideBanner } from "../../controllers";

const user = userEvent.setup();

describe("s-banner", () => {
describe("banner", () => {
it("trigger should make banner visible", async () => {
await fixture(html`
<button data-toggle="s-banner" data-target="#test-banner">
Expand All @@ -29,10 +29,12 @@ describe("s-banner", () => {
const button = screen.getByRole("button");
const banner = screen.getByTestId("test-banner");

// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
expect(banner).to.have.attribute("aria-hidden", "true");
button.addEventListener("click", () => showBanner(banner));

await user.click(button);
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
expect(banner).to.have.attribute("aria-hidden", "false");
});

Expand Down Expand Up @@ -64,10 +66,12 @@ describe("s-banner", () => {
const button = screen.getByRole("button");
const banner = screen.getByTestId("test-banner");

// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
expect(banner).to.have.attribute("aria-hidden", "false");
button.addEventListener("click", () => hideBanner(banner));

await user.click(button);
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
expect(banner).to.have.attribute("aria-hidden", "true");
});
});
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as Stacks from "../stacks";
import * as Stacks from "../../stacks";

export class BannerController extends Stacks.StacksController {
static targets = ["banner"];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { runComponentTests } from "./test-utils";
import "../ts/index";
import { runComponentTests } from "../../test/test-utils";
import "../../index";

const bannerChild = `
<div
Expand All @@ -16,7 +16,7 @@ const bannerChild = `
</div>
`;

describe("s-banner", () => {
describe("banner", () => {
runComponentTests({
type: "visual",
baseClass: "s-banner",
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { runComponentTests } from "./test-utils";
import "../ts/index";
import { runComponentTests } from "../../test/test-utils";
import "../../index";

describe("s-btn", () => {
describe("button", () => {
runComponentTests({
type: "a11y",
baseClass: "s-btn",
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { html } from "@open-wc/testing";
import { runComponentTests } from "./test-utils";
import "../ts/index";
import { runComponentTests } from "../../test/test-utils";
import "../../index";

const getChild = (child) => {
const getChild = (child?: string): string => {
switch (child) {
case "badge":
return `Ask question
Expand All @@ -14,7 +14,7 @@ const getChild = (child) => {
}
};

describe("s-btn", () => {
describe("button", () => {
// TODO test disabled states, interaction pseudo-classes
runComponentTests({
type: "visual",
Expand All @@ -33,7 +33,7 @@ describe("s-btn", () => {
type: "button",
},
children: {
default: getChild(""),
default: getChild(),
badge: getChild("badge"),
},
tag: "button",
Expand Down
File renamed without changes.
17 changes: 17 additions & 0 deletions lib/components/check-control/check-control.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.s-check-control { // TODO would _love_ to use .s-check instead, with no class on the input itself
--_cc-ai: center;

// CONTEXTUAL STYLES
.s-check-group & {
--_cc-ai: flex-start; // manually align the checkboxes and radios to the top of the group
}

// CHILD ELEMENTS
.s-label {
font-weight: normal;
}

align-items: var(--_cc-ai);
display: flex;
gap: var(--su8);
}
19 changes: 19 additions & 0 deletions lib/components/check-group/check-group.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
.s-check-group {
--_cg-fd: column;

// MODIFIERS
&&__horizontal {
--_cg-fd: row;
}

// CHILD ELEMENTS
// TODO HACK? <legend> isn't respecting gap...
legend.s-label {
margin-bottom: var(--su8);
}

flex-direction: var(--_cg-fd);

display: flex;
gap: var(--su8);
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit c637b49

Please sign in to comment.