Skip to content

Commit 92a8405

Browse files
authored
Merge pull request #1262 from joshunrau/data-table
implement data table in libui
2 parents da7d638 + 9846d3a commit 92a8405

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1249
-228
lines changed

apps/gateway/src/Root.tsx

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { useEffect, useRef } from 'react';
22

3-
import { LanguageToggle, NotificationHub, ThemeToggle } from '@douglasneuroinformatics/libui/components';
3+
import { LanguageToggle, ThemeToggle } from '@douglasneuroinformatics/libui/components';
44
import { useNotificationsStore } from '@douglasneuroinformatics/libui/hooks';
5+
import { CoreProvider } from '@douglasneuroinformatics/libui/providers';
56
import { Branding, InstrumentRenderer } from '@opendatacapture/react-core';
67
import type { InstrumentSubmitHandler } from '@opendatacapture/react-core';
78
import type { UpdateRemoteAssignmentData } from '@opendatacapture/schemas/assignment';
@@ -52,31 +53,32 @@ export const Root = ({ id, initialSeriesIndex, target, token }: RootProps) => {
5253
};
5354

5455
return (
55-
<div className="flex h-screen flex-col" ref={ref} style={{ display: 'none' }}>
56-
<header className="fixed top-0 z-10 w-full bg-white/80 text-slate-700 shadow-sm backdrop-blur-lg dark:bg-slate-800/75 dark:text-slate-300">
57-
<div className="container flex items-center justify-between py-3 font-medium">
58-
<Branding className="[&>span]:hidden sm:[&>span]:block" fontSize="md" />
59-
<div className="flex gap-3">
60-
<ThemeToggle className="h-9 w-9" />
61-
<LanguageToggle
62-
options={{
63-
en: 'English',
64-
fr: 'Français'
65-
}}
66-
triggerClassName="h-9 w-9"
67-
/>
56+
<CoreProvider>
57+
<div className="flex h-screen flex-col" ref={ref} style={{ display: 'none' }}>
58+
<header className="fixed top-0 z-10 w-full bg-white/80 text-slate-700 shadow-sm backdrop-blur-lg dark:bg-slate-800/75 dark:text-slate-300">
59+
<div className="container flex items-center justify-between py-3 font-medium">
60+
<Branding className="[&>span]:hidden sm:[&>span]:block" fontSize="md" />
61+
<div className="flex gap-3">
62+
<ThemeToggle className="h-9 w-9" />
63+
<LanguageToggle
64+
options={{
65+
en: 'English',
66+
fr: 'Français'
67+
}}
68+
triggerClassName="h-9 w-9"
69+
/>
70+
</div>
6871
</div>
69-
</div>
70-
</header>
71-
<main className="container flex min-h-0 max-w-3xl grow flex-col pb-16 pt-32 xl:max-w-5xl">
72-
<InstrumentRenderer
73-
className="min-h-full w-full"
74-
initialSeriesIndex={initialSeriesIndex}
75-
target={target}
76-
onSubmit={handleSubmit}
77-
/>
78-
</main>
79-
<NotificationHub />
80-
</div>
72+
</header>
73+
<main className="container flex min-h-0 max-w-3xl grow flex-col pb-16 pt-32 xl:max-w-5xl">
74+
<InstrumentRenderer
75+
className="min-h-full w-full"
76+
initialSeriesIndex={initialSeriesIndex}
77+
target={target}
78+
onSubmit={handleSubmit}
79+
/>
80+
</main>
81+
</div>
82+
</CoreProvider>
8183
);
8284
};

apps/playground/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@
2121
"@opendatacapture/runtime-core": "workspace:*",
2222
"@opendatacapture/runtime-v1": "workspace:*",
2323
"@opendatacapture/schemas": "workspace:*",
24+
"@radix-ui/react-context-menu": "^2.2.6",
2425
"axios": "catalog:",
26+
"cmdk": "^1.1.1",
2527
"esbuild-wasm": "catalog:",
2628
"idb-keyval": "^6.2.2",
2729
"immer": "^10.1.1",
@@ -37,6 +39,7 @@
3739
"react-dom": "workspace:react-dom__19.x@*",
3840
"react-dropzone": "^14.3.8",
3941
"react-error-boundary": "^5.0.0",
42+
"react-resizable-panels": "^2.1.7",
4043
"stacktrace-parser": "^0.1.11",
4144
"ts-pattern": "workspace:ts-pattern__5.x@*",
4245
"zod": "workspace:zod__3.x@*",

apps/playground/src/App.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React from 'react';
22

3-
import { NotificationHub } from '@douglasneuroinformatics/libui/components';
3+
import { CoreProvider } from '@douglasneuroinformatics/libui/providers';
44
import { ErrorPage, LoadingPage } from '@opendatacapture/react-core';
55
import { ErrorBoundary } from 'react-error-boundary';
66

@@ -13,10 +13,11 @@ export const App = () => {
1313
<LoadingPage subtitle="Please Be Patient, This May Take a While" title="Loading Editor and Toolchain" />
1414
}
1515
>
16-
<ErrorBoundary FallbackComponent={ErrorPage}>
17-
<NotificationHub />
18-
<IndexPage />
19-
</ErrorBoundary>
16+
<CoreProvider>
17+
<ErrorBoundary FallbackComponent={ErrorPage}>
18+
<IndexPage />
19+
</ErrorBoundary>
20+
</CoreProvider>
2021
</React.Suspense>
2122
);
2223
};
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import type { Meta, StoryObj } from '@storybook/react-vite';
2+
import { CalculatorIcon, CalendarIcon, CreditCardIcon, SettingsIcon, SmileIcon, UserIcon } from 'lucide-react';
3+
4+
import { Command } from './Command';
5+
6+
type Story = StoryObj<typeof Command>;
7+
8+
export default { component: Command } as Meta<typeof Command>;
9+
10+
export const Default: Story = {
11+
args: {
12+
children: (
13+
<>
14+
<Command.Input placeholder="Type a command or search..." />
15+
<Command.List>
16+
<Command.Empty>No results found.</Command.Empty>
17+
<Command.Group heading="Suggestions">
18+
<Command.Item>
19+
<CalendarIcon className="mr-2 h-4 w-4" />
20+
<span>Calendar</span>
21+
</Command.Item>
22+
<Command.Item>
23+
<SmileIcon className="mr-2 h-4 w-4" />
24+
<span>Search Emoji</span>
25+
</Command.Item>
26+
<Command.Item>
27+
<CalculatorIcon className="mr-2 h-4 w-4" />
28+
<span>Calculator</span>
29+
</Command.Item>
30+
</Command.Group>
31+
<Command.Separator />
32+
<Command.Group heading="Settings">
33+
<Command.Item>
34+
<UserIcon className="mr-2 h-4 w-4" />
35+
<span>Profile</span>
36+
<Command.Shortcut>⌘P</Command.Shortcut>
37+
</Command.Item>
38+
<Command.Item>
39+
<CreditCardIcon className="mr-2 h-4 w-4" />
40+
<span>Billing</span>
41+
<Command.Shortcut>⌘B</Command.Shortcut>
42+
</Command.Item>
43+
<Command.Item>
44+
<SettingsIcon className="mr-2 h-4 w-4" />
45+
<span>Settings</span>
46+
<Command.Shortcut>⌘S</Command.Shortcut>
47+
</Command.Item>
48+
</Command.Group>
49+
</Command.List>
50+
</>
51+
)
52+
}
53+
};
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import * as React from 'react';
2+
3+
import { cn } from '@douglasneuroinformatics/libui/utils';
4+
import { Command as CommandPrimitive } from 'cmdk';
5+
import type { Simplify } from 'type-fest';
6+
7+
import { CommandEmpty } from './CommandEmpty';
8+
import { CommandGroup } from './CommandGroup';
9+
import { CommandInput } from './CommandInput';
10+
import { CommandItem } from './CommandItem';
11+
import { CommandList } from './CommandList';
12+
import { CommandSeparator } from './CommandSeparator';
13+
import { CommandShortcut } from './CommandShortcut';
14+
15+
type CommandRootProps = Simplify<React.ComponentPropsWithoutRef<typeof CommandPrimitive>>;
16+
17+
const CommandRoot = React.forwardRef<React.ElementRef<typeof CommandPrimitive>, CommandRootProps>(function Command(
18+
{ className, ...props },
19+
ref
20+
) {
21+
return (
22+
<CommandPrimitive
23+
className={cn(
24+
'bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-md',
25+
className
26+
)}
27+
ref={ref}
28+
{...props}
29+
/>
30+
);
31+
});
32+
33+
export const Command = Object.assign(CommandRoot, {
34+
Empty: CommandEmpty,
35+
Group: CommandGroup,
36+
Input: CommandInput,
37+
Item: CommandItem,
38+
List: CommandList,
39+
Separator: CommandSeparator,
40+
Shortcut: CommandShortcut
41+
});
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import React, { forwardRef } from 'react';
2+
3+
import { Command as CommandPrimitive } from 'cmdk';
4+
5+
export const CommandEmpty = forwardRef<
6+
React.ElementRef<typeof CommandPrimitive.Empty>,
7+
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>
8+
>(function CommandEmpty(props, ref) {
9+
return <CommandPrimitive.Empty className="py-6 text-center text-sm" ref={ref} {...props} />;
10+
});
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import React, { forwardRef } from 'react';
2+
3+
import { cn } from '@douglasneuroinformatics/libui/utils';
4+
import { Command as CommandPrimitive } from 'cmdk';
5+
6+
export const CommandGroup = forwardRef<
7+
React.ElementRef<typeof CommandPrimitive.Group>,
8+
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Group>
9+
>(function CommandGroup({ className, ...props }, ref) {
10+
return (
11+
<CommandPrimitive.Group
12+
className={cn(
13+
'text-foreground [&_[cmdk-group-heading]]:text-muted-foreground overflow-hidden p-1 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium',
14+
className
15+
)}
16+
ref={ref}
17+
{...props}
18+
/>
19+
);
20+
});
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import React, { forwardRef } from 'react';
2+
3+
import { cn } from '@douglasneuroinformatics/libui/utils';
4+
import { Command as CommandPrimitive } from 'cmdk';
5+
import { SearchIcon } from 'lucide-react';
6+
7+
export const CommandInput = forwardRef<
8+
React.ElementRef<typeof CommandPrimitive.Input>,
9+
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
10+
>(function CommandInput({ className, ...props }, ref) {
11+
return (
12+
// eslint-disable-next-line react/no-unknown-property
13+
<div className="flex items-center border-b px-3" cmdk-input-wrapper="">
14+
<SearchIcon className="mr-2 h-4 w-4 shrink-0 opacity-50" />
15+
<CommandPrimitive.Input
16+
className={cn(
17+
'placeholder:text-muted-foreground outline-hidden flex h-10 w-full rounded-md bg-transparent py-3 text-sm disabled:cursor-not-allowed disabled:opacity-50',
18+
className
19+
)}
20+
ref={ref}
21+
{...props}
22+
/>
23+
</div>
24+
);
25+
});
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import React, { forwardRef } from 'react';
2+
3+
import { cn } from '@douglasneuroinformatics/libui/utils';
4+
import { Command as CommandPrimitive } from 'cmdk';
5+
6+
export const CommandItem = forwardRef<
7+
React.ElementRef<typeof CommandPrimitive.Item>,
8+
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>
9+
>(function CommandItem({ className, ...props }, ref) {
10+
return (
11+
<CommandPrimitive.Item
12+
className={cn(
13+
'aria-selected:bg-accent aria-selected:text-accent-foreground rounded-xs outline-hidden relative flex cursor-pointer select-none items-center px-2 py-1.5 text-sm data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50',
14+
className
15+
)}
16+
ref={ref}
17+
{...props}
18+
/>
19+
);
20+
});
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import React, { forwardRef } from 'react';
2+
3+
import { cn } from '@douglasneuroinformatics/libui/utils';
4+
import { Command as CommandPrimitive } from 'cmdk';
5+
6+
export const CommandList = forwardRef<
7+
React.ElementRef<typeof CommandPrimitive.List>,
8+
React.ComponentPropsWithoutRef<typeof CommandPrimitive.List>
9+
>(function CommandList({ className, ...props }, ref) {
10+
return (
11+
<CommandPrimitive.List
12+
className={cn('max-h-[300px] overflow-y-auto overflow-x-hidden', className)}
13+
ref={ref}
14+
{...props}
15+
/>
16+
);
17+
});

0 commit comments

Comments
 (0)