Skip to content
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
111 changes: 68 additions & 43 deletions packages/raystack/v1/components/breadcrumb/breadcrumb.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { ChevronDownIcon,DotsHorizontalIcon } from "@radix-ui/react-icons";
import { cva, type VariantProps } from "class-variance-authority";
import React, { forwardRef, PropsWithChildren } from "react";
import { ChevronDownIcon, DotsHorizontalIcon } from '@radix-ui/react-icons';
import { type VariantProps, cva } from 'class-variance-authority';
import React, { forwardRef, PropsWithChildren } from 'react';

import { DropdownMenu } from "../dropdown-menu";
import styles from "./breadcrumb.module.css";
import { DropdownMenu } from '../dropdown-menu';
import styles from './breadcrumb.module.css';

interface BreadcrumbItem {
label: string;
Expand All @@ -15,16 +15,18 @@ interface BreadcrumbItem {
const breadcrumb = cva(styles['breadcrumb'], {
variants: {
size: {
small: styles["breadcrumb-small"],
medium: styles["breadcrumb-medium"],
},
small: styles['breadcrumb-small'],
medium: styles['breadcrumb-medium']
}
},
defaultVariants: {
size: "medium",
},
size: 'medium'
}
});

type BreadcrumbProps = PropsWithChildren<Omit<VariantProps<typeof breadcrumb>, 'size'>> & {
type BreadcrumbProps = PropsWithChildren<
Omit<VariantProps<typeof breadcrumb>, 'size'>
> & {
items: BreadcrumbItem[];
maxVisibleItems?: number;
separator?: React.ReactNode;
Expand All @@ -34,82 +36,105 @@ type BreadcrumbProps = PropsWithChildren<Omit<VariantProps<typeof breadcrumb>, '
};

export const Breadcrumb = forwardRef<HTMLDivElement, BreadcrumbProps>(
({
className,
size = 'medium',
items,
maxVisibleItems,
separator = '/',
onItemClick,
...props
}, ref) => {
const visibleItems = maxVisibleItems && items.length > maxVisibleItems
? [
...items.slice(0, 1),
{ label: 'ellipsis', href: '#' },
...items.slice(-Math.min(maxVisibleItems - 1, items.length - 1))
]
: items;
(
{
className,
size = 'medium',
items,
maxVisibleItems,
separator = '/',
onItemClick,
...props
},
ref
) => {
const visibleItems =
maxVisibleItems && items.length > maxVisibleItems
? [
...items.slice(0, 1),
{ label: 'ellipsis', href: '#' },
...items.slice(-Math.min(maxVisibleItems - 1, items.length - 1))
]
: items;

const renderItem = (item: BreadcrumbItem, index: number, isLast: boolean) => (
const renderItem = (
item: BreadcrumbItem,
index: number,
isLast: boolean
) => (
<li key={index} className={styles['breadcrumb-item']}>
{item.label === 'ellipsis' ? (
<span className={styles['breadcrumb-ellipsis']}>
<DotsHorizontalIcon />
</span>
) : item?.dropdownItems ? (
<DropdownMenu>
<DropdownMenu.Trigger className={styles['breadcrumb-dropdown-trigger']}>
{item.icon && <span className={styles['breadcrumb-icon']}>{item.icon}</span>}
<DropdownMenu.Trigger
className={styles['breadcrumb-dropdown-trigger']}
>
{item.icon && (
<span className={styles['breadcrumb-icon']}>{item.icon}</span>
)}
<span>{item.label}</span>
<ChevronDownIcon className={styles['breadcrumb-dropdown-icon']} />
</DropdownMenu.Trigger>
<DropdownMenu.Content className={styles['breadcrumb-dropdown-content']}>
<DropdownMenu.Content
className={styles['breadcrumb-dropdown-content']}
>
{item.dropdownItems.map((dropdownItem, dropdownIndex) => (
<DropdownMenu.Item
<DropdownMenu.Item
key={dropdownIndex}
className={styles['breadcrumb-dropdown-item']}
onSelect={() => onItemClick && onItemClick({
label: dropdownItem.label,
href: dropdownItem.href
})}
onClick={() =>
onItemClick &&
onItemClick({
label: dropdownItem.label,
href: dropdownItem.href
})
}
>
{dropdownItem.label}
</DropdownMenu.Item>
))}
</DropdownMenu.Content>
</DropdownMenu>
) : (
<a
<a
href={item.href}
className={`${styles['breadcrumb-link']} ${isLast ? styles['breadcrumb-link-active'] : ''}`}
onClick={(e) => {
onClick={e => {
if (onItemClick && item.href !== '#') {
e.preventDefault();
onItemClick(item);
}
}}
>
{item.icon && <span className={styles['breadcrumb-icon']}>{item.icon}</span>}
{item.icon && (
<span className={styles['breadcrumb-icon']}>{item.icon}</span>
)}
<span>{item.label}</span>
</a>
)}
{!isLast && <span className={styles['breadcrumb-separator']}>{separator}</span>}
{!isLast && (
<span className={styles['breadcrumb-separator']}>{separator}</span>
)}
</li>
);

return (
<nav
<nav
className={breadcrumb({ size: size as 'small' | 'medium', className })}
ref={ref}
{...props}
>
<ol className={styles['breadcrumb-list']}>
{visibleItems.map((item, index) => renderItem(item, index, index === visibleItems.length - 1))}
{visibleItems.map((item, index) =>
renderItem(item, index, index === visibleItems.length - 1)
)}
</ol>
</nav>
);
}
);

Breadcrumb.displayName = "Breadcrumb";
Breadcrumb.displayName = 'Breadcrumb';
54 changes: 26 additions & 28 deletions packages/raystack/v1/components/data-table/components/filters.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { Button } from "../../button";
import { DropdownMenu } from "../../dropdown-menu";
import { FilterChip } from "../../filter-chip";
import { Flex } from "../../flex";
import { IconButton } from "../../icon-button";
import { FilterIcon } from "~/icons";
import { DataTableColumn } from "../data-table.types";
import { useDataTable } from "../hooks/useDataTable";
import { FilterOperatorTypes, FilterType } from "~/v1/types/filters";
import { useFilters } from "../hooks/useFilters";
import { FilterIcon } from '~/icons';
import { FilterOperatorTypes, FilterType } from '~/v1/types/filters';
import { Button } from '../../button';
import { DropdownMenu } from '../../dropdown-menu';
import { FilterChip } from '../../filter-chip';
import { Flex } from '../../flex';
import { IconButton } from '../../icon-button';
import { DataTableColumn } from '../data-table.types';
import { useDataTable } from '../hooks/useDataTable';
import { useFilters } from '../hooks/useFilters';

interface AddFilterProps<TData, TValue> {
columnList: DataTableColumn<TData, TValue>[];
Expand All @@ -18,10 +18,10 @@ interface AddFilterProps<TData, TValue> {
function AddFilter<TData, TValue>({
columnList = [],
appliedFiltersSet,
onAddFilter,
onAddFilter
}: AddFilterProps<TData, TValue>) {
const availableFilters = columnList?.filter(
(col) => !appliedFiltersSet.has(col.id)
col => !appliedFiltersSet.has(col.id)
);

return availableFilters.length > 0 ? (
Expand All @@ -32,17 +32,17 @@ function AddFilter<TData, TValue>({
<FilterIcon />
</IconButton>
) : (
<Button variant={"text"} size={"small"} leadingIcon={<FilterIcon />}>
<Button variant={'text'} size={'small'} leadingIcon={<FilterIcon />}>
Filter
</Button>
)}
</DropdownMenu.Trigger>
<DropdownMenu.Content align="start">
{availableFilters?.map((column) => {
<DropdownMenu.Content>
{availableFilters?.map(column => {
const columnDef = column.columnDef;
const id = columnDef.accessorKey || column.id;
return (
<DropdownMenu.Item key={id} onSelect={() => onAddFilter(column)}>
<DropdownMenu.Item key={id} onClick={() => onAddFilter(column)}>
{columnDef.header || id}
</DropdownMenu.Item>
);
Expand All @@ -60,45 +60,43 @@ export function Filters<TData, TValue>() {
onAddFilter,
handleRemoveFilter,
handleFilterValueChange,
handleFilterOperationChange,
handleFilterOperationChange
} = useFilters<TData, TValue>();

const columnList = columns?.filter(
(column) => column.columnDef.enableColumnFilter
column => column.columnDef.enableColumnFilter
);

const appliedFiltersSet = new Set(
tableQuery?.filters?.map((filter) => filter.name)
tableQuery?.filters?.map(filter => filter.name)
);

const appliedFilters =
tableQuery?.filters?.map((filter) => {
const columnDef = columns?.find((col) => {
tableQuery?.filters?.map(filter => {
const columnDef = columns?.find(col => {
const columnDef = col.columnDef;
const id = columnDef.accessorKey || col.id;
return id === filter.name;
})?.columnDef;
return {
filterType: columnDef?.filterType || FilterType.string,
label: (columnDef?.header as string) || "",
label: (columnDef?.header as string) || '',
options: columnDef?.filterOptions || [],
...filter,
...filter
};
}) || [];

return (
<Flex gap={3}>
<Flex gap={3}>
{appliedFilters.map((filter) => (
{appliedFilters.map(filter => (
<FilterChip
key={filter.name}
label={filter.label}
value={filter.value}
onRemove={() => handleRemoveFilter(filter.name)}
onValueChange={(value) =>
handleFilterValueChange(filter.name, value)
}
onOperationChange={(operator) =>
onValueChange={value => handleFilterValueChange(filter.name, value)}
onOperationChange={operator =>
handleFilterOperationChange(
filter.name,
operator as FilterOperatorTypes
Expand Down