diff --git a/src/App.tsx b/src/App.tsx
index dc3fb29..ecd2488 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -5,7 +5,6 @@ import { GlobalStyle } from "./styles/global-style";
import { lightTheme, darkTheme } from "./styles/themes";
import Button from "./lib/button";
import Tabs from "./lib/pagination/tabs";
-import Card from "./lib/container/card";
import Buttons from "./examples/buttons";
import Pagination from "./examples/pagination";
import Containers from "./examples/containers";
@@ -19,6 +18,7 @@ import TimelineProgress from "./examples/timeline";
import Input from "./examples/input";
import Tooltips from "./examples/tooltip";
import Copiable from "./examples/copiable";
+import clsx from "clsx";
const StyledDiv = styled.div`
position: fixed;
@@ -38,29 +38,9 @@ const StyledDiv = styled.div`
${(props) => props.theme.klerosUIComponentsTransitionSpeed};
`;
-const StyledCard = styled(Card)`
- height: 500px;
- width: 1000px;
- display: flex;
- justify-content: space-around;
- align-items: center;
- gap: 24px;
- overflow: auto;
- flex-wrap: wrap;
- padding: 36px 36px;
- background: ${(props) => props.theme.klerosUIComponentsLightBackground};
- transition: background ease
- ${(props) => props.theme.klerosUIComponentsTransitionSpeed};
-`;
-
-const StyledTabs = styled(Tabs)`
- width: 995px;
-`;
-
const App = () => {
const [theme, setTheme] = useState(lightTheme);
const [tailwindTheme, setTailwindTheme] = useState("light");
- const [example, setExample] = useState("buttons");
// temporary
const changeTheme = () => {
@@ -80,40 +60,97 @@ const App = () => {
- ,
+ },
+ {
+ text: "Pagination",
+ value: "pagination",
+ id: "pagination",
+ content: ,
+ },
+ {
+ text: "Containers",
+ value: "containers",
+ id: "containers",
+ content: ,
+ },
+ {
+ text: "Accordion",
+ value: "accordion",
+ id: "accordion",
+ content: ,
+ },
+ {
+ text: "Form",
+ value: "form",
+ id: "content",
+ content: ,
+ },
+ {
+ text: "Dropdowns",
+ value: "dropdowns",
+ id: "dropdowns",
+ content: ,
+ },
+ {
+ text: "Displays",
+ value: "displays",
+ id: "displays",
+ content: ,
+ },
+ {
+ text: "Messages",
+ value: "messages",
+ id: "messages",
+ content: ,
+ },
+ {
+ text: "Timeline",
+ value: "timeline",
+ id: "timeline",
+ content: ,
+ },
+ {
+ text: "Progress",
+ value: "progress",
+ id: "progress",
+ content: ,
+ },
+ {
+ text: "Input",
+ value: "input",
+ id: "input",
+ content: ,
+ },
+ {
+ text: "Tooltip",
+ value: "tooltip",
+ id: "tooltip",
+ content: ,
+ },
+ {
+ text: "Copiable",
+ value: "copiable",
+ id: "copiable",
+ content: ,
+ },
]}
- callback={setExample}
- currentValue={example}
/>
-
- {example === "buttons" && }
- {example === "pagination" && }
- {example === "containers" && }
- {example === "accordion" && }
- {example === "form" && }
- {example === "dropdowns" && }
- {example === "displays" && }
- {example === "messages" && }
- {example === "timeline" && }
- {example === "progress" && }
- {example === "input" && }
- {example === "tooltip" && }
- {example === "copiable" && }
-
},
{
text: "Telegram",
value: 1,
Icon: Telegram,
+ id: "telegram",
+ content: Telegram
,
+ },
+ {
+ text: "disabled",
+ value: 2,
+ disabled: true,
+ id: "disabled",
+ content: Disabled
,
},
- { text: "hello1", value: 2, disabled: true },
]}
- callback={() => {
- // function called when a tab is clicked
- }}
- currentValue={0}
/>
- props.disabled
- ? props.theme.klerosUIComponentsStroke
- : props.theme.klerosUIComponentsPrimaryBlue};
- transition: fill ease
- ${({ theme }) => theme.klerosUIComponentsTransitionSpeed};
- }
-
- :hover:enabled {
- & ${StyledSVG} {
- fill: ${({ theme }) => theme.klerosUIComponentsSecondaryBlue};
- }
- }
-`;
-
-const StyledLabel = styled.small`
- ${small}
- color: ${(props) => props.theme.klerosUIComponentsPrimaryText};
-`;
-
-const LeftArrow = styled(ArrowButton)`
- margin-left: 16px;
-`;
-
-const RightArrow = styled(ArrowButton)`
- margin-left: 8px;
-
- & ${StyledSVG} {
- transform: rotate(180deg);
- }
-`;
-
-const CloseButton = styled(ArrowButton)`
- margin-left: 8px;
-
- & ${StyledSVG} {
- fill: ${(props) => props.theme.klerosUIComponentsPrimaryBlue};
- }
-
- :hover:enabled {
- & ${StyledSVG} {
- fill: ${({ theme }) => theme.klerosUIComponentsSecondaryBlue};
- }
- }
-`;
+const ArrowButton: React.FC = ({
+ children,
+ isDisabled,
+ className,
+ ...props
+}) => {
+ return (
+
+ );
+};
interface CompactPaginationProps {
currentPage: number;
numPages: number;
callback: (newPage: number) => void;
+ /** Callback function called when end of pages has been reached */
onCloseOnLastPage?: () => void;
label?: ReactNode;
className?: string;
}
-const CompactPagination: React.FC = ({
+function CompactPagination({
currentPage,
numPages,
callback,
onCloseOnLastPage,
label,
className,
-}) => {
+}: Readonly) {
const [{ incrementPage, decrementPage, minPageReached, maxPageReached }] =
usePagination(currentPage, numPages, callback, onCloseOnLastPage);
return (
-
- {label}
-
-
-
+
+
+ {label}
+
+
+
+
{currentPage === numPages && onCloseOnLastPage ? (
-
-
-
+
+
+
) : (
-
-
-
+
+
+
)}
-
+
);
-};
+}
export default CompactPagination;
diff --git a/src/lib/pagination/standard.tsx b/src/lib/pagination/standard.tsx
index 59d9440..efcc67d 100644
--- a/src/lib/pagination/standard.tsx
+++ b/src/lib/pagination/standard.tsx
@@ -1,112 +1,58 @@
import React from "react";
-import styled from "styled-components";
import usePagination from "../../hooks/pagination/use-pagination";
import Arrow from "../../assets/svgs/arrows/light-left.svg";
-import { borderBox, button, svg } from "../../styles/common-style";
-
-const Wrapper = styled.div`
- ${borderBox}
- display: flex;
- align-items: center;
- justify-content: center;
-`;
-
-const PageButton = styled.button<{ selected?: boolean }>`
- ${button}
- height: 32px;
- width: 32px;
- margin: 4px;
- background: ${(props) =>
- props.selected
- ? props.theme.klerosUIComponentsLightBlue
- : props.theme.klerosUIComponentsWhiteBackground};
- border: 1px solid
- ${(props) =>
- props.selected
- ? props.theme.klerosUIComponentsPrimaryBlue
- : props.theme.klerosUIComponentsStroke};
- border-radius: 3px;
- display: flex;
- align-items: center;
- justify-content: center;
-
- font-size: 14px;
- color: ${(props) =>
- props.selected
- ? props.theme.klerosUIComponentsPrimaryBlue
- : props.theme.klerosUIComponentsPrimaryText};
-
- :hover:enabled {
- background: ${(props) =>
- props.selected
- ? props.theme.klerosUIComponentsWhiteBackground
- : props.theme.klerosUIComponentsLightBlue};
- border: 1px solid
- ${(props) =>
- props.selected
- ? props.theme.klerosUIComponentsPrimaryBlue
- : props.theme.klerosUIComponentsSecondaryBlue};
- color: ${(props) =>
- props.selected
- ? props.theme.klerosUIComponentsPrimaryBlue
- : props.theme.klerosUIComponentsSecondaryBlue};
- }
-
- :hover:disabled {
- cursor: default;
- }
-`;
-
-const StyledArrow = styled.svg``;
-
-const ArrowButton = styled(PageButton)`
- & ${StyledArrow} {
- ${svg}
- fill: ${(props) =>
- props.disabled
- ? props.theme.klerosUIComponentsStroke
- : props.theme.klerosUIComponentsPrimaryText};
- transition: fill ease
- ${({ theme }) => theme.klerosUIComponentsTransitionSpeed};
- }
-
- :hover:enabled {
- & ${StyledArrow} {
- fill: ${({ theme }) => theme.klerosUIComponentsSecondaryBlue};
- }
- }
-`;
-
-const LeftArrow = styled(ArrowButton)`
- & ${StyledArrow} {
- padding-right: 1px;
- }
-`;
-
-const RightArrow = styled(ArrowButton)`
- & ${StyledArrow} {
- padding-left: 1px;
- transform: rotate(180deg);
- }
-`;
+import { cn } from "../../utils";
+import { Button, type ButtonProps } from "react-aria-components";
+import clsx from "clsx";
+const PageButton: React.FC = ({
+ children,
+ selected,
+ className,
+ ...props
+}) => (
+
+);
interface StandardPaginationProps {
currentPage: number;
numPages: number;
callback: (newPage: number) => void;
className?: string;
+ /** Disables the number buttons, allowing only use of arrows */
disableNumbers?: boolean;
+ /** Hides the number buttons */
hideNumbers?: boolean;
}
-const StandardPagination: React.FC = ({
+function StandardPagination({
currentPage,
numPages,
callback,
disableNumbers,
hideNumbers,
className,
-}) => {
+}: Readonly) {
const [
{
incrementPage,
@@ -119,26 +65,50 @@ const StandardPagination: React.FC = ({
] = usePagination(currentPage, numPages, callback);
return (
-
-
-
-
+
+
+
+
{!hideNumbers &&
getPageRange().map((i) => (
goToPage(i)}
- disabled={disableNumbers}
+ onPress={() => goToPage(i)}
+ isDisabled={disableNumbers}
>
{i}
))}
-
-
-
-
+
+
+
+
);
-};
+}
export default StandardPagination;
diff --git a/src/lib/pagination/tabs.tsx b/src/lib/pagination/tabs.tsx
index 6f125c6..8e5ba52 100644
--- a/src/lib/pagination/tabs.tsx
+++ b/src/lib/pagination/tabs.tsx
@@ -1,98 +1,147 @@
-import React from "react";
-import styled from "styled-components";
-import {
- borderBox,
- button,
- hoverShortTransitionTiming,
- hoverLongTransitionTiming,
- svg,
-} from "../../styles/common-style";
-
-const Wrapper = styled.div`
- ${borderBox}
- height: fit-content;
- width: 500px;
- display: flex;
-`;
-
-const StyledSVG = styled.svg``;
-
-const StyledTab = styled.button<{ selected?: boolean }>`
- ${button}
- ${hoverShortTransitionTiming}
- flex-grow: 1;
- height: 45px;
- background: none;
- border-bottom: 3px solid
- ${(props) =>
- props.selected
- ? props.theme.klerosUIComponentsPrimaryBlue
- : props.theme.klerosUIComponentsStroke};
- display: flex;
- align-items: center;
- justify-content: center;
-
- color: ${(props) => {
- if (props.selected) return props.theme.klerosUIComponentsPrimaryBlue;
- else if (props.disabled) return props.theme.klerosUIComponentsStroke;
- else return props.theme.klerosUIComponentsPrimaryText;
- }};
-
- ${(props) =>
- !props.disabled && !props.selected
- ? `:hover {
- ${hoverLongTransitionTiming}
- border-bottom: 3px solid
- ${props.theme.klerosUIComponentsSecondaryBlue};
- }`
- : ""}
-
- & ${StyledSVG} {
- ${svg}
- ${hoverShortTransitionTiming}
- height: 16px;
- width: 16px;
- margin-right: 16px;
+import React, { ReactNode, useCallback, useState } from "react";
- fill: ${(props) => {
- if (props.selected) return props.theme.klerosUIComponentsPrimaryBlue;
- else if (props.disabled) return props.theme.klerosUIComponentsStroke;
- else return props.theme.klerosUIComponentsPrimaryText;
- }};
- }
-`;
+import { cn } from "../../utils";
+import {
+ Tabs as AriaTabs,
+ Collection,
+ Tab,
+ TabList,
+ TabPanel,
+ type TabsProps as AriaTabsProps,
+ type Key,
+ type TabListProps,
+ type TabPanelProps,
+ type TabProps,
+} from "react-aria-components";
interface TabsItem {
+ /** Unique id for each tab panel */
+ id: Key;
text: string;
+ /** Value associated with each tab. Passed as an arg to callback function. */
value: any;
Icon?: React.FC>;
icon?: React.ReactNode;
disabled?: boolean;
+ /** Content to display when this tab is selected. */
+ content: ReactNode;
+ /** Props for Tab
+ * [See TabProps](https://react-spectrum.adobe.com/react-aria/Tabs.html#tab)
+ */
+ tabProps?: TabProps;
+ /**
+ * Can be used to provide separate styling for a TabPanel, apart from one passed in panelClassName parent props.
+ * [See TabPanelProps](https://react-spectrum.adobe.com/react-aria/Tabs.html#tabpanel)
+ */
+ tabPanelProps?: TabPanelProps;
}
-interface TabsProps {
- currentValue: any;
+interface TabsProps extends Omit {
items: TabsItem[];
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
- callback: Function;
+ callback?: Function;
+ className?: string;
+ /** ClassName to provide a common style for all TabPanels */
+ panelClassName?: string;
+ /**
+ * Can be used to override default style.
+ * [See TablistProps](https://react-spectrum.adobe.com/react-aria/Tabs.html#tablist)
+ */
+ tabListProps?: TabListProps;
}
-const Tabs: React.FC = ({ items, ...props }) => {
+/** Tabs organize content into multiple sections and allow users to navigate between them. */
+function Tabs({
+ items,
+ className,
+ tabListProps,
+ panelClassName,
+ callback,
+ defaultSelectedKey,
+ ...props
+}: Readonly) {
+ const [selectedKey, setSelectedKey] = useState(
+ defaultSelectedKey,
+ );
+
+ const handleSelection = useCallback(
+ (key: Key) => {
+ setSelectedKey(key);
+ const selectedItem = items.find((item) => item.text === key);
+ if (selectedItem && callback) callback(key, selectedItem.value);
+ },
+ [items, callback],
+ );
+
return (
-
- {items.map(({ Icon, icon, text, value, disabled }) => (
- props.callback(value)}
- >
- {icon ?? (Icon && )}
- {text}
-
- ))}
-
+
+
+ {items.map(({ id, Icon, icon, text, disabled }) => (
+
+ {icon ??
+ (Icon && (
+
+ ))}
+
+ {text}
+
+
+ ))}
+
+
+
+ {(item) => (
+
+ {item.content}
+
+ )}
+
+
);
-};
+}
export default Tabs;
diff --git a/src/stories/compactPagination.stories.tsx b/src/stories/compactPagination.stories.tsx
new file mode 100644
index 0000000..bceb284
--- /dev/null
+++ b/src/stories/compactPagination.stories.tsx
@@ -0,0 +1,74 @@
+import type { Meta, StoryObj } from "@storybook/react";
+
+import { IPreviewArgs } from "./utils";
+
+import Pagination from "../lib/pagination/compact";
+import React, { useState } from "react";
+
+const meta = {
+ component: Pagination,
+ title: "Pagination/Compact Pagination",
+ tags: ["autodocs"],
+ argTypes: {
+ numPages: {
+ control: "number",
+ },
+ currentPage: {
+ control: "number",
+ },
+ className: {
+ control: "text",
+ },
+ },
+} satisfies Meta;
+
+export default meta;
+
+type Story = StoryObj & IPreviewArgs;
+
+export const CompactPagination: Story = {
+ args: {
+ themeUI: "light",
+ backgroundUI: "light",
+ numPages: 6,
+ currentPage: 0,
+ callback: () => {},
+ className: "w-full",
+ label: "Label:",
+ },
+ render: function Render(args) {
+ const [currentPage, setCurrentPage] = useState(1);
+
+ return (
+
+ );
+ },
+};
+
+export const CompactPaginationWithCloseCallback: Story = {
+ args: {
+ themeUI: "light",
+ backgroundUI: "light",
+ numPages: 6,
+ currentPage: 0,
+ callback: () => {},
+ className: "w-full",
+ label: "Shows close button in end.",
+ },
+ render: function Render(args) {
+ const [currentPage, setCurrentPage] = useState(1);
+
+ return (
+ {}}
+ />
+ );
+ },
+};
diff --git a/src/stories/standardPagination.stories.tsx b/src/stories/standardPagination.stories.tsx
new file mode 100644
index 0000000..c91f1da
--- /dev/null
+++ b/src/stories/standardPagination.stories.tsx
@@ -0,0 +1,57 @@
+import type { Meta, StoryObj } from "@storybook/react";
+
+import { IPreviewArgs } from "./utils";
+
+import Pagination from "../lib/pagination/standard";
+import React, { useState } from "react";
+
+const meta = {
+ component: Pagination,
+ title: "Pagination/Standard Pagination",
+ tags: ["autodocs"],
+ argTypes: {
+ numPages: {
+ control: "number",
+ },
+ currentPage: {
+ control: "number",
+ },
+ className: {
+ control: "text",
+ },
+ disableNumbers: {
+ control: "boolean",
+ },
+ hideNumbers: {
+ control: "boolean",
+ },
+ },
+} satisfies Meta;
+
+export default meta;
+
+type Story = StoryObj & IPreviewArgs;
+
+export const StandardPagination: Story = {
+ args: {
+ themeUI: "light",
+ backgroundUI: "light",
+ numPages: 6,
+ currentPage: 0,
+ callback: () => {},
+ className: "w-full",
+ disableNumbers: false,
+ hideNumbers: false,
+ },
+ render: function Render(args) {
+ const [currentPage, setCurrentPage] = useState(1);
+
+ return (
+
+ );
+ },
+};
diff --git a/src/stories/tabs.stories.tsx b/src/stories/tabs.stories.tsx
new file mode 100644
index 0000000..3661310
--- /dev/null
+++ b/src/stories/tabs.stories.tsx
@@ -0,0 +1,44 @@
+import type { Meta, StoryObj } from "@storybook/react";
+import React from "react";
+import { IPreviewArgs } from "./utils";
+
+import TabsComponent from "../lib/pagination/tabs";
+import Telegram from "../assets/svgs/telegram.svg";
+
+const meta = {
+ component: TabsComponent,
+ title: "Pagination/Tabs",
+ tags: ["autodocs"],
+ argTypes: {},
+} satisfies Meta;
+
+export default meta;
+
+type Story = StoryObj & IPreviewArgs;
+
+export const Tabs: Story = {
+ args: {
+ themeUI: "light",
+ backgroundUI: "light",
+ className: "w-[500px]",
+ defaultSelectedKey: "discord",
+ panelClassName: "bg-klerosUIComponentsLightBlue p-4",
+ items: [
+ { text: "Discord", value: 0, id: "discord", content: Discord
},
+ {
+ text: "Telegram",
+ value: 1,
+ Icon: Telegram,
+ id: "telegram",
+ content: Telegram
,
+ },
+ {
+ text: "Disabled",
+ value: 2,
+ disabled: true,
+ id: "disabled",
+ content: Disabled
,
+ },
+ ],
+ },
+};