Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added new Pagination component #12

Merged
merged 3 commits into from
Apr 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/eleven-walls-try.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@utima/ui": patch
---

Fixed button and patch invalid border styles on non-outline variatns
5 changes: 5 additions & 0 deletions .changeset/smooth-flies-thank.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@utima/ui": minor
---

Added new `Pagination` component
13 changes: 13 additions & 0 deletions packages/ui/src/components/badge/Badge.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,16 @@ export const TextWrap: Story = {
'Lorem ipsum dolor sit amet consectetur adipisicing elit. Sint, voluptate?',
},
};

export const Multiline: Story = {
args: {
children: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit',
},
decorators: [
Story => (
<div style={{ width: 50 }}>
<Story />
</div>
),
],
};
30 changes: 15 additions & 15 deletions packages/ui/src/components/badge/Badge.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { twOverrides } from '@/overrides';
export const badgeDef = twOverrides(
{
badge:
'rounded-radius border font-semibold inline-flex items-center transition-all h-atuo',
'rounded-radius font-semibold inline-flex items-center transition-all h-atuo',
variants: {
variant: {
primary: 'bg-primary border-primary text-primary-fg',
Expand All @@ -19,22 +19,22 @@ export const badgeDef = twOverrides(
link: 'text-foreground border-transparent underline underline-offset-4',
},
size: {
xs: 'py-0.5 px-1 gap-1 text-[10px]',
sm: 'py-[2px] px-1.5 gap-1 text-xs',
md: 'py-1 px-2 gap-1 text-xs',
lg: 'py-1.5 px-3 gap-1.5 text-sm',
xl: 'py-2 px-3 gap-2 text-base',
xs: 'min-h-5 px-1 gap-1 text-[10px]',
sm: 'min-h-6 py-[2px] px-1.5 gap-1 text-xs',
md: 'min-h-7 py-[2px] px-2 gap-1 text-xs',
lg: 'min-h-9 py-1 px-3 gap-1.5 text-sm',
xl: 'min-h-10 py-1 px-3 gap-2 text-base',
},
outline: {
primary: `bg-background text-primary`,
secondary: `bg-background text-secondary`,
muted: `bg-background text-muted`,
success: `bg-background text-success`,
danger: `bg-background text-danger`,
warning: `bg-background text-warning`,
info: `bg-background text-info`,
ghost: `bg-background`,
link: `bg-background`,
primary: `bg-background border text-primary`,
secondary: `bg-background border text-secondary`,
muted: `bg-background border text-muted`,
success: `bg-background border text-success`,
danger: `bg-background border text-danger`,
warning: `bg-background border text-warning`,
info: `bg-background border text-info`,
ghost: `bg-background border`,
link: `bg-background border`,
},
disabled: {
DEFAULT: 'opacity-65 cursor-not-allowed',
Expand Down
13 changes: 13 additions & 0 deletions packages/ui/src/components/button/Button.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,16 @@ export const Icon: Story = {
children: null,
},
};

export const Multiline: Story = {
args: {
children: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit',
},
decorators: [
Story => (
<div style={{ width: 50 }}>
<Story />
</div>
),
],
};
36 changes: 18 additions & 18 deletions packages/ui/src/components/button/Button.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { globalDef } from '../global.styles';
*/
export const buttonDef = twOverrides(
{
button: `${globalDef.ring} border outline-none box-border inline-flex font-semibold items-center justify-center rounded-radius transition-all disabled:opacity-65 disabled:cursor-not-allowed`,
button: `${globalDef.ring} outline-none box-border inline-flex font-semibold items-center justify-center rounded-radius transition-all disabled:opacity-65 disabled:cursor-not-allowed`,
variants: {
variant: {
primary:
Expand All @@ -30,27 +30,27 @@ export const buttonDef = twOverrides(
link: 'text-foreground hover:text-foreground/70 active:text-foreground/90 underline-offset-4 hover:underline ring-foreground',
},
size: {
xs: 'py-1 px-2 text-xs gap-x-1',
sm: 'py-1.5 px-3 text-sm gap-x-1',
md: 'py-2 px-4 text-sm gap-x-1',
lg: 'py-2.5 px-5 text-base gap-x-1.5',
xl: 'py-2.5 px-6 text-lg gap-x-2',
xs: 'min-h-7 py-1 px-2 text-xs gap-x-1',
sm: 'min-h-9 py-1 px-3 text-sm gap-x-1',
md: 'min-h-10 py-1.5 px-4 text-sm gap-x-1',
lg: 'min-h-11 py-1.5 px-5 text-base gap-x-1.5',
xl: 'min-h-12 py-2 px-6 text-lg gap-x-2',
'icon-xs': 'size-7',
'icon-sm': 'size-8',
'icon-md': 'size-9',
'icon-lg': 'size-10',
'icon-sm': 'size-9',
'icon-md': 'size-10',
'icon-lg': 'size-11',
'icon-xl': 'size-12',
},
outline: {
primary: `bg-background text-primary hover:bg-primary/10 active:bg-primary/15`,
secondary: `bg-background text-secondary hover:bg-secondary/10 active:bg-secondary/15`,
muted: `bg-background text-default hover:bg-default/10 active:bg-default/15`,
success: `bg-background text-success hover:bg-success/10 active:bg-success/15`,
danger: `bg-background text-danger hover:bg-danger/10 active:bg-danger/15`,
warning: `bg-background text-warning hover:bg-warning/10 active:bg-warning/15`,
info: `bg-background text-info hover:bg-info/10 active:bg-info/15`,
ghost: `bg-background border-primary/25`,
link: `bg-background border-primary`,
primary: `bg-background border text-primary hover:bg-primary/10 active:bg-primary/15`,
secondary: `bg-background border text-secondary hover:bg-secondary/10 active:bg-secondary/15`,
muted: `bg-background border text-default hover:bg-default/10 active:bg-default/15`,
success: `bg-background border text-success hover:bg-success/10 active:bg-success/15`,
danger: `bg-background border text-danger hover:bg-danger/10 active:bg-danger/15`,
warning: `bg-background border text-warning hover:bg-warning/10 active:bg-warning/15`,
info: `bg-background border text-info hover:bg-info/10 active:bg-info/15`,
ghost: `bg-background border border-primary/25`,
link: `bg-background border border-primary`,
},
},
},
Expand Down
44 changes: 44 additions & 0 deletions packages/ui/src/components/pagination/Pagination.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import type { Meta, StoryObj } from '@storybook/react';

import * as Pagination from './index';
import { PaginationEllipsis } from './PaginationEllipsis';
import { PaginationLink } from './PaginationLink';

const meta: Meta<typeof Pagination.Root> = {
component: Pagination.Root,
tags: ['autodocs'],
title: 'Components/Pagination',
args: {
children: (
<Pagination.Content>
<Pagination.Item>
<Pagination.Prev>Previous</Pagination.Prev>
</Pagination.Item>
<Pagination.Item>
<PaginationLink>1</PaginationLink>
</Pagination.Item>
<Pagination.Item>
<PaginationLink active>3</PaginationLink>
</Pagination.Item>
<Pagination.Item>
<PaginationEllipsis />
</Pagination.Item>
<Pagination.Item>
<PaginationLink>10</PaginationLink>
</Pagination.Item>
<Pagination.Item>
<PaginationLink>12</PaginationLink>
</Pagination.Item>
<Pagination.Item>
<Pagination.Next>Next</Pagination.Next>
</Pagination.Item>
</Pagination.Content>
),
},
};

export default meta;

type Story = StoryObj<typeof Pagination.Root>;

export const Basic: Story = {};
10 changes: 10 additions & 0 deletions packages/ui/src/components/pagination/Pagination.styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export const paginationDef = {
root: 'mx-auto flex w-full justify-center',
content: 'flex flex-row items-center gap-1',
icon: 'size-4',
ellipsis: {
content: 'flex h-9 w-9 items-center text-primary justify-center',
},
item: '',
link: 'cursor-pointer',
};
12 changes: 12 additions & 0 deletions packages/ui/src/components/pagination/PaginationContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { memo, type ComponentPropsWithoutRef } from 'react';

import { cn } from '@/utils';

import { paginationDef } from './Pagination.styles';

export const PaginationContent = memo(function PaginationContent({
className,
...restProps
}: ComponentPropsWithoutRef<'nav'>) {
return <ul className={cn(paginationDef.content, className)} {...restProps} />;
});
21 changes: 21 additions & 0 deletions packages/ui/src/components/pagination/PaginationEllipsis.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { MoreHorizontal } from 'lucide-react';
import { memo, type ComponentPropsWithoutRef } from 'react';

import { cn } from '@/utils';

import { paginationDef } from './Pagination.styles';

export const PaginationEllipsis = memo(function PaginationEllipsis({
className,
...restProps
}: ComponentPropsWithoutRef<'span'>) {
return (
<span
aria-hidden
className={cn(paginationDef.ellipsis.content, className)}
{...restProps}
>
<MoreHorizontal className={paginationDef.icon} />
</span>
);
});
12 changes: 12 additions & 0 deletions packages/ui/src/components/pagination/PaginationItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { memo, type ComponentPropsWithoutRef } from 'react';

import { cn } from '@/utils';

import { paginationDef } from './Pagination.styles';

export const PaginationItem = memo(function PaginationItem({
className,
...props
}: ComponentPropsWithoutRef<'li'>) {
return <li className={cn(paginationDef.item, className)} {...props} />;
});
51 changes: 51 additions & 0 deletions packages/ui/src/components/pagination/PaginationLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Slot } from '@radix-ui/react-slot';
import type { VariantProps } from 'class-variance-authority';
import { forwardRef, type ComponentPropsWithoutRef } from 'react';

import { cn } from '@/utils';

import { paginationDef } from './Pagination.styles';
import { usePaginationContext } from './usePaginationContext';
import { buttonStyles } from '../button/Button.styles';

export interface PaginationLinkProps
extends ComponentPropsWithoutRef<'a'>,
Pick<VariantProps<typeof buttonStyles>, 'size'> {
asChild?: boolean;
active?: boolean;
}

export const PaginationLink = forwardRef<
HTMLAnchorElement,
PaginationLinkProps
>(function PaginationLink(
{
className,
children,
size = 'md',
active = false,
asChild = false,
...restProps
},
ref,
) {
const { size: contextSize } = usePaginationContext();
const Comp = asChild ? Slot : 'a';

return (
<Comp
className={cn(
buttonStyles({
size: contextSize ?? size,
variant: 'ghost',
outline: active ? 'ghost' : null,
}),
paginationDef.link,
)}
ref={ref}
{...restProps}
>
{children}
</Comp>
);
});
17 changes: 17 additions & 0 deletions packages/ui/src/components/pagination/PaginationNext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { ChevronRight } from 'lucide-react';
import { memo } from 'react';

import { paginationDef } from './Pagination.styles';
import { PaginationLink, type PaginationLinkProps } from './PaginationLink';

export const PaginationNext = memo(function PaginationNext({
children,
...restProps
}: PaginationLinkProps) {
return (
<PaginationLink {...restProps}>
{children}
<ChevronRight className={paginationDef.icon} />
</PaginationLink>
);
});
17 changes: 17 additions & 0 deletions packages/ui/src/components/pagination/PaginationPrev.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { ChevronLeft } from 'lucide-react';
import { memo } from 'react';

import { paginationDef } from './Pagination.styles';
import { PaginationLink, type PaginationLinkProps } from './PaginationLink';

export const PaginationPrev = memo(function PaginationPrev({
children,
...restProps
}: PaginationLinkProps) {
return (
<PaginationLink {...restProps}>
<ChevronLeft className={paginationDef.icon} />
{children}
</PaginationLink>
);
});
31 changes: 31 additions & 0 deletions packages/ui/src/components/pagination/PaginationRoot.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import type { VariantProps } from 'class-variance-authority';
import { memo, useMemo, type ComponentPropsWithoutRef } from 'react';

import { cn } from '@/utils';

import { paginationDef } from './Pagination.styles';
import { PaginationContext } from './usePaginationContext';
import type { buttonStyles } from '../button/Button.styles';

export interface PaginationRootProps extends ComponentPropsWithoutRef<'nav'> {
size?: VariantProps<typeof buttonStyles>['size'];
}

export const PaginationRoot = memo(function PaginationRoot({
className,
size,
...props
}: PaginationRootProps) {
const contextValue = useMemo(() => ({ size }), [size]);

return (
<PaginationContext.Provider value={contextValue}>
<nav
role='navigation'
aria-label='pagination'
className={cn(paginationDef.root, className)}
{...props}
/>
</PaginationContext.Provider>
);
});
7 changes: 7 additions & 0 deletions packages/ui/src/components/pagination/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export { PaginationRoot as Root } from './PaginationRoot';
export { PaginationEllipsis as Ellipsis } from './PaginationEllipsis';
export { PaginationLink as Link } from './PaginationLink';
export { PaginationNext as Next } from './PaginationNext';
export { PaginationPrev as Prev } from './PaginationPrev';
export { PaginationContent as Content } from './PaginationContent';
export { PaginationItem as Item } from './PaginationItem';
Loading
Loading