Compare commits

...

2 Commits

Author SHA1 Message Date
Junior Garcia e839b34e02 Merge branch 'main' of github.com:nextui-org/nextui into feature-tabs-tab-position 2024-03-03 17:39:20 -03:00
winches 330675e05e feat(components): tabs component add tabPosition prop 2024-02-22 14:44:04 +08:00
7 changed files with 130 additions and 13 deletions
@@ -10,6 +10,7 @@ import icons from "./icons";
import form from "./form";
import controlled from "./controlled";
import customStyles from "./custom-styles";
import tabPosition from "./tab-position";
export const tabsContent = {
usage,
@@ -24,4 +25,5 @@ export const tabsContent = {
form,
controlled,
customStyles,
tabPosition,
};
@@ -0,0 +1,54 @@
const App = `import {Tabs, Tab, Card, CardBody, RadioGroup, Radio} from "@nextui-org/react";
export default function App() {
const [position, setPosition] = React.useState("top");
return (
<div className="flex flex-col px-4">
<RadioGroup
className="mb-4"
value={position}
label="Tab Position"
orientation="horizontal"
onValueChange={(value) => setPosition(value)}
>
<Radio value="top">top</Radio>
<Radio value="bottom">bottom</Radio>
<Radio value="left">left</Radio>
<Radio value="right">right</Radio>
</RadioGroup>
<div className="flex w-full flex-col">
<Tabs aria-label="Options" tabPosition={position}>
<Tab key="photos" title="Photos">
<Card>
<CardBody>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
</CardBody>
</Card>
</Tab>
<Tab key="music" title="Music">
<Card>
<CardBody>
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
</CardBody>
</Card>
</Tab>
<Tab key="videos" title="Videos">
<Card>
<CardBody>
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</CardBody>
</Card>
</Tab>
</Tabs>
</div>
</div>
);
}`;
const react = {
"/App.jsx": App,
};
export default {
...react,
};
+8 -1
View File
@@ -73,6 +73,12 @@ You can use the `onSelectionChange` and `selectedKey` props to control the selec
<CodeDemo title="Controlled" files={tabsContent.controlled} />
### Tab Position
You can change the position of the tabs by using the `position` prop. The default value is `top`.
<CodeDemo title="Tab Position" files={tabsContent.tabPosition} />
### Links
Tabs items can be rendered as links by passing the `href` prop to the `Tab` component. By
@@ -237,7 +243,8 @@ You can customize the `Tabs` component by passing custom Tailwind CSS classes to
| disableCursorAnimation | `boolean` | Whether the cursor should be hidden. | `false` |
| isDisabled | `boolean` | Whether the tab list should be disabled. | `false` |
| disableAnimation | `boolean` | Whether the tab list should be animated. | `false` |
| classNames | `Record<"base" "tabList" "tab" "tabContent" "cursor" "panel", string>` | Allows to set custom class names for the card slots. | - |
| classNames | `Record<"base" "tabList" "tab" "tabContent" "cursor" "panel", string>` | Allows to set custom class names for the card slots. | - |
| tabPosition | `top` \| `bottom` \| `left` \| `right` | The position of the tabs. | `top` |
### Tabs Events
+13 -11
View File
@@ -9,7 +9,7 @@ import TabPanel from "./tab-panel";
interface Props<T> extends UseTabsProps<T> {}
function Tabs<T extends object>(props: Props<T>, ref: ForwardedRef<HTMLDivElement>) {
const {Component, values, state, getBaseProps, getTabListProps} = useTabs<T>({
const {Component, values, state, getBaseProps, getTabListProps, getWrapperProps} = useTabs<T>({
...props,
ref,
});
@@ -36,17 +36,19 @@ function Tabs<T extends object>(props: Props<T>, ref: ForwardedRef<HTMLDivElemen
return (
<>
<div {...getBaseProps()}>
<Component {...getTabListProps()}>
{layoutGroupEnabled ? <LayoutGroup id={layoutId}>{tabs}</LayoutGroup> : tabs}
</Component>
<div {...getWrapperProps()}>
<div {...getBaseProps()}>
<Component {...getTabListProps()}>
{layoutGroupEnabled ? <LayoutGroup id={layoutId}>{tabs}</LayoutGroup> : tabs}
</Component>
</div>
<TabPanel
key={state.selectedItem?.key}
classNames={values.classNames}
slots={values.slots}
state={values.state}
/>
</div>
<TabPanel
key={state.selectedItem?.key}
classNames={values.classNames}
slots={values.slots}
state={values.state}
/>
</>
);
}
+17 -1
View File
@@ -47,6 +47,11 @@ export interface Props extends Omit<HTMLNextUIProps, "children"> {
* ``
*/
classNames?: SlotsToClasses<TabsSlots>;
/**
* The position of the tabs.
* @default 'top'
*/
tabPosition?: "top" | "right" | "bottom" | "left";
}
export type UseTabsProps<T> = Props &
@@ -79,6 +84,7 @@ export function useTabs<T extends object>(originalProps: UseTabsProps<T>) {
disableCursorAnimation,
shouldSelectOnPressUp = true,
motionProps,
tabPosition = "top",
...otherProps
} = props;
@@ -97,9 +103,10 @@ export function useTabs<T extends object>(originalProps: UseTabsProps<T>) {
() =>
tabs({
...variantProps,
[tabPosition]: true,
className,
}),
[...Object.values(variantProps), className],
[...Object.values(variantProps), className, tabPosition],
);
const baseStyles = clsx(classNames?.base, className);
@@ -143,6 +150,14 @@ export function useTabs<T extends object>(originalProps: UseTabsProps<T>) {
[baseStyles, otherProps, slots],
);
const getWrapperProps: PropGetter = useCallback(
(props) => ({
"data-slot": "tabWrapper",
className: slots.wrapper({class: clsx(classNames?.wrapper, props?.className)}),
}),
[classNames, slots],
);
const getTabListProps: PropGetter = useCallback(
(props) => ({
ref: domRef,
@@ -160,6 +175,7 @@ export function useTabs<T extends object>(originalProps: UseTabsProps<T>) {
values,
getBaseProps,
getTabListProps,
getWrapperProps,
};
}
@@ -316,6 +316,22 @@ export const ManualKeyboardActivation = {
},
};
export const TabPosition = {
render: StaticTemplate,
args: {
tabPosition: "top",
},
argTypes: {
tabPosition: {
options: ["top", "bottom", "left", "right"],
control: {
type: "inline-radio",
},
},
},
};
export const DisabledItems = {
render: StaticTemplate,
@@ -71,6 +71,7 @@ const tabs = tv({
// focus ring
...dataFocusVisibleClasses,
],
wrapper: [],
},
variants: {
variant: {
@@ -159,6 +160,25 @@ const tabs = tv({
tabContent: "transition-none",
},
},
left: {
true: {
tabList: "flex-col",
panel: "py-0 px-3",
wrapper: "flex",
},
},
right: {
true: {
tabList: "flex-col",
panel: "py-0 px-3",
wrapper: "flex flex-row-reverse",
},
},
bottom: {
true: {
wrapper: "flex flex-col-reverse",
},
},
},
defaultVariants: {
color: "default",