refactor: Prefix Paper components
This commit is contained in:
11 files changed
+87
-70
No files matched your search
@@ -17,7 +17,7 @@
|
||||
],
|
||||
"scripts": {
|
||||
"dev": "vite build --watch",
|
||||
"build": "tsc && vite build",
|
||||
"build": "tsc --noEmit && vite build",
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch",
|
||||
"test:coverage": "jest --coverage",
|
||||
@@ -59,6 +59,7 @@
|
||||
"@testing-library/jest-dom": "^6.9.1",
|
||||
"@testing-library/react": "^16.3.1",
|
||||
"@testing-library/user-event": "^14.6.1",
|
||||
"@types/jest": "^30.0.0",
|
||||
"@types/react": "^19.1.2",
|
||||
"@types/react-dom": "^19.1.2",
|
||||
"concurrently": "^9.1.2",
|
||||
|
||||
+12
-12
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
|
||||
import { Button } from './Button';
|
||||
import { PaperButton } from './PaperButton';
|
||||
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
|
||||
@@ -15,9 +15,9 @@ import type { Meta, StoryObj } from '@storybook/react';
|
||||
* - Accessible interaction patterns via react-aria
|
||||
* - Responsive hover and focus states
|
||||
*/
|
||||
const meta: Meta<typeof Button> = {
|
||||
title: 'components/paper-kit/Button',
|
||||
component: Button,
|
||||
const meta: Meta<typeof PaperButton> = {
|
||||
title: 'components/paper/PaperButton',
|
||||
component: PaperButton,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
docs: {
|
||||
@@ -111,18 +111,18 @@ export const LongText: Story = {
|
||||
export const AllVariants: Story = {
|
||||
render: () => (
|
||||
<div className="flex flex-col gap-4 items-start">
|
||||
<Button variant="default" onPress={() => console.log('Default')}>
|
||||
<PaperButton variant="default" onPress={() => console.log('Default')}>
|
||||
Default Style
|
||||
</Button>
|
||||
<Button variant="primary" onPress={() => console.log('Primary')}>
|
||||
</PaperButton>
|
||||
<PaperButton variant="primary" onPress={() => console.log('Primary')}>
|
||||
Primary Style
|
||||
</Button>
|
||||
<Button variant="secondary" onPress={() => console.log('Secondary')}>
|
||||
</PaperButton>
|
||||
<PaperButton variant="secondary" onPress={() => console.log('Secondary')}>
|
||||
Secondary Style
|
||||
</Button>
|
||||
<Button isDisabled>
|
||||
</PaperButton>
|
||||
<PaperButton isDisabled>
|
||||
Disabled State
|
||||
</Button>
|
||||
</PaperButton>
|
||||
</div>
|
||||
),
|
||||
};
|
||||
+22
-22
@@ -1,27 +1,27 @@
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
|
||||
import { Button } from './Button';
|
||||
import { PaperButton } from './PaperButton';
|
||||
import { render, screen } from '../../../test-utils';
|
||||
|
||||
/**
|
||||
* Test suite for the newspaper-style Button component
|
||||
* Test suite for the newspaper-style PaperButton component
|
||||
*/
|
||||
describe('components/paper-kit/Button/Button', () => {
|
||||
describe('components/paper/PaperButton/PaperButton', () => {
|
||||
const defaultProps = {
|
||||
children: 'Test Button',
|
||||
children: 'Test PaperButton',
|
||||
};
|
||||
|
||||
it('renders correctly with default props', () => {
|
||||
render(<Button {...defaultProps} />);
|
||||
render(<PaperButton {...defaultProps} />);
|
||||
|
||||
const button = screen.getByRole('button', { name: 'Test Button' });
|
||||
const button = screen.getByRole('button', { name: 'Test PaperButton' });
|
||||
expect(button).toBeInTheDocument();
|
||||
expect(button).toHaveTextContent('Test Button');
|
||||
expect(button).toHaveTextContent('Test PaperButton');
|
||||
});
|
||||
|
||||
it('applies correct styling classes', () => {
|
||||
render(<Button {...defaultProps} />);
|
||||
render(<PaperButton {...defaultProps} />);
|
||||
|
||||
const button = screen.getByRole('button');
|
||||
|
||||
@@ -37,7 +37,7 @@ describe('components/paper-kit/Button/Button', () => {
|
||||
const user = userEvent.setup();
|
||||
const handlePress = jest.fn();
|
||||
|
||||
render(<Button onPress={handlePress}>{defaultProps.children}</Button>);
|
||||
render(<PaperButton onPress={handlePress}>{defaultProps.children}</PaperButton>);
|
||||
|
||||
const button = screen.getByRole('button');
|
||||
await user.click(button);
|
||||
@@ -47,19 +47,19 @@ describe('components/paper-kit/Button/Button', () => {
|
||||
|
||||
it('supports different variants', () => {
|
||||
const { rerender } = render(
|
||||
<Button variant="primary">{defaultProps.children}</Button>
|
||||
<PaperButton variant="primary">{defaultProps.children}</PaperButton>
|
||||
);
|
||||
|
||||
let button = screen.getByRole('button');
|
||||
expect(button).toHaveClass('bg-primary');
|
||||
|
||||
rerender(<Button variant="secondary">{defaultProps.children}</Button>);
|
||||
rerender(<PaperButton variant="secondary">{defaultProps.children}</PaperButton>);
|
||||
button = screen.getByRole('button');
|
||||
expect(button).toHaveClass('bg-secondary');
|
||||
});
|
||||
|
||||
it('handles disabled state correctly', () => {
|
||||
render(<Button isDisabled>{defaultProps.children}</Button>);
|
||||
render(<PaperButton isDisabled>{defaultProps.children}</PaperButton>);
|
||||
|
||||
const button = screen.getByRole('button');
|
||||
expect(button).toBeDisabled();
|
||||
@@ -72,9 +72,9 @@ describe('components/paper-kit/Button/Button', () => {
|
||||
const handlePress = jest.fn();
|
||||
|
||||
render(
|
||||
<Button isDisabled onPress={handlePress}>
|
||||
<PaperButton isDisabled onPress={handlePress}>
|
||||
{defaultProps.children}
|
||||
</Button>
|
||||
</PaperButton>
|
||||
);
|
||||
|
||||
const button = screen.getByRole('button');
|
||||
@@ -86,7 +86,7 @@ describe('components/paper-kit/Button/Button', () => {
|
||||
it('supports custom className prop', () => {
|
||||
const customClass = 'custom-button-class';
|
||||
|
||||
render(<Button className={customClass}>{defaultProps.children}</Button>);
|
||||
render(<PaperButton className={customClass}>{defaultProps.children}</PaperButton>);
|
||||
|
||||
const button = screen.getByRole('button');
|
||||
expect(button).toHaveClass(customClass);
|
||||
@@ -95,27 +95,27 @@ describe('components/paper-kit/Button/Button', () => {
|
||||
it('supports data-testid prop', () => {
|
||||
const testId = 'my-test-button';
|
||||
|
||||
render(<Button data-testid={testId}>{defaultProps.children}</Button>);
|
||||
render(<PaperButton data-testid={testId}>{defaultProps.children}</PaperButton>);
|
||||
|
||||
const button = screen.getByTestId(testId);
|
||||
expect(button).toBeInTheDocument();
|
||||
expect(button).toHaveTextContent('Test Button');
|
||||
expect(button).toHaveTextContent('Test PaperButton');
|
||||
});
|
||||
|
||||
it('only accepts string children', () => {
|
||||
// This test verifies TypeScript constraint - should compile without error
|
||||
render(<Button>Simple string</Button>);
|
||||
render(<PaperButton>Simple string</PaperButton>);
|
||||
expect(screen.getByText('Simple string')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('maintains accessibility attributes', () => {
|
||||
render(
|
||||
<Button
|
||||
<PaperButton
|
||||
aria-describedby="button-description"
|
||||
aria-label="Custom accessibility label"
|
||||
>
|
||||
{defaultProps.children}
|
||||
</Button>
|
||||
</PaperButton>
|
||||
);
|
||||
|
||||
const button = screen.getByRole('button');
|
||||
@@ -127,7 +127,7 @@ describe('components/paper-kit/Button/Button', () => {
|
||||
const user = userEvent.setup();
|
||||
const handlePress = jest.fn();
|
||||
|
||||
render(<Button onPress={handlePress}>{defaultProps.children}</Button>);
|
||||
render(<PaperButton onPress={handlePress}>{defaultProps.children}</PaperButton>);
|
||||
|
||||
const button = screen.getByRole('button');
|
||||
button.focus();
|
||||
@@ -142,7 +142,7 @@ describe('components/paper-kit/Button/Button', () => {
|
||||
});
|
||||
|
||||
it('renders string content correctly', () => {
|
||||
render(<Button>Simple text content</Button>);
|
||||
render(<PaperButton>Simple text content</PaperButton>);
|
||||
expect(screen.getByText('Simple text content')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
+6
-6
@@ -5,9 +5,9 @@ import type { ClassNameProps, TestIdProps } from '@ermnvldmr/stl';
|
||||
import type { AriaButtonProps } from 'react-aria';
|
||||
|
||||
/**
|
||||
* Props for the newspaper-style Button component.
|
||||
* Props for the newspaper-style PaperButton component.
|
||||
*/
|
||||
export interface ButtonProps extends AriaButtonProps, ClassNameProps, TestIdProps {
|
||||
export interface PaperButtonProps extends AriaButtonProps, ClassNameProps, TestIdProps {
|
||||
/** The button text content */
|
||||
children: string;
|
||||
/** Visual style variant */
|
||||
@@ -26,18 +26,18 @@ export interface ButtonProps extends AriaButtonProps, ClassNameProps, TestIdProp
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* <Button onPress={() => console.log('Clicked!')}>
|
||||
* <PaperButton onPress={() => console.log('Clicked!')}>
|
||||
* Explore all the articles
|
||||
* </Button>
|
||||
* </PaperButton>
|
||||
* ```
|
||||
*/
|
||||
export const Button = memo(function Button({
|
||||
export const PaperButton = memo(function PaperButton({
|
||||
children,
|
||||
variant = 'default',
|
||||
className = '',
|
||||
'data-testid': testId,
|
||||
...buttonProps
|
||||
}: ButtonProps) {
|
||||
}: PaperButtonProps) {
|
||||
const ref = React.useRef<HTMLButtonElement>(null);
|
||||
const { buttonProps: ariaButtonProps } = useButton(buttonProps, ref);
|
||||
|
||||
+16
-16
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
|
||||
import { Separator } from './Separator';
|
||||
import { PaperSeparator } from './PaperSeparator';
|
||||
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
|
||||
@@ -15,9 +15,9 @@ import type { Meta, StoryObj } from '@storybook/react';
|
||||
* - 2px stroke width following print design standards
|
||||
* - Semantic div elements with proper ARIA separator role for accessibility
|
||||
*/
|
||||
const meta: Meta<typeof Separator> = {
|
||||
title: 'components/paper-kit/Separator',
|
||||
component: Separator,
|
||||
const meta: Meta<typeof PaperSeparator> = {
|
||||
title: 'components/paper/PaperSeparator',
|
||||
component: PaperSeparator,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
docs: {
|
||||
@@ -56,7 +56,7 @@ const meta: Meta<typeof Separator> = {
|
||||
|
||||
export default meta;
|
||||
/**
|
||||
* Story type for Separator component stories.
|
||||
* Story type for PaperSeparator component stories.
|
||||
*/
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
@@ -201,7 +201,7 @@ export const VerticalDouble: Story = {
|
||||
};
|
||||
|
||||
/**
|
||||
* Separator without thinned ends showing clean, sharp line edges.
|
||||
* PaperSeparator without thinned ends showing clean, sharp line edges.
|
||||
* Compare with default to see the gradient fade difference.
|
||||
*/
|
||||
export const NonThinned: Story = {
|
||||
@@ -232,15 +232,15 @@ export const AllColors: Story = {
|
||||
<div className="space-y-8 w-96">
|
||||
<div>
|
||||
<h3 className="text-sm font-medium mb-2">Black</h3>
|
||||
<Separator color="black" />
|
||||
<PaperSeparator color="black" />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-sm font-medium mb-2">Outline (Default for Double)</h3>
|
||||
<Separator color="outline" />
|
||||
<PaperSeparator color="outline" />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-sm font-medium mb-2">Outline Light (Default for Single)</h3>
|
||||
<Separator color="outline-light" />
|
||||
<PaperSeparator color="outline-light" />
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
@@ -255,11 +255,11 @@ export const AllTypes: Story = {
|
||||
<div className="space-y-8 w-96">
|
||||
<div>
|
||||
<h3 className="text-sm font-medium mb-2">Single (Default: Outline Light)</h3>
|
||||
<Separator type="single" />
|
||||
<PaperSeparator type="single" />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-sm font-medium mb-2">Double (Default: Outline)</h3>
|
||||
<Separator type="double" />
|
||||
<PaperSeparator type="double" />
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
@@ -274,11 +274,11 @@ export const ThinnedComparison: Story = {
|
||||
<div className="space-y-8 w-96">
|
||||
<div>
|
||||
<h3 className="text-sm font-medium mb-2">With Thinned Ends (Default)</h3>
|
||||
<Separator thinned />
|
||||
<PaperSeparator thinned />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-sm font-medium mb-2">Without Thinned Ends</h3>
|
||||
<Separator thinned={false} />
|
||||
<PaperSeparator thinned={false} />
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
@@ -296,7 +296,7 @@ export const VerticalShowcase: Story = {
|
||||
Short
|
||||
</div>
|
||||
<div className="px-2">
|
||||
<Separator direction="vertical" />
|
||||
<PaperSeparator direction="vertical" />
|
||||
</div>
|
||||
<div className="flex items-center justify-center w-20 text-xs text-muted-foreground">
|
||||
Content
|
||||
@@ -308,7 +308,7 @@ export const VerticalShowcase: Story = {
|
||||
Medium
|
||||
</div>
|
||||
<div className="px-2">
|
||||
<Separator direction="vertical" type="double" />
|
||||
<PaperSeparator direction="vertical" type="double" />
|
||||
</div>
|
||||
<div className="flex items-center justify-center w-20 text-xs text-muted-foreground">
|
||||
Content
|
||||
@@ -320,7 +320,7 @@ export const VerticalShowcase: Story = {
|
||||
Tall
|
||||
</div>
|
||||
<div className="px-2">
|
||||
<Separator color="black" direction="vertical" />
|
||||
<PaperSeparator color="black" direction="vertical" />
|
||||
</div>
|
||||
<div className="flex items-center justify-center w-20 text-xs text-muted-foreground">
|
||||
Content
|
||||
+8
-8
@@ -7,9 +7,9 @@ import type { ClassNameProps, TestIdProps } from '@ermnvldmr/stl';
|
||||
|
||||
|
||||
/**
|
||||
* Props for the newspaper-style Separator component.
|
||||
* Props for the newspaper-style PaperSeparator component.
|
||||
*/
|
||||
export interface SeparatorProps extends ClassNameProps, TestIdProps {
|
||||
export interface PaperSeparatorProps extends ClassNameProps, TestIdProps {
|
||||
/** Type of separator line styling */
|
||||
type?: 'single' | 'double';
|
||||
/** Color variant following newspaper design patterns */
|
||||
@@ -37,26 +37,26 @@ export interface SeparatorProps extends ClassNameProps, TestIdProps {
|
||||
* @example
|
||||
* ```tsx
|
||||
* // Basic horizontal separator
|
||||
* <Separator />
|
||||
* <PaperSeparator />
|
||||
*
|
||||
* // Double-line separator with black color
|
||||
* <Separator type="double" color="black" />
|
||||
* <PaperSeparator type="double" color="black" />
|
||||
*
|
||||
* // Vertical separator without thinned ends
|
||||
* <Separator direction="vertical" thinned={false} />
|
||||
* <PaperSeparator direction="vertical" thinned={false} />
|
||||
*
|
||||
* // Light separator for subtle content division
|
||||
* <Separator color="outline-light" />
|
||||
* <PaperSeparator color="outline-light" />
|
||||
* ```
|
||||
*/
|
||||
export const Separator = memo(function Separator({
|
||||
export const PaperSeparator = memo(function PaperSeparator({
|
||||
type = 'single',
|
||||
color,
|
||||
direction = 'horizontal',
|
||||
thinned = true,
|
||||
className,
|
||||
'data-testid': testId,
|
||||
}: SeparatorProps) {
|
||||
}: PaperSeparatorProps) {
|
||||
// Default color based on type as specified
|
||||
const defaultColor = type === 'single' ? 'outline-light' : 'outline';
|
||||
const finalColor = color ?? defaultColor;
|
||||
@@ -1,2 +1,3 @@
|
||||
export { Button } from './PaperButton/Button'
|
||||
export { Separator } from './PaperSeparator/Separator'
|
||||
export { PaperButton } from './PaperButton/PaperButton';
|
||||
|
||||
export { PaperSeparator } from './PaperSeparator/PaperSeparator'
|
||||
@@ -6,5 +6,5 @@
|
||||
"declarationMap": true
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["dist", "**/*.test.ts", "**/*.test.tsx", "**/*.stories.tsx"]
|
||||
"exclude": ["dist"]
|
||||
}
|
||||
@@ -1,3 +1,7 @@
|
||||
import { createLibConfig } from '@ermnvldmr/vite-config/lib';
|
||||
|
||||
export default createLibConfig('ErmnvldmrUI', 'src/index.ts', ['@ermnvldmr/stl']);
|
||||
export default createLibConfig('ErmnvldmrUI', 'src/index.ts', ['@ermnvldmr/stl'], {
|
||||
dts: {
|
||||
exclude: ['**/*.test.ts', '**/*.test.tsx', '**/*.stories.tsx', 'src/setupTests.ts', 'src/test-utils.tsx'],
|
||||
},
|
||||
});
|
||||
@@ -2,6 +2,11 @@ import { defineConfig } from 'vite';
|
||||
import { resolve } from 'path';
|
||||
import dts from 'vite-plugin-dts';
|
||||
import type { UserConfig } from 'vite';
|
||||
import type { PluginOptions as DtsPluginOptions } from 'vite-plugin-dts';
|
||||
|
||||
export interface LibConfigOptions {
|
||||
dts?: DtsPluginOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base Vite configuration for library packages.
|
||||
@@ -9,6 +14,7 @@ import type { UserConfig } from 'vite';
|
||||
* @param packageName - The name for the library build
|
||||
* @param entry - Entry point file path (relative to package root)
|
||||
* @param external - Array of external dependencies to exclude from bundle
|
||||
* @param options - Additional configuration options
|
||||
* @returns Vite configuration object
|
||||
*
|
||||
* @example
|
||||
@@ -21,12 +27,14 @@ import type { UserConfig } from 'vite';
|
||||
export function createLibConfig(
|
||||
packageName: string,
|
||||
entry: string = 'src/index.ts',
|
||||
external: string[] = []
|
||||
external: string[] = [],
|
||||
options: LibConfigOptions = {}
|
||||
): UserConfig {
|
||||
return defineConfig({
|
||||
plugins: [
|
||||
dts({
|
||||
insertTypesEntry: true,
|
||||
...options.dts,
|
||||
}),
|
||||
],
|
||||
build: {
|
||||
|
||||
Reference in new issue
Block a user