@betterinternship/components 2.5.1 → 2.7.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.
@@ -0,0 +1,8 @@
1
+ /**
2
+ * A number that rolls up or down when its value changes.
3
+ * @prop value The number displayed by the component.
4
+ */
5
+ export declare const AnimatedCount: ({ value }: {
6
+ value: number;
7
+ }) => import("react/jsx-runtime").JSX.Element;
8
+ export default AnimatedCount;
@@ -0,0 +1,22 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { useRef, useEffect } from 'react';
3
+ import { useReducedMotion, AnimatePresence, motion } from 'framer-motion';
4
+
5
+ /**
6
+ * A number that rolls up or down when its value changes.
7
+ * @prop value The number displayed by the component.
8
+ */
9
+ const AnimatedCount = ({ value }) => {
10
+ const reduceMotion = useReducedMotion();
11
+ const prev = useRef(value);
12
+ const direction = value >= prev.current ? 1 : -1;
13
+ useEffect(() => {
14
+ prev.current = value;
15
+ }, [value]);
16
+ return (jsxs("span", { className: "relative inline-flex justify-center overflow-hidden tabular-nums", children: [jsx("span", { className: "invisible", children: value }), jsx(AnimatePresence, { initial: false, children: jsx(motion.span, { className: "absolute inset-0 flex items-center justify-center", initial: reduceMotion ? false : { y: `${direction * 100}%`, opacity: 0 }, animate: { y: '0%', opacity: 1 }, exit: reduceMotion
17
+ ? { opacity: 0 }
18
+ : { y: `${direction * -100}%`, opacity: 0 }, transition: { duration: 0.18, ease: 'easeOut' }, children: value }, value) })] }));
19
+ };
20
+
21
+ export { AnimatedCount, AnimatedCount as default };
22
+ //# sourceMappingURL=animated-count.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"animated-count.js","sources":["../../../src/components/ui/animated-count.tsx"],"sourcesContent":["import { useRef, useEffect } from 'react';\nimport { AnimatePresence, motion, useReducedMotion } from 'framer-motion';\n\n/**\n * A number that rolls up or down when its value changes.\n * @prop value The number displayed by the component.\n */\nexport const AnimatedCount = ({ value }: { value: number }) => {\n const reduceMotion = useReducedMotion();\n const prev = useRef(value);\n const direction = value >= prev.current ? 1 : -1;\n\n useEffect(() => {\n prev.current = value;\n }, [value]);\n\n return (\n <span className=\"relative inline-flex justify-center overflow-hidden tabular-nums\">\n {/* keeps the box the right width without clipping the rolling digit */}\n <span className=\"invisible\">{value}</span>\n <AnimatePresence initial={false}>\n <motion.span\n key={value}\n className=\"absolute inset-0 flex items-center justify-center\"\n initial={\n reduceMotion ? false : { y: `${direction * 100}%`, opacity: 0 }\n }\n animate={{ y: '0%', opacity: 1 }}\n exit={\n reduceMotion\n ? { opacity: 0 }\n : { y: `${direction * -100}%`, opacity: 0 }\n }\n transition={{ duration: 0.18, ease: 'easeOut' }}\n >\n {value}\n </motion.span>\n </AnimatePresence>\n </span>\n );\n};\n\nexport default AnimatedCount;\n"],"names":["_jsxs","_jsx"],"mappings":";;;;AAGA;;;AAGG;MACU,aAAa,GAAG,CAAC,EAAE,KAAK,EAAqB,KAAI;AAC5D,IAAA,MAAM,YAAY,GAAG,gBAAgB,EAAE;AACvC,IAAA,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC;AAC1B,IAAA,MAAM,SAAS,GAAG,KAAK,IAAI,IAAI,CAAC,OAAO,GAAG,CAAC,GAAG,EAAE;IAEhD,SAAS,CAAC,MAAK;AACb,QAAA,IAAI,CAAC,OAAO,GAAG,KAAK;AACtB,IAAA,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;AAEX,IAAA,QACEA,IAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,kEAAkE,EAAA,QAAA,EAAA,CAEhFC,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,WAAW,EAAA,QAAA,EAAE,KAAK,EAAA,CAAQ,EAC1CA,GAAA,CAAC,eAAe,EAAA,EAAC,OAAO,EAAE,KAAK,EAAA,QAAA,EAC7BA,GAAA,CAAC,MAAM,CAAC,IAAI,EAAA,EAEV,SAAS,EAAC,mDAAmD,EAC7D,OAAO,EACL,YAAY,GAAG,KAAK,GAAG,EAAE,CAAC,EAAE,CAAA,EAAG,SAAS,GAAG,GAAG,CAAA,CAAA,CAAG,EAAE,OAAO,EAAE,CAAC,EAAE,EAEjE,OAAO,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,EAChC,IAAI,EACF;AACE,0BAAE,EAAE,OAAO,EAAE,CAAC;AACd,0BAAE,EAAE,CAAC,EAAE,GAAG,SAAS,GAAG,IAAI,GAAG,EAAE,OAAO,EAAE,CAAC,EAAE,EAE/C,UAAU,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,EAAA,QAAA,EAE9C,KAAK,IAbD,KAAK,CAcE,EAAA,CACE,CAAA,EAAA,CACb;AAEX;;;;"}
@@ -3,7 +3,7 @@ import { type VariantProps } from 'class-variance-authority';
3
3
  declare const badgeVariants: (props?: ({
4
4
  variant?: "outline" | "solid" | null | undefined;
5
5
  type?: "default" | "primary" | "supportive" | "destructive" | "accent" | "warning" | null | undefined;
6
- strength?: "default" | "medium" | "light" | "invisible" | null | undefined;
6
+ strength?: "default" | "invisible" | "medium" | "light" | null | undefined;
7
7
  } & import("class-variance-authority/dist/types").ClassProp) | undefined) => string;
8
8
  export interface BadgeProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof badgeVariants> {
9
9
  }
@@ -1 +1 @@
1
- {"version":3,"file":"status-notice.js","sources":["../../../src/components/ui/status-notice.tsx"],"sourcesContent":["import type { ComponentProps, ReactNode } from \"react\";\r\nimport type { LucideIcon } from \"lucide-react\";\r\nimport { cn } from \"@/utils\";\r\n\r\ntype StatusNoticeVariant = \"primary\" | \"warning\" | \"destructive\";\r\n\r\nconst variantClasses: Record<\r\n StatusNoticeVariant,\r\n { container: string; icon: string }\r\n> = {\r\n primary: {\r\n container:\r\n \"border-primary/25 bg-primary/[0.035] transition-colors hover:bg-primary/[0.06]\",\r\n icon: \"bg-primary/5 text-primary\",\r\n },\r\n warning: {\r\n container:\r\n \"border-warning/30 bg-warning/10 transition-colors hover:bg-warning/15\",\r\n icon: \"bg-warning/10 text-warning\",\r\n },\r\n destructive: {\r\n container:\r\n \"border-destructive/30 bg-destructive/5 transition-colors hover:bg-destructive/10\",\r\n icon: \"bg-destructive/10 text-destructive\",\r\n },\r\n};\r\n\r\nfunction StatusNotice({\r\n icon: Icon,\r\n media,\r\n title,\r\n description,\r\n action,\r\n actionClassName,\r\n variant = \"primary\",\r\n compact = false,\r\n className,\r\n ...props\r\n}: ComponentProps<\"div\"> & {\r\n icon?: LucideIcon;\r\n media?: ReactNode;\r\n title: ReactNode;\r\n description?: ReactNode;\r\n action?: ReactNode;\r\n actionClassName?: string;\r\n variant?: StatusNoticeVariant;\r\n compact?: boolean;\r\n}) {\r\n const styles = variantClasses[variant];\r\n\r\n return (\r\n <div\r\n data-slot=\"status-notice\"\r\n className={cn(\r\n \"group/status-notice flex flex-col rounded-[0.33em] border\",\r\n compact\r\n ? \"items-start gap-3 p-3 sm:flex-row sm:items-start sm:gap-2\"\r\n : \"gap-4 px-4 py-4 sm:flex-row sm:items-stretch sm:gap-3 sm:px-5\",\r\n styles.container,\r\n className,\r\n )}\r\n {...props}\r\n >\r\n <div\r\n className={cn(\r\n \"flex min-w-0 flex-1 items-start gap-3 sm:items-stretch sm:gap-3\",\r\n compact && \"gap-2 sm:items-start sm:gap-2\",\r\n )}\r\n >\r\n <span\r\n className={cn(\r\n \"flex shrink-0 items-center justify-center rounded-[0.33em]\",\r\n compact ? \"size-8\" : \"size-10 sm:self-center\",\r\n styles.icon,\r\n )}\r\n >\r\n {media ??\r\n (Icon && (\r\n <Icon\r\n className={compact ? \"size-4\" : \"size-5\"}\r\n aria-hidden=\"true\"\r\n />\r\n ))}\r\n </span>\r\n <div className=\"min-w-0 flex-1 space-y-0.5\">\r\n <p className=\"text-sm font-medium text-gray-900\">{title}</p>\r\n {description && (\r\n <div className=\"text-muted-foreground text-sm\">{description}</div>\r\n )}\r\n </div>\r\n </div>\r\n {action && (\r\n <div\r\n className={cn(\r\n \"w-full shrink-0 sm:w-auto sm:self-center\",\r\n actionClassName,\r\n )}\r\n >\r\n {action}\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n\r\nexport { StatusNotice, type StatusNoticeVariant };\r\n"],"names":["_jsxs","_jsx"],"mappings":";;;AAMA,MAAM,cAAc,GAGhB;AACF,IAAA,OAAO,EAAE;AACP,QAAA,SAAS,EACP,gFAAgF;AAClF,QAAA,IAAI,EAAE,2BAA2B;AAClC,KAAA;AACD,IAAA,OAAO,EAAE;AACP,QAAA,SAAS,EACP,uEAAuE;AACzE,QAAA,IAAI,EAAE,4BAA4B;AACnC,KAAA;AACD,IAAA,WAAW,EAAE;AACX,QAAA,SAAS,EACP,kFAAkF;AACpF,QAAA,IAAI,EAAE,oCAAoC;AAC3C,KAAA;CACF;AAED,SAAS,YAAY,CAAC,EACpB,IAAI,EAAE,IAAI,EACV,KAAK,EACL,KAAK,EACL,WAAW,EACX,MAAM,EACN,eAAe,EACf,OAAO,GAAG,SAAS,EACnB,OAAO,GAAG,KAAK,EACf,SAAS,EACT,GAAG,KAAK,EAUT,EAAA;AACC,IAAA,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC;IAEtC,QACEA,IAAA,CAAA,KAAA,EAAA,EAAA,WAAA,EACY,eAAe,EACzB,SAAS,EAAE,EAAE,CACX,2DAA2D,EAC3D;AACE,cAAE;cACA,+DAA+D,EACnE,MAAM,CAAC,SAAS,EAChB,SAAS,CACV,EAAA,GACG,KAAK,EAAA,QAAA,EAAA,CAETA,IAAA,CAAA,KAAA,EAAA,EACE,SAAS,EAAE,EAAE,CACX,iEAAiE,EACjE,OAAO,IAAI,+BAA+B,CAC3C,aAEDC,GAAA,CAAA,MAAA,EAAA,EACE,SAAS,EAAE,EAAE,CACX,4DAA4D,EAC5D,OAAO,GAAG,QAAQ,GAAG,wBAAwB,EAC7C,MAAM,CAAC,IAAI,CACZ,EAAA,QAAA,EAEA,KAAK;AACJ,6BAAC,IAAI,KACHA,GAAA,CAAC,IAAI,EAAA,EACH,SAAS,EAAE,OAAO,GAAG,QAAQ,GAAG,QAAQ,EAAA,aAAA,EAC5B,MAAM,EAAA,CAClB,CACH,CAAC,GACC,EACPD,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,4BAA4B,EAAA,QAAA,EAAA,CACzCC,GAAA,CAAA,GAAA,EAAA,EAAG,SAAS,EAAC,mCAAmC,EAAA,QAAA,EAAE,KAAK,EAAA,CAAK,EAC3D,WAAW,KACVA,aAAK,SAAS,EAAC,+BAA+B,EAAA,QAAA,EAAE,WAAW,EAAA,CAAO,CACnE,CAAA,EAAA,CACG,IACF,EACL,MAAM,KACLA,GAAA,CAAA,KAAA,EAAA,EACE,SAAS,EAAE,EAAE,CACX,0CAA0C,EAC1C,eAAe,CAChB,YAEA,MAAM,EAAA,CACH,CACP,CAAA,EAAA,CACG;AAEV;;;;"}
1
+ {"version":3,"file":"status-notice.js","sources":["../../../src/components/ui/status-notice.tsx"],"sourcesContent":["import type { ComponentProps, ReactNode } from \"react\";\nimport type { LucideIcon } from \"lucide-react\";\nimport { cn } from \"@/utils\";\n\ntype StatusNoticeVariant = \"primary\" | \"warning\" | \"destructive\";\n\nconst variantClasses: Record<\n StatusNoticeVariant,\n { container: string; icon: string }\n> = {\n primary: {\n container:\n \"border-primary/25 bg-primary/[0.035] transition-colors hover:bg-primary/[0.06]\",\n icon: \"bg-primary/5 text-primary\",\n },\n warning: {\n container:\n \"border-warning/30 bg-warning/10 transition-colors hover:bg-warning/15\",\n icon: \"bg-warning/10 text-warning\",\n },\n destructive: {\n container:\n \"border-destructive/30 bg-destructive/5 transition-colors hover:bg-destructive/10\",\n icon: \"bg-destructive/10 text-destructive\",\n },\n};\n\nfunction StatusNotice({\n icon: Icon,\n media,\n title,\n description,\n action,\n actionClassName,\n variant = \"primary\",\n compact = false,\n className,\n ...props\n}: ComponentProps<\"div\"> & {\n icon?: LucideIcon;\n media?: ReactNode;\n title: ReactNode;\n description?: ReactNode;\n action?: ReactNode;\n actionClassName?: string;\n variant?: StatusNoticeVariant;\n compact?: boolean;\n}) {\n const styles = variantClasses[variant];\n\n return (\n <div\n data-slot=\"status-notice\"\n className={cn(\n \"group/status-notice flex flex-col rounded-[0.33em] border\",\n compact\n ? \"items-start gap-3 p-3 sm:flex-row sm:items-start sm:gap-2\"\n : \"gap-4 px-4 py-4 sm:flex-row sm:items-stretch sm:gap-3 sm:px-5\",\n styles.container,\n className,\n )}\n {...props}\n >\n <div\n className={cn(\n \"flex min-w-0 flex-1 items-start gap-3 sm:items-stretch sm:gap-3\",\n compact && \"gap-2 sm:items-start sm:gap-2\",\n )}\n >\n <span\n className={cn(\n \"flex shrink-0 items-center justify-center rounded-[0.33em]\",\n compact ? \"size-8\" : \"size-10 sm:self-center\",\n styles.icon,\n )}\n >\n {media ??\n (Icon && (\n <Icon\n className={compact ? \"size-4\" : \"size-5\"}\n aria-hidden=\"true\"\n />\n ))}\n </span>\n <div className=\"min-w-0 flex-1 space-y-0.5\">\n <p className=\"text-sm font-medium text-gray-900\">{title}</p>\n {description && (\n <div className=\"text-muted-foreground text-sm\">{description}</div>\n )}\n </div>\n </div>\n {action && (\n <div\n className={cn(\n \"w-full shrink-0 sm:w-auto sm:self-center\",\n actionClassName,\n )}\n >\n {action}\n </div>\n )}\n </div>\n );\n}\n\nexport { StatusNotice, type StatusNoticeVariant };\n"],"names":["_jsxs","_jsx"],"mappings":";;;AAMA,MAAM,cAAc,GAGhB;AACF,IAAA,OAAO,EAAE;AACP,QAAA,SAAS,EACP,gFAAgF;AAClF,QAAA,IAAI,EAAE,2BAA2B;AAClC,KAAA;AACD,IAAA,OAAO,EAAE;AACP,QAAA,SAAS,EACP,uEAAuE;AACzE,QAAA,IAAI,EAAE,4BAA4B;AACnC,KAAA;AACD,IAAA,WAAW,EAAE;AACX,QAAA,SAAS,EACP,kFAAkF;AACpF,QAAA,IAAI,EAAE,oCAAoC;AAC3C,KAAA;CACF;AAED,SAAS,YAAY,CAAC,EACpB,IAAI,EAAE,IAAI,EACV,KAAK,EACL,KAAK,EACL,WAAW,EACX,MAAM,EACN,eAAe,EACf,OAAO,GAAG,SAAS,EACnB,OAAO,GAAG,KAAK,EACf,SAAS,EACT,GAAG,KAAK,EAUT,EAAA;AACC,IAAA,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC;IAEtC,QACEA,IAAA,CAAA,KAAA,EAAA,EAAA,WAAA,EACY,eAAe,EACzB,SAAS,EAAE,EAAE,CACX,2DAA2D,EAC3D;AACE,cAAE;cACA,+DAA+D,EACnE,MAAM,CAAC,SAAS,EAChB,SAAS,CACV,EAAA,GACG,KAAK,EAAA,QAAA,EAAA,CAETA,IAAA,CAAA,KAAA,EAAA,EACE,SAAS,EAAE,EAAE,CACX,iEAAiE,EACjE,OAAO,IAAI,+BAA+B,CAC3C,aAEDC,GAAA,CAAA,MAAA,EAAA,EACE,SAAS,EAAE,EAAE,CACX,4DAA4D,EAC5D,OAAO,GAAG,QAAQ,GAAG,wBAAwB,EAC7C,MAAM,CAAC,IAAI,CACZ,EAAA,QAAA,EAEA,KAAK;AACJ,6BAAC,IAAI,KACHA,GAAA,CAAC,IAAI,EAAA,EACH,SAAS,EAAE,OAAO,GAAG,QAAQ,GAAG,QAAQ,EAAA,aAAA,EAC5B,MAAM,EAAA,CAClB,CACH,CAAC,GACC,EACPD,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,4BAA4B,EAAA,QAAA,EAAA,CACzCC,GAAA,CAAA,GAAA,EAAA,EAAG,SAAS,EAAC,mCAAmC,EAAA,QAAA,EAAE,KAAK,EAAA,CAAK,EAC3D,WAAW,KACVA,aAAK,SAAS,EAAC,+BAA+B,EAAA,QAAA,EAAE,WAAW,EAAA,CAAO,CACnE,CAAA,EAAA,CACG,IACF,EACL,MAAM,KACLA,GAAA,CAAA,KAAA,EAAA,EACE,SAAS,EAAE,EAAE,CACX,0CAA0C,EAC1C,eAAe,CAChB,YAEA,MAAM,EAAA,CACH,CACP,CAAA,EAAA,CACG;AAEV;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"table.js","sources":["../../../src/components/ui/table.tsx"],"sourcesContent":["import * as React from 'react';\r\n\r\nimport { cn } from '@/utils';\r\n\r\nfunction Table({ className, ...props }: React.ComponentProps<'table'>) {\r\n return (\r\n <div\r\n data-slot=\"table-container\"\r\n className=\"relative w-full overflow-x-auto [scrollbar-gutter:stable]\"\r\n >\r\n <table\r\n data-slot=\"table\"\r\n className={cn('w-full caption-bottom text-sm', className)}\r\n {...props}\r\n />\r\n </div>\r\n );\r\n}\r\n\r\nfunction TableHeader({ className, ...props }: React.ComponentProps<'thead'>) {\r\n return (\r\n <thead\r\n data-slot=\"table-header\"\r\n className={cn('[&_tr]:border-b', className)}\r\n {...props}\r\n />\r\n );\r\n}\r\n\r\nfunction TableBody({ className, ...props }: React.ComponentProps<'tbody'>) {\r\n return (\r\n <tbody\r\n data-slot=\"table-body\"\r\n className={cn('[&_tr:last-child]:border-0', className)}\r\n {...props}\r\n />\r\n );\r\n}\r\n\r\nfunction TableFooter({ className, ...props }: React.ComponentProps<'tfoot'>) {\r\n return (\r\n <tfoot\r\n data-slot=\"table-footer\"\r\n className={cn(\r\n 'bg-muted/50 border-t font-medium [&>tr]:last:border-b-0',\r\n className,\r\n )}\r\n {...props}\r\n />\r\n );\r\n}\r\n\r\nfunction TableRow({ className, ...props }: React.ComponentProps<'tr'>) {\r\n return (\r\n <tr\r\n data-slot=\"table-row\"\r\n className={cn(\r\n 'hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors',\r\n className,\r\n )}\r\n {...props}\r\n />\r\n );\r\n}\r\n\r\nfunction TableHead({ className, ...props }: React.ComponentProps<'th'>) {\r\n return (\r\n <th\r\n data-slot=\"table-head\"\r\n className={cn(\r\n 'text-foreground h-10 px-2 text-left align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]',\r\n className,\r\n )}\r\n {...props}\r\n />\r\n );\r\n}\r\n\r\nfunction TableCell({ className, ...props }: React.ComponentProps<'td'>) {\r\n return (\r\n <td\r\n data-slot=\"table-cell\"\r\n className={cn(\r\n 'p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]',\r\n className,\r\n )}\r\n {...props}\r\n />\r\n );\r\n}\r\n\r\nfunction TableCaption({\r\n className,\r\n ...props\r\n}: React.ComponentProps<'caption'>) {\r\n return (\r\n <caption\r\n data-slot=\"table-caption\"\r\n className={cn('text-muted-foreground mt-4 text-sm', className)}\r\n {...props}\r\n />\r\n );\r\n}\r\n\r\nexport {\r\n Table,\r\n TableHeader,\r\n TableBody,\r\n TableFooter,\r\n TableHead,\r\n TableRow,\r\n TableCell,\r\n TableCaption,\r\n};\r\n"],"names":["_jsx"],"mappings":";;;AAIA,SAAS,KAAK,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAiC,EAAA;IACnE,QACEA,GAAA,CAAA,KAAA,EAAA,EAAA,WAAA,EACY,iBAAiB,EAC3B,SAAS,EAAC,2DAA2D,EAAA,QAAA,EAErEA,GAAA,CAAA,OAAA,EAAA,EAAA,WAAA,EACY,OAAO,EACjB,SAAS,EAAE,EAAE,CAAC,+BAA+B,EAAE,SAAS,CAAC,KACrD,KAAK,EAAA,CACT,EAAA,CACE;AAEV;AAEA,SAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAiC,EAAA;AACzE,IAAA,QACEA,GAAA,CAAA,OAAA,EAAA,EAAA,WAAA,EACY,cAAc,EACxB,SAAS,EAAE,EAAE,CAAC,iBAAiB,EAAE,SAAS,CAAC,EAAA,GACvC,KAAK,EAAA,CACT;AAEN;AAEA,SAAS,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAiC,EAAA;AACvE,IAAA,QACEA,GAAA,CAAA,OAAA,EAAA,EAAA,WAAA,EACY,YAAY,EACtB,SAAS,EAAE,EAAE,CAAC,4BAA4B,EAAE,SAAS,CAAC,EAAA,GAClD,KAAK,EAAA,CACT;AAEN;AAEA,SAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAiC,EAAA;AACzE,IAAA,QACEA,GAAA,CAAA,OAAA,EAAA,EAAA,WAAA,EACY,cAAc,EACxB,SAAS,EAAE,EAAE,CACX,yDAAyD,EACzD,SAAS,CACV,EAAA,GACG,KAAK,EAAA,CACT;AAEN;AAEA,SAAS,QAAQ,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAA8B,EAAA;AACnE,IAAA,QACEA,GAAA,CAAA,IAAA,EAAA,EAAA,WAAA,EACY,WAAW,EACrB,SAAS,EAAE,EAAE,CACX,6EAA6E,EAC7E,SAAS,CACV,EAAA,GACG,KAAK,EAAA,CACT;AAEN;AAEA,SAAS,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAA8B,EAAA;AACpE,IAAA,QACEA,GAAA,CAAA,IAAA,EAAA,EAAA,WAAA,EACY,YAAY,EACtB,SAAS,EAAE,EAAE,CACX,oJAAoJ,EACpJ,SAAS,CACV,EAAA,GACG,KAAK,EAAA,CACT;AAEN;AAEA,SAAS,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAA8B,EAAA;AACpE,IAAA,QACEA,GAAA,CAAA,IAAA,EAAA,EAAA,WAAA,EACY,YAAY,EACtB,SAAS,EAAE,EAAE,CACX,wGAAwG,EACxG,SAAS,CACV,EAAA,GACG,KAAK,EAAA,CACT;AAEN;AAEA,SAAS,YAAY,CAAC,EACpB,SAAS,EACT,GAAG,KAAK,EACwB,EAAA;AAChC,IAAA,QACEA,GAAA,CAAA,SAAA,EAAA,EAAA,WAAA,EACY,eAAe,EACzB,SAAS,EAAE,EAAE,CAAC,oCAAoC,EAAE,SAAS,CAAC,EAAA,GAC1D,KAAK,EAAA,CACT;AAEN;;;;"}
1
+ {"version":3,"file":"table.js","sources":["../../../src/components/ui/table.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { cn } from '@/utils';\n\nfunction Table({ className, ...props }: React.ComponentProps<'table'>) {\n return (\n <div\n data-slot=\"table-container\"\n className=\"relative w-full overflow-x-auto [scrollbar-gutter:stable]\"\n >\n <table\n data-slot=\"table\"\n className={cn('w-full caption-bottom text-sm', className)}\n {...props}\n />\n </div>\n );\n}\n\nfunction TableHeader({ className, ...props }: React.ComponentProps<'thead'>) {\n return (\n <thead\n data-slot=\"table-header\"\n className={cn('[&_tr]:border-b', className)}\n {...props}\n />\n );\n}\n\nfunction TableBody({ className, ...props }: React.ComponentProps<'tbody'>) {\n return (\n <tbody\n data-slot=\"table-body\"\n className={cn('[&_tr:last-child]:border-0', className)}\n {...props}\n />\n );\n}\n\nfunction TableFooter({ className, ...props }: React.ComponentProps<'tfoot'>) {\n return (\n <tfoot\n data-slot=\"table-footer\"\n className={cn(\n 'bg-muted/50 border-t font-medium [&>tr]:last:border-b-0',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction TableRow({ className, ...props }: React.ComponentProps<'tr'>) {\n return (\n <tr\n data-slot=\"table-row\"\n className={cn(\n 'hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction TableHead({ className, ...props }: React.ComponentProps<'th'>) {\n return (\n <th\n data-slot=\"table-head\"\n className={cn(\n 'text-foreground h-10 px-2 text-left align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction TableCell({ className, ...props }: React.ComponentProps<'td'>) {\n return (\n <td\n data-slot=\"table-cell\"\n className={cn(\n 'p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction TableCaption({\n className,\n ...props\n}: React.ComponentProps<'caption'>) {\n return (\n <caption\n data-slot=\"table-caption\"\n className={cn('text-muted-foreground mt-4 text-sm', className)}\n {...props}\n />\n );\n}\n\nexport {\n Table,\n TableHeader,\n TableBody,\n TableFooter,\n TableHead,\n TableRow,\n TableCell,\n TableCaption,\n};\n"],"names":["_jsx"],"mappings":";;;AAIA,SAAS,KAAK,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAiC,EAAA;IACnE,QACEA,GAAA,CAAA,KAAA,EAAA,EAAA,WAAA,EACY,iBAAiB,EAC3B,SAAS,EAAC,2DAA2D,EAAA,QAAA,EAErEA,GAAA,CAAA,OAAA,EAAA,EAAA,WAAA,EACY,OAAO,EACjB,SAAS,EAAE,EAAE,CAAC,+BAA+B,EAAE,SAAS,CAAC,KACrD,KAAK,EAAA,CACT,EAAA,CACE;AAEV;AAEA,SAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAiC,EAAA;AACzE,IAAA,QACEA,GAAA,CAAA,OAAA,EAAA,EAAA,WAAA,EACY,cAAc,EACxB,SAAS,EAAE,EAAE,CAAC,iBAAiB,EAAE,SAAS,CAAC,EAAA,GACvC,KAAK,EAAA,CACT;AAEN;AAEA,SAAS,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAiC,EAAA;AACvE,IAAA,QACEA,GAAA,CAAA,OAAA,EAAA,EAAA,WAAA,EACY,YAAY,EACtB,SAAS,EAAE,EAAE,CAAC,4BAA4B,EAAE,SAAS,CAAC,EAAA,GAClD,KAAK,EAAA,CACT;AAEN;AAEA,SAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAiC,EAAA;AACzE,IAAA,QACEA,GAAA,CAAA,OAAA,EAAA,EAAA,WAAA,EACY,cAAc,EACxB,SAAS,EAAE,EAAE,CACX,yDAAyD,EACzD,SAAS,CACV,EAAA,GACG,KAAK,EAAA,CACT;AAEN;AAEA,SAAS,QAAQ,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAA8B,EAAA;AACnE,IAAA,QACEA,GAAA,CAAA,IAAA,EAAA,EAAA,WAAA,EACY,WAAW,EACrB,SAAS,EAAE,EAAE,CACX,6EAA6E,EAC7E,SAAS,CACV,EAAA,GACG,KAAK,EAAA,CACT;AAEN;AAEA,SAAS,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAA8B,EAAA;AACpE,IAAA,QACEA,GAAA,CAAA,IAAA,EAAA,EAAA,WAAA,EACY,YAAY,EACtB,SAAS,EAAE,EAAE,CACX,oJAAoJ,EACpJ,SAAS,CACV,EAAA,GACG,KAAK,EAAA,CACT;AAEN;AAEA,SAAS,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAA8B,EAAA;AACpE,IAAA,QACEA,GAAA,CAAA,IAAA,EAAA,EAAA,WAAA,EACY,YAAY,EACtB,SAAS,EAAE,EAAE,CACX,wGAAwG,EACxG,SAAS,CACV,EAAA,GACG,KAAK,EAAA,CACT;AAEN;AAEA,SAAS,YAAY,CAAC,EACpB,SAAS,EACT,GAAG,KAAK,EACwB,EAAA;AAChC,IAAA,QACEA,GAAA,CAAA,SAAA,EAAA,EAAA,WAAA,EACY,eAAe,EACzB,SAAS,EAAE,EAAE,CAAC,oCAAoC,EAAE,SAAS,CAAC,EAAA,GAC1D,KAAK,EAAA,CACT;AAEN;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"useMQJob.js","sources":["../../src/hooks/useMQJob.tsx"],"sourcesContent":["'use client';\r\n\r\nimport { createContext, useContext, useRef } from 'react';\r\nimport { useQueries, useQuery, Query } from '@tanstack/react-query';\r\n\r\nexport type MQJobStatus = 'queued' | 'processing' | 'done' | 'failed';\r\n\r\nexport interface MQJob<T = unknown> {\r\n id: string;\r\n type: string;\r\n status: MQJobStatus;\r\n progress?: { total: number; done: number; failed: number };\r\n result?: T;\r\n error?: string;\r\n}\r\n\r\ninterface MQJobsConfig {\r\n /**\r\n * Fetches the current state of a job. The package knows no URL and no\r\n * response envelope — the consuming app owns both (plan §5.2). Reject/throw\r\n * on a transport or not-found failure; React Query's own retry handles it.\r\n */\r\n poll: (jobId: string) => Promise<MQJob>;\r\n}\r\n\r\nconst MQJobsContext = createContext<MQJobsConfig | null>(null);\r\n\r\n/** Mount once near the root, alongside the app's other data providers. */\r\nexport const MQJobsProvider = ({\r\n poll,\r\n children,\r\n}: MQJobsConfig & { children: React.ReactNode }) => (\r\n <MQJobsContext.Provider value={{ poll }}>{children}</MQJobsContext.Provider>\r\n);\r\n\r\nconst useMQJobsConfig = (caller: string): MQJobsConfig => {\r\n const ctx = useContext(MQJobsContext);\r\n if (!ctx)\r\n throw new Error(`${caller}() must be used within a <MQJobsProvider>.`);\r\n return ctx;\r\n};\r\n\r\nconst BASE_INTERVAL_MS = 2000;\r\nconst MAX_INTERVAL_MS = 10000;\r\n\r\n/** Capped backoff keyed per job id, so each job restarts its own count. */\r\nconst nextInterval = (\r\n attempts: { current: Record<string, number> },\r\n key: string,\r\n status: MQJobStatus | undefined,\r\n): number | false => {\r\n if (status === 'done' || status === 'failed') return false;\r\n const attempt = attempts.current[key] ?? 0;\r\n attempts.current[key] = attempt + 1;\r\n return Math.min(BASE_INTERVAL_MS * 1.5 ** attempt, MAX_INTERVAL_MS);\r\n};\r\n\r\nconst summarize = <T,>(job: MQJob<T> | undefined) => ({\r\n job,\r\n status: job?.status,\r\n result: job?.result,\r\n error: job?.error,\r\n isPending: !job || job.status === 'queued' || job.status === 'processing',\r\n isDone: job?.status === 'done',\r\n isFailed: job?.status === 'failed',\r\n});\r\n\r\n/**\r\n * Polls a single `internal.mq_jobs` row to completion. Replaces\r\n * `useClientProcess` for anything queued through the broker: no\r\n * callback-URL dance, the result comes back inline on the job itself once\r\n * `status` is terminal.\r\n */\r\nexport function useMQJob<T = unknown>(jobId?: string | null) {\r\n const { poll } = useMQJobsConfig('useMQJob');\r\n const attempts = useRef<Record<string, number>>({});\r\n\r\n const query = useQuery<MQJob<T>>({\r\n queryKey: ['.__mq_job', jobId],\r\n // `poll`'s result field is caller-typed via `T`; the transport itself\r\n // doesn't know or care what shape a given job's result has.\r\n queryFn: () => poll(jobId as string) as Promise<MQJob<T>>,\r\n enabled: !!jobId,\r\n staleTime: Infinity,\r\n refetchOnWindowFocus: true,\r\n refetchIntervalInBackground: true,\r\n refetchInterval: (query: Query<MQJob<T>>) =>\r\n nextInterval(attempts, jobId ?? '', query.state.data?.status),\r\n });\r\n\r\n return summarize(query.data);\r\n}\r\n\r\n/**\r\n * Polls a dynamic set of `internal.mq_jobs` rows to completion — for a\r\n * feature that can have several jobs in flight at once (e.g. a list of\r\n * pending/handled items). Built on `useQueries` directly rather than\r\n * composing `useMQJob` in a loop, since the number of tracked ids changes\r\n * over time and that would violate the rules of hooks.\r\n */\r\nexport function useMQJobs<T = unknown>(jobIds: readonly string[]) {\r\n const { poll } = useMQJobsConfig('useMQJobs');\r\n const attempts = useRef<Record<string, number>>({});\r\n\r\n const queries = useQueries({\r\n queries: jobIds.map((jobId) => ({\r\n queryKey: ['.__mq_job', jobId],\r\n queryFn: () => poll(jobId) as Promise<MQJob<T>>,\r\n staleTime: Infinity,\r\n refetchOnWindowFocus: true,\r\n refetchIntervalInBackground: true,\r\n refetchInterval: (query: Query<MQJob<T>>) =>\r\n nextInterval(attempts, jobId, query.state.data?.status),\r\n })),\r\n });\r\n\r\n return jobIds.map((jobId, index) => ({\r\n jobId,\r\n ...summarize(queries[index]?.data as MQJob<T> | undefined),\r\n }));\r\n}\r\n"],"names":[],"mappings":";;;;;AAyBA;AAEA;AACO;AAOP;AACE;AACA;AACE;AACF;AACF;AAEA;AACA;AAEA;AACA;AAKE;AAA8C;;;AAG9C;AACF;AAEA;;;;;AAKE;AACA;AACA;AACD;AAED;;;;;AAKG;AACG;;AAEJ;;AAGE;;;AAGA;;AAEA;AACA;AACA;;AAGD;AAED;AACF;AAEA;;;;;;AAMG;AACG;;AAEJ;;;AAII;AACA;AACA;AACA;AACA;AACA;AAED;AACF;;;;AAKA;AACH;;"}
1
+ {"version":3,"file":"useMQJob.js","sources":["../../src/hooks/useMQJob.tsx"],"sourcesContent":["'use client';\n\nimport { createContext, useContext, useRef } from 'react';\nimport { useQueries, useQuery, Query } from '@tanstack/react-query';\n\nexport type MQJobStatus = 'queued' | 'processing' | 'done' | 'failed';\n\nexport interface MQJob<T = unknown> {\n id: string;\n type: string;\n status: MQJobStatus;\n progress?: { total: number; done: number; failed: number };\n result?: T;\n error?: string;\n}\n\ninterface MQJobsConfig {\n /**\n * Fetches the current state of a job. The package knows no URL and no\n * response envelope — the consuming app owns both (plan §5.2). Reject/throw\n * on a transport or not-found failure; React Query's own retry handles it.\n */\n poll: (jobId: string) => Promise<MQJob>;\n}\n\nconst MQJobsContext = createContext<MQJobsConfig | null>(null);\n\n/** Mount once near the root, alongside the app's other data providers. */\nexport const MQJobsProvider = ({\n poll,\n children,\n}: MQJobsConfig & { children: React.ReactNode }) => (\n <MQJobsContext.Provider value={{ poll }}>{children}</MQJobsContext.Provider>\n);\n\nconst useMQJobsConfig = (caller: string): MQJobsConfig => {\n const ctx = useContext(MQJobsContext);\n if (!ctx)\n throw new Error(`${caller}() must be used within a <MQJobsProvider>.`);\n return ctx;\n};\n\nconst BASE_INTERVAL_MS = 2000;\nconst MAX_INTERVAL_MS = 10000;\n\n/** Capped backoff keyed per job id, so each job restarts its own count. */\nconst nextInterval = (\n attempts: { current: Record<string, number> },\n key: string,\n status: MQJobStatus | undefined,\n): number | false => {\n if (status === 'done' || status === 'failed') return false;\n const attempt = attempts.current[key] ?? 0;\n attempts.current[key] = attempt + 1;\n return Math.min(BASE_INTERVAL_MS * 1.5 ** attempt, MAX_INTERVAL_MS);\n};\n\nconst summarize = <T,>(job: MQJob<T> | undefined) => ({\n job,\n status: job?.status,\n result: job?.result,\n error: job?.error,\n isPending: !job || job.status === 'queued' || job.status === 'processing',\n isDone: job?.status === 'done',\n isFailed: job?.status === 'failed',\n});\n\n/**\n * Polls a single `internal.mq_jobs` row to completion. Replaces\n * `useClientProcess` for anything queued through the broker: no\n * callback-URL dance, the result comes back inline on the job itself once\n * `status` is terminal.\n */\nexport function useMQJob<T = unknown>(jobId?: string | null) {\n const { poll } = useMQJobsConfig('useMQJob');\n const attempts = useRef<Record<string, number>>({});\n\n const query = useQuery<MQJob<T>>({\n queryKey: ['.__mq_job', jobId],\n // `poll`'s result field is caller-typed via `T`; the transport itself\n // doesn't know or care what shape a given job's result has.\n queryFn: () => poll(jobId as string) as Promise<MQJob<T>>,\n enabled: !!jobId,\n staleTime: Infinity,\n refetchOnWindowFocus: true,\n refetchIntervalInBackground: true,\n refetchInterval: (query: Query<MQJob<T>>) =>\n nextInterval(attempts, jobId ?? '', query.state.data?.status),\n });\n\n return summarize(query.data);\n}\n\n/**\n * Polls a dynamic set of `internal.mq_jobs` rows to completion — for a\n * feature that can have several jobs in flight at once (e.g. a list of\n * pending/handled items). Built on `useQueries` directly rather than\n * composing `useMQJob` in a loop, since the number of tracked ids changes\n * over time and that would violate the rules of hooks.\n */\nexport function useMQJobs<T = unknown>(jobIds: readonly string[]) {\n const { poll } = useMQJobsConfig('useMQJobs');\n const attempts = useRef<Record<string, number>>({});\n\n const queries = useQueries({\n queries: jobIds.map((jobId) => ({\n queryKey: ['.__mq_job', jobId],\n queryFn: () => poll(jobId) as Promise<MQJob<T>>,\n staleTime: Infinity,\n refetchOnWindowFocus: true,\n refetchIntervalInBackground: true,\n refetchInterval: (query: Query<MQJob<T>>) =>\n nextInterval(attempts, jobId, query.state.data?.status),\n })),\n });\n\n return jobIds.map((jobId, index) => ({\n jobId,\n ...summarize(queries[index]?.data as MQJob<T> | undefined),\n }));\n}\n"],"names":[],"mappings":";;;;;AAyBA;AAEA;AACO;AAOP;AACE;AACA;AACE;AACF;AACF;AAEA;AACA;AAEA;AACA;AAKE;AAA8C;;;AAG9C;AACF;AAEA;;;;;AAKE;AACA;AACA;AACD;AAED;;;;;AAKG;AACG;;AAEJ;;AAGE;;;AAGA;;AAEA;AACA;AACA;;AAGD;AAED;AACF;AAEA;;;;;;AAMG;AACG;;AAEJ;;;AAII;AACA;AACA;AACA;AACA;AACA;AAED;AACF;;;;AAKA;AACH;;"}
package/dist/index.d.ts CHANGED
@@ -1,9 +1,8 @@
1
- export * from './config';
2
1
  export * from './utils';
3
- export * from './hooks/useClientProcess';
4
2
  export * from './hooks/useMQJob';
5
3
  export * from './components/ui/button';
6
4
  export * from './components/ui/accordion';
5
+ export * from './components/ui/animated-count';
7
6
  export * from './components/ui/app-header';
8
7
  export * from './components/ui/input';
9
8
  export * from './components/ui/icons';
package/dist/index.js CHANGED
@@ -1,9 +1,8 @@
1
- export { config, configure } from './config.js';
2
1
  export { cn } from './utils.js';
3
- export { ClientProcessesProvider, useClientProcess } from './hooks/useClientProcess.js';
4
2
  export { MQJobsProvider, useMQJob, useMQJobs } from './hooks/useMQJob.js';
5
3
  export { Button, buttonVariants } from './components/ui/button.js';
6
4
  export { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from './components/ui/accordion.js';
5
+ export { AnimatedCount } from './components/ui/animated-count.js';
7
6
  export { AppHeader } from './components/ui/app-header.js';
8
7
  export { Input } from './components/ui/input.js';
9
8
  export { BooleanCheckIcon, JobModeIcon, JobTypeIcon, SalaryIcon } from './components/ui/icons.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;"}
package/dist/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sources":["../src/utils.ts"],"sourcesContent":["import { clsx, type ClassValue } from \"clsx\";\r\nimport { twMerge } from \"tailwind-merge\";\r\n\r\nexport function cn(...inputs: ClassValue[]) {\r\n return twMerge(clsx(inputs));\r\n}"],"names":[],"mappings":";;;AAGM,SAAU,EAAE,CAAC,GAAG,MAAoB,EAAA;AACxC,IAAA,OAAO,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC9B;;;;"}
1
+ {"version":3,"file":"utils.js","sources":["../src/utils.ts"],"sourcesContent":["import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}"],"names":[],"mappings":";;;AAGM,SAAU,EAAE,CAAC,GAAG,MAAoB,EAAA;AACxC,IAAA,OAAO,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC9B;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@betterinternship/components",
3
- "version": "2.5.1",
3
+ "version": "2.7.0",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -150,6 +150,7 @@
150
150
  "@radix-ui/react-toggle-group": "^1.1.1",
151
151
  "@radix-ui/react-tooltip": "^1.2.7",
152
152
  "@tanstack/react-query": "^5.0.0",
153
+ "framer-motion": ">=11",
153
154
  "lucide-react": ">=0.454.0",
154
155
  "next": "^16.3.1",
155
156
  "react": "^19",
@@ -173,6 +174,7 @@
173
174
  "devDependencies": {
174
175
  "@eslint/eslintrc": "^3.2.0",
175
176
  "@eslint/js": "^9.18.0",
177
+ "framer-motion": "^13.1.1",
176
178
  "@radix-ui/react-accordion": "^1.2.11",
177
179
  "@radix-ui/react-alert-dialog": "^1.1.15",
178
180
  "@radix-ui/react-aspect-ratio": "^1.1.1",