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
2 changes: 1 addition & 1 deletion .storybook/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Meta } from '@storybook/blocks';

<Meta title="Welcome" />

# Welcome to the Douglasneuroinformatics UI Library
# Welcome to the DouglasNeuroinformatics UI Library

This library includes generic UI components built using shadcn/ui with React and TailwindCSS.

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
"zod": "^3.25.x"
},
"dependencies": {
"@douglasneuroinformatics/libjs": "^2.8.0",
"@douglasneuroinformatics/libjs": "^3.0.1",
"@douglasneuroinformatics/libui-form-types": "^0.11.0",
"@radix-ui/react-accordion": "^1.2.3",
"@radix-ui/react-alert-dialog": "^1.1.6",
Expand Down
12 changes: 6 additions & 6 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 14 additions & 14 deletions src/components/DataTable/DataTable.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { range, toBasicISOString } from '@douglasneuroinformatics/libjs';
import { range, toBasicISOString, unwrap } from '@douglasneuroinformatics/libjs';
import { faker } from '@faker-js/faker';
import type { Meta, StoryObj } from '@storybook/react';

Expand Down Expand Up @@ -31,27 +31,27 @@ const columns: DataTableColumn<User>[] = [
}
];

const data: User[] = range(60)
.unwrap()
.map(() => ({
birthday: faker.date.birthdate(),
email: faker.internet.email(),
firstName: faker.person.firstName(),
lastName: faker.person.lastName()
}));
const data: User[] = unwrap(range(60)).map(() => ({
birthday: faker.date.birthdate(),
email: faker.internet.email(),
firstName: faker.person.firstName(),
lastName: faker.person.lastName()
}));

export default { component: DataTable } as Meta<typeof DataTable<User>>;

export const Default: Story = {
args: {
columns,
data,
headerAction: {
label: 'Do Something',
onClick: () => {
alert('Something!');
headerActions: [
{
label: 'Do Something',
onClick: () => {
alert('Something!');
}
}
},
],
rowActions: [
{
destructive: true,
Expand Down
47 changes: 24 additions & 23 deletions src/components/DataTable/DataTable.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Fragment, useEffect, useMemo, useState } from 'react';
import { useEffect, useMemo, useState } from 'react';

import {
flexRender,
Expand Down Expand Up @@ -45,10 +45,10 @@ type DataTableColumn<TData extends { [key: string]: unknown }> =
type DataTableProps<TData extends { [key: string]: unknown }> = {
columns: DataTableColumn<TData>[];
data: TData[];
headerAction?: {
headerActions?: {
label: string;
onClick: () => void;
};
}[];
rowActions?: RowAction<TData>[];
search?: {
key: Extract<keyof TData, string>;
Expand All @@ -65,7 +65,7 @@ function isStaticColumn<TData extends { [key: string]: unknown }>(
export const DataTable = <TData extends { [key: string]: unknown }>({
columns,
data,
headerAction,
headerActions,
rowActions,
search
}: DataTableProps<TData>) => {
Expand Down Expand Up @@ -173,7 +173,7 @@ export const DataTable = <TData extends { [key: string]: unknown }>({
const pageIndexOptions = range(start, end);

return (
<Fragment>
<div className="flex flex-col">
<DestructiveActionDialog
destructiveActionPending={destructiveActionPending}
setDestructiveActionPending={setDestructiveActionPending}
Expand All @@ -186,10 +186,14 @@ export const DataTable = <TData extends { [key: string]: unknown }>({
value={searchValue}
onValueChange={setSearchValue}
/>
{headerAction && (
<Button type="button" variant="outline" onClick={headerAction.onClick}>
{headerAction.label}
</Button>
{headerActions && (
<div className="flex gap-2">
{headerActions.map(({ label, onClick }, i) => (
<Button key={i} type="button" variant="outline" onClick={onClick}>
{label}
</Button>
))}
</div>
)}
</div>
)}
Expand Down Expand Up @@ -230,30 +234,29 @@ export const DataTable = <TData extends { [key: string]: unknown }>({
</Table.Body>
</Table>
</div>
<div className="mx-auto flex w-min pt-6 pb-4">
<div className="flex w-min gap-0.5 py-4 [&>button]:h-9">
<Button
className="flex gap-1"
disabled={!table.getCanPreviousPage()}
size="icon"
type="button"
variant="ghost"
onClick={() => table.firstPage()}
>
<ChevronsLeftIcon className="-ml-1 h-4 w-4" />
<span>{t('pagination.first')}</span>
<ChevronsLeftIcon className="h-4 w-4" />
</Button>
<Button
className="mr-1 flex gap-1"
disabled={!table.getCanPreviousPage()}
size="icon"
type="button"
variant="ghost"
onClick={() => table.previousPage()}
>
<ChevronLeftIcon className="-ml-1 h-4 w-4" />
<span>{t('pagination.previous')}</span>
<ChevronLeftIcon className="h-4 w-4" />
</Button>
{pageIndexOptions.map((index) => (
<Button
key={index}
size="icon"
type="button"
variant={index === pagination.pageIndex ? 'outline' : 'ghost'}
onClick={() => table.setPageIndex(index)}
Expand All @@ -262,27 +265,25 @@ export const DataTable = <TData extends { [key: string]: unknown }>({
</Button>
))}
<Button
className="ml-1 flex gap-1"
disabled={!table.getCanNextPage()}
size="icon"
type="button"
variant="ghost"
onClick={() => table.nextPage()}
>
<span>{t('pagination.next')}</span>
<ChevronRightIcon className="-mr-1 h-4 w-4" />
<ChevronRightIcon className="h-4 w-4" />
</Button>
<Button
className="flex gap-1"
disabled={!table.getCanNextPage()}
size="icon"
type="button"
variant="ghost"
onClick={() => table.lastPage()}
>
<span>{t('pagination.last')}</span>
<ChevronsRightIcon className="-mr-1 h-4 w-4" />
<ChevronsRightIcon className="h-4 w-4" />
</Button>
</div>
</Fragment>
</div>
);
};

Expand Down
8 changes: 2 additions & 6 deletions src/components/DataTable/DestructiveActionDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
/* eslint-disable @typescript-eslint/no-misused-promises */
/* eslint-disable jsx-a11y/no-autofocus */

import type React from 'react';

Expand All @@ -26,7 +25,7 @@ export const DestructiveActionDialog: React.FC<{
}
}}
>
<Dialog.Content>
<Dialog.Content onOpenAutoFocus={(event) => event.preventDefault()}>
<Dialog.Header>
<Dialog.Title>
{t({
Expand All @@ -44,9 +43,8 @@ export const DestructiveActionDialog: React.FC<{
<Dialog.Footer>
<Button
className="min-w-16"
size="sm"
type="button"
variant="outline"
variant="danger"
onClick={async () => {
await destructiveActionPending?.();
setDestructiveActionPending(null);
Expand All @@ -55,9 +53,7 @@ export const DestructiveActionDialog: React.FC<{
{t('libui.yes')}
</Button>
<Button
autoFocus={true}
className="min-w-16"
size="sm"
type="button"
variant="primary"
onClick={() => setDestructiveActionPending(null)}
Expand Down
3 changes: 1 addition & 2 deletions src/components/Form/Form.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { useEffect, useState } from 'react';

import { sleep } from '@douglasneuroinformatics/libjs';
import type { ZodTypeLike } from '@douglasneuroinformatics/libjs';
import type { FormFields } from '@douglasneuroinformatics/libui-form-types';
import type FormTypes from '@douglasneuroinformatics/libui-form-types';
import type { Meta, StoryObj } from '@storybook/react';
Expand All @@ -12,8 +13,6 @@ import { z } from 'zod/v4';
import { Heading } from '../Heading';
import { Form } from './Form';

import type { ZodTypeLike } from './types';

const DISABLED = false;

const $ExampleFormData = z.object({
Expand Down
7 changes: 4 additions & 3 deletions src/components/Form/Form.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useEffect, useState } from 'react';

import type { ZodErrorLike, ZodTypeLike } from '@douglasneuroinformatics/libjs';
import type {
FormContent,
FormDataType,
Expand All @@ -21,9 +22,9 @@ import { ErrorMessage } from './ErrorMessage';
import { FieldsComponent } from './FieldsComponent';
import { getInitialValues } from './utils';

import type { FormErrors, ZodErrorLike, ZodTypeLike } from './types';
import type { FormErrors } from './types';

type FormProps<TSchema extends ZodTypeLike<FormDataType>, TData extends TSchema['_input'] = TSchema['_input']> = {
type FormProps<TSchema extends ZodTypeLike<FormDataType>, TData extends TSchema['_output'] = TSchema['_output']> = {
[key: `data-${string}`]: unknown;
additionalButtons?: {
left?: React.ReactNode;
Expand Down Expand Up @@ -52,7 +53,7 @@ type FormProps<TSchema extends ZodTypeLike<FormDataType>, TData extends TSchema[
validationSchema: ZodTypeLike<TData>;
};

const Form = <TSchema extends ZodTypeLike<FormDataType>, TData extends TSchema['_input'] = TSchema['_input']>({
const Form = <TSchema extends ZodTypeLike<FormDataType>, TData extends TSchema['_output'] = TSchema['_output']>({
additionalButtons,
className,
content,
Expand Down
33 changes: 0 additions & 33 deletions src/components/Form/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,36 +25,3 @@ export type BaseFieldComponentProps<TValue extends FormFieldValue = FormFieldVal
export type FormErrors<TData extends FormDataType = FormDataType> = {
[K in keyof TData]?: FieldError<TData[K]>;
};

export type ZodIssueLike = {
[key: string]: any;
readonly code: string;
readonly message: string;
readonly path: PropertyKey[];
};

export type ZodErrorLike = {
cause?: unknown;
issues: ZodIssueLike[];
name: string;
};

export type ZodSafeParseResultLike<T> = ZodSafeParseErrorLike | ZodSafeParseSuccessLike<T>;

export type ZodSafeParseSuccessLike<TOutput> = {
data: TOutput;
error?: never;
success: true;
};

export type ZodSafeParseErrorLike = {
data?: never;
error: ZodErrorLike;
success: false;
};

export type ZodTypeLike<TOutput, TInput = TOutput> = {
readonly _input: TInput;
readonly _output: TOutput;
safeParseAsync: (data: unknown) => Promise<ZodSafeParseResultLike<TOutput>>;
};
1 change: 1 addition & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export * from './Collapsible';
export * from './Command';
export * from './ContextMenu';
export * from './CopyButton';
export * from './DataTable';
export * from './DatePicker';
export * from './Dialog';
export * from './Drawer';
Expand Down