@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.
Files changed (106) hide show
  1. package/README.md +7 -9
  2. package/dist/{chunk-IYOZHDZL.js → chunk-655XRTXX.js} +1 -1
  3. package/dist/{chunk-IYOZHDZL.js.map → chunk-655XRTXX.js.map} +1 -1
  4. package/dist/{chunk-VJSOLDCS.js → chunk-HCQE34RL.js} +1 -1
  5. package/dist/chunk-HCQE34RL.js.map +1 -0
  6. package/dist/{chunk-JTEI2ZYI.js → chunk-KI6BSSS6.js} +3 -4
  7. package/dist/chunk-KI6BSSS6.js.map +1 -0
  8. package/dist/components.d.ts +77 -29
  9. package/dist/components.js +67 -69
  10. package/dist/components.js.map +1 -1
  11. package/dist/hooks.d.ts +1 -1
  12. package/dist/hooks.js +3 -3
  13. package/dist/i18n.d.ts +2 -2
  14. package/dist/i18n.js +1 -1
  15. package/dist/tailwind/globals.css +181 -39
  16. package/dist/{types-CU3FS63U.d.ts → types-CMuti1SJ.d.ts} +2 -2
  17. package/dist/utils.js +1 -1
  18. package/package.json +87 -82
  19. package/src/components/ActionDropdown/ActionDropdown.tsx +1 -1
  20. package/src/components/ArrowToggle/ArrowToggle.spec.tsx +3 -1
  21. package/src/components/ArrowToggle/ArrowToggle.tsx +3 -1
  22. package/src/components/Badge/Badge.tsx +7 -5
  23. package/src/components/Button/Button.tsx +7 -6
  24. package/src/components/Card/Card.tsx +3 -3
  25. package/src/components/Chart/ChartContainer.tsx +1 -1
  26. package/src/components/Checkbox/Checkbox.tsx +1 -1
  27. package/src/components/ClientTable/ClientTable.stories.tsx +12 -9
  28. package/src/components/ClientTable/ClientTable.tsx +3 -3
  29. package/src/components/Collapsible/Collapsible.stories.tsx +3 -3
  30. package/src/components/Command/CommandInput.tsx +1 -1
  31. package/src/components/Command/CommandItem.tsx +1 -1
  32. package/src/components/ContextMenu/ContextMenuCheckboxItem.tsx +1 -1
  33. package/src/components/ContextMenu/ContextMenuItem.tsx +1 -1
  34. package/src/components/ContextMenu/ContextMenuRadioItem.tsx +1 -1
  35. package/src/components/ContextMenu/ContextMenuSubTrigger.tsx +1 -1
  36. package/src/components/CopyButton/CopyButton.tsx +3 -1
  37. package/src/components/DatePicker/DatePicker.tsx +3 -3
  38. package/src/components/Dialog/DialogContent.tsx +2 -2
  39. package/src/components/DropdownButton/DropdownButton.tsx +1 -1
  40. package/src/components/DropdownMenu/DropdownMenuCheckboxItem.tsx +1 -1
  41. package/src/components/DropdownMenu/DropdownMenuItem.tsx +1 -1
  42. package/src/components/DropdownMenu/DropdownMenuRadioItem.tsx +1 -1
  43. package/src/components/DropdownMenu/DropdownMenuSubTrigger.tsx +1 -1
  44. package/src/components/FileDropzone/FileDropzone.stories.tsx +4 -6
  45. package/src/components/FileDropzone/FileDropzone.tsx +2 -1
  46. package/src/components/Form/BooleanField/BooleanField.spec.tsx +3 -1
  47. package/src/components/Form/BooleanField/BooleanField.tsx +5 -2
  48. package/src/components/Form/DateField/DateField.tsx +2 -1
  49. package/src/components/Form/Form.stories.tsx +15 -15
  50. package/src/components/Form/NumberField/NumberField.tsx +7 -3
  51. package/src/components/Form/NumberField/NumberFieldSelect.tsx +2 -1
  52. package/src/components/Form/RecordArrayField.tsx +1 -3
  53. package/src/components/Form/ScalarField.tsx +10 -5
  54. package/src/components/Form/StaticField.tsx +2 -1
  55. package/src/components/Form/StringField/StringField.tsx +9 -4
  56. package/src/components/Form/StringField/StringFieldPassword.tsx +5 -5
  57. package/src/components/Form/StringField/StringFieldSelect.tsx +2 -1
  58. package/src/components/HoverCard/HoverCardContent.tsx +1 -1
  59. package/src/components/Input/Input.tsx +1 -1
  60. package/src/components/Label/Label.tsx +2 -1
  61. package/src/components/LanguageToggle/LanguageToggle.tsx +3 -1
  62. package/src/components/LineGraph/LineGraph.tsx +3 -2
  63. package/src/components/ListboxDropdown/ListboxDropdown.stories.tsx +4 -4
  64. package/src/components/ListboxDropdown/ListboxDropdown.tsx +2 -1
  65. package/src/components/MenuBar/MenuBarCheckboxItem.tsx +1 -1
  66. package/src/components/MenuBar/MenuBarItem.tsx +1 -1
  67. package/src/components/MenuBar/MenuBarRadioItem.tsx +1 -1
  68. package/src/components/MenuBar/MenuBarRoot.tsx +1 -1
  69. package/src/components/MenuBar/MenuBarSubTrigger.tsx +1 -1
  70. package/src/components/MenuBar/MenuBarTrigger.tsx +1 -1
  71. package/src/components/NotificationHub/NotificationHub.tsx +3 -3
  72. package/src/components/NotificationHub/NotificationIcon.tsx +1 -1
  73. package/src/components/Pagination/PaginationLink.tsx +3 -1
  74. package/src/components/Pagination/PaginationPrevious.tsx +3 -1
  75. package/src/components/Popover/PopoverContent.tsx +1 -1
  76. package/src/components/RadioGroup/RadioGroup.spec.tsx +3 -1
  77. package/src/components/RadioGroup/RadioGroupItem.tsx +1 -1
  78. package/src/components/Resizable/Resizable.tsx +7 -3
  79. package/src/components/Resizable/ResizableHandle.tsx +2 -2
  80. package/src/components/SearchBar/SearchBar.tsx +3 -1
  81. package/src/components/Select/SelectItem.tsx +1 -1
  82. package/src/components/Sheet/SheetContent.tsx +3 -2
  83. package/src/components/Slider/Slider.tsx +4 -4
  84. package/src/components/StatisticCard/StatisticCard.tsx +2 -1
  85. package/src/components/Switch/Switch.tsx +2 -2
  86. package/src/components/Tabs/TabsContent.tsx +1 -1
  87. package/src/components/Tabs/TabsTrigger.tsx +1 -1
  88. package/src/components/TextArea/TextArea.tsx +1 -1
  89. package/src/components/ThemeToggle/ThemeToggle.tsx +3 -1
  90. package/src/components/Tooltip/TooltipTrigger.tsx +3 -1
  91. package/src/hooks/useEventListener/useEventListener.ts +2 -1
  92. package/src/hooks/useOnClickOutside/useOnClickOutside.ts +1 -1
  93. package/src/hooks/useStorage/useLocalStorage.ts +3 -1
  94. package/src/hooks/useStorage/useSessionStorage.ts +3 -1
  95. package/src/hooks/useTheme/useTheme.test.ts +14 -11
  96. package/src/i18n/internal.ts +1 -1
  97. package/src/i18n/types.ts +2 -2
  98. package/src/tailwind/globals.css +181 -39
  99. package/src/utils/index.ts +2 -1
  100. package/dist/chunk-JTEI2ZYI.js.map +0 -1
  101. package/dist/chunk-VJSOLDCS.js.map +0 -1
  102. package/dist/tailwind/config.cjs +0 -178
  103. package/dist/tailwind/config.cjs.map +0 -1
  104. package/dist/tailwind/config.d.cts +0 -16
  105. package/src/tailwind/config.cts +0 -174
  106. 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 select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
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 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
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 select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
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 bg-background p-1 shadow-sm', className)}
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
- 'flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground',
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
- 'flex cursor-default select-none items-center rounded-sm px-3 py-1 text-sm font-medium outline-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground',
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 flex-grow font-medium text-slate-900 dark:text-slate-100">
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:outline-none focus:ring-1 focus:ring-sky-500 dark:focus:ring-sky-600"
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="my-2 text-muted-foreground">{item.message}</p>
49
+ <p className="text-muted-foreground my-2">{item.message}</p>
50
50
  </div>
51
51
  <motion.div
52
52
  animate={{ width: '100%' }}
@@ -1,4 +1,4 @@
1
- import { type NotificationInterface } from '@/hooks/useNotificationsStore';
1
+ import type { NotificationInterface } from '@/hooks/useNotificationsStore';
2
2
 
3
3
  export type NotificationIconProps = {
4
4
  type: NotificationInterface['type'];
@@ -4,7 +4,9 @@ import type { Simplify } from 'type-fest';
4
4
 
5
5
  import { cn } from '@/utils';
6
6
 
7
- import { type ButtonProps, buttonVariants } from '../Button';
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, type PaginationLinkProps } from './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
- 'z-50 w-72 rounded-md border bg-popover px-3 py-1.5 text-popover-foreground shadow-md outline-none 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',
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, type RadioGroupProps } from './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 border-primary text-primary shadow focus:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',
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, type PanelProps } from 'react-resizable-panels';
3
+ import { Panel } from 'react-resizable-panels';
4
+ import type { PanelProps } from 'react-resizable-panels';
4
5
 
5
- import { ResizableHandle, type ResizableHandleProps } from './ResizableHandle';
6
- import { ResizablePanelGroup, type ResizablePanelGroupProps } from './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 bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 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-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 [&[data-panel-group-direction=vertical]>div]:rotate-90',
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-sm border bg-border">
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
- export type BaseSearchBarProps = {
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 select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
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, type VariantProps } from 'class-variance-authority';
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 right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
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 select-none items-center py-1.5', className)}
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 bg-primary opacity-15 aria-disabled:cursor-not-allowed aria-disabled:opacity-10"
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 bg-primary" />
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 bg-background shadow transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring aria-disabled:cursor-not-allowed"
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?: JSX.Element;
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-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input',
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 bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0'
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
- 'mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
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 whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow',
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 border-input bg-transparent px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground placeholder:opacity-80 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',
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, type ButtonProps } from '../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, type ButtonProps } from '../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,4 +1,5 @@
1
- import { type RefObject, useEffect, useRef } from 'react';
1
+ import { useEffect, useRef } from 'react';
2
+ import type { RefObject } from 'react';
2
3
 
3
4
  import { useIsomorphicLayoutEffect } from '../useIsomorphicLayoutEffect';
4
5
 
@@ -1,4 +1,4 @@
1
- import { type RefObject } from 'react';
1
+ import type { RefObject } from 'react';
2
2
 
3
3
  import { useEventListener } from '../useEventListener';
4
4
 
@@ -1,6 +1,8 @@
1
1
  import type { Dispatch, SetStateAction } from 'react';
2
2
 
3
- import { useStorage, type UseStorageOptions } from './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, type UseStorageOptions } from './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
- await act(async () => {
50
+ expect(result.current[0]).toBe('light');
51
+ act(() => {
51
52
  result.current[1]('dark');
52
- return Promise.resolve();
53
53
  });
54
- expect(result.current[0]).toBe('dark');
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
- await act(async () => {
62
+ act(() => {
61
63
  result.current[1]('dark');
62
- return Promise.resolve();
63
64
  });
64
- expect(window.localStorage.getItem(THEME_KEY)).toBe('dark');
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
- await act(async () => {
70
- document.documentElement.setAttribute(THEME_ATTRIBUTE, 'INVALID_THEME');
71
- return Promise.resolve();
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
  });
@@ -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 } | string,
8
+ target: string | { [L in Language]?: string },
9
9
  state: {
10
10
  fallbackLanguage: Language;
11
11
  resolvedLanguage: Language;
package/src/i18n/types.ts CHANGED
@@ -11,10 +11,10 @@ export declare namespace UserConfig {
11
11
  }
12
12
  interface Translations {
13
13
  [key: string]:
14
+ | Translations
14
15
  | {
15
16
  [L in Language]?: string;
16
- }
17
- | Translations;
17
+ };
18
18
  }
19
19
  }
20
20