squared-package
Critical architecture knowledge for the squared component library package. Use this skill when working on squared package components, troubleshooting build/transpilation issues, or setting up apps to consume squared. Covers the NO BUILD STEP architecture, CSS Modules-only styling requirement, Next.js transpilation configuration, direct TypeScript source exports, and testing infrastructure.
When & Why to Use This Skill
This Claude skill provides comprehensive architectural guidance for the @lsst-sqre/squared React component library. It details the unique 'no build step' strategy where TypeScript source is exported directly, alongside strict CSS Modules styling requirements and essential Next.js transpilation configurations for seamless integration.
Use Cases
- Troubleshooting 'Unexpected token' build errors in Next.js by implementing the required transpilePackages configuration.
- Developing new UI components that adhere to the library's specific TypeScript patterns and CSS Modules styling standards.
- Configuring and executing the dual-track testing infrastructure using Vitest for unit tests and Storybook for interaction testing.
- Setting up consuming applications to correctly resolve direct TypeScript source exports and design tokens from the monorepo.
| name | squared-package |
|---|---|
| description | Critical architecture knowledge for the squared component library package. Use this skill when working on squared package components, troubleshooting build/transpilation issues, or setting up apps to consume squared. Covers the NO BUILD STEP architecture, CSS Modules-only styling requirement, Next.js transpilation configuration, direct TypeScript source exports, and testing infrastructure. |
Squared Package Architecture
The @lsst-sqre/squared package is a React component library with a unique architecture designed for flexibility and type safety.
Critical Architecture Rules
NO BUILD STEP
⚠️ The squared package does NOT have a build step - it exports TypeScript source files directly.
This means:
- package.json
main,module, andtypesall point tosrc/index.ts(not adist/directory) - Consuming apps must transpile the package themselves
- No
tsup,tsc, or other build tools in the squared package - Changes are immediately available without rebuilding the package
Why This Architecture?
- Flexibility: Consuming apps control transpilation (target browsers, polyfills, etc.)
- Type Safety: Source TypeScript available for better IDE integration
- Development Speed: No build step means instant updates during development
- Simplicity: Fewer build tools to configure and maintain
Package.json Configuration
See the actual package configuration at packages/squared/package.json.
Key fields:
{
"main": "./src/index.ts",
"module": "./src/index.ts",
"types": "./src/index.ts",
"exports": {
".": {
"types": "./src/index.ts",
"default": "./src/index.ts"
},
"./components/*": "./src/components/*"
},
"sideEffects": false
}
Important:
- All entry points are TypeScript source files
sideEffects: falseenables tree-shaking- Component-level exports for granular imports
Styling Requirements
CSS Modules Only
⚠️ Squared package MUST use CSS Modules - NO styled-components allowed.
Why:
- Avoids runtime CSS-in-JS overhead
- Better SSR performance
- Consistent with design token system
- Clear separation of styles and logic
Pattern:
MyComponent/
├── MyComponent.tsx
├── MyComponent.module.css
├── MyComponent.stories.tsx
├── MyComponent.test.tsx
└── index.ts
Using Design Tokens
Styles use design tokens from @lsst-sqre/rubin-style-dictionary and @lsst-sqre/global-css.
See the design-system skill for complete CSS variable reference.
/* MyComponent.module.css */
.container {
padding: var(--sqo-space-md);
background-color: var(--rsd-color-primary-600);
border-radius: var(--sqo-border-radius-1);
box-shadow: var(--sqo-elevation-md);
}
.title {
font-size: 1.125rem;
font-weight: 600;
color: var(--rsd-component-text-color);
}
Available via:
packages/rubin-style-dictionary/dist/tokens.css- Foundation tokens (prefix:--rsd-*)packages/global-css/src/tokens.css- Application tokens (prefix:--sqo-*)- Import
@lsst-sqre/global-cssin your app to load all tokens
Consuming Squared in Apps
Apps that use squared must configure transpilation.
Next.js Configuration
Required in next.config.js:
module.exports = {
transpilePackages: ['@lsst-sqre/squared'],
// ... other config
};
This tells Next.js to transpile the squared package's TypeScript source.
See consuming-app-setup.md for complete setup guide.
Without Transpilation Configuration
If you forget to add transpilePackages, you'll see errors like:
Module parse failed: Unexpected token
You may need an appropriate loader to handle this file type
Testing Infrastructure
Vitest with Two Projects
Squared uses vitest with two separate test projects:
- Unit tests - Traditional vitest tests (
.test.tsfiles) - Storybook tests - Tests in Storybook stories via addon-vitest
See the actual test configuration at packages/squared/vitest.config.ts.
Running Tests
# Unit tests only
pnpm test --filter @lsst-sqre/squared
# Storybook tests only
pnpm test-storybook --filter @lsst-sqre/squared
# Storybook tests in watch mode
pnpm test-storybook:watch --filter @lsst-sqre/squared
# All tests (run from root)
pnpm test
pnpm test-storybook
Test Setup
Unit tests:
- Setup file:
src/test-setup.ts - Environment: jsdom
- Globals: enabled
- CSS Modules: non-scoped classNameStrategy
Storybook tests:
- Browser: Playwright (chromium)
- Environment: browser + jsdom
- Setup file:
.storybook/vitest.setup.ts
Component Development
TypeScript Patterns
Prefer type over interface:
// ✅ Good
type MyComponentProps = {
title: string;
onClick?: () => void;
};
// ❌ Avoid (unless extending/merging needed)
interface MyComponentProps {
title: string;
onClick?: () => void;
}
Avoid React.FC - type props directly:
// ✅ Good
export default function MyComponent({ title, onClick }: MyComponentProps) {
return <div onClick={onClick}>{title}</div>;
}
// ❌ Avoid
const MyComponent: React.FC<MyComponentProps> = ({ title, onClick }) => {
return <div onClick={onClick}>{title}</div>;
};
Component Structure
// MyComponent/MyComponent.tsx
import styles from './MyComponent.module.css';
type MyComponentProps = {
title: string;
variant?: 'primary' | 'secondary';
};
/**
* Component description for documentation
*/
export default function MyComponent({
title,
variant = 'primary'
}: MyComponentProps) {
return (
<div className={styles.container} data-variant={variant}>
<h2 className={styles.title}>{title}</h2>
</div>
);
}
Export Pattern
// MyComponent/index.ts
export { default } from './MyComponent';
export type { MyComponentProps } from './MyComponent';
// src/index.ts
export { default as MyComponent } from './components/MyComponent';
export type { MyComponentProps } from './components/MyComponent';
Dependencies
Workspace Dependencies
Squared depends on other monorepo packages:
@lsst-sqre/global-css- Global styles and design token application@lsst-sqre/rubin-style-dictionary- Design tokens@lsst-sqre/eslint-config- Linting configuration@lsst-sqre/tsconfig- TypeScript configuration
These use workspace protocol: "@lsst-sqre/global-css": "workspace:*"
Key External Dependencies
- React 19 - Component framework (peer dependency)
- Radix UI - Unstyled UI primitives
- react-feather - Icon library
- Font Awesome - Additional icons
- date-fns - Date manipulation
- react-day-picker - Date picker component
Dev Dependencies
- Next.js - Required for type checking (peer dep)
- Vitest - Test runner
- Storybook 9 - Component documentation
- Testing Library - React testing utilities
- Playwright - Browser testing (for Storybook tests)
Storybook Integration
Running Storybook
# Start Storybook dev server
pnpm storybook --filter @lsst-sqre/squared
# Build static Storybook
pnpm build-storybook --filter @lsst-sqre/squared
Story Pattern
// MyComponent.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import MyComponent from './MyComponent';
const meta: Meta<typeof MyComponent> = {
title: 'Components/MyComponent',
component: MyComponent,
tags: ['autodocs'],
};
export default meta;
type Story = StoryObj<typeof MyComponent>;
export const Default: Story = {
args: {
title: 'Example Title',
variant: 'primary',
},
};
export const Secondary: Story = {
args: {
title: 'Example Title',
variant: 'secondary',
},
};
Testing Stories
With @storybook/addon-vitest, stories can include tests:
import { expect, within } from '@storybook/test';
export const WithTest: Story = {
args: {
title: 'Test Title',
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
await expect(canvas.getByText('Test Title')).toBeInTheDocument();
},
};
Run with: pnpm test-storybook --filter @lsst-sqre/squared
Creating New Components
Manual Creation
- Create component directory in
src/components/ - Add
.tsx,.module.css,.stories.tsx,.test.tsxfiles - Create
index.tswith exports - Export from
src/index.ts - Import design tokens in CSS
- Write Storybook stories
- Write tests
Troubleshooting
Build Errors: "Unexpected token"
Cause: App not configured to transpile squared package.
Solution: Add to next.config.js:
transpilePackages: ['@lsst-sqre/squared']
CSS Module Styles Not Applying
Cause: CSS Module not imported or class name mismatch.
Solution:
- Import:
import styles from './Component.module.css'; - Use:
className={styles.className} - Check CSS file has
.classNamedefined
Design Tokens Not Working
Cause: @lsst-sqre/global-css not imported in app.
Solution: Import in app's root layout/component:
import '@lsst-sqre/global-css';
TypeScript Errors in Consuming App
Cause: Type resolution issues with direct source imports.
Solution: Ensure consuming app's tsconfig.json includes squared source:
{
"include": ["src", "node_modules/@lsst-sqre/squared/src"]
}
Tests Failing
Unit tests:
# Run specific test
pnpm test --filter @lsst-sqre/squared -- MyComponent.test.tsx
# Run in watch mode
pnpm test --filter @lsst-sqre/squared -- --watch
Storybook tests:
# Run in watch mode for debugging
pnpm test-storybook:watch --filter @lsst-sqre/squared
# Run specific story test
pnpm test-storybook --filter @lsst-sqre/squared -- --grep "MyComponent"
Best Practices
- Always use CSS Modules for styling
- Always use design tokens (CSS variables) in styles
- Prefer
typeoverinterfacefor props - Avoid
React.FC- type props directly in function parameters - Write Storybook stories for all components
- Write tests for components (unit or story tests)
- Use Radix UI for accessible primitives when possible
- Document components with JSDoc comments
- Export components and types from
src/index.ts - Keep components focused - one responsibility per component
Related Files
packages/squared/package.json- Package configurationpackages/squared/vitest.config.ts- Test configuration- consuming-app-setup.md - App integration guide (in this skill)
Related Skills
- design-system - Complete CSS variable and design token reference
- component-creation - Creating new components with CSS Modules
- testing-infrastructure - Testing patterns and tools
Package Scripts
# Test commands
pnpm test # Unit tests
pnpm test-storybook # Storybook tests
pnpm test-storybook:watch # Watch mode
# Quality commands
pnpm lint # ESLint
pnpm type-check # TypeScript checking
# Storybook commands
pnpm storybook # Dev server
pnpm build-storybook # Build static site
# Utility commands
pnpm clean # Clean caches
Remember: Always run from repository root with --filter @lsst-sqre/squared for proper Turborepo caching!