mirror of https://github.com/buster-so/buster.git
Update AppSegmented.tsx
This commit is contained in:
parent
969becb306
commit
f915e4caea
|
@ -44,7 +44,6 @@ export const PreventNavigation: React.FC<PreventNavigationProps> = React.memo(
|
|||
* @param e The triggered event.
|
||||
*/
|
||||
const handleClick = useMemoizedFn((event: MouseEvent) => {
|
||||
console.log('handleClick');
|
||||
let target = event.target as HTMLElement;
|
||||
let href: string | null = null;
|
||||
|
||||
|
@ -61,10 +60,11 @@ export const PreventNavigation: React.FC<PreventNavigationProps> = React.memo(
|
|||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
console.log(href);
|
||||
console.log(target);
|
||||
|
||||
confirmationFn.current = () => {
|
||||
if (href) router.push(href);
|
||||
target.click();
|
||||
// if (href) router.push(href);
|
||||
};
|
||||
|
||||
setLeavingPage(true);
|
||||
|
|
|
@ -1,6 +1,32 @@
|
|||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { AppSegmented } from './AppSegmented';
|
||||
import { BottleChampagne, Grid, HouseModern, PaintRoller } from '../icons';
|
||||
import { PreventNavigation } from '../layouts/PreventNavigation';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { usePathname, useSearchParams } from 'next/navigation';
|
||||
import { useState } from 'react';
|
||||
import { Checkbox } from '../checkbox';
|
||||
|
||||
// Mock the Next.js router
|
||||
const MockNextRouter = ({ children }: { children: React.ReactNode }) => {
|
||||
const mockRouter = {
|
||||
back: () => {},
|
||||
forward: () => {},
|
||||
push: () => {},
|
||||
replace: () => {},
|
||||
refresh: () => {},
|
||||
prefetch: () => Promise.resolve()
|
||||
};
|
||||
|
||||
// @ts-ignore - we're mocking the router
|
||||
useRouter.mockImplementation(() => mockRouter);
|
||||
// @ts-ignore - we're mocking the pathname
|
||||
usePathname.mockImplementation(() => '/');
|
||||
// @ts-ignore - we're mocking the search params
|
||||
useSearchParams.mockImplementation(() => new URLSearchParams());
|
||||
|
||||
return <>{children}</>;
|
||||
};
|
||||
|
||||
const meta: Meta<typeof AppSegmented> = {
|
||||
title: 'UI/Segmented/AppSegmented',
|
||||
|
@ -9,6 +35,13 @@ const meta: Meta<typeof AppSegmented> = {
|
|||
layout: 'centered'
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
decorators: [
|
||||
(Story) => (
|
||||
<MockNextRouter>
|
||||
<Story />
|
||||
</MockNextRouter>
|
||||
)
|
||||
],
|
||||
argTypes: {
|
||||
size: {
|
||||
control: 'radio',
|
||||
|
@ -120,3 +153,62 @@ export const WithOnlyIcons: Story = {
|
|||
]
|
||||
}
|
||||
};
|
||||
|
||||
export const WithPreventDefault: Story = {
|
||||
args: {
|
||||
options: [
|
||||
{
|
||||
value: 'tab1',
|
||||
icon: <HouseModern />,
|
||||
link: 'https://www.google.com',
|
||||
label: 'Tab 1',
|
||||
tooltip: 'Tooltip 1'
|
||||
},
|
||||
{
|
||||
value: 'tab2',
|
||||
icon: <Grid />,
|
||||
link: 'https://www.google.com',
|
||||
label: 'Tab 2',
|
||||
tooltip: 'Tooltip 2'
|
||||
},
|
||||
{
|
||||
value: 'tab3',
|
||||
icon: <BottleChampagne />,
|
||||
link: 'https://www.google.com',
|
||||
label: 'Tab 3',
|
||||
tooltip: 'Tooltip 3'
|
||||
}
|
||||
]
|
||||
},
|
||||
render: (args) => {
|
||||
const [isDirty, setIsDirty] = useState(true);
|
||||
|
||||
return (
|
||||
<div className="flex w-full min-w-[500px] flex-col items-center justify-center gap-4">
|
||||
<AppSegmented {...args} />
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<Checkbox
|
||||
checked={isDirty}
|
||||
onCheckedChange={(checked) => setIsDirty(checked === 'indeterminate' ? true : checked)}
|
||||
/>
|
||||
<p>{isDirty ? 'Dirty' : 'Clean'}</p>
|
||||
</div>
|
||||
|
||||
<PreventNavigation
|
||||
isDirty={isDirty}
|
||||
title="Title"
|
||||
description="Description"
|
||||
onOk={() => {
|
||||
alert('ok');
|
||||
return Promise.resolve();
|
||||
}}
|
||||
onCancel={() => {
|
||||
alert('cancel');
|
||||
return Promise.resolve();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -6,9 +6,17 @@ import { motion } from 'framer-motion';
|
|||
import { cn } from '@/lib/classMerge';
|
||||
import { useEffect, useState, useLayoutEffect, useTransition } from 'react';
|
||||
import { cva } from 'class-variance-authority';
|
||||
import { useMemoizedFn, useMergedRefs, useSize, useThrottleFn, useWhyDidYouUpdate } from '@/hooks';
|
||||
import {
|
||||
useMemoizedFn,
|
||||
useMergedRefs,
|
||||
useMount,
|
||||
useSize,
|
||||
useThrottleFn,
|
||||
useWhyDidYouUpdate
|
||||
} from '@/hooks';
|
||||
import { Tooltip } from '../tooltip/Tooltip';
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
export interface SegmentedItem<T extends string | number = string> {
|
||||
value: T;
|
||||
|
@ -126,8 +134,8 @@ export const AppSegmented: AppSegmentedComponent = React.memo(
|
|||
console.log('handleTabClick called with:', value);
|
||||
const item = options.find((item) => item.value === value);
|
||||
if (item && !item.disabled && value !== selectedValue) {
|
||||
setSelectedValue(item.value);
|
||||
startTransition(() => {
|
||||
setSelectedValue(item.value);
|
||||
onChange?.(item);
|
||||
});
|
||||
}
|
||||
|
@ -160,13 +168,12 @@ export const AppSegmented: AppSegmentedComponent = React.memo(
|
|||
setSelectedValue(value);
|
||||
});
|
||||
}
|
||||
}, [value, selectedValue]);
|
||||
}, [value]);
|
||||
|
||||
return (
|
||||
<Tabs.Root
|
||||
ref={rootRef}
|
||||
value={selectedValue as string}
|
||||
onValueChange={handleTabClick}
|
||||
className={cn(segmentedVariants({ block, type }), heightVariants({ size }), className)}>
|
||||
{isMeasured && (
|
||||
<motion.div
|
||||
|
@ -197,6 +204,7 @@ export const AppSegmented: AppSegmentedComponent = React.memo(
|
|||
size={size}
|
||||
block={block}
|
||||
tabRefs={tabRefs}
|
||||
handleTabClick={handleTabClick}
|
||||
/>
|
||||
))}
|
||||
</Tabs.List>
|
||||
|
@ -213,37 +221,48 @@ interface SegmentedTriggerProps<T extends string = string> {
|
|||
size: AppSegmentedProps<T>['size'];
|
||||
block: AppSegmentedProps<T>['block'];
|
||||
tabRefs: React.MutableRefObject<Map<string, HTMLButtonElement>>;
|
||||
handleTabClick: (value: string) => void;
|
||||
}
|
||||
|
||||
function SegmentedTriggerComponent<T extends string = string>(props: SegmentedTriggerProps<T>) {
|
||||
const { item, selectedValue, size, block, tabRefs } = props;
|
||||
const { item, selectedValue, size, block, tabRefs, handleTabClick } = props;
|
||||
const { tooltip, label, icon, disabled, value, link } = item;
|
||||
const router = useRouter();
|
||||
|
||||
const LinkDiv = link ? Link : 'div';
|
||||
|
||||
useMount(() => {
|
||||
if (link) {
|
||||
router.prefetch(link);
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<Tooltip title={tooltip || ''} sideOffset={10} delayDuration={150}>
|
||||
<Tabs.Trigger
|
||||
key={value}
|
||||
value={value}
|
||||
disabled={disabled}
|
||||
asChild
|
||||
ref={(el) => {
|
||||
if (el) tabRefs.current.set(value, el);
|
||||
}}
|
||||
className={cn(
|
||||
triggerVariants({
|
||||
size,
|
||||
block,
|
||||
disabled,
|
||||
selected: selectedValue === value
|
||||
})
|
||||
)}>
|
||||
<LinkDiv href={link || ''}>
|
||||
{icon && <span className={cn('flex items-center text-sm')}>{icon}</span>}
|
||||
{label && <span className={cn('text-sm')}>{label}</span>}
|
||||
</LinkDiv>
|
||||
</Tabs.Trigger>
|
||||
<LinkDiv href={link || ''}>
|
||||
<Tabs.Trigger
|
||||
key={value}
|
||||
value={value}
|
||||
disabled={disabled}
|
||||
asChild
|
||||
onClick={() => handleTabClick(value)}
|
||||
ref={(el) => {
|
||||
if (el) tabRefs.current.set(value, el);
|
||||
}}
|
||||
className={cn(
|
||||
triggerVariants({
|
||||
size,
|
||||
block,
|
||||
disabled,
|
||||
selected: selectedValue === value
|
||||
})
|
||||
)}>
|
||||
<div className="">
|
||||
{icon && <span className={cn('flex items-center text-sm')}>{icon}</span>}
|
||||
{label && <span className={cn('text-sm')}>{label}</span>}
|
||||
</div>
|
||||
</Tabs.Trigger>
|
||||
</LinkDiv>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue