Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Standardize templates #47

Merged
merged 4 commits into from
Apr 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/qwik-app/src/components/header/header.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Header, HeaderProps } from "./header";
import { Meta, StoryObj } from "../../../../storybook-framework-qwik/dist";
import { Meta, StoryObj } from "storybook-framework-qwik";

export default {
title: "Story Example",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Meta, StoryObj } from "../../../../storybook-framework-qwik/dist";
import { Meta, StoryObj } from "storybook-framework-qwik";
import { Lite } from "../lite/lite";
import { Counter, CounterProps } from "./counter";

Expand Down
6 changes: 4 additions & 2 deletions packages/storybook-framework-qwik/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
"files": [
"README.md",
"./preset.js",
"./dist/*.js",
"./dist/**/*.js",
"./template/cli/**",
"*.js",
"*.d.ts",
Expand All @@ -78,7 +78,9 @@
"watch": "tsc --watch --outDir ./dist --listEmittedFiles",
"build": "tsc --outDir ./dist --listEmittedFiles",
"//semantic-release": "this should be a GHA eventually. I only made this work once locally using tokens in env vars",
"semantic-release": "semantic-release"
"semantic-release": "semantic-release",
"fmt": "prettier --write .",
"fmt.check": "prettier --check ."
},
"dependencies": {
"@storybook/builder-vite": ">=7.0.0-beta.7",
Expand Down
2 changes: 2 additions & 0 deletions packages/storybook-framework-qwik/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type {
LoaderFunction,
StoryContext as GenericStoryContext,
StrictArgs,
ProjectAnnotations,
StorybookConfig as StorybookConfigBase,
} from "@storybook/types";

Expand All @@ -18,6 +19,7 @@ export interface QwikRenderer<T> extends WebRenderer {
storyResult: ReturnType<Component<T>>;
}

export type Preview = ProjectAnnotations<QwikRenderer<unknown>>;
/**
* Metadata to configure the stories for a component.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,37 +1,28 @@
import { action } from "@storybook/addon-actions";
import { $ } from "@builder.io/qwik";
import { Meta, StoryObj } from "storybook-framework-qwik";
import { ButtonProps, Button } from "./button";
import type { Meta, StoryObj } from "storybook-framework-qwik";
import type { ButtonProps, onClickEvent } from "./button";
import { Button } from "./button";

export default {
const meta = {
title: "Button",
args: {
// automatic actions are not yet supported.
// See https://github.com/literalpie/storybook-framework-qwik/issues/16
// For now, use the legacy addon-actions API wrapped in a $ to make your own QRL action.
onClick$: $((event, element) => {
onClick$: $<onClickEvent>((event, element) => {
action("click action")({ event, element });
}),
},
argTypes: {
backgroundColor: { control: "color" },
},
render: ({ label, backgroundColor, primary, onClick$, size }) => {
return (
<Button
backgroundColor={backgroundColor}
primary={primary}
onClick$={(args, element) => onClick$?.(args, element)}
size={size}
>
{label}
</Button>
);
},
component: Button,
} as Meta<ButtonProps & { label: string }>;
} satisfies Meta<ButtonProps>;

export default meta;

type Story = StoryObj<ButtonProps & { label: string }>;
type Story = StoryObj<ButtonProps>;

// More on writing stories with args: https://storybook.js.org/docs/7.0/react/writing-stories/args
export const Primary: Story = {
Expand Down
25 changes: 12 additions & 13 deletions packages/storybook-framework-qwik/template/cli/button.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
import {
component$,
QRL,
QwikMouseEvent,
Slot,
useStylesScoped$,
} from "@builder.io/qwik";
import type { PropFunction, QwikMouseEvent } from "@builder.io/qwik";
import { component$, useStylesScoped$ } from "@builder.io/qwik";
import buttonStyles from "./button.css?inline";

export interface ButtonProps {
Expand All @@ -20,10 +15,14 @@ export interface ButtonProps {
* How large should the button be?
*/
size?: "small" | "medium" | "large";
/**
* Button contents
*/
label: string;
/**
* Optional click handler
*/
onClick$?: QRL<onClickEvent> | undefined;
onClick$?: PropFunction<onClickEvent> | undefined;
}

export const getClassForSize = (size: "small" | "medium" | "large") => {
Expand All @@ -37,13 +36,13 @@ export const getClassForSize = (size: "small" | "medium" | "large") => {
}
};

type onClickEvent = (
export type onClickEvent = (
event: QwikMouseEvent<HTMLButtonElement, MouseEvent>,
element: Element
) => any;
) => void;

export const Button = component$<ButtonProps>(
({ primary = false, size = "medium", backgroundColor, onClick$ }) => {
({ primary = false, size = "medium", backgroundColor, label, onClick$ }) => {
useStylesScoped$(buttonStyles);
const classes = [
"storybook-button",
Expand All @@ -54,9 +53,9 @@ export const Button = component$<ButtonProps>(
<button
class={classes}
style={backgroundColor ? { backgroundColor } : {}}
onClick$={(event, element) => onClick$?.(event, element)}
onClick$={onClick$}
>
<Slot />
{label}
</button>
);
}
Expand Down
43 changes: 43 additions & 0 deletions packages/storybook-framework-qwik/template/cli/header.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import type { Meta, StoryObj } from "storybook-framework-qwik";
import type { HeaderProps } from "./header";
import { Header } from "./header";
import { $ } from "@builder.io/qwik";
import { action } from "@storybook/addon-actions";

const meta = {
title: "Example/Header",
component: Header,
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/react/writing-docs/autodocs
tags: ["autodocs"],
parameters: {
// More on how to position stories at: https://storybook.js.org/docs/react/configure/story-layout
layout: "fullscreen",
},
args: {
// automatic actions are not yet supported.
// See https://github.com/literalpie/storybook-framework-qwik/issues/16
// For now, use the legacy addon-actions API wrapped in a $ to make your own QRL action.
onCreateAccount$: $<() => void>(() => {
action("Create Account Action")();
}),
onLogin$: $<() => void>(() => {
action("Login Action")();
}),
onLogout$: $<() => void>(() => {
action("Logout Action")();
}),
},
} satisfies Meta<HeaderProps>;

export default meta;
type Story = StoryObj<HeaderProps>;

export const LoggedIn: Story = {
args: {
user: {
name: "Jane Doe",
},
},
};

export const LoggedOut: Story = {};
69 changes: 69 additions & 0 deletions packages/storybook-framework-qwik/template/cli/header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import type { PropFunction } from "@builder.io/qwik";
import { component$ } from "@builder.io/qwik";
import { Button } from "./button";
import "./header.css";

type User = {
name: string;
};

export type HeaderProps = {
user?: User;
onLogin$: PropFunction<() => void>;
onLogout$: PropFunction<() => void>;
onCreateAccount$: PropFunction<() => void>;
};

/** The header component includes the app title and information about the currently logged in user. */
export const Header = component$(
({ user, onLogin$, onLogout$, onCreateAccount$ }: HeaderProps) => (
<header>
<div class="wrapper">
<div>
<svg
width="32"
height="32"
viewBox="0 0 32 32"
xmlns="http://www.w3.org/2000/svg"
>
<g fill="none" fillRule="evenodd">
<path
d="M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z"
fill="#FFF"
/>
<path
d="M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z"
fill="#555AB9"
/>
<path
d="M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z"
fill="#91BAF8"
/>
</g>
</svg>
<h1>Acme</h1>
</div>
<div>
{user ? (
<>
<span class="welcome">
Welcome, <b>{user.name}</b>!
</span>
<Button size="small" onClick$={onLogout$} label="Log out" />
</>
) : (
<>
<Button size="small" onClick$={onLogin$} label="Log in" />
<Button
primary
size="small"
onClick$={onCreateAccount$}
label="Sign up"
/>
</>
)}
</div>
</div>
</header>
)
);
30 changes: 30 additions & 0 deletions packages/storybook-framework-qwik/template/cli/page.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type { Meta, StoryObj } from "storybook-framework-qwik";
import { within, userEvent } from "@storybook/testing-library";

import { Page } from "./page";

const meta = {
title: "Example/Page",
component: Page,
parameters: {
// More on how to position stories at: https://storybook.js.org/docs/react/configure/story-layout
layout: "fullscreen",
},
args: { test: "hello" },
} satisfies Meta<{}>;

export default meta;
type Story = StoryObj<{}>;

export const LoggedOut: Story = {};

// More on interaction testing: https://storybook.js.org/docs/react/writing-tests/interaction-testing
export const LoggedIn: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const loginButton = await canvas.getByRole("button", {
name: /Log in/i,
});
await userEvent.click(loginButton);
},
};
94 changes: 94 additions & 0 deletions packages/storybook-framework-qwik/template/cli/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { component$, useSignal } from "@builder.io/qwik";
import { Header } from "./header";
import "./page.css";

type User = {
name: string;
};

export const Page = component$(() => {
const user = useSignal<User>();
return (
<article>
<Header
user={user.value}
onLogin$={() => {
user.value = { name: "Jane Doe" };
}}
onLogout$={() => {
user.value = undefined;
}}
onCreateAccount$={() => {
user.value = { name: "Jane Doe" };
}}
/>

<section>
<h2>Pages in Storybook</h2>
<p>
We recommend building UIs with a{" "}
<a
href="https://componentdriven.org"
target="_blank"
rel="noopener noreferrer"
>
<strong>component-driven</strong>
</a>{" "}
process starting with atomic components and ending with pages.
</p>
<p>
Render pages with mock data. This makes it easy to build and review
page states without needing to navigate to them in your app. Here are
some handy patterns for managing page data in Storybook:
</p>
<ul>
<li>
Use a higher-level connected component. Storybook helps you compose
such data from the "args" of child component stories
</li>
<li>
Assemble data in the page component from your services. You can mock
these services out using Storybook.
</li>
</ul>
<p>
Get a guided tutorial on component-driven development at{" "}
<a
href="https://storybook.js.org/tutorials/"
target="_blank"
rel="noopener noreferrer"
>
Storybook tutorials
</a>
. Read more in the{" "}
<a
href="https://storybook.js.org/docs"
target="_blank"
rel="noopener noreferrer"
>
docs
</a>
.
</p>
<div class="tip-wrapper">
<span class="tip">Tip</span> Adjust the width of the canvas with the{" "}
<svg
width="10"
height="10"
viewBox="0 0 12 12"
xmlns="http://www.w3.org/2000/svg"
>
<g fill="none" fillRule="evenodd">
<path
d="M1.5 5.2h4.8c.3 0 .5.2.5.4v5.1c-.1.2-.3.3-.4.3H1.4a.5.5 0 01-.5-.4V5.7c0-.3.2-.5.5-.5zm0-2.1h6.9c.3 0 .5.2.5.4v7a.5.5 0 01-1 0V4H1.5a.5.5 0 010-1zm0-2.1h9c.3 0 .5.2.5.4v9.1a.5.5 0 01-1 0V2H1.5a.5.5 0 010-1zm4.3 5.2H2V10h3.8V6.2z"
id="a"
fill="#999"
/>
</g>
</svg>
Viewports addon in the toolbar
</div>
</section>
</article>
);
});