@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/dist/components.d.ts +51 -31
- package/dist/components.js +948 -651
- package/dist/components.js.map +1 -1
- package/package.json +2 -2
- package/src/components/DataTable/DataTable.stories.tsx +14 -14
- package/src/components/DataTable/DataTable.tsx +24 -23
- package/src/components/DataTable/DestructiveActionDialog.tsx +2 -6
- package/src/components/Form/Form.stories.tsx +1 -2
- package/src/components/Form/Form.tsx +4 -3
- package/src/components/Form/types.ts +0 -33
- package/src/components/index.ts +1 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@douglasneuroinformatics/libui",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "4.4.
|
|
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": "^
|
|
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
|
-
.
|
|
36
|
-
.
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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 {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
<
|
|
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
|
-
{
|
|
190
|
-
<
|
|
191
|
-
{
|
|
192
|
-
|
|
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="
|
|
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="
|
|
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="
|
|
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
|
-
<
|
|
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
|
-
<
|
|
282
|
-
<ChevronsRightIcon className="-mr-1 h-4 w-4" />
|
|
283
|
+
<ChevronsRightIcon className="h-4 w-4" />
|
|
283
284
|
</Button>
|
|
284
285
|
</div>
|
|
285
|
-
</
|
|
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="
|
|
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
|
|
25
|
+
import type { FormErrors } from './types';
|
|
25
26
|
|
|
26
|
-
type FormProps<TSchema extends ZodTypeLike<FormDataType>, TData extends TSchema['
|
|
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['
|
|
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
|
-
};
|
package/src/components/index.ts
CHANGED