visuals, fixes & storybook upd
This commit is contained in:
@@ -26,6 +26,7 @@ const meta = {
|
||||
iconOnly: { control: 'boolean', description: 'Square padding for a single glyph.' },
|
||||
disabled: { control: 'boolean' },
|
||||
children: { control: 'text' },
|
||||
className: { control: 'text' },
|
||||
},
|
||||
args: { children: 'Button', variant: 'key' },
|
||||
} satisfies Meta<typeof Button>;
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
Th,
|
||||
Td,
|
||||
Badge,
|
||||
Chip,
|
||||
} from '../components/ui';
|
||||
|
||||
const meta = {
|
||||
@@ -18,18 +19,23 @@ const meta = {
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
component: 'Cards, selectable lists/rows, and the bordered table.',
|
||||
component: 'Cards, selectable lists/rows, badges, chips, and the bordered table.',
|
||||
},
|
||||
},
|
||||
},
|
||||
argTypes: {
|
||||
className: { control: 'text' },
|
||||
},
|
||||
} satisfies Meta<typeof Card>;
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const CardSurface: Story = {
|
||||
render: () => (
|
||||
<Card style={{ maxWidth: 320, padding: 20 }}>
|
||||
export const CardPlayground: Story = {
|
||||
name: 'Card',
|
||||
args: { children: 'Card content' },
|
||||
render: (args) => (
|
||||
<Card {...args} style={{ maxWidth: 320, padding: 20 }}>
|
||||
<h3 className="modern-sk-h3">Storage</h3>
|
||||
<p className="modern-sk-body">128 GB of 256 GB used.</p>
|
||||
</Card>
|
||||
@@ -47,6 +53,27 @@ export const ListRows: Story = {
|
||||
),
|
||||
};
|
||||
|
||||
export const BadgeShowcase: Story = {
|
||||
render: () => (
|
||||
<div style={{ display: 'flex', gap: 10, alignItems: 'center', flexWrap: 'wrap' }}>
|
||||
<Badge variant="lime">Lime</Badge>
|
||||
<Badge variant="ember">Ember</Badge>
|
||||
<Badge variant="neutral">Neutral</Badge>
|
||||
<Badge variant="outline">Outline</Badge>
|
||||
<Badge variant="lime" dot>Online</Badge>
|
||||
</div>
|
||||
),
|
||||
};
|
||||
|
||||
export const Chips: Story = {
|
||||
render: () => (
|
||||
<div style={{ display: 'flex', gap: 10, flexWrap: 'wrap' }}>
|
||||
<Chip>Design</Chip>
|
||||
<Chip onRemove={() => {}}>Removable</Chip>
|
||||
</div>
|
||||
),
|
||||
};
|
||||
|
||||
export const DataTable: Story = {
|
||||
render: () => (
|
||||
<Table>
|
||||
|
||||
@@ -14,11 +14,24 @@ const meta = {
|
||||
},
|
||||
},
|
||||
},
|
||||
argTypes: {
|
||||
value: { control: { type: 'range', min: 0, max: 100, step: 1 } },
|
||||
className: { control: 'text' },
|
||||
},
|
||||
args: { value: 40 },
|
||||
} satisfies Meta<typeof Progress>;
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Playground: Story = {
|
||||
render: (args) => (
|
||||
<div style={{ width: 320 }}>
|
||||
<Progress {...args} />
|
||||
</div>
|
||||
),
|
||||
};
|
||||
|
||||
function ProgressDemo() {
|
||||
const [v, setV] = useState(40);
|
||||
return (
|
||||
|
||||
@@ -14,8 +14,17 @@ const meta = {
|
||||
},
|
||||
},
|
||||
argTypes: {
|
||||
variant: { control: 'inline-radio', options: ['key', 'primary', 'ember', 'ghost'] },
|
||||
size: { control: 'inline-radio', options: ['sm', undefined, 'lg'] },
|
||||
variant: {
|
||||
control: 'inline-radio',
|
||||
options: ['key', 'primary', 'ember', 'ghost'],
|
||||
description: 'Visual emphasis. `key` is the default neutral button.',
|
||||
},
|
||||
size: {
|
||||
control: 'inline-radio',
|
||||
options: ['sm', undefined, 'lg'],
|
||||
description: 'Button size: `sm` compact, default regular, `lg` large.',
|
||||
},
|
||||
disabled: { control: 'boolean' },
|
||||
},
|
||||
} satisfies Meta<typeof IconButton>;
|
||||
|
||||
|
||||
@@ -25,17 +25,32 @@ const meta = {
|
||||
},
|
||||
argTypes: {
|
||||
children: { control: false },
|
||||
content: { control: false },
|
||||
content: { control: 'text' },
|
||||
delayDuration: { control: 'number' },
|
||||
open: { control: 'boolean' },
|
||||
defaultOpen: { control: 'boolean' },
|
||||
onOpenChange: { action: 'open changed' },
|
||||
sideOffset: { control: 'number' },
|
||||
},
|
||||
args: {
|
||||
content: '',
|
||||
content: 'Tooltip text',
|
||||
children: null,
|
||||
delayDuration: 0,
|
||||
},
|
||||
} satisfies Meta<typeof Tooltip>;
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Playground: Story = {
|
||||
name: 'Tooltip Playground',
|
||||
render: (args) => (
|
||||
<Tooltip {...args}>
|
||||
<Button variant="ghost">Hover me</Button>
|
||||
</Tooltip>
|
||||
),
|
||||
};
|
||||
|
||||
export const TooltipStory: Story = {
|
||||
name: 'Tooltip',
|
||||
render: () => (
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
import type { Meta, StoryObj } from 'storybook-react-rsbuild';
|
||||
import { ScrollArea } from '../components/ui';
|
||||
|
||||
const meta = {
|
||||
title: 'Layout/ScrollArea',
|
||||
component: ScrollArea,
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
component:
|
||||
'Radix ScrollArea with custom styled scrollbars. Wraps content in a viewport with vertical and horizontal scrollbars.',
|
||||
},
|
||||
},
|
||||
},
|
||||
argTypes: {
|
||||
children: { control: false },
|
||||
className: { control: 'text' },
|
||||
},
|
||||
} satisfies Meta<typeof ScrollArea>;
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Playground: Story = {
|
||||
render: () => (
|
||||
<ScrollArea style={{ width: 300, height: 200, border: '1px solid var(--neutral-border)' }}>
|
||||
<div style={{ padding: 16 }}>
|
||||
<h4 className="modern-sk-h4" style={{ marginBottom: 8 }}>Scrollable content</h4>
|
||||
{Array.from({ length: 20 }).map((_, i) => (
|
||||
<p key={i} className="modern-sk-body" style={{ marginBottom: 12 }}>
|
||||
Item {i + 1}: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
</ScrollArea>
|
||||
),
|
||||
};
|
||||
|
||||
export const Vertical: Story = {
|
||||
render: () => (
|
||||
<ScrollArea style={{ width: 280, height: 150, border: '1px solid var(--neutral-border)' }}>
|
||||
<div style={{ padding: 12 }}>
|
||||
{Array.from({ length: 30 }).map((_, i) => (
|
||||
<div key={i} style={{ padding: 8, borderBottom: '1px solid var(--neutral-border)' }}>
|
||||
Row {i + 1}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</ScrollArea>
|
||||
),
|
||||
};
|
||||
|
||||
export const Horizontal: Story = {
|
||||
render: () => (
|
||||
<ScrollArea style={{ width: 320, height: 80, border: '1px solid var(--neutral-border)' }}>
|
||||
<div style={{ display: 'flex', gap: 8, padding: 12, width: 'fit-content' }}>
|
||||
{Array.from({ length: 20 }).map((_, i) => (
|
||||
<div
|
||||
key={i}
|
||||
style={{
|
||||
padding: 8,
|
||||
minWidth: 100,
|
||||
background: 'var(--neutral-surface)',
|
||||
borderRadius: 4,
|
||||
}}
|
||||
>
|
||||
Item {i + 1}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</ScrollArea>
|
||||
),
|
||||
};
|
||||
@@ -0,0 +1,68 @@
|
||||
import { useState } from 'react';
|
||||
import type { Meta, StoryObj } from 'storybook-react-rsbuild';
|
||||
import { SegmentedControl } from '../components/ui';
|
||||
|
||||
const meta = {
|
||||
title: 'Selection/SegmentedControl',
|
||||
component: SegmentedControl,
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
component:
|
||||
'Single-select button group with animated thumb. Pass `items` array of `{ value, label }` objects, plus `value` and `onValueChange` for control.',
|
||||
},
|
||||
},
|
||||
},
|
||||
argTypes: {
|
||||
value: { control: 'text' },
|
||||
onValueChange: { action: 'value changed' },
|
||||
items: { control: false },
|
||||
className: { control: 'text' },
|
||||
disabled: { control: 'boolean' },
|
||||
},
|
||||
} satisfies Meta<typeof SegmentedControl>;
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
function SegmentedDemo() {
|
||||
const [v, setV] = useState('day');
|
||||
return (
|
||||
<SegmentedControl
|
||||
value={v}
|
||||
onValueChange={setV}
|
||||
items={[
|
||||
{ value: 'day', label: 'Day' },
|
||||
{ value: 'week', label: 'Week' },
|
||||
{ value: 'month', label: 'Month' },
|
||||
]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export const Playground: Story = {
|
||||
render: () => <SegmentedDemo />,
|
||||
};
|
||||
|
||||
export const TimeRange: Story = {
|
||||
render: () => <SegmentedDemo />,
|
||||
};
|
||||
|
||||
function OptionsDemo() {
|
||||
const [v, setV] = useState('draft');
|
||||
return (
|
||||
<SegmentedControl
|
||||
value={v}
|
||||
onValueChange={setV}
|
||||
items={[
|
||||
{ value: 'draft', label: 'Draft' },
|
||||
{ value: 'published', label: 'Published' },
|
||||
{ value: 'archived', label: 'Archived' },
|
||||
]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export const Options: Story = {
|
||||
render: () => <OptionsDemo />,
|
||||
};
|
||||
@@ -19,6 +19,15 @@ const meta = {
|
||||
},
|
||||
},
|
||||
},
|
||||
argTypes: {
|
||||
items: { control: false },
|
||||
placeholder: { control: 'text' },
|
||||
disabled: { control: 'boolean' },
|
||||
defaultValue: { control: 'text' },
|
||||
value: { control: 'text' },
|
||||
onValueChange: { action: 'value changed' },
|
||||
'aria-label': { control: 'text' },
|
||||
},
|
||||
args: { items, placeholder: 'Pick a release…', 'aria-label': 'macOS release' },
|
||||
} satisfies Meta<typeof Select>;
|
||||
|
||||
|
||||
@@ -22,11 +22,21 @@ const meta = {
|
||||
},
|
||||
},
|
||||
},
|
||||
argTypes: {
|
||||
defaultChecked: { control: 'boolean' },
|
||||
checked: { control: 'boolean' },
|
||||
disabled: { control: 'boolean' },
|
||||
onCheckedChange: { action: 'checked changed' },
|
||||
},
|
||||
} satisfies Meta<typeof Switch>;
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Playground: Story = {
|
||||
args: { defaultChecked: false },
|
||||
};
|
||||
|
||||
export const Switches: Story = {
|
||||
render: () => (
|
||||
<div style={{ display: 'flex', gap: 20, alignItems: 'center' }}>
|
||||
|
||||
@@ -8,16 +8,67 @@ const meta = {
|
||||
docs: {
|
||||
description: {
|
||||
component:
|
||||
'Radix Slider in the carved-track skin. All Radix Slider props pass through (`defaultValue`, `min`, `max`, `step`, `onValueChange`).',
|
||||
'Radix Slider in the carved-track skin. All Radix Slider props pass through (`defaultValue`, `min`, `max`, `step`, `onValueChange`). Set `marks` to carve step notches into the track — `marks` snaps to the Radix `step`.',
|
||||
},
|
||||
},
|
||||
},
|
||||
args: { defaultValue: [60], min: 0, max: 100, step: 1 },
|
||||
argTypes: {
|
||||
defaultValue: { control: 'object', description: 'Uncontrolled starting value(s).' },
|
||||
min: { control: 'number' },
|
||||
max: { control: 'number' },
|
||||
step: { control: 'number', description: 'Snap increment (also drives auto `marks`).' },
|
||||
disabled: { control: 'boolean' },
|
||||
marks: {
|
||||
control: 'boolean',
|
||||
description: 'Step marks. `true` derives one per `step`; or pass an array for custom/labelled marks.',
|
||||
},
|
||||
notches: {
|
||||
control: 'inline-radio',
|
||||
options: ['top', 'bottom', 'both', 'none'],
|
||||
description: 'Notch tick placement relative to the track (labels still render when `none`).',
|
||||
},
|
||||
knobStyle: {
|
||||
control: 'inline-radio',
|
||||
options: ['square', 'round'],
|
||||
description: 'Knob shape: `square` (default) or `round`.',
|
||||
},
|
||||
className: { control: 'text' },
|
||||
},
|
||||
decorators: [(Story) => <div style={{ width: 280 }}><Story /></div>],
|
||||
} satisfies Meta<typeof Slider>;
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Playground: Story = { args: { defaultValue: [60], max: 100, step: 1 } };
|
||||
export const Playground: Story = {};
|
||||
|
||||
export const Stepped: Story = { args: { defaultValue: [40], max: 100, step: 10 } };
|
||||
/** `marks` auto-derives one notch per `step`. */
|
||||
export const Stepped: Story = {
|
||||
args: { defaultValue: [40], step: 10, marks: true },
|
||||
};
|
||||
|
||||
/** `notches='both'` carves ticks above and below the bar. */
|
||||
export const NotchesBoth: Story = {
|
||||
args: { defaultValue: [60], step: 20, marks: true, notches: 'both' },
|
||||
};
|
||||
|
||||
/** Pass an array of `{ value, label }` for labelled ticks. */
|
||||
export const LabelledMarks: Story = {
|
||||
args: {
|
||||
defaultValue: [50],
|
||||
step: 25,
|
||||
notches: 'bottom',
|
||||
marks: [
|
||||
{ value: 0, label: 'Off' },
|
||||
{ value: 25, label: 'Low' },
|
||||
{ value: 50, label: 'Mid' },
|
||||
{ value: 75, label: 'High' },
|
||||
{ value: 100, label: 'Max' },
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export const Disabled: Story = {
|
||||
args: { defaultValue: [30], step: 10, marks: true, disabled: true },
|
||||
};
|
||||
|
||||
@@ -12,6 +12,12 @@ const meta = {
|
||||
},
|
||||
},
|
||||
},
|
||||
argTypes: {
|
||||
defaultValue: { control: 'text' },
|
||||
value: { control: 'text' },
|
||||
onValueChange: { action: 'value changed' },
|
||||
disabled: { control: 'boolean' },
|
||||
},
|
||||
} satisfies Meta<typeof Tabs>;
|
||||
|
||||
export default meta;
|
||||
|
||||
@@ -13,6 +13,16 @@ const meta = {
|
||||
},
|
||||
},
|
||||
},
|
||||
argTypes: {
|
||||
placeholder: { control: 'text' },
|
||||
value: { control: 'text' },
|
||||
defaultValue: { control: 'text' },
|
||||
disabled: { control: 'boolean' },
|
||||
readOnly: { control: 'boolean' },
|
||||
required: { control: 'boolean' },
|
||||
type: { control: 'text' },
|
||||
onChange: { action: 'changed' },
|
||||
},
|
||||
args: { placeholder: 'Type here…' },
|
||||
} satisfies Meta<typeof TextField>;
|
||||
|
||||
|
||||
@@ -12,6 +12,11 @@ const meta = {
|
||||
},
|
||||
},
|
||||
},
|
||||
argTypes: {
|
||||
title: { control: 'text' },
|
||||
badge: { control: false },
|
||||
children: { control: false },
|
||||
},
|
||||
args: { title: 'Finder' },
|
||||
} satisfies Meta<typeof Window>;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user