@podchaser/component-library
v1.19.0
Published
This is podchaser component library.
Downloads
1,928
Readme
@podchaser/component-library
A typed React component library for Podchaser. Built with TypeScript, styled-components, Rollup, and Storybook. Ships dual bundles (ESM + CJS) and type definitions.
Goal: unify Podchaser’s UI with reusable, token-driven components and faster delivery.
⸻
Why this exists
This library is the single source of truth for Podchaser UI: • Consistent visuals across apps (design tokens, theming). • Reusable, well-typed components to speed up feature work. • Migration path away from ad-hoc styles toward styled-components + Storybook.
High-level initiative details live in the repo as context for the team (purpose, rollout, testing, etc.).
⸻
Install
npm
npm i @podchaser/component-library
or yarn
yarn add @podchaser/component-library
or pnpm
pnpm add @podchaser/component-library
Peer deps • React: 19.2.0 (you must provide React in the consuming app)
⸻
Usage
Button
// ESM (recommended)
import { StandardButton } from "@podchaser/component-library";
export function Example() {
return (
<StandardButton
label="Primary CTA"
variation="primary"
size="md"
onClick={() => {
// handle click
}}
/>
);
}You can also render it as a link:
// As an anchor
<StandardButton href="https://podchaser.com" target="_blank" rel="noreferrer">
Visit Podchaser
</StandardButton>
// With a router Link (e.g. react-router-dom)
import { Link } from "react-router-dom";
<StandardButton linkComponent={Link} to="/dashboard">
Go to dashboard
</StandardButton>Props
| Prop | Type | Default | Description |
| ------------- | -------------------------------------------------- | ------------ | ----------------------------------------------------------------------------------------------------- |
| label | ReactNode | "Click Me" | Primary content shown inside the button. Falls back to title and then children. |
| title | ReactNode | undefined | Backwards‑compatible alias for label. |
| hoverLabel | ReactNode | undefined | Optional alternate label shown only while the button is hovered. |
| variation | "primary" \| "transparent" \| "actioned" \| "clear" \| "blue" \| "green" \| "red" \| "pink" \| "negative" \| "white" \| "whiteNegative" \| "subtle" \| "darkSubtle" \| "darkSuperSubtle" \| "none" | "primary" | Visual variation style of the button. |
| size | "sm" \| "md" \| "lg" | "md" | Size preset controlling padding and base font‑size (≈12px by default). |
| fullWidth | boolean | false | When true, button stretches to fill the width of its container. |
| width | string | "max-content" | Explicit width (e.g. "240px", "100%"). Overrides fullWidth logic when set. |
| height | string | "2rem" | Explicit height (e.g. "40px"). |
| padding | string | size preset | Padding override (e.g. "0.5rem 1rem"), applied on top of the chosen size. |
| margin | string | 0 | Margin override around the button (e.g. "0 0 1rem 0"). |
| justifyContent | string | "center" | Flex justify-content for the inner button content (e.g. "center", "flex-start"). |
| alignItems | string | "center" | Flex align-items for the inner button content (e.g. "center", "flex-start"). |
| borderRadius| string | "25px" | Border radius override (e.g. "4px", "25px"). |
| borderColor | string | transparent| Border color override. |
| hoveredBorderColor | string | border | Border color to use on hover. Falls back to borderColor when not provided. |
| background | string | variation | Full CSS background value (e.g. gradients like "linear-gradient(...)"). Takes precedence over variation backgrounds. |
| backgroundColor | string | variation | Background color override. When set, it takes precedence over variation (unless background is set). |
| hoveredBackgroundColor | string | background | Background color to use on hover. Falls back to backgroundColor when not provided. |
| transition | string | smooth base | CSS transition override for the button (e.g. "all 200ms ease-out"). |
| opacity | string | 1 | CSS opacity override for the button (e.g. "0.5"). |
| filter | string | none | CSS filter override (e.g. "brightness(0.8)", "blur(2px)"). |
| fontSize | string | variant/size | Font size override (e.g. "14px", "0.875rem"). |
| fontStyleKey| ButtonFontStyleKey | "avalonBold" | Key from fontStyles controlling font family/weight/style (e.g. "avalonBold", "fontRegular"). |
| fontColor | string | variant text | Text color override. |
| flat | boolean | false | Legacy “flat” appearance for specific variants (e.g. red, white, whiteNegative). |
| bordered | boolean | false | Legacy bordered appearance for specific variants (e.g. red). |
| isActive | boolean | false | Forces the button into an “active/pressed” visual state. |
| isSubmitting| boolean | false | Shows a submitting state and disables interaction (sets aria-busy). |
| disabled | boolean | false | Disables the button. |
| type | "button" \| "submit" \| "reset" | "button" | Native button type attribute (only relevant when rendered as a <button>). |
| href | string | undefined | When set, renders the button as an <a> with this href (styling stays the same). |
| to | string | undefined | When used with linkComponent, passes the route target through (e.g. to react-router’s Link). |
| linkComponent| ElementType | undefined | Optional link component to render instead of <button>/<a> (e.g. Link from react-router-dom). |
| onClick | (event: MouseEvent<HTMLButtonElement>) => void | undefined | Standard click handler (from ButtonHTMLAttributes). |
| …rest | All other ButtonHTMLAttributes<HTMLButtonElement> (except type and native title) | – | Forwarded to the underlying element (<button>, <a>, or your linkComponent). |
⸻
Getting started (local development)
install
npm ci
run storybook (component dev playground)
npm run storybook
type-check & build library
npm run build
test
npm test
lint (check)
npm run lint
lint (auto-fix)
npm run lint:fix
watch build (rollup)
npm run dev
⸻
Scripts
Script What it does build Builds ESM/CJS bundles + types via Rollup dev Rollup in watch mode storybook Launches Storybook locally on port 6006 build-storybook Builds static Storybook site test Runs Jest (jsdom) lint ESLint for src/**/*.ts,tsx lint:fix ESLint with --fix semantic-release Runs semantic-release (used by CI)
⸻
Tech stack • TypeScript (types, .d.ts output) • Rollup (CJS + ESM) • styled-components (theming, styles) • Storybook (documentation & manual verification) • Jest + @testing-library/react (unit tests) • ESLint (TS rules + React plugin) • semantic-release (automated releases from conventional commits)
⸻
Consuming apps — bundling notes • ESM first: module field → tree-shaking. • CJS fallback: main field for older build pipelines. • Types: types field provides TypeScript declarations. • The library marks React as a peer dependency to avoid duplicate React instances.
⸻
Versioning & releases
This repo is set up for semantic-release. Releases are cut from CI on main (or your configured branch) based on commit messages: • feat: ... → minor • fix: ... → patch • feat!: ... or BREAKING CHANGE: in body → major
Required CI secrets: • GITHUB_TOKEN (automatically provided in GitHub Actions) • NPM_TOKEN (publishing to npm; only if/when you’re ready to publish)
This package currently carries version 0.0.0-development and publishConfig.access = public. Adjust when publishing for real.
⸻
System design (initiative summary) • Purpose: consistent UI via shared components; reduce duplication; speed up dev. • Architecture: NPM library consumed by Podchaser Web; Storybook for docs; tokens via theme provider. • Error handling: typed props, sensible fallbacks, console warnings in dev. • Testing: unit tests for rendering, props, states; optional visual checks via Storybook. • Metrics: adoption rate in app, QA sign-off, developer feedback. • Rollout: 1. Audit legacy components/styles 2. Build core primitives (Button, Input, Select, etc.) 3. Document in Storybook 4. Integrate into Podchaser Web 5. Replace legacy pieces incrementally 6. Validate, then expand
⸻
Contributing 1. Create a feature branch:
git switch -c feat/button-variants
2. Write code + tests + stories.
3. Lint & test locally:npm run lint npm test
4. Commit using Conventional Commits:
• feat(button): add destructive variant
• fix(dropdown): close on route change
5. Open a PR to main.Commit hooks via Husky/commitlint can be enabled to enforce commit message format (the dev dependencies are present).
⸻
Project structure (typical)
/src /components /Button index.tsx styled.ts Button.stories.tsx Button.test.tsx index.ts # library public API
rollup.config.mjs tsconfig.json jest.config.(ts)
⸻
FAQ
Q: Can I tree-shake unused components? Yes—consume the ESM build (module field) and import components directly or from the root if it re-exports per-file.
Q: Do I need styled-components in my app? Only if you use theme-aware components. If a component relies on the theme, wrap your app with ThemeProvider.
Q: Where do I see components live? Run Storybook locally with npm run storybook.
⸻
Links • Repo: https://github.com/acast-tech/podchaser-ui-library • Issues: https://github.com/acast-tech/podchaser-ui-library/issues
⸻
License
MIT © Darryl Brown
