Claude Code Plugins

Community-maintained marketplace

Feedback

squared-package

@lsst-sqre/squareone
2
0

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.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

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, and types all point to src/index.ts (not a dist/ 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?

  1. Flexibility: Consuming apps control transpilation (target browsers, polyfills, etc.)
  2. Type Safety: Source TypeScript available for better IDE integration
  3. Development Speed: No build step means instant updates during development
  4. 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: false enables 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-css in 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:

  1. Unit tests - Traditional vitest tests (.test.ts files)
  2. 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

  1. Create component directory in src/components/
  2. Add .tsx, .module.css, .stories.tsx, .test.tsx files
  3. Create index.ts with exports
  4. Export from src/index.ts
  5. Import design tokens in CSS
  6. Write Storybook stories
  7. Write tests

Migration from Styled-Components

If you encounter styled-components in squared, they need to be migrated to CSS Modules.

See the migrate-styled-components-to-css-modules skill for complete step-by-step migration guidance, including:

  • Component conversion patterns
  • Design token usage
  • Dynamic styles handling
  • Test updates
  • Before/after examples

Note: The squareone app still uses styled-components (legacy), but new squared components must use CSS Modules.

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:

  1. Import: import styles from './Component.module.css';
  2. Use: className={styles.className}
  3. Check CSS file has .className defined

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

  1. Always use CSS Modules for styling
  2. Always use design tokens (CSS variables) in styles
  3. Prefer type over interface for props
  4. Avoid React.FC - type props directly in function parameters
  5. Write Storybook stories for all components
  6. Write tests for components (unit or story tests)
  7. Use Radix UI for accessible primitives when possible
  8. Document components with JSDoc comments
  9. Export components and types from src/index.ts
  10. Keep components focused - one responsibility per component

Related Files

  • packages/squared/package.json - Package configuration
  • packages/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
  • migrate-styled-components-to-css-modules - Converting legacy styled-components
  • 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!