Skip to content

Commit

Permalink
feat: cancel and secondary button (#36)
Browse files Browse the repository at this point in the history
  • Loading branch information
VojtechVidra authored Mar 1, 2024
1 parent 57307f2 commit a44f01b
Show file tree
Hide file tree
Showing 12 changed files with 134 additions and 112 deletions.
4 changes: 2 additions & 2 deletions workspaces/e2e/tests/async-flow/async-flow.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ test("Should not continue if flow is not fully loaded", async ({ page }) => {
await page.route("**/sdk/flows/flow?projectId=my-proj", (route) => route.abort());
await page.goto("/async-flow/async-flow.html");
await expect(page.locator(".flows-tooltip")).toContainText("First");
await page.locator(".flows-continue").click();
await page.locator(".flows-next").click();
await expect(page.locator(".flows-tooltip")).toContainText("First");
});

Expand Down Expand Up @@ -44,6 +44,6 @@ test("Should continue if flow is fully loaded", async ({ page }) => {
});
await page.goto("/async-flow/async-flow.html");
await expect(page.locator(".flows-tooltip")).toContainText("First");
await page.locator(".flows-continue").click();
await page.locator(".flows-next").click();
await expect(page.locator(".flows-tooltip")).toContainText("Second");
});
16 changes: 8 additions & 8 deletions workspaces/e2e/tests/branch/branch.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import { expect, test } from "@playwright/test";

test("Enter branch by footerAction", async ({ page }) => {
await page.goto("/branch/branch.html");
await page.locator(".flows-option").nth(0).click();
await page.locator(".flows-action").nth(0).click();
await expect(page.locator(".flows-tooltip")).toContainText("Variant 1");
await page.locator(".flows-finish").click();
await page.goto("/branch/branch.html");
await page.locator(".flows-option").nth(1).click();
await page.locator(".flows-action").nth(1).click();
await expect(page.locator(".flows-tooltip")).toContainText("Variant 2");
});
test("Enter branch by click", async ({ page }) => {
Expand All @@ -22,22 +22,22 @@ test("Exits branch and returns to root step", async ({ page }) => {
await page.goto("/branch/branch.html?lastStep=true");
await page.locator(".enter-1").click();
await expect(page.locator(".flows-tooltip")).toContainText("Variant 1");
await page.locator(".flows-continue").click();
await page.locator(".flows-next").click();
await expect(page.locator(".flows-tooltip")).toContainText("Last Step");
});
test("branch can have multiple steps", async ({ page }) => {
await page.goto("/branch/branch.html?lastStep=true");
await page.locator(".enter-2").click();
await expect(page.locator(".flows-tooltip")).toContainText("Variant 2");
await page.locator(".flows-continue").click();
await page.locator(".flows-next").click();
await expect(page.locator(".flows-tooltip")).toContainText("Var 2 last step");
await page.locator(".flows-continue").click();
await page.locator(".flows-next").click();
await expect(page.locator(".flows-tooltip")).toContainText("Last Step");
});
test("should reset flow when entering branch without targetBranch", async ({ page }) => {
await page.goto("/branch/branch.html?hideNext=false&logErrors=true");
await expect(page.locator(".flows-tooltip")).toBeVisible();
await page.locator(".flows-continue").click();
await page.locator(".flows-next").click();
await expect(page.locator(".flows-tooltip")).toBeHidden();
await page.locator(".start-flow").click();
await expect(page.locator(".flows-tooltip")).toBeVisible();
Expand All @@ -46,8 +46,8 @@ test("should reset flow when entering branch without targetBranch", async ({ pag
test("should reset flow when entering out of bound step", async ({ page }) => {
await page.goto("/branch/branch.html?lastStep=true&logErrors=true");
await page.locator(".enter-1").click();
await page.locator(".flows-continue").click();
await page.locator(".flows-option").click();
await page.locator(".flows-next").click();
await page.locator(".flows-action").click();
await expect(page.locator(".flows-tooltip")).toBeHidden();
await page.locator(".start-flow").click();
await expect(page.locator(".flows-tooltip")).toBeVisible();
Expand Down
2 changes: 1 addition & 1 deletion workspaces/e2e/tests/branch/branch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ if (lastStep)
steps.push({
targetElement: ".target",
title: "Last Step",
footerActions: { right: [{ label: "Continue", targetBranch: undefined }] },
footerActions: { right: [{ label: "Continue", targetBranch: 0 }] },
});

void init({
Expand Down
67 changes: 39 additions & 28 deletions workspaces/e2e/tests/buttons/buttons.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,75 +13,75 @@ test("Hides close", async ({ page }) => {

test("Next is visible", async ({ page }) => {
await page.goto("/buttons/buttons.html");
await expect(page.locator(".flows-continue")).toBeVisible();
await page.locator(".flows-continue").click();
await expect(page.locator(".flows-continue")).not.toBeVisible();
await expect(page.locator(".flows-next")).toBeVisible();
await page.locator(".flows-next").click();
await expect(page.locator(".flows-next")).not.toBeVisible();
await expect(page.locator(".flows-finish")).toBeVisible();
});
test("Hides next", async ({ page }) => {
await page.goto("/buttons/buttons.html?hideNext=true");
await expect(page.locator(".flows-continue")).not.toBeVisible();
await expect(page.locator(".flows-next")).not.toBeVisible();
});

test("Prev is visible", async ({ page }) => {
await page.goto("/buttons/buttons.html");
await expect(page.locator(".flows-back")).not.toBeVisible();
await page.locator(".flows-continue").click();
await expect(page.locator(".flows-back")).toBeVisible();
await expect(page.locator(".flows-prev")).not.toBeVisible();
await page.locator(".flows-next").click();
await expect(page.locator(".flows-prev")).toBeVisible();
});
test("Hides prev", async ({ page }) => {
await page.goto("/buttons/buttons.html?hidePrev=true");
await expect(page.locator(".flows-back")).not.toBeVisible();
await page.locator(".flows-continue").click();
await expect(page.locator(".flows-back")).not.toBeVisible();
await expect(page.locator(".flows-prev")).not.toBeVisible();
await page.locator(".flows-next").click();
await expect(page.locator(".flows-prev")).not.toBeVisible();
});

test("Default next text", async ({ page }) => {
await page.goto("/buttons/buttons.html");
await expect(page.locator(".flows-continue")).toHaveText("Continue");
await page.locator(".flows-continue").click();
await expect(page.locator(".flows-next")).toHaveText("Continue");
await page.locator(".flows-next").click();
await expect(page.locator(".flows-finish")).toHaveText("Finish");
});
test("Custom next text", async ({ page }) => {
await page.goto("/buttons/buttons.html?nextLabel=Next");
await expect(page.locator(".flows-continue")).toHaveText("Next");
await page.locator(".flows-continue").click();
await expect(page.locator(".flows-next")).toHaveText("Next");
await page.locator(".flows-next").click();
await expect(page.locator(".flows-finish")).toHaveText("Next");
});

test("Default prev text", async ({ page }) => {
await page.goto("/buttons/buttons.html");
await page.locator(".flows-continue").click();
await expect(page.locator(".flows-back")).toHaveText("Back");
await page.locator(".flows-next").click();
await expect(page.locator(".flows-prev")).toHaveText("Back");
});
test("Custom prev text", async ({ page }) => {
await page.goto("/buttons/buttons.html?prevLabel=Previous");
await page.locator(".flows-continue").click();
await expect(page.locator(".flows-back")).toHaveText("Previous");
await page.locator(".flows-next").click();
await expect(page.locator(".flows-prev")).toHaveText("Previous");
});

test("Custom link", async ({ page }) => {
await page.goto("/buttons/buttons.html?customLink=true&hideNext=true");
await expect(page.locator(".flows-option")).toHaveCount(3);
const firstLink = page.locator(".flows-option").first();
await expect(page.locator("a.flows-primary-btn")).toHaveCount(3);
const firstLink = page.locator("a.flows-primary-btn").first();
await expect(firstLink).toBeVisible();
await expect(firstLink).toHaveText("Google");
await expect(firstLink).toHaveAttribute("href", "https://google.com");
await expect(firstLink).not.toHaveAttribute("target", "_blank");
});
test("Custom external link", async ({ page }) => {
await page.goto("/buttons/buttons.html?customExternalLink=true&hideNext=true");
await expect(page.locator(".flows-option")).toHaveCount(3);
const firstLink = page.locator(".flows-option").first();
await expect(page.locator("a.flows-primary-btn")).toHaveCount(3);
const firstLink = page.locator("a.flows-primary-btn").first();
await expect(firstLink).toBeVisible();
await expect(firstLink).toHaveText("Google");
await expect(firstLink).toHaveAttribute("href", "https://google.com");
await expect(firstLink).toHaveAttribute("target", "_blank");
});
test("Custom action", async ({ page }) => {
await page.goto("/buttons/buttons.html?customAction=true&hideNext=true");
await expect(page.locator(".flows-option")).toHaveCount(3);
const firstLink = page.locator(".flows-option").first();
await expect(page.locator(".flows-action")).toHaveCount(3);
const firstLink = page.locator(".flows-action").first();
await expect(firstLink).toBeVisible();
await expect(firstLink).toHaveText("Action");
await expect(firstLink).toHaveAttribute("data-action", "0");
Expand All @@ -90,19 +90,30 @@ test("Custom action", async ({ page }) => {
});
test("Custom next", async ({ page }) => {
await page.goto("/buttons/buttons.html?customNext=true&hideNext=true");
await expect(page.locator(".flows-continue")).toHaveCount(3);
const firstLink = page.locator(".flows-continue").first();
await expect(page.locator(".flows-next")).toHaveCount(3);
const firstLink = page.locator(".flows-next").first();
await expect(firstLink).toBeVisible();
await expect(firstLink).toHaveText("My Next");
await expect(firstLink).not.toHaveAttribute("href");
await expect(firstLink).not.toHaveAttribute("target");
});
test("Custom prev", async ({ page }) => {
await page.goto("/buttons/buttons.html?customPrev=true&hideNext=true");
await expect(page.locator(".flows-back")).toHaveCount(3);
const firstLink = page.locator(".flows-back").first();
await expect(page.locator(".flows-prev")).toHaveCount(3);
const firstLink = page.locator(".flows-prev").first();
await expect(firstLink).toBeVisible();
await expect(firstLink).toHaveText("My Prev");
await expect(firstLink).not.toHaveAttribute("href");
await expect(firstLink).not.toHaveAttribute("target");
});
test("Custom cancel", async ({ page }) => {
await page.goto("/buttons/buttons.html?customCancel=true&hideNext=true&hideClose=true");
await expect(page.locator(".flows-cancel")).toHaveCount(3);
const firstLink = page.locator(".flows-cancel").first();
await expect(firstLink).toBeVisible();
await expect(firstLink).toHaveText("My Cancel");
await expect(firstLink).not.toHaveAttribute("href");
await expect(firstLink).not.toHaveAttribute("target");
await firstLink.click();
await expect(page.locator(".flows-tooltip")).not.toBeVisible();
});
6 changes: 6 additions & 0 deletions workspaces/e2e/tests/buttons/buttons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const customExternalLink =
const customAction = new URLSearchParams(window.location.search).get("customAction") === "true";
const customNext = new URLSearchParams(window.location.search).get("customNext") === "true";
const customPrev = new URLSearchParams(window.location.search).get("customPrev") === "true";
const customCancel = new URLSearchParams(window.location.search).get("customCancel") === "true";

const footerActionsArray: NonNullable<FlowTooltipStep["footerActions"]>["left"] = [];
if (customLink)
Expand Down Expand Up @@ -40,6 +41,11 @@ if (customPrev)
label: "My Prev",
prev: true,
});
if (customCancel)
footerActionsArray.push({
label: "My Cancel",
cancel: true,
});
const footerActions = {
left: footerActionsArray,
center: footerActionsArray,
Expand Down
4 changes: 2 additions & 2 deletions workspaces/e2e/tests/multi-page/multi-page.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ test("Resumes flow when page is reopened", async ({ page }) => {
await page.click(".start-flow");
await expect(page.locator(".flows-tooltip")).toBeVisible();
await expect(page.locator(".flows-tooltip")).toContainText("First");
await page.click(".flows-continue");
await page.click(".flows-next");
await expect(page.locator(".flows-tooltip")).toContainText("Second");
await page.goto("/");
await expect(page.locator(".flows-tooltip")).not.toBeVisible();
Expand All @@ -21,7 +21,7 @@ test("Doesn't resume flow when page is reopened after timeout", async ({ page })
await page.click(".start-flow");
await expect(page.locator(".flows-tooltip")).toBeVisible();
await expect(page.locator(".flows-tooltip")).toContainText("First");
await page.click(".flows-continue");
await page.click(".flows-next");
await expect(page.locator(".flows-tooltip")).toContainText("Second");
await page.evaluate(() =>
localStorage.setItem(
Expand Down
6 changes: 3 additions & 3 deletions workspaces/e2e/tests/tracking/tracking.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import { expect, test } from "@playwright/test";
test("Emits correct events", async ({ page }) => {
await page.goto("/tracking/tracking.html");
await page.locator(".start").click();
await page.locator(".flows-continue").click();
await page.locator(".flows-back").click();
await page.locator(".flows-next").click();
await page.locator(".flows-prev").click();
await page.locator(".flows-cancel").click();
await page.locator(".start").click();
await page.locator(".flows-continue").click();
await page.locator(".flows-next").click();
await page.locator(".flows-finish").click();
const logs = page.locator(".log-item");
await expect(logs.nth(0)).toHaveAttribute("data-type", "startFlow");
Expand Down
68 changes: 30 additions & 38 deletions workspaces/js/css/template.css
Original file line number Diff line number Diff line change
Expand Up @@ -48,62 +48,54 @@
justify-content: flex-end;
}

.flows-button {
background-color: var(--flows-bg-subtle);
border: var(--flows-border);
color: var(--flows-fg-default);
.flows-primary-btn,
.flows-secondary-btn,
.flows-close-btn {
border-radius: var(--flows-borderRadius-small);
padding: 4px 8px;
text-wrap: nowrap;
font-family: var(--flows-font-family);
font-size: var(--flows-base-font-size);
line-height: var(--flows-base-line-height);
font-weight: 600;
cursor: pointer;
transition:
background-color 120ms ease-in-out,
border-color 120ms ease-in-out;
}
.flows-button svg {
pointer-events: none;
}
.flows-button:hover {
background-color: var(--flows-bg-hover);
.flows-primary-btn,
.flows-secondary-btn {
padding: 4px 8px;
font-family: var(--flows-font-family);
font-size: var(--flows-base-font-size);
line-height: var(--flows-base-line-height);
font-weight: 600;
text-wrap: nowrap;
text-decoration: none;
}

.flows-continue,
.flows-option {
.flows-primary-btn {
background-color: var(--flows-bg-primary);
border: 1px solid var(--flows-bg-primary);
color: var(--flows-fg-onPrimary);
}

.flows-continue:hover,
.flows-option:hover {
.flows-primary-btn:hover {
background-color: var(--flows-bg-primary-hover);
border: 1px solid var(--flows-bg-primary-hover);
}

.flows-finish {
background-color: var(--flows-bg-primary);
border: 1px solid var(--flows-bg-primary);
color: var(--flows-fg-onPrimary);
.flows-secondary-btn {
background-color: var(--flows-bg-subtle);
border: var(--flows-border);
color: var(--flows-fg-default);
}

.flows-finish:hover {
background-color: var(--flows-bg-primary-hover);
border: 1px solid var(--flows-bg-primary-hover);
.flows-secondary-btn:hover {
background-color: var(--flows-bg-hover);
}

.flows-cancel {
.flows-close-btn {
background-color: rgba(0, 0, 0, 0);
border: none;
padding: 0;
width: 20px;
height: 20px;
border: none;
position: absolute;
background-color: rgba(0, 0, 0, 0);
padding: 0;
}
.flows-cancel:after {
.flows-close-btn:hover {
background-color: var(--flows-bg-hover);
}
.flows-close-btn:after {
content: "";
position: absolute;
top: 0;
Expand Down Expand Up @@ -156,7 +148,7 @@
position: fixed;
inset: 0;
}
.flows-tooltip .flows-cancel {
.flows-tooltip .flows-close-btn {
top: var(--flows-tooltip-padding);
right: var(--flows-tooltip-padding);
}
Expand Down Expand Up @@ -209,7 +201,7 @@
min-width: var(--flows-modal-minWidth);
max-width: var(--flows-modal-maxWidth);
}
.flows-modal .flows-cancel {
.flows-modal .flows-close-btn {
top: var(--flows-modal-padding);
right: var(--flows-modal-padding);
}
6 changes: 3 additions & 3 deletions workspaces/js/src/core/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,19 +68,19 @@ const _init = (options: FlowsInitOptions): void => {
if (matchingWait) state.nextStep(matchingWait.targetBranch).render();
});

if (eventTarget.matches(".flows-back")) {
if (eventTarget.matches(".flows-prev")) {
const flow = Array.from(FlowsContext.getInstance().instances.values()).find((s) =>
s.flowElement?.element.contains(eventTarget),
);
flow?.prevStep().render();
}
if (eventTarget.matches(".flows-continue")) {
if (eventTarget.matches(".flows-next")) {
const flow = Array.from(FlowsContext.getInstance().instances.values()).find((s) =>
s.flowElement?.element.contains(eventTarget),
);
flow?.nextStep().render();
}
if (eventTarget.matches(".flows-option")) {
if (eventTarget.matches(".flows-action")) {
const action = Number(eventTarget.getAttribute("data-action"));
if (Number.isNaN(action)) return;
const flow = Array.from(FlowsContext.getInstance().instances.values()).find((s) =>
Expand Down
Loading

0 comments on commit a44f01b

Please sign in to comment.