kmod-cli 1.0.10

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 (66) hide show
  1. package/README.md +53 -0
  2. package/bin/gen-components.js +68 -0
  3. package/bin/index.js +153 -0
  4. package/component-templates/components/access-denied.tsx +130 -0
  5. package/component-templates/components/breadcumb.tsx +42 -0
  6. package/component-templates/components/count-down.tsx +94 -0
  7. package/component-templates/components/count-input.tsx +221 -0
  8. package/component-templates/components/date-range-calendar/button.tsx +61 -0
  9. package/component-templates/components/date-range-calendar/calendar.tsx +132 -0
  10. package/component-templates/components/date-range-calendar/date-input.tsx +259 -0
  11. package/component-templates/components/date-range-calendar/date-range-picker.tsx +594 -0
  12. package/component-templates/components/date-range-calendar/label.tsx +31 -0
  13. package/component-templates/components/date-range-calendar/popover.tsx +32 -0
  14. package/component-templates/components/date-range-calendar/select.tsx +125 -0
  15. package/component-templates/components/date-range-calendar/switch.tsx +30 -0
  16. package/component-templates/components/datetime-picker/button.tsx +61 -0
  17. package/component-templates/components/datetime-picker/calendar.tsx +156 -0
  18. package/component-templates/components/datetime-picker/datetime-picker.tsx +75 -0
  19. package/component-templates/components/datetime-picker/input.tsx +20 -0
  20. package/component-templates/components/datetime-picker/label.tsx +18 -0
  21. package/component-templates/components/datetime-picker/period-input.tsx +62 -0
  22. package/component-templates/components/datetime-picker/popover.tsx +32 -0
  23. package/component-templates/components/datetime-picker/select.tsx +125 -0
  24. package/component-templates/components/datetime-picker/time-picker-input.tsx +131 -0
  25. package/component-templates/components/datetime-picker/time-picker-utils.tsx +204 -0
  26. package/component-templates/components/datetime-picker/time-picker.tsx +59 -0
  27. package/component-templates/components/gradient-outline.tsx +233 -0
  28. package/component-templates/components/gradient-svg.tsx +157 -0
  29. package/component-templates/components/grid-layout.tsx +69 -0
  30. package/component-templates/components/hydrate-guard.tsx +40 -0
  31. package/component-templates/components/image.tsx +92 -0
  32. package/component-templates/components/loader-slash-gradient.tsx +85 -0
  33. package/component-templates/components/masonry-gallery.tsx +221 -0
  34. package/component-templates/components/modal.tsx +110 -0
  35. package/component-templates/components/multi-select.tsx +447 -0
  36. package/component-templates/components/non-hydration.tsx +27 -0
  37. package/component-templates/components/portal.tsx +34 -0
  38. package/component-templates/components/segments-circle.tsx +235 -0
  39. package/component-templates/components/single-select.tsx +248 -0
  40. package/component-templates/components/stroke-circle.tsx +57 -0
  41. package/component-templates/components/table/column-table.tsx +15 -0
  42. package/component-templates/components/table/data-table.tsx +339 -0
  43. package/component-templates/components/table/readme.tsx +95 -0
  44. package/component-templates/components/table/table.tsx +60 -0
  45. package/component-templates/components/text-hover-effect.tsx +120 -0
  46. package/component-templates/components/timout-loader.tsx +52 -0
  47. package/component-templates/components/toast.tsx +994 -0
  48. package/component-templates/configs/config.ts +33 -0
  49. package/component-templates/configs/feature-config.tsx +432 -0
  50. package/component-templates/configs/keys.ts +7 -0
  51. package/component-templates/core/api-service.ts +202 -0
  52. package/component-templates/core/calculate.ts +18 -0
  53. package/component-templates/core/idb.ts +166 -0
  54. package/component-templates/core/storage.ts +213 -0
  55. package/component-templates/hooks/count-down.ts +38 -0
  56. package/component-templates/hooks/fade-on-scroll.ts +52 -0
  57. package/component-templates/hooks/safe-action.ts +59 -0
  58. package/component-templates/hooks/spam-guard.ts +31 -0
  59. package/component-templates/lib/utils.ts +6 -0
  60. package/component-templates/providers/feature-guard.tsx +432 -0
  61. package/component-templates/queries/query.tsx +775 -0
  62. package/component-templates/utils/colors/color-by-text.ts +307 -0
  63. package/component-templates/utils/colors/stripe-effect.ts +100 -0
  64. package/component-templates/utils/hash/hash-aes.ts +35 -0
  65. package/components.json +348 -0
  66. package/package.json +60 -0
@@ -0,0 +1,125 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react';
4
+
5
+ import {
6
+ CheckIcon,
7
+ ChevronDownIcon,
8
+ } from '@radix-ui/react-icons';
9
+ import * as SelectPrimitive from '@radix-ui/react-select';
10
+
11
+ import { cn } from '../../lib/utils';
12
+
13
+ const Select = SelectPrimitive.Root
14
+
15
+ const SelectGroup = SelectPrimitive.Group
16
+
17
+ const SelectValue = SelectPrimitive.Value
18
+
19
+ const SelectTrigger = React.forwardRef<
20
+ React.ElementRef<typeof SelectPrimitive.Trigger>,
21
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
22
+ >(({ className, children, ...props }, ref) => (
23
+ <SelectPrimitive.Trigger
24
+ ref={ref}
25
+ className={cn(
26
+ 'flex h-10 w-full items-center justify-between rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
27
+ className
28
+ )}
29
+ {...props}
30
+ >
31
+ {children}
32
+ <SelectPrimitive.Icon asChild>
33
+ <ChevronDownIcon className="h-4 w-4 opacity-50" />
34
+ </SelectPrimitive.Icon>
35
+ </SelectPrimitive.Trigger>
36
+ ))
37
+ SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
38
+
39
+ const SelectContent = React.forwardRef<
40
+ React.ElementRef<typeof SelectPrimitive.Content>,
41
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
42
+ >(({ className, children, position = 'popper', ...props }, ref) => (
43
+ <SelectPrimitive.Portal>
44
+ <SelectPrimitive.Content
45
+ ref={ref}
46
+ className={cn(
47
+ 'relative z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md 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',
48
+ position === 'popper' &&
49
+ 'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
50
+ className
51
+ )}
52
+ position={position}
53
+ {...props}
54
+ >
55
+ <SelectPrimitive.Viewport
56
+ className={cn(
57
+ 'p-1',
58
+ position === 'popper' &&
59
+ 'h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]'
60
+ )}
61
+ >
62
+ {children}
63
+ </SelectPrimitive.Viewport>
64
+ </SelectPrimitive.Content>
65
+ </SelectPrimitive.Portal>
66
+ ))
67
+ SelectContent.displayName = SelectPrimitive.Content.displayName
68
+
69
+ const SelectLabel = React.forwardRef<
70
+ React.ElementRef<typeof SelectPrimitive.Label>,
71
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
72
+ >(({ className, ...props }, ref) => (
73
+ <SelectPrimitive.Label
74
+ ref={ref}
75
+ className={cn('py-1.5 pl-8 pr-2 text-sm font-semibold', className)}
76
+ {...props}
77
+ />
78
+ ))
79
+ SelectLabel.displayName = SelectPrimitive.Label.displayName
80
+
81
+ const SelectItem = React.forwardRef<
82
+ React.ElementRef<typeof SelectPrimitive.Item>,
83
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
84
+ >(({ className, children, ...props }, ref) => (
85
+ <SelectPrimitive.Item
86
+ ref={ref}
87
+ className={cn(
88
+ 'relative flex w-full 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',
89
+ className
90
+ )}
91
+ {...props}
92
+ >
93
+ <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
94
+ <SelectPrimitive.ItemIndicator>
95
+ <CheckIcon className="h-4 w-4" />
96
+ </SelectPrimitive.ItemIndicator>
97
+ </span>
98
+
99
+ <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
100
+ </SelectPrimitive.Item>
101
+ ))
102
+ SelectItem.displayName = SelectPrimitive.Item.displayName
103
+
104
+ const SelectSeparator = React.forwardRef<
105
+ React.ElementRef<typeof SelectPrimitive.Separator>,
106
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
107
+ >(({ className, ...props }, ref) => (
108
+ <SelectPrimitive.Separator
109
+ ref={ref}
110
+ className={cn('-mx-1 my-1 h-px bg-muted', className)}
111
+ {...props}
112
+ />
113
+ ))
114
+ SelectSeparator.displayName = SelectPrimitive.Separator.displayName
115
+
116
+ export {
117
+ Select,
118
+ SelectContent,
119
+ SelectGroup,
120
+ SelectItem,
121
+ SelectLabel,
122
+ SelectSeparator,
123
+ SelectTrigger,
124
+ SelectValue,
125
+ };
@@ -0,0 +1,30 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react';
4
+
5
+ import * as SwitchPrimitives from '@radix-ui/react-switch';
6
+
7
+ import { cn } from '../../lib/utils';
8
+
9
+ const Switch = React.forwardRef<
10
+ React.ElementRef<typeof SwitchPrimitives.Root>,
11
+ React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>
12
+ >(({ className, ...props }, ref) => (
13
+ <SwitchPrimitives.Root
14
+ className={cn(
15
+ 'peer inline-flex h-[20px] w-[36px] 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-white disabled:cursor-not-allowed disabled:opacity-50 bg-indigo-200',
16
+ className
17
+ )}
18
+ {...props}
19
+ ref={ref}
20
+ >
21
+ <SwitchPrimitives.Thumb
22
+ className={cn(
23
+ 'pointer-events-none block h-4 w-4 rounded-full data-[state=unchecked]:bg-white data-[state=checked]:bg-indigo-500 shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0'
24
+ )}
25
+ />
26
+ </SwitchPrimitives.Root>
27
+ ))
28
+ Switch.displayName = SwitchPrimitives.Root.displayName
29
+
30
+ export { Switch };
@@ -0,0 +1,61 @@
1
+ import * as React from 'react';
2
+
3
+ import {
4
+ cva,
5
+ type VariantProps,
6
+ } from 'class-variance-authority';
7
+
8
+ import { Slot } from '@radix-ui/react-slot';
9
+
10
+ import { cn } from '../../lib/utils';
11
+
12
+ const buttonVariants = cva(
13
+ 'inline-flex items-center justify-center rounded-full text-sm ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
14
+ {
15
+ variants: {
16
+ variant: {
17
+ default: 'bg-black text-white',
18
+ destructive:
19
+ 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
20
+ outline:
21
+ 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
22
+ secondary:
23
+ 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
24
+ ghost: 'hover:bg-hover-secondary hover:text-accent-foreground',
25
+ link: 'text-primary underline-offset-4 hover:underline'
26
+ },
27
+ size: {
28
+ default: 'h-10 px-4 py-2',
29
+ sm: 'h-9 rounded-full px-3',
30
+ lg: 'h-11 rounded-full px-8',
31
+ icon: 'h-10 w-10'
32
+ }
33
+ },
34
+ defaultVariants: {
35
+ variant: 'default',
36
+ size: 'default'
37
+ }
38
+ }
39
+ )
40
+
41
+ export interface ButtonProps
42
+ extends React.ButtonHTMLAttributes<HTMLButtonElement>,
43
+ VariantProps<typeof buttonVariants> {
44
+ asChild?: boolean
45
+ }
46
+
47
+ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
48
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
49
+ const Comp = asChild ? Slot : 'button'
50
+ return (
51
+ <Comp
52
+ className={cn(buttonVariants({ variant, size, className }))}
53
+ ref={ref}
54
+ {...props}
55
+ />
56
+ )
57
+ }
58
+ )
59
+ Button.displayName = 'Button'
60
+
61
+ export { Button, buttonVariants };
@@ -0,0 +1,156 @@
1
+ "use client";
2
+
3
+ import * as React from 'react';
4
+
5
+ import {
6
+ ChevronDownIcon,
7
+ ChevronLeftIcon,
8
+ ChevronRightIcon,
9
+ } from 'lucide-react';
10
+ import {
11
+ DayButton,
12
+ DayPicker,
13
+ getDefaultClassNames,
14
+ } from 'react-day-picker';
15
+
16
+ import { cn } from '../../lib/utils';
17
+ import {
18
+ Button,
19
+ buttonVariants,
20
+ } from './button';
21
+
22
+ function Calendar({
23
+ className,
24
+ classNames,
25
+ showOutsideDays = true,
26
+ captionLayout = "label",
27
+ buttonVariant = "ghost",
28
+ formatters,
29
+ components,
30
+ ...props
31
+ }: React.ComponentProps<typeof DayPicker> & {
32
+ buttonVariant?: React.ComponentProps<typeof Button>["variant"];
33
+ }) {
34
+ const defaultClassNames = getDefaultClassNames();
35
+
36
+ return (
37
+ <DayPicker
38
+ showOutsideDays={showOutsideDays}
39
+ className={cn(
40
+ "bg-background group/calendar p-3 [--cell-size:2rem] [[data-slot=card-content]_&]:bg-transparent [[data-slot=popover-content]_&]:bg-transparent",
41
+ String.raw`rtl:**:[.rdp-button\_next>svg]:rotate-180`,
42
+ String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,
43
+ className,
44
+ )}
45
+ captionLayout={captionLayout}
46
+ formatters={{
47
+ formatMonthDropdown: (date) => date.toLocaleString("default", { month: "short" }),
48
+ ...formatters,
49
+ }}
50
+ classNames={{
51
+ root: cn("w-full", defaultClassNames.root),
52
+ months: cn("relative flex flex-col gap-4 md:flex-row", defaultClassNames.months),
53
+ month: cn("flex w-full flex-col gap-4", defaultClassNames.month),
54
+ nav: cn("absolute inset-x-0 top-0 flex w-full items-center justify-between gap-1", defaultClassNames.nav),
55
+ button_previous: cn(
56
+ buttonVariants({ variant: buttonVariant }),
57
+ "h-[--cell-size] w-[--cell-size] select-none p-0 aria-disabled:opacity-50",
58
+ defaultClassNames.button_previous,
59
+ ),
60
+ button_next: cn(
61
+ buttonVariants({ variant: buttonVariant }),
62
+ "h-[--cell-size] w-[--cell-size] select-none p-0 aria-disabled:opacity-50",
63
+ defaultClassNames.button_next,
64
+ ),
65
+ month_caption: cn("flex h-[--cell-size] w-full items-center justify-center px-[--cell-size]", defaultClassNames.month_caption),
66
+ dropdowns: cn("flex h-[--cell-size] w-full items-center justify-center gap-1.5 text-sm font-medium", defaultClassNames.dropdowns),
67
+ dropdown_root: cn(
68
+ "has-focus:border-ring border-input shadow-xs has-focus:ring-ring/50 has-focus:ring-[3px] relative rounded-md border",
69
+ defaultClassNames.dropdown_root,
70
+ ),
71
+ dropdown: cn("absolute inset-0 opacity-0", defaultClassNames.dropdown),
72
+ caption_label: cn(
73
+ "select-none font-medium",
74
+ captionLayout === "label"
75
+ ? "text-sm"
76
+ : "[&>svg]:text-muted-foreground flex h-8 items-center gap-1 rounded-md pl-2 pr-1 text-sm [&>svg]:size-3.5",
77
+ defaultClassNames.caption_label,
78
+ ),
79
+ table: "w-full border-collapse",
80
+ weekdays: cn("flex", defaultClassNames.weekdays),
81
+ weekday: cn("text-primary-foreground flex-1 select-none rounded-md text-[0.8rem] font-normal", defaultClassNames.weekday),
82
+ week: cn("mt-2 flex w-full", defaultClassNames.week),
83
+ week_number_header: cn("w-[--cell-size] select-none", defaultClassNames.week_number_header),
84
+ week_number: cn("text-primary-foreground select-none text-[0.8rem]", defaultClassNames.week_number),
85
+ day: cn(
86
+ "group/day relative aspect-square h-full w-full select-none p-0 text-center data-[selected=true]:text-primary-foreground [&:first-child[data-selected=true]_button]:rounded-l-md [&:last-child[data-selected=true]_button]:rounded-r-md",
87
+ defaultClassNames.day,
88
+ ),
89
+ range_start: cn("bg-accent rounded-l-md", defaultClassNames.range_start),
90
+ range_middle: cn("rounded-none", defaultClassNames.range_middle),
91
+ range_end: cn("bg-accent rounded-r-md", defaultClassNames.range_end),
92
+ today: cn("bg-accent text-accent-foreground rounded-md data-[selected=true]:text-primary-foreground data-[selected=true]:rounded-none", defaultClassNames.today),
93
+ outside: cn("text-muted-foreground aria-selected:text-muted-foreground", defaultClassNames.outside),
94
+ disabled: cn("text-muted-foreground opacity-50", defaultClassNames.disabled),
95
+ hidden: cn("invisible", defaultClassNames.hidden),
96
+ ...classNames,
97
+ }}
98
+ components={{
99
+ Root: ({ className, rootRef, ...props }) => {
100
+ return <div data-slot="calendar" ref={rootRef} className={cn(className)} {...props} />;
101
+ },
102
+ Chevron: ({ className, orientation, ...props }) => {
103
+ if (orientation === "left") {
104
+ return <ChevronLeftIcon className={cn("size-4", className)} {...props} />;
105
+ }
106
+
107
+ if (orientation === "right") {
108
+ return <ChevronRightIcon className={cn("size-4", className)} {...props} />;
109
+ }
110
+
111
+ return <ChevronDownIcon className={cn("size-4", className)} {...props} />;
112
+ },
113
+ DayButton: CalendarDayButton,
114
+ WeekNumber: ({ children, ...props }) => {
115
+ return (
116
+ <td {...props}>
117
+ <div className="flex size-[--cell-size] items-center justify-center text-center">{children}</div>
118
+ </td>
119
+ );
120
+ },
121
+ ...components,
122
+ }}
123
+ {...props}
124
+ />
125
+ );
126
+ }
127
+
128
+ function CalendarDayButton({ className, day, modifiers, ...props }: React.ComponentProps<typeof DayButton>) {
129
+ const defaultClassNames = getDefaultClassNames();
130
+
131
+ const ref = React.useRef<HTMLButtonElement>(null);
132
+ React.useEffect(() => {
133
+ if (modifiers.focused) ref.current?.focus();
134
+ }, [modifiers.focused]);
135
+
136
+ return (
137
+ <Button
138
+ ref={ref}
139
+ variant="ghost"
140
+ size="icon"
141
+ data-day={day.date.toLocaleDateString()}
142
+ data-selected-single={modifiers.selected && !modifiers.range_start && !modifiers.range_end && !modifiers.range_middle}
143
+ data-range-start={modifiers.range_start}
144
+ data-range-end={modifiers.range_end}
145
+ data-range-middle={modifiers.range_middle}
146
+ className={cn(
147
+ "data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground data-[range-middle=true]:bg-accent data-[range-middle=true]:text-accent-foreground data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-ring/50 flex aspect-square h-auto w-full min-w-[--cell-size] flex-col gap-1 leading-none font-normal group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:ring-[3px] data-[range-end=true]:rounded-md data-[range-middle=true]:rounded-none data-[range-start=true]:rounded-md [&>span]:text-xs [&>span]:opacity-70",
148
+ defaultClassNames.day,
149
+ className,
150
+ )}
151
+ {...props}
152
+ />
153
+ );
154
+ }
155
+
156
+ export { Calendar, CalendarDayButton };
@@ -0,0 +1,75 @@
1
+ "use client";
2
+
3
+ import * as React from 'react';
4
+
5
+ import {
6
+ add,
7
+ format,
8
+ } from 'date-fns';
9
+ import { Calendar as CalendarIcon } from 'lucide-react';
10
+
11
+ import { cn } from '../../lib/utils';
12
+ import { Button } from './button';
13
+ import { Calendar } from './calendar';
14
+ import {
15
+ Popover,
16
+ PopoverContent,
17
+ PopoverTrigger,
18
+ } from './popover';
19
+ import { TimePicker } from './time-picker';
20
+
21
+ export function DateTimePicker({
22
+ date: selectedDate,
23
+ onSelectDate,
24
+ }: {
25
+ date: Date | undefined;
26
+ onSelectDate: (date: Date | undefined) => void;
27
+ }) {
28
+ const [date, setDate] = React.useState<Date | undefined>(selectedDate || new Date());
29
+
30
+ /**
31
+ * carry over the current time when a user clicks a new day
32
+ * instead of resetting to 00:00
33
+ */
34
+ const handleSelect = (newDay: Date | undefined) => {
35
+ if (!newDay) return;
36
+ if (!date) {
37
+ setDate(newDay);
38
+ return;
39
+ }
40
+ const diff = newDay.getTime() - date.getTime();
41
+ const diffInDays = diff / (1000 * 60 * 60 * 24);
42
+ const newDateFull = add(date, { days: Math.ceil(diffInDays) });
43
+ setDate(newDateFull);
44
+ onSelectDate(newDateFull);
45
+ };
46
+
47
+ return (
48
+ <Popover>
49
+ <PopoverTrigger asChild>
50
+ <Button
51
+ variant={"outline"}
52
+ className={cn(
53
+ "w-full shadow-none justify-start text-left ",
54
+ !date && "text-muted-foreground"
55
+ )}
56
+ >
57
+ <CalendarIcon className="mr-2 h-4 w-4" />
58
+ {date ? format(date, "PPP HH:mm:ss") : <span>MM/DD/YYYY HH:MM:SS</span>}
59
+ </Button>
60
+ </PopoverTrigger>
61
+ <PopoverContent className="w-full p-0 !z-[120] overflow-hidden">
62
+ <Calendar
63
+ mode="single"
64
+ selected={date}
65
+ className="min-w-[250px]"
66
+ onSelect={(d) => handleSelect(d)}
67
+ initialFocus
68
+ />
69
+ <div className="p-3 border-t border-border">
70
+ <TimePicker setDate={setDate} date={date} />
71
+ </div>
72
+ </PopoverContent>
73
+ </Popover>
74
+ );
75
+ }
@@ -0,0 +1,20 @@
1
+ import * as React from "react";
2
+
3
+ import { cn } from "../../lib/utils";
4
+
5
+ const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<"input">>(({ className, type, ...props }, ref) => {
6
+ return (
7
+ <input
8
+ type={type}
9
+ className={cn(
10
+ "border-input file:text-foreground placeholder:text-muted-foreground focus-visible:ring-ring flex h-9 w-full rounded-md border bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:ring-1 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
11
+ className,
12
+ )}
13
+ ref={ref}
14
+ {...props}
15
+ />
16
+ );
17
+ });
18
+ Input.displayName = "Input";
19
+
20
+ export { Input };
@@ -0,0 +1,18 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+
5
+ import { cva, type VariantProps } from "class-variance-authority";
6
+
7
+ import * as LabelPrimitive from "@radix-ui/react-label";
8
+ import { cn } from "../../lib/utils";
9
+
10
+ const labelVariants = cva("text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70");
11
+
12
+ const Label = React.forwardRef<
13
+ React.ElementRef<typeof LabelPrimitive.Root>,
14
+ React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> & VariantProps<typeof labelVariants>
15
+ >(({ className, ...props }, ref) => <LabelPrimitive.Root ref={ref} className={cn(labelVariants(), className)} {...props} />);
16
+ Label.displayName = LabelPrimitive.Root.displayName;
17
+
18
+ export { Label };
@@ -0,0 +1,62 @@
1
+ "use client";
2
+
3
+ import * as React from 'react';
4
+
5
+ import {
6
+ Select,
7
+ SelectContent,
8
+ SelectItem,
9
+ SelectTrigger,
10
+ SelectValue,
11
+ } from './select';
12
+ import {
13
+ display12HourValue,
14
+ Period,
15
+ setDateByType,
16
+ } from './time-picker-utils';
17
+
18
+ export interface PeriodSelectorProps {
19
+ period: Period;
20
+ setPeriod: (m: Period) => void;
21
+ date: Date | undefined;
22
+ setDate: (date: Date | undefined) => void;
23
+ onRightFocus?: () => void;
24
+ onLeftFocus?: () => void;
25
+ }
26
+
27
+ export const TimePeriodSelect = React.forwardRef<HTMLButtonElement, PeriodSelectorProps>(({ period, setPeriod, date, setDate, onLeftFocus, onRightFocus }, ref) => {
28
+ const handleKeyDown = (e: React.KeyboardEvent<HTMLButtonElement>) => {
29
+ if (e.key === "ArrowRight") onRightFocus?.();
30
+ if (e.key === "ArrowLeft") onLeftFocus?.();
31
+ };
32
+
33
+ const handleValueChange = (value: Period) => {
34
+ setPeriod(value);
35
+
36
+ /**
37
+ * trigger an update whenever the user switches between AM and PM;
38
+ * otherwise user must manually change the hour each time
39
+ */
40
+ if (date) {
41
+ const tempDate = new Date(date);
42
+ const hours = display12HourValue(date.getHours());
43
+ setDate(setDateByType(tempDate, hours.toString(), "12hours", period === "AM" ? "PM" : "AM"));
44
+ }
45
+ };
46
+
47
+ return (
48
+ <div className="flex h-10 items-center">
49
+ <Select value={period} onValueChange={(value: Period) => handleValueChange(value)}>
50
+ <SelectTrigger ref={ref} className="w-[65px] focus:bg-accent focus:text-accent-foreground" onKeyDown={handleKeyDown}>
51
+ <SelectValue />
52
+ </SelectTrigger>
53
+ <SelectContent>
54
+ <SelectItem value="AM">AM</SelectItem>
55
+ <SelectItem value="PM">PM</SelectItem>
56
+ </SelectContent>
57
+ </Select>
58
+ </div>
59
+ );
60
+ });
61
+
62
+ TimePeriodSelect.displayName = "TimePeriodSelect";
@@ -0,0 +1,32 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react';
4
+
5
+ import * as PopoverPrimitive from '@radix-ui/react-popover';
6
+
7
+ import { cn } from '../../lib/utils';
8
+
9
+ const Popover = PopoverPrimitive.Root
10
+
11
+ const PopoverTrigger = PopoverPrimitive.Trigger
12
+
13
+ const PopoverContent = React.forwardRef<
14
+ React.ElementRef<typeof PopoverPrimitive.Content>,
15
+ React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
16
+ >(({ className, align = 'center', sideOffset = 4, ...props }, ref) => (
17
+ <PopoverPrimitive.Portal>
18
+ <PopoverPrimitive.Content
19
+ ref={ref}
20
+ align={align}
21
+ sideOffset={sideOffset}
22
+ className={cn(
23
+ 'z-50 w-72 rounded-md border bg-white p-4 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',
24
+ className
25
+ )}
26
+ {...props}
27
+ />
28
+ </PopoverPrimitive.Portal>
29
+ ))
30
+ PopoverContent.displayName = PopoverPrimitive.Content.displayName
31
+
32
+ export { Popover, PopoverContent, PopoverTrigger };