Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/*/dist/
/*/storybook-static/
/pnpm-lock.yaml
/icons/svg/
/styles/.tikui-cache/
Expand Down
8 changes: 8 additions & 0 deletions mise.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,14 @@ run = "pnpm --filter react lint"
[tasks.react-test-unit-ci]
run = "pnpm --filter react test:unit:ci"

[tasks.react-dev]
description = "Serve the React components Storybook (requires styles to be built)"
run = "pnpm --filter react dev"

[tasks.react-build]
description = "Build the React library then its static Storybook (requires styles to be built)"
run = "pnpm --filter react build"

[tasks.icons-build]
run = "pnpm --filter icons build"

Expand Down
1,308 changes: 1,260 additions & 48 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions react/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ lerna-debug.log*
node_modules
dist
dist-ssr
storybook-static
*.local

# Editor directories and files
Expand Down
12 changes: 12 additions & 0 deletions react/.storybook/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { StorybookConfig } from '@storybook/react-vite';

const config: StorybookConfig = {
stories: ['../stories/**/*.stories.@(ts|tsx)'],
addons: ['@storybook/addon-docs'],
framework: {
name: '@storybook/react-vite',
options: {},
},
};

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

import '@ippon-ui/styles/fonts/open-sans/400.css';
import '@ippon-ui/styles/fonts/open-sans/600.css';
import '@ippon-ui/styles/fonts/open-sans/700.css';
import '@ippon-ui/styles/fonts/saira-extra-condensed/700.css';
import '@ippon-ui/styles/icons/ionicons.css';
import '@ippon-ui/styles/tikui.css';

const preview: Preview = {
tags: ['autodocs'],
parameters: {
layout: 'centered',
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/i,
},
},
},
};

export default preview;
16 changes: 16 additions & 0 deletions react/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,22 @@ export const SaveButton = () => (
);
```

## Documentation

Every component is documented in [Storybook](https://storybook.js.org). Stories live in
[`stories/`](./stories) (one file per component) and render against the built
`@ippon-ui/styles` stylesheet.

Build the styles first (from the monorepo root), then serve Storybook on port `4230`:

```sh
mise build # builds icons + styles + react
mise react-dev # serves Storybook at http://localhost:4230
```

`mise react-build` builds the React library and then its static Storybook (output in
`storybook-static/`).

## License

[Apache-2.0](./LICENCE) © Ippon Technologies
4 changes: 3 additions & 1 deletion react/eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import js from '@eslint/js';
import globals from 'globals';
import reactHooks from 'eslint-plugin-react-hooks';
import reactRefresh from 'eslint-plugin-react-refresh';
import storybook from 'eslint-plugin-storybook';
import tseslint from 'typescript-eslint';
import { defineConfig, globalIgnores } from 'eslint/config';

export default defineConfig([
globalIgnores(['dist']),
globalIgnores(['dist', 'storybook-static']),
{
files: ['**/*.{ts,tsx}'],
extends: [
Expand All @@ -19,4 +20,5 @@ export default defineConfig([
globals: globals.browser,
},
},
storybook.configs['flat/recommended'],
]);
11 changes: 9 additions & 2 deletions react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@
"author": "Ippon Technologies",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"dev": "storybook dev -p 4230",
"build": "pnpm run build:lib && pnpm run build:storybook",
"build:lib": "tsc -b && vite build",
"build:storybook": "storybook build",
"lint": "eslint .",
"preview": "vite preview",
"test:unit": "vitest",
Expand Down Expand Up @@ -45,7 +47,10 @@
"vite-plugin-dts": "^5.0.1",
"@eslint/js": "^10.0.1",
"@ippon-ui/icons": "workspace:*",
"@ippon-ui/styles": "workspace:*",
"@rolldown/plugin-babel": "^0.2.3",
"@storybook/addon-docs": "^10.4.4",
"@storybook/react-vite": "^10.4.4",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.2",
"@types/babel__core": "^7.20.5",
Expand All @@ -58,8 +63,10 @@
"eslint": "^10.3.0",
"eslint-plugin-react-hooks": "^7.1.1",
"eslint-plugin-react-refresh": "^0.5.2",
"eslint-plugin-storybook": "^10.4.4",
"globals": "^17.6.0",
"jsdom": "^29.1.1",
"storybook": "^10.4.4",
"typescript": "~6.0.2",
"typescript-eslint": "^8.59.2",
"vite": "^8.0.12",
Expand Down
67 changes: 67 additions & 0 deletions react/stories/IpponBadge.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import type { Meta, StoryObj } from '@storybook/react-vite';
import { IpponBadge } from '../src/IpponBadge.tsx';

const meta = {
title: 'Atom/Badge',
component: IpponBadge,
args: {
children: 'Badge',
},
argTypes: {
color: {
control: 'select',
options: ['brand', 'neutral', 'success', 'error', 'warning', 'information'],
},
variant: {
control: 'select',
options: [undefined, 'secondary'],
},
},
} satisfies Meta<typeof IpponBadge>;

export default meta;

type Story = StoryObj<typeof meta>;

export const Default: Story = {};

export const Colors: Story = {
render: (args) => (
<>
<IpponBadge {...args} color="brand">
Brand
</IpponBadge>{' '}
<IpponBadge {...args} color="neutral">
Neutral
</IpponBadge>{' '}
<IpponBadge {...args} color="success">
Success
</IpponBadge>{' '}
<IpponBadge {...args} color="error">
Error
</IpponBadge>{' '}
<IpponBadge {...args} color="warning">
Warning
</IpponBadge>{' '}
<IpponBadge {...args} color="information">
Information
</IpponBadge>
</>
),
};

export const Secondary: Story = {
args: { color: 'information', variant: 'secondary' },
};

export const WithIcons: Story = {
args: {
color: 'information',
iconLeft: { name: 'information-circle' },
iconRight: { name: 'close', onClick: () => {} },
},
};

export const Placeholder: Story = {
args: { placeholder: true },
};
112 changes: 112 additions & 0 deletions react/stories/IpponButton.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import type { Meta, StoryObj } from '@storybook/react-vite';
import { IpponButton } from '../src/IpponButton.tsx';

const meta = {
title: 'Atom/Button',
component: IpponButton,
args: {
children: 'Button',
},
argTypes: {
color: {
control: 'select',
options: ['success', 'error', 'information', 'warning', 'neutral'],
},
variant: {
control: 'select',
options: ['secondary', 'outline', 'text'],
},
size: {
control: 'select',
options: ['small', 'large'],
},
onClick: { action: 'clicked' },
},
} satisfies Meta<typeof IpponButton>;

export default meta;

type Story = StoryObj<typeof meta>;

export const Default: Story = {};

export const Information: Story = {
args: { color: 'information' },
};

export const Colors: Story = {
render: (args) => (
<>
<IpponButton {...args} color="success">
Success
</IpponButton>{' '}
<IpponButton {...args} color="error">
Error
</IpponButton>{' '}
<IpponButton {...args} color="information">
Information
</IpponButton>{' '}
<IpponButton {...args} color="warning">
Warning
</IpponButton>{' '}
<IpponButton {...args} color="neutral">
Neutral
</IpponButton>
</>
),
};

export const Variants: Story = {
render: (args) => (
<>
<IpponButton {...args} color="information">
Primary
</IpponButton>{' '}
<IpponButton {...args} color="information" variant="secondary">
Secondary
</IpponButton>{' '}
<IpponButton {...args} color="information" variant="outline">
Outline
</IpponButton>{' '}
<IpponButton {...args} color="information" variant="text">
Text
</IpponButton>
</>
),
};

export const Sizes: Story = {
render: (args) => (
<>
<IpponButton {...args} color="information" size="small">
Small
</IpponButton>{' '}
<IpponButton {...args} color="information">
Default
</IpponButton>{' '}
<IpponButton {...args} color="information" size="large">
Large
</IpponButton>
</>
),
};

export const WithIcons: Story = {
args: {
color: 'information',
iconLeft: { name: 'add' },
iconRight: { name: 'chevron-forward' },
},
};

export const Disabled: Story = {
args: { color: 'information', disabled: true },
};

export const Loading: Story = {
args: {
color: 'information',
iconRight: { name: 'checkmark' },
onClick: () => new Promise((resolve) => setTimeout(resolve, 2000)),
},
};
39 changes: 39 additions & 0 deletions react/stories/IpponButtonCard.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import type { Meta, StoryObj } from '@storybook/react-vite';
import { IpponButtonCard } from '../src/IpponButtonCard.tsx';
import { IpponText } from '../src/IpponText.tsx';

const meta = {
Comment thread
Gnuk marked this conversation as resolved.
title: 'Organism/ButtonCard',
component: IpponButtonCard,
args: {
children: <IpponText variant="body">Clickable card</IpponText>,
},
argTypes: {
children: { control: false },
shadow: {
control: 'select',
options: [undefined, 'l1', 'l2', 'l3', 'l4', 'l5', 'l6'],
},
size: {
control: 'select',
options: [undefined, 'small', 'large'],
},
onClick: { action: 'clicked' },
},
} satisfies Meta<typeof IpponButtonCard>;

export default meta;

type Story = StoryObj<typeof meta>;

export const Default: Story = {
args: { border: true },
};

export const WithShadow: Story = {
args: { shadow: 'l2' },
};

export const FullWidth: Story = {
args: { border: true, fullWidth: true },
};
Loading
Loading