-
Notifications
You must be signed in to change notification settings - Fork 222
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(component-library): initialize component library
- Loading branch information
Showing
28 changed files
with
5,850 additions
and
176 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,3 +19,5 @@ patches/ | |
apps/api-reference | ||
apps/staking | ||
governance/pyth_staking_sdk | ||
packages/component-library | ||
packages/fonts |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
coverage/ | ||
node_modules/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import { createRequire } from "node:module"; | ||
|
||
import type { StorybookConfig } from "@storybook/nextjs"; | ||
|
||
const resolve = createRequire(import.meta.url).resolve; | ||
|
||
const config = { | ||
framework: "@storybook/nextjs", | ||
|
||
stories: [ | ||
"../src/**/*.mdx", | ||
"../src/**/?(*.)story.tsx", | ||
"../src/**/?(*.)stories.tsx", | ||
], | ||
|
||
addons: [ | ||
"@storybook/addon-essentials", | ||
"@storybook/addon-themes", | ||
{ | ||
name: "@storybook/addon-styling-webpack", | ||
options: { | ||
rules: [ | ||
{ | ||
test: /\.css$/, | ||
use: [ | ||
"style-loader", | ||
{ | ||
loader: "css-loader", | ||
options: { importLoaders: 1 }, | ||
}, | ||
{ | ||
loader: "postcss-loader", | ||
options: { implementation: resolve("postcss") }, | ||
}, | ||
], | ||
}, | ||
], | ||
}, | ||
}, | ||
], | ||
|
||
webpackFinal: (config) => ({ | ||
...config, | ||
resolve: { | ||
...config.resolve, | ||
extensionAlias: { | ||
".js": [".js", ".ts", ".tsx"], | ||
}, | ||
}, | ||
}), | ||
} satisfies StorybookConfig; | ||
export default config; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
module.exports = { | ||
plugins: { | ||
tailwindcss: { | ||
config: `${__dirname}/../tailwind.config.ts`, | ||
}, | ||
autoprefixer: {}, | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { sans } from "@pythnetwork/fonts"; | ||
import { withThemeByClassName } from "@storybook/addon-themes"; | ||
import type { Preview, Decorator } from "@storybook/react"; | ||
import clsx from "clsx"; | ||
|
||
import "./tailwind.css"; | ||
|
||
const preview = { | ||
parameters: { | ||
backgrounds: { disable: true }, | ||
actions: { argTypesRegex: "^on[A-Z].*" }, | ||
}, | ||
} satisfies Preview; | ||
|
||
export default preview; | ||
|
||
export const decorators: Decorator[] = [ | ||
(Story) => ( | ||
<main className={clsx("font-sans antialiased", sans.variable)}> | ||
<Story /> | ||
</main> | ||
), | ||
withThemeByClassName({ | ||
themes: { | ||
white: "light bg-white", | ||
light: "light bg-stone-100", | ||
dark: "dark bg-slate-800", | ||
darker: "dark bg-slate-900", | ||
}, | ||
defaultTheme: "light", | ||
}), | ||
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
@tailwind base; | ||
@tailwind components; | ||
@tailwind utilities; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# @pythnetwork/component-library |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { fileURLToPath } from "node:url"; | ||
|
||
import { react, tailwind, storybook } from "@cprussin/eslint-config"; | ||
|
||
const config = [ | ||
...react, | ||
...tailwind(fileURLToPath(import.meta.resolve("./tailwind.config.ts"))), | ||
...storybook, | ||
]; | ||
export default config; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { base as default } from "@cprussin/jest-config"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
{ | ||
"name": "@pythnetwork/component-library", | ||
"version": "0.0.0", | ||
"private": true, | ||
"type": "module", | ||
"scripts": { | ||
"build:storybook": "storybook build", | ||
"fix": "pnpm fix:lint && pnpm fix:format", | ||
"fix:format": "prettier --write .", | ||
"fix:lint": "eslint --fix .", | ||
"start:storybook": "storybook dev --port 4000 --no-open", | ||
"test": "pnpm test:types && pnpm test:lint && pnpm test:format", | ||
"test:format": "prettier --check .", | ||
"test:lint": "jest --selectProjects lint", | ||
"test:types": "tsc" | ||
}, | ||
"peerDependencies": { | ||
"react": "^18.3.1" | ||
}, | ||
"dependencies": { | ||
"clsx": "^2.1.1", | ||
"react-aria": "^3.35.0", | ||
"react-aria-components": "^1.4.0" | ||
}, | ||
"devDependencies": { | ||
"@cprussin/eslint-config": "^3.0.0", | ||
"@cprussin/jest-config": "^1.4.1", | ||
"@cprussin/prettier-config": "^2.1.1", | ||
"@cprussin/tsconfig": "^3.0.1", | ||
"@phosphor-icons/react": "^2.1.7", | ||
"@pythnetwork/fonts": "workspace:^", | ||
"@storybook/addon-essentials": "^8.3.5", | ||
"@storybook/addon-styling-webpack": "^1.0.0", | ||
"@storybook/addon-themes": "^8.3.5", | ||
"@storybook/blocks": "^8.3.5", | ||
"@storybook/nextjs": "^8.3.5", | ||
"@storybook/react": "^8.3.5", | ||
"@tailwindcss/forms": "^0.5.9", | ||
"@types/jest": "^29.5.13", | ||
"@types/react": "^18.3.11", | ||
"autoprefixer": "^10.4.20", | ||
"css-loader": "^7.1.2", | ||
"eslint": "^9.12.0", | ||
"jest": "^29.7.0", | ||
"postcss": "^8.4.47", | ||
"postcss-loader": "^8.1.1", | ||
"prettier": "^3.3.3", | ||
"react": "^18.3.1", | ||
"storybook": "^8.3.5", | ||
"style-loader": "^4.0.0", | ||
"tailwindcss": "^3.4.13", | ||
"tailwindcss-animate": "^1.0.7", | ||
"tailwindcss-react-aria-components": "^1.1.6", | ||
"typescript": "^5.6.3" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { fileURLToPath } from "node:url"; | ||
|
||
import { base, tailwind, mergeConfigs } from "@cprussin/prettier-config"; | ||
|
||
const config = mergeConfigs([ | ||
base, | ||
tailwind(fileURLToPath(import.meta.resolve("./tailwind.config.ts"))), | ||
]); | ||
|
||
export default config; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import * as Icon from "@phosphor-icons/react/dist/ssr"; | ||
import type { ArgTypes } from "@storybook/react"; | ||
|
||
export const argTypes = { | ||
isDisabled: { | ||
control: "boolean", | ||
}, | ||
variant: { | ||
control: "inline-radio", | ||
}, | ||
size: { | ||
control: "inline-radio", | ||
}, | ||
beforeIcon: { | ||
control: "select", | ||
options: Object.keys(Icon), | ||
mapping: Icon, | ||
}, | ||
afterIcon: { | ||
control: "select", | ||
options: Object.keys(Icon), | ||
mapping: Icon, | ||
}, | ||
} satisfies ArgTypes; |
21 changes: 21 additions & 0 deletions
21
packages/component-library/src/Button/button-link.stories.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import type { Meta, StoryObj } from "@storybook/react"; | ||
|
||
import { argTypes } from "./arg-types.js"; | ||
import { ButtonLink as ButtonLinkComponent } from "./index.js"; | ||
|
||
const meta = { | ||
component: ButtonLinkComponent, | ||
title: "Button/ButtonLink", | ||
argTypes, | ||
} satisfies Meta<typeof ButtonLinkComponent>; | ||
export default meta; | ||
|
||
export const ButtonLink = { | ||
args: { | ||
children: "Link", | ||
href: "https://www.pyth.network", | ||
target: "_blank", | ||
variant: "primary", | ||
size: "md", | ||
}, | ||
} satisfies StoryObj<typeof ButtonLinkComponent>; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import type { Meta, StoryObj } from "@storybook/react"; | ||
|
||
import { argTypes } from "./arg-types.js"; | ||
import { Button as ButtonComponent } from "./index.js"; | ||
|
||
const meta = { | ||
component: ButtonComponent, | ||
argTypes: { | ||
...argTypes, | ||
onPress: {}, | ||
}, | ||
} satisfies Meta<typeof ButtonComponent>; | ||
export default meta; | ||
|
||
export const Button = { | ||
args: { | ||
children: "Button", | ||
variant: "primary", | ||
size: "md", | ||
}, | ||
} satisfies StoryObj<typeof ButtonComponent>; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
import clsx from "clsx"; | ||
import type { ComponentProps, ComponentType, SVGProps } from "react"; | ||
import { Button as BaseButton, Link } from "react-aria-components"; | ||
|
||
type Icon = ComponentType<SVGProps<SVGSVGElement>>; | ||
|
||
type OwnProps = { | ||
variant?: "primary" | "secondary" | "solid" | "outline" | "ghost"; | ||
size?: "xs" | "sm" | "md" | "lg"; | ||
rounded?: boolean; | ||
children?: string; | ||
beforeIcon?: Icon; | ||
afterIcon?: Icon; | ||
}; | ||
|
||
export type ButtonProps = Omit< | ||
ComponentProps<typeof BaseButton>, | ||
keyof OwnProps | ||
> & | ||
OwnProps; | ||
|
||
export const Button = (props: ButtonProps) => ( | ||
<BaseButton | ||
{...props} | ||
{...dataAttributes(props)} | ||
className={clsx( | ||
baseClasses, | ||
|
||
// Pending | ||
"data-[pending]:data-[variant]:cursor-wait data-[pending]:data-[variant]:border-transparent data-[pending]:data-[variant]:bg-stone-200 data-[pending]:data-[variant]:text-stone-400 data-[pending]:data-[variant]:data-[focus-visible]:outline-stone-300 dark:data-[pending]:data-[variant]:bg-slate-600 dark:data-[pending]:data-[variant]:text-slate-400 dark:data-[pending]:data-[variant]:data-[focus-visible]:outline-slate-500", | ||
|
||
props.className, | ||
)} | ||
{...props} | ||
> | ||
<ButtonInner {...props} /> | ||
</BaseButton> | ||
); | ||
|
||
export type ButtonLinkProps = Omit< | ||
ComponentProps<typeof Link>, | ||
keyof OwnProps | ||
> & | ||
OwnProps; | ||
|
||
export const ButtonLink = (props: ButtonLinkProps) => ( | ||
<Link | ||
{...props} | ||
{...dataAttributes(props)} | ||
className={clsx(baseClasses, props.className)} | ||
> | ||
<ButtonInner {...props} /> | ||
</Link> | ||
); | ||
|
||
const Icon = ({ icon: IconComponent }: { icon: Icon }) => ( | ||
<IconComponent className="inline-block size-6 group-data-[size=sm]:size-5 group-data-[size=xs]:size-4" /> | ||
); | ||
|
||
const ButtonInner = (props: OwnProps) => ( | ||
<> | ||
{"beforeIcon" in props && <Icon icon={props.beforeIcon} />} | ||
{"children" in props && props.children !== "" && ( | ||
<span className="px-2 align-middle group-data-[size=lg]:px-3 group-data-[size=xs]:px-1"> | ||
{props.children} | ||
</span> | ||
)} | ||
{"afterIcon" in props && <Icon icon={props.afterIcon} />} | ||
</> | ||
); | ||
|
||
const dataAttributes = ({ | ||
variant = "primary", | ||
size = "md", | ||
rounded = false, | ||
}: OwnProps) => ({ | ||
"data-variant": variant, | ||
"data-size": size, | ||
"data-rounded": rounded ? "" : undefined, | ||
}); | ||
|
||
const baseClasses = clsx( | ||
"group inline-block cursor-pointer border border-transparent font-medium outline-none transition-colors duration-100 data-[size]:data-[rounded]:rounded-full data-[focus-visible]:outline-2", | ||
|
||
// xs | ||
"data-[size=xs]:rounded-md data-[size=xs]:px-1.5 data-[size=xs]:py-1 data-[size=xs]:text-[0.6875rem]/4", | ||
|
||
// sm | ||
"data-[size=sm]:rounded-lg data-[size=sm]:p-2 data-[size=sm]:text-sm", | ||
|
||
// md (default) | ||
"data-[size=md]:rounded-xl data-[size=md]:p-3", | ||
|
||
// lg | ||
"data-[size=lg]:rounded-2xl data-[size=lg]:p-4 data-[size=lg]:text-xl/6", | ||
|
||
// Primary (default) | ||
"data-[variant=primary]:bg-violet-500 data-[variant=primary]:data-[hovered]:bg-violet-700 data-[variant=primary]:data-[pressed]:bg-violet-800 data-[variant=primary]:text-violet-50 data-[variant=primary]:data-[focus-visible]:outline-violet-500", | ||
|
||
// Dark Mode Primary (default) | ||
"dark:data-[variant=primary]:bg-violet-600 dark:data-[variant=primary]:data-[hovered]:bg-violet-700 dark:data-[variant=primary]:data-[pressed]:bg-violet-800 dark:data-[variant=primary]:text-violet-50 dark:data-[variant=primary]:data-[focus-visible]:outline-violet-600", | ||
|
||
// Secondary | ||
"data-[variant=secondary]:bg-purple-200 data-[variant=secondary]:data-[hovered]:bg-purple-300 data-[variant=secondary]:data-[pressed]:bg-purple-400 data-[variant=secondary]:text-slate-900 data-[variant=secondary]:data-[focus-visible]:outline-purple-300", | ||
|
||
// Dark Mode Secondary | ||
"dark:data-[variant=secondary]:bg-purple-200 dark:data-[variant=secondary]:data-[hovered]:bg-purple-300 dark:data-[variant=secondary]:data-[pressed]:bg-purple-400 dark:data-[variant=secondary]:text-slate-900 dark:data-[variant=secondary]:data-[focus-visible]:outline-purple-300", | ||
|
||
// Solid | ||
"data-[variant=solid]:bg-slate-900 data-[variant=solid]:data-[hovered]:bg-slate-600 data-[variant=solid]:data-[pressed]:bg-slate-900 data-[variant=solid]:text-slate-50 data-[variant=solid]:data-[focus-visible]:outline-slate-600", | ||
|
||
// Dark Mode Solid | ||
"dark:data-[variant=solid]:bg-slate-50 dark:data-[variant=solid]:data-[hovered]:bg-slate-200 dark:data-[variant=solid]:data-[pressed]:bg-slate-50 dark:data-[variant=solid]:text-slate-900 dark:data-[variant=solid]:data-[focus-visible]:outline-slate-300", | ||
|
||
// Outline | ||
"data-[variant=outline]:border-stone-300 data-[variant=outline]:bg-transparent data-[variant=outline]:data-[hovered]:bg-black/5 data-[variant=outline]:data-[pressed]:bg-black/10 data-[variant=outline]:text-stone-900 data-[variant=outline]:data-[focus-visible]:outline-stone-400", | ||
|
||
// Dark Mode Outline | ||
"dark:data-[variant=outline]:border-slate-600 dark:data-[variant=outline]:bg-transparent dark:data-[variant=outline]:data-[hovered]:bg-white/5 dark:data-[variant=outline]:data-[pressed]:bg-white/10 dark:data-[variant=outline]:text-slate-50 dark:data-[variant=outline]:data-[focus-visible]:outline-slate-500", | ||
|
||
// Ghost | ||
"data-[variant=ghost]:bg-transparent data-[variant=ghost]:data-[hovered]:bg-black/5 data-[variant=ghost]:data-[pressed]:bg-black/10 data-[variant=ghost]:text-stone-900 data-[variant=ghost]:data-[focus-visible]:outline-stone-400", | ||
|
||
// Dark Mode Ghost | ||
"dark:data-[variant=ghost]:bg-transparent dark:data-[variant=ghost]:data-[hovered]:bg-white/5 dark:data-[variant=ghost]:data-[pressed]:bg-white/10 dark:data-[variant=ghost]:text-slate-50 dark:data-[variant=ghost]:data-[focus-visible]:outline-slate-500", | ||
|
||
// Disabled | ||
"data-[disabled]:data-[variant]:cursor-not-allowed data-[disabled]:data-[variant]:border-transparent data-[disabled]:data-[variant]:bg-stone-200 data-[disabled]:data-[variant]:text-stone-400 dark:data-[disabled]:data-[variant]:bg-slate-600 dark:data-[disabled]:data-[variant]:text-slate-400", | ||
); |
Oops, something went wrong.