@hunterchen/canvas 0.1.0 → 0.1.1

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 (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +242 -0
  3. package/dist/components/canvas/canvas.d.ts.map +1 -1
  4. package/dist/components/canvas/canvas.js +0 -15
  5. package/dist/components/canvas/canvas.js.map +1 -1
  6. package/dist/components/canvas/navbar/single-button.d.ts.map +1 -1
  7. package/dist/components/canvas/navbar/single-button.js +0 -26
  8. package/dist/components/canvas/navbar/single-button.js.map +1 -1
  9. package/dist/hooks/usePerformanceMode.d.ts +11 -3
  10. package/dist/hooks/usePerformanceMode.d.ts.map +1 -1
  11. package/dist/hooks/usePerformanceMode.js +37 -3
  12. package/dist/hooks/usePerformanceMode.js.map +1 -1
  13. package/dist/index.d.ts +0 -8
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +0 -9
  16. package/dist/index.js.map +1 -1
  17. package/package.json +50 -48
  18. package/src/components/canvas/canvas.tsx +0 -16
  19. package/src/components/canvas/navbar/single-button.tsx +0 -30
  20. package/src/hooks/usePerformanceMode.ts +53 -3
  21. package/src/index.ts +0 -10
  22. package/dist/components/canvas/cursor.d.ts +0 -8
  23. package/dist/components/canvas/cursor.d.ts.map +0 -1
  24. package/dist/components/canvas/cursor.js +0 -32
  25. package/dist/components/canvas/cursor.js.map +0 -1
  26. package/dist/components/ui/FolderIcon.d.ts +0 -9
  27. package/dist/components/ui/FolderIcon.d.ts.map +0 -1
  28. package/dist/components/ui/FolderIcon.js +0 -25
  29. package/dist/components/ui/FolderIcon.js.map +0 -1
  30. package/dist/components/ui/button.d.ts +0 -14
  31. package/dist/components/ui/button.d.ts.map +0 -1
  32. package/dist/components/ui/button.js +0 -54
  33. package/dist/components/ui/button.js.map +0 -1
  34. package/dist/components/ui/label.d.ts +0 -6
  35. package/dist/components/ui/label.d.ts.map +0 -1
  36. package/dist/components/ui/label.js +0 -10
  37. package/dist/components/ui/label.js.map +0 -1
  38. package/dist/components/ui/toast.d.ts +0 -16
  39. package/dist/components/ui/toast.d.ts.map +0 -1
  40. package/dist/components/ui/toast.js +0 -41
  41. package/dist/components/ui/toast.js.map +0 -1
  42. package/dist/components/ui/toaster.d.ts +0 -2
  43. package/dist/components/ui/toaster.d.ts.map +0 -1
  44. package/dist/components/ui/toaster.js +0 -10
  45. package/dist/components/ui/toaster.js.map +0 -1
  46. package/dist/hooks/use-mobile.d.ts +0 -2
  47. package/dist/hooks/use-mobile.d.ts.map +0 -1
  48. package/dist/hooks/use-mobile.js +0 -16
  49. package/dist/hooks/use-mobile.js.map +0 -1
  50. package/dist/hooks/use-toast.d.ts +0 -45
  51. package/dist/hooks/use-toast.d.ts.map +0 -1
  52. package/dist/hooks/use-toast.js +0 -126
  53. package/dist/hooks/use-toast.js.map +0 -1
  54. package/src/components/canvas/cursor.tsx +0 -161
  55. package/src/components/ui/FolderIcon.tsx +0 -116
  56. package/src/components/ui/button.tsx +0 -162
  57. package/src/components/ui/label.tsx +0 -24
  58. package/src/components/ui/toast.tsx +0 -136
  59. package/src/components/ui/toaster.tsx +0 -33
  60. package/src/hooks/use-mobile.ts +0 -21
  61. package/src/hooks/use-toast.ts +0 -186
  62. package/src/lib/copy.ts +0 -18
  63. package/src/lib/utils.ts +0 -18
@@ -1,162 +0,0 @@
1
- import * as React from "react";
2
- import Image from "next/image";
3
- import { Slot } from "@radix-ui/react-slot";
4
- import { cva, type VariantProps } from "class-variance-authority";
5
- import { cn } from "../../lib/utils";
6
-
7
- const buttonBase =
8
- "inline-flex items-center justify-center whitespace-nowrap rounded-lg text-sm font-medium 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 text-white font-figtree cursor-pointer";
9
-
10
- const lift =
11
- "-translate-y-[3px] group-hover:-translate-y-[4px] group-active:-translate-y-[1px] transition-all duration-100";
12
-
13
- export const buttonVariants = cva(buttonBase, {
14
- variants: {
15
- variant: {
16
- default: "",
17
- primary: cn(
18
- "bg-button-primary shadow-button-primary hover:bg-button-primary-hover active:bg-button-primary-active",
19
- lift,
20
- ),
21
- secondary: cn(
22
- "text-[#625679] bg-button-secondary hover:bg-button-secondary-hover active:bg-button-secondary-active active:shadow-button-secondary",
23
- lift,
24
- ),
25
- tertiary: "bg-transparent text-[#625679] px-4 active:text-[#8F57AD]",
26
- "tertiary-arrow":
27
- "bg-transparent text-[#625679] px-4 active:text-[#8F57AD] flex items-center gap-2",
28
- destructive:
29
- "bg-destructive text-destructive-foreground hover:bg-destructive-dark",
30
- outline: "bg-violet-100 hover:bg-muted border border-[1px] border-muted",
31
- ghost: "hover:bg-accent hover:text-accent-foreground",
32
- link: "text-primary underline-offset-4 hover:underline",
33
- "apply-ghost":
34
- "bg-[#ebdff7] bg-opacity-50 text-heavy font-semibold hover:bg-[#e6cdff] w-full justify-start",
35
- apply: "text-medium hover:bg-[#ebdff7] hover:text-heavy",
36
- },
37
- size: {
38
- default: "h-10 px-4 py-2",
39
- sm: "h-8 rounded-md px-3",
40
- lg: "h-11 rounded-md px-8",
41
- icon: "h-10 w-10",
42
- },
43
- },
44
- defaultVariants: { variant: "default", size: "default" },
45
- });
46
-
47
- export interface ButtonProps
48
- extends React.ButtonHTMLAttributes<HTMLButtonElement>,
49
- VariantProps<typeof buttonVariants> {
50
- asChild?: boolean;
51
- isPending?: boolean;
52
- full?: boolean;
53
- secondClass?: string;
54
- }
55
-
56
- const overlays = {
57
- primary: { bg: "bg-button-primary-back", border: "border border-white/30" },
58
- secondary: {
59
- bg: "bg-button-secondary-back",
60
- border: "border border-white/50",
61
- },
62
- } as const;
63
-
64
- const pressedByVariant: Record<"primary" | "secondary", string> = {
65
- primary:
66
- "!-translate-y-[1px] shadow-none bg-button-primary-active hover:!bg-button-primary-active",
67
- secondary:
68
- "!-translate-y-[1px] shadow-button-secondary bg-button-secondary-active hover:!bg-button-secondary-active",
69
- };
70
-
71
- const noLift =
72
- "group-hover:!translate-y-[1px] group-active:!translate-y-[1px] transition-none";
73
-
74
- export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
75
- (
76
- {
77
- className,
78
- variant = "default",
79
- size,
80
- isPending = false,
81
- full = false,
82
- asChild = false,
83
- disabled,
84
- secondClass = "",
85
- children,
86
- ...props
87
- },
88
- ref,
89
- ) => {
90
- const Comp = asChild ? Slot : "button";
91
- const lockPressed =
92
- isPending && (variant === "primary" || variant === "secondary");
93
-
94
- const btnClasses = cn(
95
- buttonVariants({ variant, size, className }),
96
- lockPressed && [pressedByVariant[variant], noLift],
97
- full && "w-full",
98
- );
99
-
100
- const overlay = overlays[variant as keyof typeof overlays];
101
-
102
- const wrapperClasses = cn(
103
- "group relative inline-block w-max",
104
- full && "block w-full",
105
- lockPressed && ["pointer-events-none", noLift],
106
- );
107
-
108
- return (
109
- <div className={wrapperClasses}>
110
- {overlay && (
111
- <>
112
- <span
113
- className={cn(
114
- "pointer-events-none absolute inset-0 h-full w-full rounded-lg",
115
- overlay.bg,
116
- )}
117
- />
118
- <span
119
- className={cn(
120
- "pointer-events-none absolute inset-0 z-50 h-full w-full rounded-lg",
121
- overlay.border,
122
- lockPressed ? "-translate-y-[1px] " + noLift : lift,
123
- )}
124
- />
125
- </>
126
- )}
127
-
128
- <Comp
129
- ref={ref}
130
- {...props}
131
- className={cn("flex flex-row gap-2", btnClasses)}
132
- disabled={disabled ?? isPending}
133
- >
134
- {variant === "tertiary-arrow" ? (
135
- <div className="w-full">
136
- <Image
137
- src="/arrow-left.svg"
138
- alt="Left Arrow"
139
- width={10}
140
- height={10}
141
- />
142
- {children}
143
- </div>
144
- ) : (
145
- children
146
- )}
147
- </Comp>
148
-
149
- {(variant === "tertiary" || variant === "tertiary-arrow") && (
150
- <span
151
- className={cn(
152
- "block h-0 max-w-0 border-b-2 border-dashed border-[#625679] transition-all duration-200 group-hover:max-w-full group-active:border-[#8F57AD]",
153
- secondClass,
154
- )}
155
- />
156
- )}
157
- </div>
158
- );
159
- },
160
- );
161
-
162
- Button.displayName = "Button";
@@ -1,24 +0,0 @@
1
- import * as React from "react";
2
- import * as LabelPrimitive from "@radix-ui/react-label";
3
- import { cva, type VariantProps } from "class-variance-authority";
4
-
5
- import { cn } from "../../lib/utils";
6
-
7
- const labelVariants = cva(
8
- "text-[#5f476c] text-xs font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
9
- );
10
-
11
- const Label = React.forwardRef<
12
- React.ElementRef<typeof LabelPrimitive.Root>,
13
- React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
14
- VariantProps<typeof labelVariants>
15
- >(({ className, ...props }, ref) => (
16
- <LabelPrimitive.Root
17
- ref={ref}
18
- className={cn(labelVariants(), className)}
19
- {...props}
20
- />
21
- ));
22
- Label.displayName = LabelPrimitive.Root.displayName;
23
-
24
- export { Label };
@@ -1,136 +0,0 @@
1
- import * as React from "react";
2
- import * as ToastPrimitives from "@radix-ui/react-toast";
3
- import { cva, type VariantProps } from "class-variance-authority";
4
- import { X } from "lucide-react";
5
-
6
- import { cn } from "../../lib/utils";
7
-
8
- const ToastProvider = ToastPrimitives.Provider;
9
-
10
- const ToastViewport = React.forwardRef<
11
- React.ElementRef<typeof ToastPrimitives.Viewport>,
12
- React.ComponentPropsWithoutRef<typeof ToastPrimitives.Viewport>
13
- >(({ className, ...props }, ref) => (
14
- <ToastPrimitives.Viewport
15
- ref={ref}
16
- className={cn(
17
- "fixed left-1/2 top-4 z-[100] flex max-h-screen w-auto -translate-x-1/2 flex-col p-4 sm:max-w-fit",
18
- className,
19
- )}
20
- {...props}
21
- />
22
- ));
23
- ToastViewport.displayName = ToastPrimitives.Viewport.displayName;
24
-
25
- const toastVariants = cva(
26
- "group pointer-events-auto relative flex w-auto min-w-fit items-center justify-between space-x-4 overflow-hidden rounded-md border px-4 py-3 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-top-full data-[state=open]:slide-in-from-top-full",
27
- {
28
- variants: {
29
- variant: {
30
- default: "border bg-background text-foreground",
31
- destructive:
32
- "destructive group border-destructive bg-destructive text-destructive-foreground",
33
- success: "border-green-200 bg-green-50 text-green-900 shadow-lg",
34
- cute: cn(
35
- "border-purple-200 bg-gradient-to-r from-purple-50 to-pink-50 text-purple-900 shadow-lg rounded-lg", // Base styling
36
- "w-[calc(100vw-4rem)]", // Mobile: take (100vw - 4rem) width for near full-bleed with margin
37
- "mx-auto", // Center it (viewport already centers, but keep safety)
38
- "min-w-0", // Prevent it from shrinking too small if content wraps
39
- "sm:w-auto", // On larger screens revert to intrinsic sizing
40
- "justify-center text-center space-x-0", // Center content & text horizontally
41
- ),
42
- },
43
- },
44
- defaultVariants: {
45
- variant: "default",
46
- },
47
- },
48
- );
49
-
50
- const Toast = React.forwardRef<
51
- React.ElementRef<typeof ToastPrimitives.Root>,
52
- React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> &
53
- VariantProps<typeof toastVariants>
54
- >(({ className, variant, ...props }, ref) => {
55
- return (
56
- <ToastPrimitives.Root
57
- ref={ref}
58
- className={cn(toastVariants({ variant }), className)}
59
- {...props}
60
- />
61
- );
62
- });
63
- Toast.displayName = ToastPrimitives.Root.displayName;
64
-
65
- const ToastAction = React.forwardRef<
66
- React.ElementRef<typeof ToastPrimitives.Action>,
67
- React.ComponentPropsWithoutRef<typeof ToastPrimitives.Action>
68
- >(({ className, ...props }, ref) => (
69
- <ToastPrimitives.Action
70
- ref={ref}
71
- className={cn(
72
- "inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium ring-offset-background transition-colors hover:bg-secondary focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive",
73
- className,
74
- )}
75
- {...props}
76
- />
77
- ));
78
- ToastAction.displayName = ToastPrimitives.Action.displayName;
79
-
80
- const ToastClose = React.forwardRef<
81
- React.ElementRef<typeof ToastPrimitives.Close>,
82
- React.ComponentPropsWithoutRef<typeof ToastPrimitives.Close>
83
- >(({ className, ...props }, ref) => (
84
- <ToastPrimitives.Close
85
- ref={ref}
86
- className={cn(
87
- "absolute right-1 top-1 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-2 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600",
88
- className,
89
- )}
90
- toast-close=""
91
- {...props}
92
- >
93
- <X className="h-3 w-3" />
94
- </ToastPrimitives.Close>
95
- ));
96
- ToastClose.displayName = ToastPrimitives.Close.displayName;
97
-
98
- const ToastTitle = React.forwardRef<
99
- React.ElementRef<typeof ToastPrimitives.Title>,
100
- React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title>
101
- >(({ className, ...props }, ref) => (
102
- <ToastPrimitives.Title
103
- ref={ref}
104
- className={cn("text-sm font-semibold", className)}
105
- {...props}
106
- />
107
- ));
108
- ToastTitle.displayName = ToastPrimitives.Title.displayName;
109
-
110
- const ToastDescription = React.forwardRef<
111
- React.ElementRef<typeof ToastPrimitives.Description>,
112
- React.ComponentPropsWithoutRef<typeof ToastPrimitives.Description>
113
- >(({ className, ...props }, ref) => (
114
- <ToastPrimitives.Description
115
- ref={ref}
116
- className={cn("text-sm opacity-90", className)}
117
- {...props}
118
- />
119
- ));
120
- ToastDescription.displayName = ToastPrimitives.Description.displayName;
121
-
122
- type ToastProps = React.ComponentPropsWithoutRef<typeof Toast>;
123
-
124
- type ToastActionElement = React.ReactElement<typeof ToastAction>;
125
-
126
- export {
127
- type ToastProps,
128
- type ToastActionElement,
129
- ToastProvider,
130
- ToastViewport,
131
- Toast,
132
- ToastTitle,
133
- ToastDescription,
134
- ToastClose,
135
- ToastAction,
136
- };
@@ -1,33 +0,0 @@
1
- import { useToast } from "../../hooks/use-toast";
2
- import {
3
- Toast,
4
- ToastClose,
5
- ToastDescription,
6
- ToastProvider,
7
- ToastTitle,
8
- ToastViewport,
9
- } from "./toast";
10
-
11
- export function Toaster() {
12
- const { toasts } = useToast();
13
-
14
- return (
15
- <ToastProvider>
16
- {toasts.map(function ({ id, title, description, action, ...props }) {
17
- return (
18
- <Toast key={id} {...props}>
19
- <div className="grid gap-1">
20
- {title && <ToastTitle>{title}</ToastTitle>}
21
- {description && (
22
- <ToastDescription>{description}</ToastDescription>
23
- )}
24
- </div>
25
- {action}
26
- <ToastClose />
27
- </Toast>
28
- );
29
- })}
30
- <ToastViewport />
31
- </ToastProvider>
32
- );
33
- }
@@ -1,21 +0,0 @@
1
- import * as React from "react";
2
-
3
- const MOBILE_BREAKPOINT = 768;
4
-
5
- export function useIsMobile() {
6
- const [isMobile, setIsMobile] = React.useState<boolean | undefined>(
7
- undefined,
8
- );
9
-
10
- React.useEffect(() => {
11
- const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
12
- const onChange = () => {
13
- setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
14
- };
15
- mql.addEventListener("change", onChange);
16
- setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
17
- return () => mql.removeEventListener("change", onChange);
18
- }, []);
19
-
20
- return !!isMobile;
21
- }
@@ -1,186 +0,0 @@
1
- import * as React from "react";
2
-
3
- import type { ToastActionElement, ToastProps } from "../components/ui/toast";
4
-
5
- const TOAST_LIMIT = 1;
6
- const TOAST_REMOVE_DELAY = 5000;
7
-
8
- type ToasterToast = ToastProps & {
9
- id: string;
10
- title?: React.ReactNode;
11
- description?: React.ReactNode;
12
- action?: ToastActionElement;
13
- };
14
-
15
- const actionTypes = {
16
- ADD_TOAST: "ADD_TOAST",
17
- UPDATE_TOAST: "UPDATE_TOAST",
18
- DISMISS_TOAST: "DISMISS_TOAST",
19
- REMOVE_TOAST: "REMOVE_TOAST",
20
- } as const;
21
-
22
- let count = 0;
23
-
24
- function genId() {
25
- count = (count + 1) % Number.MAX_SAFE_INTEGER;
26
- return count.toString();
27
- }
28
-
29
- type ActionType = typeof actionTypes;
30
-
31
- type Action =
32
- | {
33
- type: ActionType["ADD_TOAST"];
34
- toast: ToasterToast;
35
- }
36
- | {
37
- type: ActionType["UPDATE_TOAST"];
38
- toast: Partial<ToasterToast>;
39
- }
40
- | {
41
- type: ActionType["DISMISS_TOAST"];
42
- toastId?: ToasterToast["id"];
43
- }
44
- | {
45
- type: ActionType["REMOVE_TOAST"];
46
- toastId?: ToasterToast["id"];
47
- };
48
-
49
- interface State {
50
- toasts: ToasterToast[];
51
- }
52
-
53
- const toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>();
54
-
55
- const addToRemoveQueue = (toastId: string) => {
56
- if (toastTimeouts.has(toastId)) {
57
- return;
58
- }
59
-
60
- const timeout = setTimeout(() => {
61
- toastTimeouts.delete(toastId);
62
- dispatch({
63
- type: "REMOVE_TOAST",
64
- toastId: toastId,
65
- });
66
- }, TOAST_REMOVE_DELAY);
67
-
68
- toastTimeouts.set(toastId, timeout);
69
- };
70
-
71
- export const reducer = (state: State, action: Action): State => {
72
- switch (action.type) {
73
- case "ADD_TOAST":
74
- return {
75
- ...state,
76
- toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),
77
- };
78
-
79
- case "UPDATE_TOAST":
80
- return {
81
- ...state,
82
- toasts: state.toasts.map((t) =>
83
- t.id === action.toast.id ? { ...t, ...action.toast } : t,
84
- ),
85
- };
86
-
87
- case "DISMISS_TOAST": {
88
- const { toastId } = action;
89
-
90
- // ! Side effects ! - This could be extracted into a dismissToast() action,
91
- // but I'll keep it here for simplicity
92
- if (toastId) {
93
- addToRemoveQueue(toastId);
94
- } else {
95
- state.toasts.forEach((toast) => {
96
- addToRemoveQueue(toast.id);
97
- });
98
- }
99
-
100
- return {
101
- ...state,
102
- toasts: state.toasts.map((t) =>
103
- t.id === toastId || toastId === undefined
104
- ? {
105
- ...t,
106
- open: false,
107
- }
108
- : t,
109
- ),
110
- };
111
- }
112
- case "REMOVE_TOAST":
113
- if (action.toastId === undefined) {
114
- return {
115
- ...state,
116
- toasts: [],
117
- };
118
- }
119
- return {
120
- ...state,
121
- toasts: state.toasts.filter((t) => t.id !== action.toastId),
122
- };
123
- }
124
- };
125
-
126
- const listeners: Array<(state: State) => void> = [];
127
-
128
- let memoryState: State = { toasts: [] };
129
-
130
- function dispatch(action: Action) {
131
- memoryState = reducer(memoryState, action);
132
- listeners.forEach((listener) => {
133
- listener(memoryState);
134
- });
135
- }
136
-
137
- type Toast = Omit<ToasterToast, "id">;
138
-
139
- export function toast({ ...props }: Toast) {
140
- const id = genId();
141
-
142
- const update = (props: ToasterToast) =>
143
- dispatch({
144
- type: "UPDATE_TOAST",
145
- toast: { ...props, id },
146
- });
147
- const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id });
148
-
149
- dispatch({
150
- type: "ADD_TOAST",
151
- toast: {
152
- ...props,
153
- id,
154
- open: true,
155
- onOpenChange: (open) => {
156
- if (!open) dismiss();
157
- },
158
- },
159
- });
160
-
161
- return {
162
- id: id,
163
- dismiss,
164
- update,
165
- };
166
- }
167
-
168
- export function useToast() {
169
- const [state, setState] = React.useState<State>(memoryState);
170
-
171
- React.useEffect(() => {
172
- listeners.push(setState);
173
- return () => {
174
- const index = listeners.indexOf(setState);
175
- if (index > -1) {
176
- listeners.splice(index, 1);
177
- }
178
- };
179
- }, [state]);
180
-
181
- return {
182
- ...state,
183
- toast,
184
- dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }),
185
- };
186
- }
package/src/lib/copy.ts DELETED
@@ -1,18 +0,0 @@
1
- export const copyText = async (text: string): Promise<boolean> => {
2
- try {
3
- if (navigator.clipboard?.writeText && window.isSecureContext) {
4
- await navigator.clipboard.writeText(text);
5
- return true;
6
- }
7
- // fallback: execCommand
8
- const ta = document.createElement("textarea");
9
- ta.value = text;
10
- document.body.appendChild(ta);
11
- ta.select();
12
- const ok = document.execCommand("copy");
13
- document.body.removeChild(ta);
14
- return ok;
15
- } catch {
16
- return false;
17
- }
18
- };
package/src/lib/utils.ts DELETED
@@ -1,18 +0,0 @@
1
- import { type ClassValue, clsx } from "clsx";
2
- import { twMerge } from "tailwind-merge";
3
-
4
- export function cn(...inputs: ClassValue[]) {
5
- return twMerge(clsx(inputs));
6
- }
7
-
8
- export function debounce<T extends (...args: unknown[]) => void>(
9
- cb: T,
10
- wait = 20,
11
- ) {
12
- let h: number | NodeJS.Timeout = 0;
13
- const callable = (...args: unknown[]) => {
14
- clearTimeout(h);
15
- h = setTimeout(() => cb(...args), wait);
16
- };
17
- return callable as T;
18
- }