@douglasneuroinformatics/libui 3.9.0 → 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-IYOZHDZL.js → chunk-655XRTXX.js} +1 -1
- package/dist/{chunk-IYOZHDZL.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-JTEI2ZYI.js → chunk-KI6BSSS6.js} +3 -4
- package/dist/chunk-KI6BSSS6.js.map +1 -0
- package/dist/components.d.ts +77 -29
- package/dist/components.js +67 -69
- 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-CU3FS63U.d.ts → types-CMuti1SJ.d.ts} +2 -2
- package/dist/utils.js +1 -1
- package/package.json +87 -82
- package/src/components/ActionDropdown/ActionDropdown.tsx +1 -1
- package/src/components/ArrowToggle/ArrowToggle.spec.tsx +3 -1
- package/src/components/ArrowToggle/ArrowToggle.tsx +3 -1
- package/src/components/Badge/Badge.tsx +7 -5
- package/src/components/Button/Button.tsx +7 -6
- package/src/components/Card/Card.tsx +3 -3
- package/src/components/Chart/ChartContainer.tsx +1 -1
- package/src/components/Checkbox/Checkbox.tsx +1 -1
- package/src/components/ClientTable/ClientTable.stories.tsx +12 -9
- package/src/components/ClientTable/ClientTable.tsx +3 -3
- 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 +1 -1
- package/src/components/ContextMenu/ContextMenuRadioItem.tsx +1 -1
- package/src/components/ContextMenu/ContextMenuSubTrigger.tsx +1 -1
- 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/DropdownMenuItem.tsx +1 -1
- package/src/components/DropdownMenu/DropdownMenuRadioItem.tsx +1 -1
- package/src/components/DropdownMenu/DropdownMenuSubTrigger.tsx +1 -1
- package/src/components/FileDropzone/FileDropzone.stories.tsx +4 -6
- package/src/components/FileDropzone/FileDropzone.tsx +2 -1
- 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 -15
- 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 +10 -5
- 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 +3 -2
- 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 +1 -1
- package/src/components/MenuBar/MenuBarRadioItem.tsx +1 -1
- package/src/components/MenuBar/MenuBarRoot.tsx +1 -1
- package/src/components/MenuBar/MenuBarSubTrigger.tsx +1 -1
- 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 +3 -1
- 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 +7 -3
- package/src/components/Resizable/ResizableHandle.tsx +2 -2
- package/src/components/SearchBar/SearchBar.tsx +3 -1
- 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/types.ts +2 -2
- package/src/tailwind/globals.css +181 -39
- package/src/utils/index.ts +2 -1
- package/dist/chunk-JTEI2ZYI.js.map +0 -1
- package/dist/chunk-VJSOLDCS.js.map +0 -1
- 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
|
@@ -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}
|
|
@@ -13,7 +13,7 @@ export const MenuBarItem = forwardRef<
|
|
|
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
|
)}
|
|
@@ -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
|
/>
|
|
@@ -14,7 +14,7 @@ export const MenuBarSubTrigger = forwardRef<
|
|
|
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,7 +4,9 @@ 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
12
|
Pick<ButtonProps, 'size'> &
|
|
@@ -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');
|
|
@@ -32,7 +32,7 @@ export const PopoverContent = React.forwardRef<React.ElementRef<typeof Content>,
|
|
|
32
32
|
align={align}
|
|
33
33
|
asChild={asChild}
|
|
34
34
|
className={cn(
|
|
35
|
-
'
|
|
35
|
+
'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-72 rounded-md border px-3 py-1.5 shadow-md outline-hidden',
|
|
36
36
|
className
|
|
37
37
|
)}
|
|
38
38
|
collisionPadding={collisionPadding}
|
|
@@ -3,7 +3,9 @@ import { userEvent } from '@testing-library/user-event';
|
|
|
3
3
|
import { describe, expect, it, vi } from 'vitest';
|
|
4
4
|
|
|
5
5
|
import { Label } from '../Label';
|
|
6
|
-
import { RadioGroup
|
|
6
|
+
import { RadioGroup } from './RadioGroup';
|
|
7
|
+
|
|
8
|
+
import type { RadioGroupProps } from './RadioGroup';
|
|
7
9
|
|
|
8
10
|
const TEST_ID = 'radio-group';
|
|
9
11
|
|
|
@@ -12,7 +12,7 @@ export const RadioGroupItem = forwardRef<
|
|
|
12
12
|
return (
|
|
13
13
|
<RadioGroupPrimitive.Item
|
|
14
14
|
className={cn(
|
|
15
|
-
'flex aspect-square h-4 w-4 items-center justify-center rounded-full border
|
|
15
|
+
'border-primary text-primary focus-visible:ring-ring flex aspect-square h-4 w-4 items-center justify-center rounded-full border shadow-sm focus:outline-hidden focus-visible:ring-1 disabled:cursor-not-allowed disabled:opacity-50',
|
|
16
16
|
className
|
|
17
17
|
)}
|
|
18
18
|
ref={ref}
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
|
|
3
|
-
import { Panel
|
|
3
|
+
import { Panel } from 'react-resizable-panels';
|
|
4
|
+
import type { PanelProps } from 'react-resizable-panels';
|
|
4
5
|
|
|
5
|
-
import { ResizableHandle
|
|
6
|
-
import { ResizablePanelGroup
|
|
6
|
+
import { ResizableHandle } from './ResizableHandle';
|
|
7
|
+
import { ResizablePanelGroup } from './ResizablePanelGroup';
|
|
8
|
+
|
|
9
|
+
import type { ResizableHandleProps } from './ResizableHandle';
|
|
10
|
+
import type { ResizablePanelGroupProps } from './ResizablePanelGroup';
|
|
7
11
|
|
|
8
12
|
type ResizableRootType = React.FC<{ children: React.ReactNode }>;
|
|
9
13
|
type ResizableType = ResizableRootType & {
|
|
@@ -12,13 +12,13 @@ export type ResizableHandleProps = React.ComponentProps<typeof PanelResizeHandle
|
|
|
12
12
|
export const ResizableHandle = ({ className, withHandle, ...props }: ResizableHandleProps) => (
|
|
13
13
|
<PanelResizeHandle
|
|
14
14
|
className={cn(
|
|
15
|
-
'relative flex w-px items-center justify-center
|
|
15
|
+
'bg-border focus-visible:ring-ring relative flex w-px items-center justify-center after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:ring-1 focus-visible:ring-offset-1 focus-visible:outline-hidden data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:translate-x-0 data-[panel-group-direction=vertical]:after:-translate-y-1/2 [&[data-panel-group-direction=vertical]>div]:rotate-90',
|
|
16
16
|
className
|
|
17
17
|
)}
|
|
18
18
|
{...props}
|
|
19
19
|
>
|
|
20
20
|
{withHandle && (
|
|
21
|
-
<div className="z-10 flex h-4 w-3 items-center justify-center rounded-
|
|
21
|
+
<div className="bg-border z-10 flex h-4 w-3 items-center justify-center rounded-xs border">
|
|
22
22
|
<GripVertical className="h-2.5 w-2.5" />
|
|
23
23
|
</div>
|
|
24
24
|
)}
|
|
@@ -5,7 +5,7 @@ import { cn } from '@/utils';
|
|
|
5
5
|
|
|
6
6
|
import { Input } from '../Input';
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
type BaseSearchBarProps = {
|
|
9
9
|
[key: `data-${string}`]: unknown;
|
|
10
10
|
/** Additional CSS classes to add to the wrapper form component, potentially overriding default styling */
|
|
11
11
|
className?: string;
|
|
@@ -60,3 +60,5 @@ export const SearchBar = ({
|
|
|
60
60
|
</form>
|
|
61
61
|
);
|
|
62
62
|
};
|
|
63
|
+
|
|
64
|
+
export type { BaseSearchBarProps };
|
|
@@ -12,7 +12,7 @@ export const SelectItem = forwardRef<
|
|
|
12
12
|
return (
|
|
13
13
|
<SelectPrimitive.Item
|
|
14
14
|
className={cn(
|
|
15
|
-
'relative flex w-full cursor-default
|
|
15
|
+
'focus:bg-accent focus:text-accent-foreground relative flex w-full cursor-default items-center rounded-xs py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
|
16
16
|
className
|
|
17
17
|
)}
|
|
18
18
|
ref={ref}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
|
|
3
3
|
import { Close, Content, Portal } from '@radix-ui/react-dialog';
|
|
4
|
-
import { cva
|
|
4
|
+
import { cva } from 'class-variance-authority';
|
|
5
|
+
import type { VariantProps } from 'class-variance-authority';
|
|
5
6
|
import { XIcon } from 'lucide-react';
|
|
6
7
|
|
|
7
8
|
import { cn } from '@/utils';
|
|
@@ -38,7 +39,7 @@ export const SheetContent = React.forwardRef<React.ElementRef<typeof Content>, S
|
|
|
38
39
|
<SheetOverlay />
|
|
39
40
|
<Content className={cn(sheetVariants({ side }), className)} ref={ref} {...props}>
|
|
40
41
|
{children}
|
|
41
|
-
<Close className="absolute
|
|
42
|
+
<Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-secondary absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none">
|
|
42
43
|
<XIcon className="h-4 w-4" />
|
|
43
44
|
<span className="sr-only">Close</span>
|
|
44
45
|
</Close>
|
|
@@ -8,21 +8,21 @@ export const Slider = forwardRef<React.ElementRef<typeof Root>, React.ComponentP
|
|
|
8
8
|
function Slider({ className, disabled, ...props }, ref) {
|
|
9
9
|
return (
|
|
10
10
|
<Root
|
|
11
|
-
className={cn('relative flex w-full touch-none
|
|
11
|
+
className={cn('relative flex w-full touch-none items-center py-1.5 select-none', className)}
|
|
12
12
|
disabled={disabled}
|
|
13
13
|
ref={ref}
|
|
14
14
|
{...props}
|
|
15
15
|
>
|
|
16
16
|
<Track
|
|
17
17
|
aria-disabled={disabled}
|
|
18
|
-
className="relative h-1.5 w-full grow overflow-hidden rounded-full
|
|
18
|
+
className="bg-primary relative h-1.5 w-full grow overflow-hidden rounded-full opacity-15 aria-disabled:cursor-not-allowed aria-disabled:opacity-10"
|
|
19
19
|
data-testid="slider-track"
|
|
20
20
|
>
|
|
21
|
-
<Range className="absolute h-full
|
|
21
|
+
<Range className="bg-primary absolute h-full" />
|
|
22
22
|
</Track>
|
|
23
23
|
<Thumb
|
|
24
24
|
aria-disabled={disabled}
|
|
25
|
-
className="block h-4 w-4 rounded-full border border-slate-500
|
|
25
|
+
className="bg-background focus-visible:ring-ring block h-4 w-4 rounded-full border border-slate-500 shadow-sm transition-colors focus-visible:ring-1 focus-visible:outline-hidden aria-disabled:cursor-not-allowed"
|
|
26
26
|
data-testid="slider-thumb"
|
|
27
27
|
/>
|
|
28
28
|
</Root>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useEffect } from 'react';
|
|
2
|
+
import type { ReactElement } from 'react';
|
|
2
3
|
|
|
3
4
|
import { motion, useSpring, useTransform } from 'motion/react';
|
|
4
5
|
|
|
@@ -9,7 +10,7 @@ import { Card } from '../Card';
|
|
|
9
10
|
type StatisticCardProps = {
|
|
10
11
|
[key: `data-${string}`]: unknown;
|
|
11
12
|
className?: string;
|
|
12
|
-
icon?:
|
|
13
|
+
icon?: ReactElement;
|
|
13
14
|
label: string;
|
|
14
15
|
value: number;
|
|
15
16
|
};
|
|
@@ -11,7 +11,7 @@ export const Switch = forwardRef<
|
|
|
11
11
|
return (
|
|
12
12
|
<SwitchPrimitives.Root
|
|
13
13
|
className={cn(
|
|
14
|
-
'peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-
|
|
14
|
+
'peer focus-visible:ring-ring focus-visible:ring-offset-background data-[state=checked]:bg-primary data-[state=unchecked]:bg-input inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-xs transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50',
|
|
15
15
|
className
|
|
16
16
|
)}
|
|
17
17
|
{...props}
|
|
@@ -19,7 +19,7 @@ export const Switch = forwardRef<
|
|
|
19
19
|
>
|
|
20
20
|
<SwitchPrimitives.Thumb
|
|
21
21
|
className={cn(
|
|
22
|
-
'pointer-events-none block h-4 w-4 rounded-full
|
|
22
|
+
'bg-background pointer-events-none block h-4 w-4 rounded-full shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0'
|
|
23
23
|
)}
|
|
24
24
|
/>
|
|
25
25
|
</SwitchPrimitives.Root>
|
|
@@ -11,7 +11,7 @@ export const TabsContent = forwardRef<
|
|
|
11
11
|
return (
|
|
12
12
|
<TabsPrimitive.Content
|
|
13
13
|
className={cn(
|
|
14
|
-
'
|
|
14
|
+
'ring-offset-background focus-visible:ring-ring mt-2 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden',
|
|
15
15
|
className
|
|
16
16
|
)}
|
|
17
17
|
ref={ref}
|
|
@@ -11,7 +11,7 @@ export const TabsTrigger = forwardRef<
|
|
|
11
11
|
return (
|
|
12
12
|
<TabsPrimitive.Trigger
|
|
13
13
|
className={cn(
|
|
14
|
-
'inline-flex items-center justify-center
|
|
14
|
+
'ring-offset-background focus-visible:ring-ring data-[state=active]:bg-background data-[state=active]:text-foreground inline-flex items-center justify-center rounded-md px-3 py-1 text-sm font-medium whitespace-nowrap transition-all focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow',
|
|
15
15
|
className
|
|
16
16
|
)}
|
|
17
17
|
ref={ref}
|
|
@@ -12,7 +12,7 @@ export const TextArea = React.forwardRef<HTMLTextAreaElement, TextAreaProps>(fun
|
|
|
12
12
|
<textarea
|
|
13
13
|
autoComplete="off"
|
|
14
14
|
className={cn(
|
|
15
|
-
'flex min-h-[60px] w-full rounded-md border
|
|
15
|
+
'border-input placeholder:text-muted-foreground focus-visible:ring-ring flex min-h-[60px] w-full rounded-md border bg-transparent px-3 py-2 text-sm shadow-xs placeholder:opacity-80 focus-visible:ring-1 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50',
|
|
16
16
|
className
|
|
17
17
|
)}
|
|
18
18
|
data-testid="text-area"
|
|
@@ -2,7 +2,9 @@ import { MoonIcon, SunIcon } from 'lucide-react';
|
|
|
2
2
|
|
|
3
3
|
import { useTheme } from '@/hooks/useTheme';
|
|
4
4
|
|
|
5
|
-
import { Button
|
|
5
|
+
import { Button } from '../Button';
|
|
6
|
+
|
|
7
|
+
import type { ButtonProps } from '../Button';
|
|
6
8
|
|
|
7
9
|
export type ThemeToggleProps = Omit<ButtonProps, 'children' | 'size'>;
|
|
8
10
|
|
|
@@ -2,7 +2,9 @@ import { forwardRef } from 'react';
|
|
|
2
2
|
|
|
3
3
|
import { Trigger } from '@radix-ui/react-tooltip';
|
|
4
4
|
|
|
5
|
-
import { Button
|
|
5
|
+
import { Button } from '../Button';
|
|
6
|
+
|
|
7
|
+
import type { ButtonProps } from '../Button';
|
|
6
8
|
|
|
7
9
|
export type TooltipTriggerProps = Omit<ButtonProps, 'asChild'>;
|
|
8
10
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { Dispatch, SetStateAction } from 'react';
|
|
2
2
|
|
|
3
|
-
import { useStorage
|
|
3
|
+
import { useStorage } from './useStorage';
|
|
4
|
+
|
|
5
|
+
import type { UseStorageOptions } from './useStorage';
|
|
4
6
|
|
|
5
7
|
/** Custom hook that uses local storage to persist state across page reloads */
|
|
6
8
|
export function useLocalStorage<T>(
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { Dispatch, SetStateAction } from 'react';
|
|
2
2
|
|
|
3
|
-
import { useStorage
|
|
3
|
+
import { useStorage } from './useStorage';
|
|
4
|
+
|
|
5
|
+
import type { UseStorageOptions } from './useStorage';
|
|
4
6
|
|
|
5
7
|
/** Custom hook that uses session storage to persist state across page reloads */
|
|
6
8
|
export function useSessionStorage<T>(
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { act, renderHook } from '@testing-library/react';
|
|
1
|
+
import { act, renderHook, waitFor } from '@testing-library/react';
|
|
2
2
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
3
|
|
|
4
4
|
import { mockMatchMedia, mockStorage } from '@/testing/mocks';
|
|
@@ -47,29 +47,32 @@ describe('useTheme', () => {
|
|
|
47
47
|
it('should change the theme when updated', async () => {
|
|
48
48
|
window.localStorage.setItem(THEME_KEY, 'light');
|
|
49
49
|
const { result } = renderHook(() => useTheme());
|
|
50
|
-
|
|
50
|
+
expect(result.current[0]).toBe('light');
|
|
51
|
+
act(() => {
|
|
51
52
|
result.current[1]('dark');
|
|
52
|
-
return Promise.resolve();
|
|
53
53
|
});
|
|
54
|
-
|
|
54
|
+
await waitFor(() => {
|
|
55
|
+
expect(result.current[0]).toBe('dark');
|
|
56
|
+
});
|
|
55
57
|
});
|
|
56
58
|
|
|
57
59
|
it('should save the theme to localStorage', async () => {
|
|
58
60
|
window.localStorage.setItem(THEME_KEY, 'light');
|
|
59
61
|
const { result } = renderHook(() => useTheme());
|
|
60
|
-
|
|
62
|
+
act(() => {
|
|
61
63
|
result.current[1]('dark');
|
|
62
|
-
return Promise.resolve();
|
|
63
64
|
});
|
|
64
|
-
|
|
65
|
+
await waitFor(() => {
|
|
66
|
+
expect(window.localStorage.getItem(THEME_KEY)).toBe('dark');
|
|
67
|
+
});
|
|
65
68
|
});
|
|
69
|
+
|
|
66
70
|
it('should print to stderr if there is an unexpected theme mutation', async () => {
|
|
67
71
|
renderHook(() => useTheme());
|
|
68
72
|
vi.spyOn(console, 'error');
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
73
|
+
document.documentElement.setAttribute(THEME_ATTRIBUTE, 'INVALID_THEME');
|
|
74
|
+
await waitFor(() => {
|
|
75
|
+
expect(console.error).toHaveBeenLastCalledWith(expect.stringContaining('INVALID_THEME'));
|
|
72
76
|
});
|
|
73
|
-
expect(console.error).toHaveBeenLastCalledWith(expect.stringContaining('INVALID_THEME'));
|
|
74
77
|
});
|
|
75
78
|
});
|
package/src/i18n/internal.ts
CHANGED
|
@@ -5,7 +5,7 @@ import type { Primitive } from 'type-fest';
|
|
|
5
5
|
import type { Language } from './types';
|
|
6
6
|
|
|
7
7
|
export function getTranslation(
|
|
8
|
-
target: { [L in Language]?: string }
|
|
8
|
+
target: string | { [L in Language]?: string },
|
|
9
9
|
state: {
|
|
10
10
|
fallbackLanguage: Language;
|
|
11
11
|
resolvedLanguage: Language;
|