feat: Add more thinned variants to Separator

This commit is contained in:
deytenit committed 2026-03-06 21:19:41 +03:00
1 parent 8d57d6ba1b
commit 4e36e800d4
5 files changed
+61 -27

No files matched your search

@@ -11,7 +11,7 @@ import type { Meta, StoryObj } from '@storybook/react';
* - Single or double line variants inspired by newspaper layout traditions
* - Multiple color options (black, outline, outline-light) with theme support
* - Horizontal and vertical orientations
* - Optional thinned gradient fade effect at line ends (10% fade length)
* - Optional thinned gradient fade effect at line ends ('thinned', 'thinned-start', 'thinned-end', 'none')
* - 2px stroke width following print design standards
* - Semantic div elements with proper ARIA separator role for accessibility
*/
@@ -44,14 +44,15 @@ const meta: Meta<typeof Separator> = {
description: 'Orientation of the separator',
},
thinned: {
control: 'boolean',
description: 'Whether line ends should be thinned with gradient fade (10% fade length)',
control: 'select',
options: ['thinned', 'thinned-start', 'thinned-end', 'none'],
description: 'How line ends should be thinned with gradient fade',
},
},
args: {
type: 'single',
direction: 'horizontal',
thinned: true,
thinned: 'thinned',
},
};
@@ -191,7 +192,7 @@ export const VerticalDouble: Story = {
*/
export const NonThinned: Story = {
args: {
thinned: false,
thinned: 'none',
},
decorators: [
(Story) => (
@@ -251,19 +252,27 @@ export const AllTypes: Story = {
};
/**
* Comparison between thinned and non-thinned effects.
* Demonstrates the 10% gradient fade at line ends.
* Comparison between different thinning effects.
* Demonstrates the gradient fade at line ends.
*/
export const ThinnedComparison: Story = {
render: () => (
<div className="space-y-8 w-96">
<div>
<h3 className="text-sm font-medium mb-2">With Thinned Ends (Default)</h3>
<Separator thinned />
<h3 className="text-sm font-medium mb-2">Full Thinned (Default)</h3>
<Separator thinned="thinned" />
</div>
<div>
<h3 className="text-sm font-medium mb-2">Without Thinned Ends</h3>
<Separator thinned={false} />
<h3 className="text-sm font-medium mb-2">Thinned Start Only</h3>
<Separator thinned="thinned-start" />
</div>
<div>
<h3 className="text-sm font-medium mb-2">Thinned End Only</h3>
<Separator thinned="thinned-end" />
</div>
<div>
<h3 className="text-sm font-medium mb-2">No Fading (None)</h3>
<Separator thinned="none" />
</div>
</div>
),
@@ -5,6 +5,11 @@ import { VStack } from '../VStack/VStack';
import type { ClassNameProps, TestIdProps } from '@ermnvldmr/stl';
/**
* Options for thinning the separator line ends with a gradient fade.
*/
export type SeparatorThinnedType = 'thinned' | 'thinned-end' | 'thinned-start' | 'none';
/**
* Props for the Separator component.
*/
@@ -15,10 +20,32 @@ export interface SeparatorProps extends ClassNameProps, TestIdProps {
color?: 'black' | 'outline' | 'outline-light';
/** Orientation of the separator */
direction?: 'horizontal' | 'vertical';
/** Whether line ends should be thinned with gradient fade */
thinned?: boolean;
/**
* How line ends should be thinned with gradient fade.
* - 'thinned': Both ends fade out (default)
* - 'thinned-start': Only the start of the line fades out
* - 'thinned-end': Only the end of the line fades out
* - 'none': No fading, sharp edges
*/
thinned?: SeparatorThinnedType;
}
const THINNED_TYPE_CLASSES: Record<
'horizontal' | 'vertical',
Record<Exclude<SeparatorThinnedType, 'none'>, string>
> = {
horizontal: {
thinned: '[mask-image:linear-gradient(to_right,transparent,black_10%,black_90%,transparent)]',
'thinned-start': '[mask-image:linear-gradient(to_right,transparent,black_10%,black)]',
'thinned-end': '[mask-image:linear-gradient(to_right,black,black_90%,transparent)]',
},
vertical: {
thinned: '[mask-image:linear-gradient(to_bottom,transparent,black_10%,black_90%,transparent)]',
'thinned-start': '[mask-image:linear-gradient(to_bottom,transparent,black_10%,black)]',
'thinned-end': '[mask-image:linear-gradient(to_bottom,black,black_90%,transparent)]',
},
};
/**
* A separator component for dividing content sections.
*
@@ -26,7 +53,7 @@ export interface SeparatorProps extends ClassNameProps, TestIdProps {
* - Single or double line variants inspired by newspaper layout traditions
* - Multiple color options (black, outline, outline-light) with theme support
* - Horizontal and vertical orientations
* - Optional thinned gradient fade effect at line ends (10% fade length)
* - Optional thinned gradient fade effect at line ends ('thinned', 'thinned-start', 'thinned-end', 'none')
* - 2px stroke width following print design standards
* - Semantic HTML with proper ARIA attributes for accessibility
*
@@ -35,14 +62,17 @@ export interface SeparatorProps extends ClassNameProps, TestIdProps {
*
* @example
* ```tsx
* // Basic horizontal separator
* // Basic horizontal separator (defaults to thinned)
* <Separator />
*
* // Double-line separator with black color
* <Separator type="double" color="black" />
*
* // Vertical separator without thinned ends
* <Separator direction="vertical" thinned={false} />
* <Separator direction="vertical" thinned="none" />
*
* // Separator with only the end thinned
* <Separator thinned="thinned-end" />
*
* // Light separator for subtle content division
* <Separator color="outline-light" />
@@ -52,7 +82,7 @@ export const Separator = memo(function Separator({
type = 'single',
color,
direction = 'horizontal',
thinned = true,
thinned = 'thinned',
className,
'data-testid': testId,
}: SeparatorProps) {
@@ -77,13 +107,8 @@ export const Separator = memo(function Separator({
];
// Thinned effect using CSS mask
const thinnedClasses = thinned
? [
direction === 'horizontal'
? '[mask-image:linear-gradient(to_right,transparent,black_10%,black_90%,transparent)]'
: '[mask-image:linear-gradient(to_bottom,transparent,black_10%,black_90%,transparent)]',
]
: [];
const thinnedClasses =
thinned !== 'none' ? [THINNED_TYPE_CLASSES[direction][thinned]] : [];
// Size classes - fill container by default
const sizeClasses =
@@ -35,7 +35,7 @@ export function ThemeSwitch(): React.JSX.Element {
/>
<Moon className="w-4 h-4 text-[var(--rb-text)] opacity-60" />
</HStack>
<Separator direction="vertical" thinned={false} />
<Separator direction="vertical" thinned="none" />
<Button
aria-label="Follow system theme"
color={preference === 'system' ? 'primary' : 'neutral'}