Skip to content
This repository was archived by the owner on Mar 13, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,10 @@ dist
.yarn/install-state.gz
.pnp.*
/.idea/
/.vscode/

# VSCode Counter
.VSCodeCounter

# MacOS
.DS_Store
.DS_Store
*storybook.log
10 changes: 10 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"editor.formatOnSave": true,
"cSpell.words": ["Eich", "eichjs"],
"prettier.enable": false,
"svg.preview.background": "transparent",
"editor.codeActionsOnSave": {
"source.fixAll": "explicit",
"source.organizeImports": "explicit"
}
}
4 changes: 1 addition & 3 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@ import antfu from '@antfu/eslint-config'

export default antfu({
rules: {
eqeqeq: 'off',
'brace-style': '1tbs',
},
ignores: [
'packages/renderer/**/*.*',
'packages/test/**/*.{ts,js,tsx,jsx,json,html,css}',
],
})
19 changes: 19 additions & 0 deletions examples/storybook/.storybook/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { StorybookConfig } from '@storybook/html-vite'

const config: StorybookConfig = {
stories: [
'../stories/**/*.mdx',
'../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)',
],
addons: [
'@storybook/addon-essentials',
'@chromatic-com/storybook',
'@storybook/addon-interactions',
],
framework: {
name: '@storybook/html-vite',
options: {},
},
}

export default config
14 changes: 14 additions & 0 deletions examples/storybook/.storybook/preview.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type { Preview } from '@storybook/html'

const preview: Preview = {
parameters: {
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/i,
},
},
},
}

export default preview
31 changes: 31 additions & 0 deletions examples/storybook/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"name": "@eichjs/examples",
"version": "1.0.0",
"description": "",
"author": "",
"license": "ISC",
"keywords": [],
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "storybook dev -p 6006",
"build": "storybook build"
},
"dependencies": {
"@eichjs/components": "workspace:^",
"@eichjs/layout": "workspace:^",
"@eichjs/renderer": "workspace:^",
"eichjs": "workspace:^"
},
"devDependencies": {
"@chromatic-com/storybook": "^3.2.5",
"@storybook/addon-essentials": "^8.6.4",
"@storybook/addon-interactions": "^8.6.4",
"@storybook/blocks": "^8.6.4",
"@storybook/html": "^8.6.4",
"@storybook/html-vite": "^8.6.4",
"@storybook/test": "^8.6.4",
"@types/node": "22.5.0",
"storybook": "^8.6.4"
}
}
21 changes: 21 additions & 0 deletions examples/storybook/stories/Button.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import './button.css';

export const createButton = ({
primary = false,
size = 'medium',
backgroundColor,
label,
onClick,
}) => {
const btn = document.createElement('button');
btn.type = 'button';
btn.innerText = label;
btn.addEventListener('click', onClick);

const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';
btn.className = ['storybook-button', `storybook-button--${size}`, mode].join(' ');

btn.style.backgroundColor = backgroundColor;

return btn;
};
54 changes: 54 additions & 0 deletions examples/storybook/stories/Button.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { fn } from '@storybook/test'

import { createButton } from './Button'

// More on how to set up stories at: https://storybook.js.org/docs/writing-stories
export default {
title: 'Example/Button',
tags: ['autodocs'],
render: ({ label, ...args }) => {
// You can either use a function to create DOM elements or use a plain html string!
// return `<div>${label}</div>`;
return createButton({ label, ...args })
},
argTypes: {
backgroundColor: { control: 'color' },
label: { control: 'text' },
onClick: { action: 'onClick' },
primary: { control: 'boolean' },
size: {
control: { type: 'select' },
options: ['small', 'medium', 'large'],
},
},
// Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
args: { onClick: fn() },
}

// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
export const Primary = {
args: {
primary: true,
label: 'Button',
},
}

export const Secondary = {
args: {
label: 'Button',
},
}

export const Large = {
args: {
size: 'large',
label: 'Button',
},
}

export const Small = {
args: {
size: 'small',
label: 'Button',
},
}
3 changes: 3 additions & 0 deletions examples/storybook/stories/Configure.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { Meta } from '@storybook/blocks'

<Meta title="Configure your project" />
47 changes: 47 additions & 0 deletions examples/storybook/stories/Header.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { createButton } from './Button';
import './header.css';

export const createHeader = ({ user, onLogout, onLogin, onCreateAccount }) => {
const header = document.createElement('header');

const wrapper = document.createElement('div');
wrapper.className = 'storybook-header';

const logo = `<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>`;

wrapper.insertAdjacentHTML('afterbegin', logo);

const account = document.createElement('div');
if (user) {
const welcomeMessage = `<span class="welcome">Welcome, <b>${user.name}</b>!</span>`;
account.innerHTML = welcomeMessage;
account.appendChild(createButton({ size: 'small', label: 'Log out', onClick: onLogout }));
} else {
account.appendChild(createButton({ size: 'small', label: 'Log in', onClick: onLogin }));
account.appendChild(
createButton({
size: 'small',
label: 'Sign up',
onClick: onCreateAccount,
primary: true,
})
);
}
wrapper.appendChild(account);
header.appendChild(wrapper);

return header;
};
29 changes: 29 additions & 0 deletions examples/storybook/stories/Header.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { fn } from '@storybook/test';

import { createHeader } from './Header';

export default {
title: 'Example/Header',
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
tags: ['autodocs'],
render: (args) => createHeader(args),
parameters: {
// More on how to position stories at: https://storybook.js.org/docs/configure/story-layout
layout: 'fullscreen',
},
args: {
onLogin: fn(),
onLogout: fn(),
onCreateAccount: fn(),
},
};

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

export const LoggedOut = {};
94 changes: 94 additions & 0 deletions examples/storybook/stories/Page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { createHeader } from './Header';
import './page.css';

export const createPage = () => {
const article = document.createElement('article');
let user = null;
let header = null;

const rerenderHeader = () => {
const wrapper = document.getElementsByTagName('article')[0];
wrapper.replaceChild(createHeaderElement(), wrapper.firstChild);
};

const onLogin = () => {
user = { name: 'Jane Doe' };
rerenderHeader();
};

const onLogout = () => {
user = null;
rerenderHeader();
};

const onCreateAccount = () => {
user = { name: 'Jane Doe' };
rerenderHeader();
};

const createHeaderElement = () => {
return createHeader({ onLogin, onLogout, onCreateAccount, user });
};

header = createHeaderElement();
article.appendChild(header);

const section = `
<section class="storybook-page">
<h2>Pages in Storybook</h2>
<p>
We recommend building UIs with a
<a
href="https://blog.hichroma.com/component-driven-development-ce1109d56c8e"
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.insertAdjacentHTML('beforeend', section);

return article;
};
28 changes: 28 additions & 0 deletions examples/storybook/stories/Page.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { expect, userEvent, within } from '@storybook/test';

import { createPage } from './Page';

export default {
title: 'Example/Page',
render: () => createPage(),
parameters: {
// More on how to position stories at: https://storybook.js.org/docs/configure/story-layout
layout: 'fullscreen',
},
};

export const LoggedOut = {};

// More on component testing: https://storybook.js.org/docs/writing-tests/component-testing
export const LoggedIn = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const loginButton = canvas.getByRole('button', { name: /Log in/i });
await expect(loginButton).toBeInTheDocument();
await userEvent.click(loginButton);
await expect(loginButton).not.toBeInTheDocument();

const logoutButton = canvas.getByRole('button', { name: /Log out/i });
await expect(logoutButton).toBeInTheDocument();
},
};
Loading