@douglasneuroinformatics/libui 4.4.0 → 4.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@douglasneuroinformatics/libui",
3
3
  "type": "module",
4
- "version": "4.4.0",
4
+ "version": "4.4.1",
5
5
  "packageManager": "pnpm@10.7.1",
6
6
  "description": "Generic UI components for DNP projects, built using React and Tailwind CSS",
7
7
  "author": "Joshua Unrau",
@@ -68,7 +68,7 @@
68
68
  "zod": "^3.25.x"
69
69
  },
70
70
  "dependencies": {
71
- "@douglasneuroinformatics/libjs": "^2.8.0",
71
+ "@douglasneuroinformatics/libjs": "^3.0.1",
72
72
  "@douglasneuroinformatics/libui-form-types": "^0.11.0",
73
73
  "@radix-ui/react-accordion": "^1.2.3",
74
74
  "@radix-ui/react-alert-dialog": "^1.1.6",
@@ -1,4 +1,4 @@
1
- import { range, toBasicISOString } from '@douglasneuroinformatics/libjs';
1
+ import { range, toBasicISOString, unwrap } from '@douglasneuroinformatics/libjs';
2
2
  import { faker } from '@faker-js/faker';
3
3
  import type { Meta, StoryObj } from '@storybook/react';
4
4
 
@@ -31,14 +31,12 @@ const columns: DataTableColumn<User>[] = [
31
31
  }
32
32
  ];
33
33
 
34
- const data: User[] = range(60)
35
- .unwrap()
36
- .map(() => ({
37
- birthday: faker.date.birthdate(),
38
- email: faker.internet.email(),
39
- firstName: faker.person.firstName(),
40
- lastName: faker.person.lastName()
41
- }));
34
+ const data: User[] = unwrap(range(60)).map(() => ({
35
+ birthday: faker.date.birthdate(),
36
+ email: faker.internet.email(),
37
+ firstName: faker.person.firstName(),
38
+ lastName: faker.person.lastName()
39
+ }));
42
40
 
43
41
  export default { component: DataTable } as Meta<typeof DataTable<User>>;
44
42
 
@@ -46,12 +44,14 @@ export const Default: Story = {
46
44
  args: {
47
45
  columns,
48
46
  data,
49
- headerAction: {
50
- label: 'Do Something',
51
- onClick: () => {
52
- alert('Something!');
47
+ headerActions: [
48
+ {
49
+ label: 'Do Something',
50
+ onClick: () => {
51
+ alert('Something!');
52
+ }
53
53
  }
54
- },
54
+ ],
55
55
  rowActions: [
56
56
  {
57
57
  destructive: true,
@@ -1,4 +1,4 @@
1
- import { Fragment, useEffect, useMemo, useState } from 'react';
1
+ import { useEffect, useMemo, useState } from 'react';
2
2
 
3
3
  import {
4
4
  flexRender,
@@ -45,10 +45,10 @@ type DataTableColumn<TData extends { [key: string]: unknown }> =
45
45
  type DataTableProps<TData extends { [key: string]: unknown }> = {
46
46
  columns: DataTableColumn<TData>[];
47
47
  data: TData[];
48
- headerAction?: {
48
+ headerActions?: {
49
49
  label: string;
50
50
  onClick: () => void;
51
- };
51
+ }[];
52
52
  rowActions?: RowAction<TData>[];
53
53
  search?: {
54
54
  key: Extract<keyof TData, string>;
@@ -65,7 +65,7 @@ function isStaticColumn<TData extends { [key: string]: unknown }>(
65
65
  export const DataTable = <TData extends { [key: string]: unknown }>({
66
66
  columns,
67
67
  data,
68
- headerAction,
68
+ headerActions,
69
69
  rowActions,
70
70
  search
71
71
  }: DataTableProps<TData>) => {
@@ -173,7 +173,7 @@ export const DataTable = <TData extends { [key: string]: unknown }>({
173
173
  const pageIndexOptions = range(start, end);
174
174
 
175
175
  return (
176
- <Fragment>
176
+ <div className="flex flex-col">
177
177
  <DestructiveActionDialog
178
178
  destructiveActionPending={destructiveActionPending}
179
179
  setDestructiveActionPending={setDestructiveActionPending}
@@ -186,10 +186,14 @@ export const DataTable = <TData extends { [key: string]: unknown }>({
186
186
  value={searchValue}
187
187
  onValueChange={setSearchValue}
188
188
  />
189
- {headerAction && (
190
- <Button type="button" variant="outline" onClick={headerAction.onClick}>
191
- {headerAction.label}
192
- </Button>
189
+ {headerActions && (
190
+ <div className="flex gap-2">
191
+ {headerActions.map(({ label, onClick }, i) => (
192
+ <Button key={i} type="button" variant="outline" onClick={onClick}>
193
+ {label}
194
+ </Button>
195
+ ))}
196
+ </div>
193
197
  )}
194
198
  </div>
195
199
  )}
@@ -230,30 +234,29 @@ export const DataTable = <TData extends { [key: string]: unknown }>({
230
234
  </Table.Body>
231
235
  </Table>
232
236
  </div>
233
- <div className="mx-auto flex w-min pt-6 pb-4">
237
+ <div className="flex w-min gap-0.5 py-4 [&>button]:h-9">
234
238
  <Button
235
- className="flex gap-1"
236
239
  disabled={!table.getCanPreviousPage()}
240
+ size="icon"
237
241
  type="button"
238
242
  variant="ghost"
239
243
  onClick={() => table.firstPage()}
240
244
  >
241
- <ChevronsLeftIcon className="-ml-1 h-4 w-4" />
242
- <span>{t('pagination.first')}</span>
245
+ <ChevronsLeftIcon className="h-4 w-4" />
243
246
  </Button>
244
247
  <Button
245
- className="mr-1 flex gap-1"
246
248
  disabled={!table.getCanPreviousPage()}
249
+ size="icon"
247
250
  type="button"
248
251
  variant="ghost"
249
252
  onClick={() => table.previousPage()}
250
253
  >
251
- <ChevronLeftIcon className="-ml-1 h-4 w-4" />
252
- <span>{t('pagination.previous')}</span>
254
+ <ChevronLeftIcon className="h-4 w-4" />
253
255
  </Button>
254
256
  {pageIndexOptions.map((index) => (
255
257
  <Button
256
258
  key={index}
259
+ size="icon"
257
260
  type="button"
258
261
  variant={index === pagination.pageIndex ? 'outline' : 'ghost'}
259
262
  onClick={() => table.setPageIndex(index)}
@@ -262,27 +265,25 @@ export const DataTable = <TData extends { [key: string]: unknown }>({
262
265
  </Button>
263
266
  ))}
264
267
  <Button
265
- className="ml-1 flex gap-1"
266
268
  disabled={!table.getCanNextPage()}
269
+ size="icon"
267
270
  type="button"
268
271
  variant="ghost"
269
272
  onClick={() => table.nextPage()}
270
273
  >
271
- <span>{t('pagination.next')}</span>
272
- <ChevronRightIcon className="-mr-1 h-4 w-4" />
274
+ <ChevronRightIcon className="h-4 w-4" />
273
275
  </Button>
274
276
  <Button
275
- className="flex gap-1"
276
277
  disabled={!table.getCanNextPage()}
278
+ size="icon"
277
279
  type="button"
278
280
  variant="ghost"
279
281
  onClick={() => table.lastPage()}
280
282
  >
281
- <span>{t('pagination.last')}</span>
282
- <ChevronsRightIcon className="-mr-1 h-4 w-4" />
283
+ <ChevronsRightIcon className="h-4 w-4" />
283
284
  </Button>
284
285
  </div>
285
- </Fragment>
286
+ </div>
286
287
  );
287
288
  };
288
289
 
@@ -1,5 +1,4 @@
1
1
  /* eslint-disable @typescript-eslint/no-misused-promises */
2
- /* eslint-disable jsx-a11y/no-autofocus */
3
2
 
4
3
  import type React from 'react';
5
4
 
@@ -26,7 +25,7 @@ export const DestructiveActionDialog: React.FC<{
26
25
  }
27
26
  }}
28
27
  >
29
- <Dialog.Content>
28
+ <Dialog.Content onOpenAutoFocus={(event) => event.preventDefault()}>
30
29
  <Dialog.Header>
31
30
  <Dialog.Title>
32
31
  {t({
@@ -44,9 +43,8 @@ export const DestructiveActionDialog: React.FC<{
44
43
  <Dialog.Footer>
45
44
  <Button
46
45
  className="min-w-16"
47
- size="sm"
48
46
  type="button"
49
- variant="outline"
47
+ variant="danger"
50
48
  onClick={async () => {
51
49
  await destructiveActionPending?.();
52
50
  setDestructiveActionPending(null);
@@ -55,9 +53,7 @@ export const DestructiveActionDialog: React.FC<{
55
53
  {t('libui.yes')}
56
54
  </Button>
57
55
  <Button
58
- autoFocus={true}
59
56
  className="min-w-16"
60
- size="sm"
61
57
  type="button"
62
58
  variant="primary"
63
59
  onClick={() => setDestructiveActionPending(null)}
@@ -3,6 +3,7 @@
3
3
  import { useEffect, useState } from 'react';
4
4
 
5
5
  import { sleep } from '@douglasneuroinformatics/libjs';
6
+ import type { ZodTypeLike } from '@douglasneuroinformatics/libjs';
6
7
  import type { FormFields } from '@douglasneuroinformatics/libui-form-types';
7
8
  import type FormTypes from '@douglasneuroinformatics/libui-form-types';
8
9
  import type { Meta, StoryObj } from '@storybook/react';
@@ -12,8 +13,6 @@ import { z } from 'zod/v4';
12
13
  import { Heading } from '../Heading';
13
14
  import { Form } from './Form';
14
15
 
15
- import type { ZodTypeLike } from './types';
16
-
17
16
  const DISABLED = false;
18
17
 
19
18
  const $ExampleFormData = z.object({
@@ -1,5 +1,6 @@
1
1
  import { useEffect, useState } from 'react';
2
2
 
3
+ import type { ZodErrorLike, ZodTypeLike } from '@douglasneuroinformatics/libjs';
3
4
  import type {
4
5
  FormContent,
5
6
  FormDataType,
@@ -21,9 +22,9 @@ import { ErrorMessage } from './ErrorMessage';
21
22
  import { FieldsComponent } from './FieldsComponent';
22
23
  import { getInitialValues } from './utils';
23
24
 
24
- import type { FormErrors, ZodErrorLike, ZodTypeLike } from './types';
25
+ import type { FormErrors } from './types';
25
26
 
26
- type FormProps<TSchema extends ZodTypeLike<FormDataType>, TData extends TSchema['_input'] = TSchema['_input']> = {
27
+ type FormProps<TSchema extends ZodTypeLike<FormDataType>, TData extends TSchema['_output'] = TSchema['_output']> = {
27
28
  [key: `data-${string}`]: unknown;
28
29
  additionalButtons?: {
29
30
  left?: React.ReactNode;
@@ -52,7 +53,7 @@ type FormProps<TSchema extends ZodTypeLike<FormDataType>, TData extends TSchema[
52
53
  validationSchema: ZodTypeLike<TData>;
53
54
  };
54
55
 
55
- const Form = <TSchema extends ZodTypeLike<FormDataType>, TData extends TSchema['_input'] = TSchema['_input']>({
56
+ const Form = <TSchema extends ZodTypeLike<FormDataType>, TData extends TSchema['_output'] = TSchema['_output']>({
56
57
  additionalButtons,
57
58
  className,
58
59
  content,
@@ -25,36 +25,3 @@ export type BaseFieldComponentProps<TValue extends FormFieldValue = FormFieldVal
25
25
  export type FormErrors<TData extends FormDataType = FormDataType> = {
26
26
  [K in keyof TData]?: FieldError<TData[K]>;
27
27
  };
28
-
29
- export type ZodIssueLike = {
30
- [key: string]: any;
31
- readonly code: string;
32
- readonly message: string;
33
- readonly path: PropertyKey[];
34
- };
35
-
36
- export type ZodErrorLike = {
37
- cause?: unknown;
38
- issues: ZodIssueLike[];
39
- name: string;
40
- };
41
-
42
- export type ZodSafeParseResultLike<T> = ZodSafeParseErrorLike | ZodSafeParseSuccessLike<T>;
43
-
44
- export type ZodSafeParseSuccessLike<TOutput> = {
45
- data: TOutput;
46
- error?: never;
47
- success: true;
48
- };
49
-
50
- export type ZodSafeParseErrorLike = {
51
- data?: never;
52
- error: ZodErrorLike;
53
- success: false;
54
- };
55
-
56
- export type ZodTypeLike<TOutput, TInput = TOutput> = {
57
- readonly _input: TInput;
58
- readonly _output: TOutput;
59
- safeParseAsync: (data: unknown) => Promise<ZodSafeParseResultLike<TOutput>>;
60
- };
@@ -14,6 +14,7 @@ export * from './Collapsible';
14
14
  export * from './Command';
15
15
  export * from './ContextMenu';
16
16
  export * from './CopyButton';
17
+ export * from './DataTable';
17
18
  export * from './DatePicker';
18
19
  export * from './Dialog';
19
20
  export * from './Drawer';