@douglasneuroinformatics/libui 3.8.7 → 4.0.0
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/README.md +7 -9
- package/dist/{chunk-CAWCERN4.js → chunk-655XRTXX.js} +10 -2
- package/dist/{chunk-CAWCERN4.js.map → chunk-655XRTXX.js.map} +1 -1
- package/dist/{chunk-VJSOLDCS.js → chunk-HCQE34RL.js} +1 -1
- package/dist/chunk-HCQE34RL.js.map +1 -0
- package/dist/{chunk-GFIT4FAN.js → chunk-KI6BSSS6.js} +3 -4
- package/dist/chunk-KI6BSSS6.js.map +1 -0
- package/dist/components.d.ts +137 -89
- package/dist/components.js +111 -77
- package/dist/components.js.map +1 -1
- package/dist/hooks.d.ts +1 -1
- package/dist/hooks.js +3 -3
- package/dist/i18n.d.ts +2 -2
- package/dist/i18n.js +1 -1
- package/dist/tailwind/globals.css +181 -39
- package/dist/{types-DTkK8l-q.d.ts → types-CMuti1SJ.d.ts} +14 -6
- package/dist/utils.js +1 -1
- package/package.json +89 -86
- package/src/components/ActionDropdown/ActionDropdown.tsx +1 -1
- package/src/components/ArrowToggle/ArrowToggle.spec.tsx +3 -1
- package/src/components/ArrowToggle/ArrowToggle.tsx +5 -3
- package/src/components/Badge/Badge.tsx +7 -5
- package/src/components/Breadcrumb/BreadcrumbLink.tsx +2 -2
- package/src/components/Breadcrumb/BreadcrumbRoot.tsx +2 -2
- package/src/components/Button/Button.tsx +13 -12
- package/src/components/Card/Card.tsx +3 -3
- package/src/components/Chart/ChartContainer.tsx +3 -3
- package/src/components/Chart/ChartLegendContent.tsx +5 -5
- package/src/components/Chart/ChartTooltipContent.tsx +8 -8
- package/src/components/Checkbox/Checkbox.tsx +1 -1
- package/src/components/ClientTable/ClientTable.spec.tsx +87 -0
- package/src/components/ClientTable/ClientTable.stories.tsx +12 -9
- package/src/components/ClientTable/ClientTable.tsx +5 -4
- package/src/components/ClientTable/ClientTablePagination.tsx +28 -1
- package/src/components/Collapsible/Collapsible.stories.tsx +3 -3
- package/src/components/Command/CommandInput.tsx +1 -1
- package/src/components/Command/CommandItem.tsx +1 -1
- package/src/components/ContextMenu/ContextMenuCheckboxItem.tsx +1 -1
- package/src/components/ContextMenu/ContextMenuItem.tsx +3 -3
- package/src/components/ContextMenu/ContextMenuLabel.tsx +2 -2
- package/src/components/ContextMenu/ContextMenuRadioItem.tsx +1 -1
- package/src/components/ContextMenu/ContextMenuSubTrigger.tsx +3 -3
- package/src/components/CopyButton/CopyButton.tsx +3 -1
- package/src/components/DatePicker/DatePicker.tsx +3 -3
- package/src/components/Dialog/DialogContent.tsx +2 -2
- package/src/components/DropdownButton/DropdownButton.tsx +1 -1
- package/src/components/DropdownMenu/DropdownMenuCheckboxItem.tsx +1 -1
- package/src/components/DropdownMenu/DropdownMenuContent.tsx +2 -2
- package/src/components/DropdownMenu/DropdownMenuItem.tsx +3 -3
- package/src/components/DropdownMenu/DropdownMenuLabel.tsx +2 -2
- package/src/components/DropdownMenu/DropdownMenuRadioItem.tsx +1 -1
- package/src/components/DropdownMenu/DropdownMenuSubTrigger.tsx +3 -3
- package/src/components/FileDropzone/FileDropzone.stories.tsx +4 -6
- package/src/components/FileDropzone/FileDropzone.tsx +2 -1
- package/src/components/Form/BaseRadioField.tsx +2 -2
- package/src/components/Form/BooleanField/BooleanField.spec.tsx +3 -1
- package/src/components/Form/BooleanField/BooleanField.tsx +5 -2
- package/src/components/Form/DateField/DateField.tsx +2 -1
- package/src/components/Form/Form.stories.tsx +15 -16
- package/src/components/Form/Form.tsx +0 -1
- package/src/components/Form/NumberField/NumberField.tsx +7 -3
- package/src/components/Form/NumberField/NumberFieldSelect.tsx +2 -1
- package/src/components/Form/RecordArrayField.tsx +1 -3
- package/src/components/Form/ScalarField.tsx +18 -13
- package/src/components/Form/SetField/SetFieldListbox.tsx +2 -2
- package/src/components/Form/SetField/SetFieldSelect.tsx +2 -2
- package/src/components/Form/StaticField.tsx +2 -1
- package/src/components/Form/StringField/StringField.tsx +9 -4
- package/src/components/Form/StringField/StringFieldPassword.tsx +5 -5
- package/src/components/Form/StringField/StringFieldSelect.tsx +2 -1
- package/src/components/HoverCard/HoverCardContent.tsx +1 -1
- package/src/components/Input/Input.tsx +1 -1
- package/src/components/Label/Label.tsx +2 -1
- package/src/components/LanguageToggle/LanguageToggle.tsx +3 -1
- package/src/components/LineGraph/LineGraph.tsx +8 -4
- package/src/components/ListboxDropdown/ListboxDropdown.stories.tsx +4 -4
- package/src/components/ListboxDropdown/ListboxDropdown.tsx +2 -1
- package/src/components/MenuBar/MenuBarCheckboxItem.tsx +1 -1
- package/src/components/MenuBar/MenuBarItem.tsx +3 -3
- package/src/components/MenuBar/MenuBarLabel.tsx +2 -2
- package/src/components/MenuBar/MenuBarRadioItem.tsx +1 -1
- package/src/components/MenuBar/MenuBarRoot.tsx +1 -1
- package/src/components/MenuBar/MenuBarSubTrigger.tsx +3 -3
- package/src/components/MenuBar/MenuBarTrigger.tsx +1 -1
- package/src/components/NotificationHub/NotificationHub.tsx +3 -3
- package/src/components/NotificationHub/NotificationIcon.tsx +1 -1
- package/src/components/Pagination/PaginationLink.tsx +7 -5
- package/src/components/Pagination/PaginationPrevious.tsx +3 -1
- package/src/components/Popover/PopoverContent.tsx +1 -1
- package/src/components/RadioGroup/RadioGroup.spec.tsx +3 -1
- package/src/components/RadioGroup/RadioGroupItem.tsx +1 -1
- package/src/components/Resizable/Resizable.tsx +9 -5
- package/src/components/Resizable/ResizableHandle.tsx +4 -4
- package/src/components/SearchBar/SearchBar.tsx +7 -5
- package/src/components/Select/SelectItem.tsx +1 -1
- package/src/components/Sheet/SheetContent.tsx +3 -2
- package/src/components/Slider/Slider.tsx +4 -4
- package/src/components/StatisticCard/StatisticCard.tsx +2 -1
- package/src/components/Switch/Switch.tsx +2 -2
- package/src/components/Tabs/TabsContent.tsx +1 -1
- package/src/components/Tabs/TabsTrigger.tsx +1 -1
- package/src/components/TextArea/TextArea.tsx +1 -1
- package/src/components/ThemeToggle/ThemeToggle.tsx +3 -1
- package/src/components/Tooltip/TooltipTrigger.tsx +3 -1
- package/src/hooks/useEventListener/useEventListener.ts +2 -1
- package/src/hooks/useOnClickOutside/useOnClickOutside.ts +1 -1
- package/src/hooks/useStorage/useLocalStorage.ts +3 -1
- package/src/hooks/useStorage/useSessionStorage.ts +3 -1
- package/src/hooks/useTheme/useTheme.test.ts +14 -11
- package/src/i18n/internal.ts +1 -1
- package/src/i18n/store.ts +1 -1
- package/src/i18n/translations/libui.json +8 -0
- package/src/i18n/types.ts +6 -6
- package/src/tailwind/globals.css +181 -39
- package/src/utils/index.ts +2 -1
- package/dist/chunk-GFIT4FAN.js.map +0 -1
- package/dist/chunk-VJSOLDCS.js.map +0 -1
- package/dist/douglasneuroinformatics-libui-3.8.7.tgz +0 -0
- package/dist/tailwind/config.cjs +0 -178
- package/dist/tailwind/config.cjs.map +0 -1
- package/dist/tailwind/config.d.cts +0 -16
- package/src/tailwind/config.cts +0 -174
- package/tailwind.config.cjs +0 -3
|
@@ -7,14 +7,14 @@ import { cn } from '@/utils';
|
|
|
7
7
|
|
|
8
8
|
export const DropdownMenuSubTrigger = forwardRef<
|
|
9
9
|
React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
|
|
10
|
-
{
|
|
10
|
+
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
|
|
11
11
|
inset?: boolean;
|
|
12
|
-
}
|
|
12
|
+
}
|
|
13
13
|
>(function DropdownMenuSubTrigger({ children, className, inset, ...props }, ref) {
|
|
14
14
|
return (
|
|
15
15
|
<DropdownMenuPrimitive.SubTrigger
|
|
16
16
|
className={cn(
|
|
17
|
-
'flex cursor-default
|
|
17
|
+
'focus:bg-accent data-[state=open]:bg-accent flex cursor-default items-center rounded-xs px-2 py-1.5 text-sm outline-hidden select-none',
|
|
18
18
|
inset && 'pl-8',
|
|
19
19
|
className
|
|
20
20
|
)}
|
|
@@ -4,14 +4,12 @@ import type { Meta, StoryObj } from '@storybook/react';
|
|
|
4
4
|
|
|
5
5
|
import { FileDropzone } from './FileDropzone.js';
|
|
6
6
|
|
|
7
|
-
const meta: Meta<typeof FileDropzone> = {
|
|
8
|
-
component: FileDropzone
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export default meta;
|
|
12
|
-
|
|
13
7
|
type Story = StoryObj<typeof FileDropzone>;
|
|
14
8
|
|
|
9
|
+
export default {
|
|
10
|
+
component: FileDropzone
|
|
11
|
+
} satisfies Meta<typeof FileDropzone>;
|
|
12
|
+
|
|
15
13
|
export const Default: Story = {
|
|
16
14
|
decorators: [
|
|
17
15
|
(Story) => {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { useCallback } from 'react';
|
|
2
2
|
|
|
3
3
|
import { UploadIcon } from 'lucide-react';
|
|
4
|
-
import {
|
|
4
|
+
import { useDropzone } from 'react-dropzone';
|
|
5
|
+
import type { FileRejection } from 'react-dropzone';
|
|
5
6
|
|
|
6
7
|
import { useTranslation } from '@/hooks/useTranslation';
|
|
7
8
|
import { cn } from '@/utils';
|
|
@@ -20,13 +20,13 @@ const baseRadioFieldVariants = cva('flex', {
|
|
|
20
20
|
});
|
|
21
21
|
|
|
22
22
|
export type BaseRadioFieldProps<T extends string> = Simplify<
|
|
23
|
-
{
|
|
23
|
+
BaseFieldComponentProps<T> & {
|
|
24
24
|
description?: string;
|
|
25
25
|
disabled?: boolean;
|
|
26
26
|
label: string;
|
|
27
27
|
options: { [K in T]: string };
|
|
28
28
|
orientation?: 'horizontal' | 'vertical';
|
|
29
|
-
}
|
|
29
|
+
}
|
|
30
30
|
>;
|
|
31
31
|
|
|
32
32
|
export const BaseRadioField = <T extends string>({
|
|
@@ -3,7 +3,9 @@ import { useState } from 'react';
|
|
|
3
3
|
import { render, screen } from '@testing-library/react';
|
|
4
4
|
import { describe, expect, it } from 'vitest';
|
|
5
5
|
|
|
6
|
-
import { BooleanField
|
|
6
|
+
import { BooleanField } from './BooleanField';
|
|
7
|
+
|
|
8
|
+
import type { BooleanFieldProps } from './BooleanField';
|
|
7
9
|
|
|
8
10
|
const TestBooleanField = ({ variant }: Pick<BooleanFieldProps, 'variant'>) => {
|
|
9
11
|
const [error, setError] = useState<string[] | undefined>();
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { match } from 'ts-pattern';
|
|
2
2
|
|
|
3
|
-
import { BooleanFieldCheckbox
|
|
4
|
-
import { BooleanFieldRadio
|
|
3
|
+
import { BooleanFieldCheckbox } from './BooleanFieldCheckbox';
|
|
4
|
+
import { BooleanFieldRadio } from './BooleanFieldRadio';
|
|
5
|
+
|
|
6
|
+
import type { BooleanFieldCheckboxProps } from './BooleanFieldCheckbox';
|
|
7
|
+
import type { BooleanFieldRadioProps } from './BooleanFieldRadio';
|
|
5
8
|
|
|
6
9
|
export type BooleanFieldProps = BooleanFieldCheckboxProps | BooleanFieldRadioProps;
|
|
7
10
|
|
|
@@ -10,7 +10,8 @@ import { Label } from '@/components/Label';
|
|
|
10
10
|
import { Popover } from '@/components/Popover';
|
|
11
11
|
|
|
12
12
|
import { FieldGroup } from '../FieldGroup';
|
|
13
|
-
|
|
13
|
+
|
|
14
|
+
import type { BaseFieldComponentProps } from '../types';
|
|
14
15
|
|
|
15
16
|
const isValidDateString = (s: string) => /^(\d{4})-((0[1-9])|(1[0-2]))-((0[1-9])|([12])[0-9]|3[01])$/.test(s);
|
|
16
17
|
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/* eslint-disable max-lines */
|
|
2
1
|
/* eslint-disable perfectionist/sort-objects */
|
|
3
2
|
|
|
4
3
|
import { useEffect, useState } from 'react';
|
|
@@ -57,21 +56,6 @@ const $SimpleExampleFormData = z.object({
|
|
|
57
56
|
});
|
|
58
57
|
type SimpleExampleFormSchemaType = typeof $SimpleExampleFormData;
|
|
59
58
|
|
|
60
|
-
export default {
|
|
61
|
-
component: Form,
|
|
62
|
-
decorators: [
|
|
63
|
-
(Story) => (
|
|
64
|
-
<div className="container mx-auto max-w-5xl">
|
|
65
|
-
<Heading className="my-8 text-center" variant="h1">
|
|
66
|
-
Example Form
|
|
67
|
-
</Heading>
|
|
68
|
-
<Story />
|
|
69
|
-
</div>
|
|
70
|
-
)
|
|
71
|
-
],
|
|
72
|
-
tags: ['autodocs']
|
|
73
|
-
} as Meta<typeof Form>;
|
|
74
|
-
|
|
75
59
|
const booleanFields: FormFields<Pick<ExampleFormData, 'booleanCheck' | 'booleanRadio'>> = {
|
|
76
60
|
booleanRadio: {
|
|
77
61
|
disabled: DISABLED,
|
|
@@ -317,6 +301,21 @@ const ungroupedContent = {
|
|
|
317
301
|
...recordArrayFields
|
|
318
302
|
} as const;
|
|
319
303
|
|
|
304
|
+
export default {
|
|
305
|
+
component: Form,
|
|
306
|
+
decorators: [
|
|
307
|
+
(Story) => (
|
|
308
|
+
<div className="container mx-auto max-w-5xl">
|
|
309
|
+
<Heading className="my-8 text-center" variant="h1">
|
|
310
|
+
Example Form
|
|
311
|
+
</Heading>
|
|
312
|
+
<Story />
|
|
313
|
+
</div>
|
|
314
|
+
)
|
|
315
|
+
],
|
|
316
|
+
tags: ['autodocs']
|
|
317
|
+
} as Meta<typeof Form>;
|
|
318
|
+
|
|
320
319
|
export const Grouped: StoryObj<typeof Form<ExampleFormSchemaType>> = {
|
|
321
320
|
args: {
|
|
322
321
|
content: [
|
|
@@ -45,7 +45,6 @@ type FormProps<TSchema extends z.ZodType<FormDataType>, TData extends z.TypeOf<T
|
|
|
45
45
|
validationSchema: z.ZodType<TData>;
|
|
46
46
|
};
|
|
47
47
|
|
|
48
|
-
// eslint-disable-next-line max-lines-per-function
|
|
49
48
|
const Form = <TSchema extends z.ZodType<FormDataType>, TData extends z.TypeOf<TSchema> = z.TypeOf<TSchema>>({
|
|
50
49
|
additionalButtons,
|
|
51
50
|
className,
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { match } from 'ts-pattern';
|
|
2
2
|
|
|
3
|
-
import { NumberFieldInput
|
|
4
|
-
import { NumberFieldRadio
|
|
3
|
+
import { NumberFieldInput } from './NumberFieldInput';
|
|
4
|
+
import { NumberFieldRadio } from './NumberFieldRadio';
|
|
5
5
|
import { NumberFieldSelect } from './NumberFieldSelect';
|
|
6
|
-
import { NumberFieldSlider
|
|
6
|
+
import { NumberFieldSlider } from './NumberFieldSlider';
|
|
7
|
+
|
|
8
|
+
import type { NumberFieldInputProps } from './NumberFieldInput';
|
|
9
|
+
import type { NumberFieldRadioProps } from './NumberFieldRadio';
|
|
10
|
+
import type { NumberFieldSliderProps } from './NumberFieldSlider';
|
|
7
11
|
|
|
8
12
|
export type NumberFieldProps = NumberFieldInputProps | NumberFieldRadioProps | NumberFieldSliderProps;
|
|
9
13
|
|
|
@@ -5,7 +5,8 @@ import { Label } from '@/components/Label';
|
|
|
5
5
|
import { Select } from '@/components/Select';
|
|
6
6
|
|
|
7
7
|
import { FieldGroup } from '../FieldGroup';
|
|
8
|
-
|
|
8
|
+
|
|
9
|
+
import type { BaseFieldComponentProps } from '../types';
|
|
9
10
|
|
|
10
11
|
export type NumberFieldSelectProps<T extends number = number> = Simplify<
|
|
11
12
|
BaseFieldComponentProps<T> & Extract<NumberFormField<T>, { options: object }>
|
|
@@ -85,9 +85,7 @@ export const RecordArrayField = memo(function RecordArrayField({
|
|
|
85
85
|
readOnly={disabled || readOnly}
|
|
86
86
|
setError={(error) => {
|
|
87
87
|
const newArrayError = arrayError ? [...arrayError] : [];
|
|
88
|
-
|
|
89
|
-
newArrayError[i] = {};
|
|
90
|
-
}
|
|
88
|
+
newArrayError[i] ??= {};
|
|
91
89
|
newArrayError[i][name] = error;
|
|
92
90
|
setArrayError(newArrayError);
|
|
93
91
|
}}
|
|
@@ -7,30 +7,35 @@ import type {
|
|
|
7
7
|
StringFormField
|
|
8
8
|
} from '@douglasneuroinformatics/libui-form-types';
|
|
9
9
|
|
|
10
|
-
import { BooleanField
|
|
11
|
-
import { DateField
|
|
12
|
-
import { NumberField
|
|
13
|
-
import { SetField
|
|
14
|
-
import { StringField
|
|
10
|
+
import { BooleanField } from './BooleanField';
|
|
11
|
+
import { DateField } from './DateField';
|
|
12
|
+
import { NumberField } from './NumberField';
|
|
13
|
+
import { SetField } from './SetField';
|
|
14
|
+
import { StringField } from './StringField';
|
|
15
15
|
|
|
16
|
+
import type { BooleanFieldProps } from './BooleanField';
|
|
17
|
+
import type { DateFieldProps } from './DateField';
|
|
18
|
+
import type { NumberFieldProps } from './NumberField';
|
|
19
|
+
import type { SetFieldProps } from './SetField';
|
|
20
|
+
import type { StringFieldProps } from './StringField';
|
|
16
21
|
import type { BaseFieldComponentProps } from './types';
|
|
17
22
|
|
|
18
|
-
export type ScalarFieldProps = {
|
|
23
|
+
export type ScalarFieldProps = BaseFieldComponentProps<ScalarFieldValue> & {
|
|
19
24
|
field: BooleanFormField | DateFormField | NumberFormField | SetFormField | StringFormField;
|
|
20
|
-
}
|
|
25
|
+
};
|
|
21
26
|
|
|
22
27
|
export const ScalarField = ({ field, ...props }: ScalarFieldProps) => {
|
|
23
28
|
switch (field.kind) {
|
|
24
|
-
case 'string':
|
|
25
|
-
return <StringField {...field} {...(props as StringFieldProps)} />;
|
|
26
|
-
case 'number':
|
|
27
|
-
return <NumberField {...field} {...(props as NumberFieldProps)} />;
|
|
28
|
-
case 'date':
|
|
29
|
-
return <DateField {...field} {...(props as DateFieldProps)} />;
|
|
30
29
|
case 'boolean':
|
|
31
30
|
return <BooleanField {...field} {...(props as BooleanFieldProps)} />;
|
|
31
|
+
case 'date':
|
|
32
|
+
return <DateField {...field} {...(props as DateFieldProps)} />;
|
|
33
|
+
case 'number':
|
|
34
|
+
return <NumberField {...field} {...(props as NumberFieldProps)} />;
|
|
32
35
|
case 'set':
|
|
33
36
|
return <SetField {...field} {...(props as SetFieldProps)} />;
|
|
37
|
+
case 'string':
|
|
38
|
+
return <StringField {...field} {...(props as StringFieldProps)} />;
|
|
34
39
|
default:
|
|
35
40
|
throw new Error(`Unexpected value for kind: ${Reflect.get(field, 'kind') satisfies never}`);
|
|
36
41
|
}
|
|
@@ -5,9 +5,9 @@ import { FieldGroup } from '../FieldGroup';
|
|
|
5
5
|
|
|
6
6
|
import type { SetFieldProps } from './SetField';
|
|
7
7
|
|
|
8
|
-
export type SetFieldListboxProps<T extends string = string> = {
|
|
8
|
+
export type SetFieldListboxProps<T extends string = string> = SetFieldProps<T> & {
|
|
9
9
|
onCheckedChange: (option: T, isChecked: boolean) => void;
|
|
10
|
-
}
|
|
10
|
+
};
|
|
11
11
|
|
|
12
12
|
export const SetFieldListbox = <T extends string = string>({
|
|
13
13
|
description,
|
|
@@ -7,9 +7,9 @@ import { FieldGroup } from '../FieldGroup';
|
|
|
7
7
|
|
|
8
8
|
import type { SetFieldProps } from './SetField';
|
|
9
9
|
|
|
10
|
-
export type SetFieldSelectProps<T extends string = string> = {
|
|
10
|
+
export type SetFieldSelectProps<T extends string = string> = SetFieldProps<T> & {
|
|
11
11
|
onCheckedChange: (option: T, isChecked: boolean) => void;
|
|
12
|
-
}
|
|
12
|
+
};
|
|
13
13
|
|
|
14
14
|
export const SetFieldSelect = <T extends string = string>({
|
|
15
15
|
description,
|
|
@@ -15,8 +15,9 @@ import { match } from 'ts-pattern';
|
|
|
15
15
|
|
|
16
16
|
import { NumberRecordField } from './NumberRecordField';
|
|
17
17
|
import { RecordArrayField } from './RecordArrayField';
|
|
18
|
-
import { ScalarField
|
|
18
|
+
import { ScalarField } from './ScalarField';
|
|
19
19
|
|
|
20
|
+
import type { ScalarFieldProps } from './ScalarField';
|
|
20
21
|
import type { FieldError, FormErrors } from './types';
|
|
21
22
|
|
|
22
23
|
export type StaticFieldProps<TData extends FormDataType> = {
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { match } from 'ts-pattern';
|
|
2
2
|
|
|
3
|
-
import { StringFieldInput
|
|
4
|
-
import { StringFieldPassword
|
|
5
|
-
import { StringFieldRadio
|
|
3
|
+
import { StringFieldInput } from './StringFieldInput';
|
|
4
|
+
import { StringFieldPassword } from './StringFieldPassword';
|
|
5
|
+
import { StringFieldRadio } from './StringFieldRadio';
|
|
6
6
|
import { StringFieldSelect } from './StringFieldSelect';
|
|
7
|
-
import { StringFieldTextArea
|
|
7
|
+
import { StringFieldTextArea } from './StringFieldTextArea';
|
|
8
|
+
|
|
9
|
+
import type { StringFieldInputProps } from './StringFieldInput';
|
|
10
|
+
import type { StringFieldPasswordProps } from './StringFieldPassword';
|
|
11
|
+
import type { StringFieldRadioProps } from './StringFieldRadio';
|
|
12
|
+
import type { StringFieldTextAreaProps } from './StringFieldTextArea';
|
|
8
13
|
|
|
9
14
|
export type StringFieldProps =
|
|
10
15
|
| StringFieldInputProps
|
|
@@ -52,26 +52,26 @@ export const StringFieldPassword = ({
|
|
|
52
52
|
onChange={(event) => setValue(event.target.value)}
|
|
53
53
|
/>
|
|
54
54
|
<button
|
|
55
|
-
className="absolute right-0 flex h-full w-8 items-center justify-center
|
|
55
|
+
className="text-muted-foreground absolute right-0 flex h-full w-8 items-center justify-center"
|
|
56
56
|
disabled={disabled || readOnly}
|
|
57
57
|
tabIndex={-1}
|
|
58
58
|
type="button"
|
|
59
59
|
onClick={() => setShow(!show)}
|
|
60
60
|
>
|
|
61
|
-
<EyeIcon className={cn('absolute transition-all', show ? '-rotate-90
|
|
62
|
-
<EyeOffIcon className={cn('absolute transition-all', !show ? 'rotate-90
|
|
61
|
+
<EyeIcon className={cn('absolute transition-all', show ? 'scale-0 -rotate-90' : 'scale-100 rotate-0')} />
|
|
62
|
+
<EyeOffIcon className={cn('absolute transition-all', !show ? 'scale-0 rotate-90' : 'scale-100 rotate-0')} />
|
|
63
63
|
</button>
|
|
64
64
|
</FieldGroup.Row>
|
|
65
65
|
{strength !== null && (
|
|
66
66
|
<motion.div
|
|
67
67
|
animate={{ width: `${Math.max(strength * 25, 5)}%` }}
|
|
68
|
-
className="h-1 w-full overflow-hidden rounded"
|
|
68
|
+
className="h-1 w-full overflow-hidden rounded-sm"
|
|
69
69
|
initial={{ width: '5%' }}
|
|
70
70
|
transition={{ duration: 0.5 }}
|
|
71
71
|
>
|
|
72
72
|
<div
|
|
73
73
|
className={cn(
|
|
74
|
-
'h-full w-full
|
|
74
|
+
'bg-destructive h-full w-full transition-colors duration-500',
|
|
75
75
|
strength === 2 && 'bg-yellow-500 dark:bg-yellow-700',
|
|
76
76
|
strength === 3 && 'bg-sky-500 dark:bg-sky-700',
|
|
77
77
|
strength === 4 && 'bg-green-500 dark:bg-green-700'
|
|
@@ -5,7 +5,8 @@ import { Label } from '@/components/Label';
|
|
|
5
5
|
import { Select } from '@/components/Select';
|
|
6
6
|
|
|
7
7
|
import { FieldGroup } from '../FieldGroup';
|
|
8
|
-
|
|
8
|
+
|
|
9
|
+
import type { BaseFieldComponentProps } from '../types';
|
|
9
10
|
|
|
10
11
|
export type StringFieldSelectProps<T extends string = string> = Simplify<
|
|
11
12
|
BaseFieldComponentProps<T> & Extract<StringFormField<T>, { options: object }>
|
|
@@ -12,7 +12,7 @@ export const HoverCardContent = forwardRef<
|
|
|
12
12
|
<Content
|
|
13
13
|
align={align}
|
|
14
14
|
className={cn(
|
|
15
|
-
'
|
|
15
|
+
'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-64 rounded-md border p-4 shadow-md outline-hidden',
|
|
16
16
|
className
|
|
17
17
|
)}
|
|
18
18
|
ref={ref}
|
|
@@ -9,7 +9,7 @@ export const Input = React.forwardRef<HTMLInputElement, InputProps>(function Inp
|
|
|
9
9
|
<input
|
|
10
10
|
autoComplete="off"
|
|
11
11
|
className={cn(
|
|
12
|
-
'flex h-9 w-full rounded-md border
|
|
12
|
+
'border-input placeholder:text-muted-foreground focus-visible:ring-ring flex h-9 w-full rounded-md border bg-transparent px-3 py-1 text-sm shadow-xs transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:opacity-80 focus-visible:ring-1 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50',
|
|
13
13
|
className
|
|
14
14
|
)}
|
|
15
15
|
data-testid="input"
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { forwardRef } from 'react';
|
|
2
2
|
|
|
3
3
|
import * as LabelPrimitive from '@radix-ui/react-label';
|
|
4
|
-
import { cva
|
|
4
|
+
import { cva } from 'class-variance-authority';
|
|
5
|
+
import type { VariantProps } from 'class-variance-authority';
|
|
5
6
|
|
|
6
7
|
import { cn } from '@/utils';
|
|
7
8
|
|
|
@@ -3,9 +3,11 @@ import { LanguagesIcon } from 'lucide-react';
|
|
|
3
3
|
import { useTranslation } from '@/hooks';
|
|
4
4
|
import type { Language } from '@/i18n';
|
|
5
5
|
|
|
6
|
-
import { Button
|
|
6
|
+
import { Button } from '../Button';
|
|
7
7
|
import { DropdownMenu } from '../DropdownMenu';
|
|
8
8
|
|
|
9
|
+
import type { ButtonProps } from '../Button';
|
|
10
|
+
|
|
9
11
|
export type LanguageToggleProps = {
|
|
10
12
|
align?: 'center' | 'end' | 'start';
|
|
11
13
|
contentClassName?: string;
|
|
@@ -8,16 +8,17 @@ import {
|
|
|
8
8
|
Legend,
|
|
9
9
|
Line,
|
|
10
10
|
LineChart,
|
|
11
|
-
type LineProps,
|
|
12
11
|
ResponsiveContainer,
|
|
13
12
|
Tooltip,
|
|
14
13
|
XAxis,
|
|
15
14
|
YAxis
|
|
16
15
|
} from 'recharts';
|
|
16
|
+
import type { LineProps } from 'recharts';
|
|
17
17
|
import type { ConditionalKeys } from 'type-fest';
|
|
18
18
|
|
|
19
19
|
import { useTranslation } from '@/hooks';
|
|
20
|
-
import {
|
|
20
|
+
import { useTheme } from '@/hooks/useTheme';
|
|
21
|
+
import type { Theme } from '@/hooks/useTheme';
|
|
21
22
|
|
|
22
23
|
/** An array of arbitrary objects with data to graph */
|
|
23
24
|
|
|
@@ -26,11 +27,14 @@ type LineGraphData = readonly { [key: string]: any }[];
|
|
|
26
27
|
/** Extract string keys from items in `T` where the value of `T[K]` extends `K` */
|
|
27
28
|
type ExtractValidKeys<T extends LineGraphData, K> = Extract<ConditionalKeys<T[number], K>, string>;
|
|
28
29
|
|
|
29
|
-
type LineGraphLine<T extends LineGraphData = { [key: string]: any }[]> =
|
|
30
|
+
type LineGraphLine<T extends LineGraphData = { [key: string]: any }[]> = Pick<
|
|
31
|
+
LineProps,
|
|
32
|
+
'legendType' | 'stroke' | 'strokeDasharray' | 'strokeWidth' | 'type'
|
|
33
|
+
> & {
|
|
30
34
|
err?: ExtractValidKeys<T, number>;
|
|
31
35
|
name: string;
|
|
32
36
|
val: ExtractValidKeys<T, number>;
|
|
33
|
-
}
|
|
37
|
+
};
|
|
34
38
|
|
|
35
39
|
const strokeColors = {
|
|
36
40
|
dark: '#cbd5e1', // slate-300
|
|
@@ -6,10 +6,6 @@ import { ListboxDropdown } from './ListboxDropdown';
|
|
|
6
6
|
|
|
7
7
|
type Story = StoryObj<typeof ListboxDropdown>;
|
|
8
8
|
|
|
9
|
-
const meta: Meta<typeof ListboxDropdown> = { component: ListboxDropdown };
|
|
10
|
-
|
|
11
|
-
export default meta;
|
|
12
|
-
|
|
13
9
|
const options = [
|
|
14
10
|
{
|
|
15
11
|
key: 'o1',
|
|
@@ -25,6 +21,10 @@ const options = [
|
|
|
25
21
|
}
|
|
26
22
|
];
|
|
27
23
|
|
|
24
|
+
export default {
|
|
25
|
+
component: ListboxDropdown
|
|
26
|
+
} satisfies Meta<typeof ListboxDropdown>;
|
|
27
|
+
|
|
28
28
|
export const Default: Story = {
|
|
29
29
|
decorators: [
|
|
30
30
|
(Story) => {
|
|
@@ -2,10 +2,11 @@ import * as React from 'react';
|
|
|
2
2
|
|
|
3
3
|
import { cn } from '@/utils';
|
|
4
4
|
|
|
5
|
-
import { type ButtonProps } from '../Button';
|
|
6
5
|
import { DropdownButton } from '../DropdownButton';
|
|
7
6
|
import { DropdownMenu } from '../DropdownMenu';
|
|
8
7
|
|
|
8
|
+
import type { ButtonProps } from '../Button';
|
|
9
|
+
|
|
9
10
|
export type ListboxDropdownOption = {
|
|
10
11
|
key: string;
|
|
11
12
|
label: string;
|
|
@@ -13,7 +13,7 @@ export const MenuBarCheckboxItem = forwardRef<
|
|
|
13
13
|
<CheckboxItem
|
|
14
14
|
checked={checked}
|
|
15
15
|
className={cn(
|
|
16
|
-
'relative flex cursor-default
|
|
16
|
+
'focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center rounded-xs py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
|
17
17
|
className
|
|
18
18
|
)}
|
|
19
19
|
ref={ref}
|
|
@@ -6,14 +6,14 @@ import { cn } from '@/utils';
|
|
|
6
6
|
|
|
7
7
|
export const MenuBarItem = forwardRef<
|
|
8
8
|
React.ElementRef<typeof Item>,
|
|
9
|
-
{
|
|
9
|
+
React.ComponentPropsWithoutRef<typeof Item> & {
|
|
10
10
|
inset?: boolean;
|
|
11
|
-
}
|
|
11
|
+
}
|
|
12
12
|
>(function MenuBarItem({ className, inset, ...props }, ref) {
|
|
13
13
|
return (
|
|
14
14
|
<Item
|
|
15
15
|
className={cn(
|
|
16
|
-
'relative flex cursor-default
|
|
16
|
+
'focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center rounded-xs px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
|
17
17
|
inset && 'pl-8',
|
|
18
18
|
className
|
|
19
19
|
)}
|
|
@@ -6,9 +6,9 @@ import { cn } from '@/utils';
|
|
|
6
6
|
|
|
7
7
|
export const MenuBarLabel = forwardRef<
|
|
8
8
|
React.ElementRef<typeof Label>,
|
|
9
|
-
{
|
|
9
|
+
React.ComponentPropsWithoutRef<typeof Label> & {
|
|
10
10
|
inset?: boolean;
|
|
11
|
-
}
|
|
11
|
+
}
|
|
12
12
|
>(function MenuBarLabel({ className, inset, ...props }, ref) {
|
|
13
13
|
return <Label className={cn('px-2 py-1.5 text-sm font-semibold', inset && 'pl-8', className)} ref={ref} {...props} />;
|
|
14
14
|
});
|
|
@@ -12,7 +12,7 @@ export const MenuBarRadioItem = forwardRef<
|
|
|
12
12
|
return (
|
|
13
13
|
<RadioItem
|
|
14
14
|
className={cn(
|
|
15
|
-
'relative flex cursor-default
|
|
15
|
+
'focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center rounded-xs py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
|
16
16
|
className
|
|
17
17
|
)}
|
|
18
18
|
ref={ref}
|
|
@@ -8,7 +8,7 @@ export const MenuBarRoot = forwardRef<React.ElementRef<typeof Root>, React.Compo
|
|
|
8
8
|
function MenuBarRoot({ className, ...props }, ref) {
|
|
9
9
|
return (
|
|
10
10
|
<Root
|
|
11
|
-
className={cn('flex h-9 items-center space-x-1 rounded-md border
|
|
11
|
+
className={cn('bg-background flex h-9 items-center space-x-1 rounded-md border p-1 shadow-xs', className)}
|
|
12
12
|
ref={ref}
|
|
13
13
|
{...props}
|
|
14
14
|
/>
|
|
@@ -7,14 +7,14 @@ import { cn } from '@/utils';
|
|
|
7
7
|
|
|
8
8
|
export const MenuBarSubTrigger = forwardRef<
|
|
9
9
|
React.ElementRef<typeof SubTrigger>,
|
|
10
|
-
{
|
|
10
|
+
React.ComponentPropsWithoutRef<typeof SubTrigger> & {
|
|
11
11
|
inset?: boolean;
|
|
12
|
-
}
|
|
12
|
+
}
|
|
13
13
|
>(function MenuBarSubTrigger({ children, className, inset, ...props }, ref) {
|
|
14
14
|
return (
|
|
15
15
|
<SubTrigger
|
|
16
16
|
className={cn(
|
|
17
|
-
'
|
|
17
|
+
'focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-xs px-2 py-1.5 text-sm outline-hidden select-none',
|
|
18
18
|
inset && 'pl-8',
|
|
19
19
|
className
|
|
20
20
|
)}
|
|
@@ -10,7 +10,7 @@ export const MenuBarTrigger = forwardRef<
|
|
|
10
10
|
return (
|
|
11
11
|
<Trigger
|
|
12
12
|
className={cn(
|
|
13
|
-
'
|
|
13
|
+
'focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-xs px-3 py-1 text-sm font-medium outline-hidden select-none',
|
|
14
14
|
className
|
|
15
15
|
)}
|
|
16
16
|
ref={ref}
|
|
@@ -33,11 +33,11 @@ const NotificationHub = ({ timeout = 5000 }: NotificationHubProps) => {
|
|
|
33
33
|
<div className="p-4">
|
|
34
34
|
<div className="mb-2 flex items-center">
|
|
35
35
|
<NotificationIcon type={item.type} />
|
|
36
|
-
<h5 className="ml-3
|
|
36
|
+
<h5 className="ml-3 grow font-medium text-slate-900 dark:text-slate-100">
|
|
37
37
|
{item.title ?? t(`notifications.types.${item.type}`)}
|
|
38
38
|
</h5>
|
|
39
39
|
<button
|
|
40
|
-
className="inline-flex rounded-md text-slate-400 hover:text-slate-500 focus:
|
|
40
|
+
className="inline-flex rounded-md text-slate-400 hover:text-slate-500 focus:ring-1 focus:ring-sky-500 focus:outline-hidden dark:focus:ring-sky-600"
|
|
41
41
|
type="button"
|
|
42
42
|
onClick={() => {
|
|
43
43
|
dismissNotification(item.id);
|
|
@@ -46,7 +46,7 @@ const NotificationHub = ({ timeout = 5000 }: NotificationHubProps) => {
|
|
|
46
46
|
<XIcon aria-hidden="true" className="h-5 w-5" />
|
|
47
47
|
</button>
|
|
48
48
|
</div>
|
|
49
|
-
<p className="
|
|
49
|
+
<p className="text-muted-foreground my-2">{item.message}</p>
|
|
50
50
|
</div>
|
|
51
51
|
<motion.div
|
|
52
52
|
animate={{ width: '100%' }}
|
|
@@ -4,13 +4,15 @@ import type { Simplify } from 'type-fest';
|
|
|
4
4
|
|
|
5
5
|
import { cn } from '@/utils';
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { buttonVariants } from '../Button';
|
|
8
|
+
|
|
9
|
+
import type { ButtonProps } from '../Button';
|
|
8
10
|
|
|
9
11
|
export type PaginationLinkProps = Simplify<
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
Pick<ButtonProps, 'size'> &
|
|
13
|
+
React.ComponentProps<'a'> & {
|
|
14
|
+
isActive?: boolean;
|
|
15
|
+
}
|
|
14
16
|
>;
|
|
15
17
|
|
|
16
18
|
export const PaginationLink = ({ children, className, isActive, size = 'icon', ...props }: PaginationLinkProps) => (
|
|
@@ -3,7 +3,9 @@ import { ChevronLeftIcon } from 'lucide-react';
|
|
|
3
3
|
import { useTranslation } from '@/hooks';
|
|
4
4
|
import { cn } from '@/utils';
|
|
5
5
|
|
|
6
|
-
import { PaginationLink
|
|
6
|
+
import { PaginationLink } from './PaginationLink';
|
|
7
|
+
|
|
8
|
+
import type { PaginationLinkProps } from './PaginationLink';
|
|
7
9
|
|
|
8
10
|
export const PaginationPrevious = ({ className, ...props }: PaginationLinkProps) => {
|
|
9
11
|
const { t } = useTranslation('libui');
|