@sqlrooms/ui 0.29.0-rc.7 → 0.29.0-rc.9

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.
package/LICENSE.md CHANGED
@@ -1,6 +1,7 @@
1
1
  MIT License
2
2
 
3
- Copyright 2025 SQLRooms Contributors
3
+ Copyright 2024-2026 SQLRooms Contributors
4
+ Copyright Vis.gl contributors
4
5
 
5
6
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
7
 
@@ -6,6 +6,8 @@ declare const ProgressModal: FC<{
6
6
  loadingStage?: string;
7
7
  progress?: number;
8
8
  indeterminate?: boolean;
9
+ error?: string;
10
+ errorDetails?: string;
9
11
  }>;
10
12
  export { ProgressModal };
11
13
  //# sourceMappingURL=progress-modal.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"progress-modal.d.ts","sourceRoot":"","sources":["../../src/components/progress-modal.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAC,EAAE,EAAC,MAAM,OAAO,CAAC;AAWzB,QAAA,MAAM,aAAa,EAAE,EAAE,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CA6BA,CAAC;AAEF,OAAO,EAAC,aAAa,EAAC,CAAC"}
1
+ {"version":3,"file":"progress-modal.d.ts","sourceRoot":"","sources":["../../src/components/progress-modal.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAC,EAAE,EAAC,MAAM,OAAO,CAAC;AAWzB,QAAA,MAAM,aAAa,EAAE,EAAE,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAwDA,CAAC;AAEF,OAAO,EAAC,aAAa,EAAC,CAAC"}
@@ -4,8 +4,8 @@ import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, }
4
4
  import { Progress } from './progress';
5
5
  import { cn } from '../lib/utils';
6
6
  const ProgressModal = (props) => {
7
- const { className, isOpen, title, loadingStage, progress, indeterminate } = props;
8
- return (_jsx(Dialog, { open: isOpen, onOpenChange: () => { }, children: _jsxs(DialogContent, { className: cn('rounded-md border-none focus:outline-hidden sm:max-w-[425px]', className), showCloseButton: false, children: [_jsx(DialogHeader, { children: _jsx(DialogTitle, { children: title ?? '' }) }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Progress, { value: progress, className: "h-2 w-full", indeterminate: indeterminate }), _jsxs(DialogDescription, { className: "text-muted-foreground flex justify-between text-sm", children: [_jsx("span", { className: "text-sm", children: loadingStage ?? '' }), progress ? _jsxs("span", { children: [progress, "%"] }) : null] })] })] }) }));
7
+ const { className, isOpen, title, loadingStage, progress, indeterminate, error, errorDetails, } = props;
8
+ return (_jsx(Dialog, { open: isOpen, onOpenChange: () => { }, children: _jsxs(DialogContent, { className: cn('rounded-md border-none focus:outline-hidden sm:max-w-[425px]', className), showCloseButton: false, children: [_jsx(DialogHeader, { children: _jsx(DialogTitle, { children: title ?? '' }) }), error ? (_jsxs("div", { className: "flex flex-col gap-3", children: [_jsx(DialogDescription, { className: "text-destructive text-sm font-medium", children: loadingStage ?? 'Initialization failed' }), _jsx("p", { className: "text-muted-foreground text-sm", children: error }), errorDetails ? (_jsxs("details", { className: "text-muted-foreground text-sm", children: [_jsx("summary", { className: "hover:text-foreground cursor-pointer font-medium", children: "Details" }), _jsx("pre", { className: "bg-muted text-muted-foreground mt-2 max-h-40 overflow-auto rounded-md p-3 text-xs whitespace-pre-wrap", children: errorDetails })] })) : null] })) : (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Progress, { value: progress, className: "h-2 w-full", indeterminate: indeterminate }), _jsxs(DialogDescription, { className: "text-muted-foreground flex justify-between text-sm", children: [_jsx("span", { className: "text-sm", children: loadingStage ?? '' }), progress !== undefined ? _jsxs("span", { children: [progress, "%"] }) : null] })] }))] }) }));
9
9
  };
10
10
  export { ProgressModal };
11
11
  //# sourceMappingURL=progress-modal.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"progress-modal.js","sourceRoot":"","sources":["../../src/components/progress-modal.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAGb,OAAO,EACL,MAAM,EACN,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,WAAW,GACZ,MAAM,UAAU,CAAC;AAClB,OAAO,EAAC,QAAQ,EAAC,MAAM,YAAY,CAAC;AACpC,OAAO,EAAC,EAAE,EAAC,MAAM,cAAc,CAAC;AAEhC,MAAM,aAAa,GAOd,CAAC,KAAK,EAAE,EAAE;IACb,MAAM,EAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAC,GACrE,KAAK,CAAC;IACR,OAAO,CACL,KAAC,MAAM,IAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,GAAG,EAAE,GAAE,CAAC,YAC1C,MAAC,aAAa,IACZ,SAAS,EAAE,EAAE,CACX,8DAA8D,EAC9D,SAAS,CACV,EACD,eAAe,EAAE,KAAK,aAEtB,KAAC,YAAY,cACX,KAAC,WAAW,cAAE,KAAK,IAAI,EAAE,GAAe,GAC3B,EACf,eAAK,SAAS,EAAC,qBAAqB,aAClC,KAAC,QAAQ,IACP,KAAK,EAAE,QAAQ,EACf,SAAS,EAAC,YAAY,EACtB,aAAa,EAAE,aAAa,GAC5B,EACF,MAAC,iBAAiB,IAAC,SAAS,EAAC,oDAAoD,aAC/E,eAAM,SAAS,EAAC,SAAS,YAAE,YAAY,IAAI,EAAE,GAAQ,EACpD,QAAQ,CAAC,CAAC,CAAC,2BAAO,QAAQ,SAAS,CAAC,CAAC,CAAC,IAAI,IACzB,IAChB,IACQ,GACT,CACV,CAAC;AACJ,CAAC,CAAC;AAEF,OAAO,EAAC,aAAa,EAAC,CAAC","sourcesContent":["'use client';\n\nimport {FC} from 'react';\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n} from './dialog';\nimport {Progress} from './progress';\nimport {cn} from '../lib/utils';\n\nconst ProgressModal: FC<{\n className?: string;\n isOpen: boolean;\n title?: string;\n loadingStage?: string;\n progress?: number;\n indeterminate?: boolean;\n}> = (props) => {\n const {className, isOpen, title, loadingStage, progress, indeterminate} =\n props;\n return (\n <Dialog open={isOpen} onOpenChange={() => {}}>\n <DialogContent\n className={cn(\n 'rounded-md border-none focus:outline-hidden sm:max-w-[425px]',\n className,\n )}\n showCloseButton={false}\n >\n <DialogHeader>\n <DialogTitle>{title ?? ''}</DialogTitle>\n </DialogHeader>\n <div className=\"flex flex-col gap-2\">\n <Progress\n value={progress}\n className=\"h-2 w-full\"\n indeterminate={indeterminate}\n />\n <DialogDescription className=\"text-muted-foreground flex justify-between text-sm\">\n <span className=\"text-sm\">{loadingStage ?? ''}</span>\n {progress ? <span>{progress}%</span> : null}\n </DialogDescription>\n </div>\n </DialogContent>\n </Dialog>\n );\n};\n\nexport {ProgressModal};\n"]}
1
+ {"version":3,"file":"progress-modal.js","sourceRoot":"","sources":["../../src/components/progress-modal.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAGb,OAAO,EACL,MAAM,EACN,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,WAAW,GACZ,MAAM,UAAU,CAAC;AAClB,OAAO,EAAC,QAAQ,EAAC,MAAM,YAAY,CAAC;AACpC,OAAO,EAAC,EAAE,EAAC,MAAM,cAAc,CAAC;AAEhC,MAAM,aAAa,GASd,CAAC,KAAK,EAAE,EAAE;IACb,MAAM,EACJ,SAAS,EACT,MAAM,EACN,KAAK,EACL,YAAY,EACZ,QAAQ,EACR,aAAa,EACb,KAAK,EACL,YAAY,GACb,GAAG,KAAK,CAAC;IACV,OAAO,CACL,KAAC,MAAM,IAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,GAAG,EAAE,GAAE,CAAC,YAC1C,MAAC,aAAa,IACZ,SAAS,EAAE,EAAE,CACX,8DAA8D,EAC9D,SAAS,CACV,EACD,eAAe,EAAE,KAAK,aAEtB,KAAC,YAAY,cACX,KAAC,WAAW,cAAE,KAAK,IAAI,EAAE,GAAe,GAC3B,EACd,KAAK,CAAC,CAAC,CAAC,CACP,eAAK,SAAS,EAAC,qBAAqB,aAClC,KAAC,iBAAiB,IAAC,SAAS,EAAC,sCAAsC,YAChE,YAAY,IAAI,uBAAuB,GACtB,EACpB,YAAG,SAAS,EAAC,+BAA+B,YAAE,KAAK,GAAK,EACvD,YAAY,CAAC,CAAC,CAAC,CACd,mBAAS,SAAS,EAAC,+BAA+B,aAChD,kBAAS,SAAS,EAAC,kDAAkD,wBAE3D,EACV,cAAK,SAAS,EAAC,uGAAuG,YACnH,YAAY,GACT,IACE,CACX,CAAC,CAAC,CAAC,IAAI,IACJ,CACP,CAAC,CAAC,CAAC,CACF,eAAK,SAAS,EAAC,qBAAqB,aAClC,KAAC,QAAQ,IACP,KAAK,EAAE,QAAQ,EACf,SAAS,EAAC,YAAY,EACtB,aAAa,EAAE,aAAa,GAC5B,EACF,MAAC,iBAAiB,IAAC,SAAS,EAAC,oDAAoD,aAC/E,eAAM,SAAS,EAAC,SAAS,YAAE,YAAY,IAAI,EAAE,GAAQ,EACpD,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,2BAAO,QAAQ,SAAS,CAAC,CAAC,CAAC,IAAI,IACvC,IAChB,CACP,IACa,GACT,CACV,CAAC;AACJ,CAAC,CAAC;AAEF,OAAO,EAAC,aAAa,EAAC,CAAC","sourcesContent":["'use client';\n\nimport {FC} from 'react';\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n} from './dialog';\nimport {Progress} from './progress';\nimport {cn} from '../lib/utils';\n\nconst ProgressModal: FC<{\n className?: string;\n isOpen: boolean;\n title?: string;\n loadingStage?: string;\n progress?: number;\n indeterminate?: boolean;\n error?: string;\n errorDetails?: string;\n}> = (props) => {\n const {\n className,\n isOpen,\n title,\n loadingStage,\n progress,\n indeterminate,\n error,\n errorDetails,\n } = props;\n return (\n <Dialog open={isOpen} onOpenChange={() => {}}>\n <DialogContent\n className={cn(\n 'rounded-md border-none focus:outline-hidden sm:max-w-[425px]',\n className,\n )}\n showCloseButton={false}\n >\n <DialogHeader>\n <DialogTitle>{title ?? ''}</DialogTitle>\n </DialogHeader>\n {error ? (\n <div className=\"flex flex-col gap-3\">\n <DialogDescription className=\"text-destructive text-sm font-medium\">\n {loadingStage ?? 'Initialization failed'}\n </DialogDescription>\n <p className=\"text-muted-foreground text-sm\">{error}</p>\n {errorDetails ? (\n <details className=\"text-muted-foreground text-sm\">\n <summary className=\"hover:text-foreground cursor-pointer font-medium\">\n Details\n </summary>\n <pre className=\"bg-muted text-muted-foreground mt-2 max-h-40 overflow-auto rounded-md p-3 text-xs whitespace-pre-wrap\">\n {errorDetails}\n </pre>\n </details>\n ) : null}\n </div>\n ) : (\n <div className=\"flex flex-col gap-2\">\n <Progress\n value={progress}\n className=\"h-2 w-full\"\n indeterminate={indeterminate}\n />\n <DialogDescription className=\"text-muted-foreground flex justify-between text-sm\">\n <span className=\"text-sm\">{loadingStage ?? ''}</span>\n {progress !== undefined ? <span>{progress}%</span> : null}\n </DialogDescription>\n </div>\n )}\n </DialogContent>\n </Dialog>\n );\n};\n\nexport {ProgressModal};\n"]}
@@ -1,5 +1,9 @@
1
1
  import * as React from 'react';
2
2
  import * as SwitchPrimitives from '@radix-ui/react-switch';
3
- declare const Switch: React.ForwardRefExoticComponent<Omit<SwitchPrimitives.SwitchProps & React.RefAttributes<HTMLButtonElement>, "ref"> & React.RefAttributes<HTMLButtonElement>>;
3
+ declare const Switch: React.ForwardRefExoticComponent<Omit<SwitchPrimitives.SwitchProps & React.RefAttributes<HTMLButtonElement>, "ref"> & {
4
+ children?: React.ReactNode;
5
+ } & React.RefAttributes<HTMLButtonElement>> & {
6
+ Thumb: React.ForwardRefExoticComponent<Omit<SwitchPrimitives.SwitchThumbProps & React.RefAttributes<HTMLSpanElement>, "ref"> & React.RefAttributes<HTMLSpanElement>>;
7
+ };
4
8
  export { Switch };
5
9
  //# sourceMappingURL=switch.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"switch.d.ts","sourceRoot":"","sources":["../../src/components/switch.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,gBAAgB,MAAM,wBAAwB,CAAC;AAI3D,QAAA,MAAM,MAAM,8JAkBV,CAAC;AAGH,OAAO,EAAC,MAAM,EAAC,CAAC"}
1
+ {"version":3,"file":"switch.d.ts","sourceRoot":"","sources":["../../src/components/switch.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,gBAAgB,MAAM,wBAAwB,CAAC;AAsC3D,QAAA,MAAM,MAAM;eAhBG,KAAK,CAAC,SAAS;;;CAkB5B,CAAC;AAEH,OAAO,EAAC,MAAM,EAAC,CAAC"}
@@ -3,7 +3,12 @@ import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import * as React from 'react';
4
4
  import * as SwitchPrimitives from '@radix-ui/react-switch';
5
5
  import { cn } from '../lib/utils';
6
- const Switch = React.forwardRef(({ className, ...props }, ref) => (_jsx(SwitchPrimitives.Root, { className: cn('focus-visible:ring-ring focus-visible:ring-offset-background data-[state=checked]:bg-primary data-[state=unchecked]:bg-input peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50', className), ...props, ref: ref, children: _jsx(SwitchPrimitives.Thumb, { className: cn('bg-background pointer-events-none block h-4 w-4 rounded-full shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0') }) })));
7
- Switch.displayName = SwitchPrimitives.Root.displayName;
6
+ const SwitchThumb = React.forwardRef(({ className, ...props }, ref) => (_jsx(SwitchPrimitives.Thumb, { className: cn('bg-background pointer-events-none block h-4 w-4 rounded-full shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0', className), ...props, ref: ref })));
7
+ SwitchThumb.displayName = SwitchPrimitives.Thumb.displayName;
8
+ const SwitchRoot = React.forwardRef(({ className, children, ...props }, ref) => (_jsx(SwitchPrimitives.Root, { className: cn('focus-visible:ring-ring focus-visible:ring-offset-background data-[state=checked]:bg-primary data-[state=unchecked]:bg-input peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50', className), ...props, ref: ref, children: children ?? _jsx(SwitchThumb, {}) })));
9
+ SwitchRoot.displayName = SwitchPrimitives.Root.displayName;
10
+ const Switch = Object.assign(SwitchRoot, {
11
+ Thumb: SwitchThumb,
12
+ });
8
13
  export { Switch };
9
14
  //# sourceMappingURL=switch.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"switch.js","sourceRoot":"","sources":["../../src/components/switch.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,gBAAgB,MAAM,wBAAwB,CAAC;AAE3D,OAAO,EAAC,EAAE,EAAC,MAAM,cAAc,CAAC;AAEhC,MAAM,MAAM,GAAG,KAAK,CAAC,UAAU,CAG7B,CAAC,EAAC,SAAS,EAAE,GAAG,KAAK,EAAC,EAAE,GAAG,EAAE,EAAE,CAAC,CAChC,KAAC,gBAAgB,CAAC,IAAI,IACpB,SAAS,EAAE,EAAE,CACX,+XAA+X,EAC/X,SAAS,CACV,KACG,KAAK,EACT,GAAG,EAAE,GAAG,YAER,KAAC,gBAAgB,CAAC,KAAK,IACrB,SAAS,EAAE,EAAE,CACX,4KAA4K,CAC7K,GACD,GACoB,CACzB,CAAC,CAAC;AACH,MAAM,CAAC,WAAW,GAAG,gBAAgB,CAAC,IAAI,CAAC,WAAW,CAAC;AAEvD,OAAO,EAAC,MAAM,EAAC,CAAC","sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport * as SwitchPrimitives from '@radix-ui/react-switch';\n\nimport {cn} from '../lib/utils';\n\nconst Switch = React.forwardRef<\n React.ElementRef<typeof SwitchPrimitives.Root>,\n React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>\n>(({className, ...props}, ref) => (\n <SwitchPrimitives.Root\n className={cn(\n 'focus-visible:ring-ring focus-visible:ring-offset-background data-[state=checked]:bg-primary data-[state=unchecked]:bg-input peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n {...props}\n ref={ref}\n >\n <SwitchPrimitives.Thumb\n className={cn(\n 'bg-background pointer-events-none block h-4 w-4 rounded-full shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0',\n )}\n />\n </SwitchPrimitives.Root>\n));\nSwitch.displayName = SwitchPrimitives.Root.displayName;\n\nexport {Switch};\n"]}
1
+ {"version":3,"file":"switch.js","sourceRoot":"","sources":["../../src/components/switch.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,gBAAgB,MAAM,wBAAwB,CAAC;AAE3D,OAAO,EAAC,EAAE,EAAC,MAAM,cAAc,CAAC;AAEhC,MAAM,WAAW,GAAG,KAAK,CAAC,UAAU,CAGlC,CAAC,EAAC,SAAS,EAAE,GAAG,KAAK,EAAC,EAAE,GAAG,EAAE,EAAE,CAAC,CAChC,KAAC,gBAAgB,CAAC,KAAK,IACrB,SAAS,EAAE,EAAE,CACX,4KAA4K,EAC5K,SAAS,CACV,KACG,KAAK,EACT,GAAG,EAAE,GAAG,GACR,CACH,CAAC,CAAC;AACH,WAAW,CAAC,WAAW,GAAG,gBAAgB,CAAC,KAAK,CAAC,WAAW,CAAC;AAE7D,MAAM,UAAU,GAAG,KAAK,CAAC,UAAU,CAKjC,CAAC,EAAC,SAAS,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAC,EAAE,GAAG,EAAE,EAAE,CAAC,CAC1C,KAAC,gBAAgB,CAAC,IAAI,IACpB,SAAS,EAAE,EAAE,CACX,+XAA+X,EAC/X,SAAS,CACV,KACG,KAAK,EACT,GAAG,EAAE,GAAG,YAEP,QAAQ,IAAI,KAAC,WAAW,KAAG,GACN,CACzB,CAAC,CAAC;AACH,UAAU,CAAC,WAAW,GAAG,gBAAgB,CAAC,IAAI,CAAC,WAAW,CAAC;AAE3D,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE;IACvC,KAAK,EAAE,WAAW;CACnB,CAAC,CAAC;AAEH,OAAO,EAAC,MAAM,EAAC,CAAC","sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport * as SwitchPrimitives from '@radix-ui/react-switch';\n\nimport {cn} from '../lib/utils';\n\nconst SwitchThumb = React.forwardRef<\n React.ComponentRef<typeof SwitchPrimitives.Thumb>,\n React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Thumb>\n>(({className, ...props}, ref) => (\n <SwitchPrimitives.Thumb\n className={cn(\n 'bg-background pointer-events-none block h-4 w-4 rounded-full shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0',\n className,\n )}\n {...props}\n ref={ref}\n />\n));\nSwitchThumb.displayName = SwitchPrimitives.Thumb.displayName;\n\nconst SwitchRoot = React.forwardRef<\n React.ComponentRef<typeof SwitchPrimitives.Root>,\n React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root> & {\n children?: React.ReactNode;\n }\n>(({className, children, ...props}, ref) => (\n <SwitchPrimitives.Root\n className={cn(\n 'focus-visible:ring-ring focus-visible:ring-offset-background data-[state=checked]:bg-primary data-[state=unchecked]:bg-input peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n {...props}\n ref={ref}\n >\n {children ?? <SwitchThumb />}\n </SwitchPrimitives.Root>\n));\nSwitchRoot.displayName = SwitchPrimitives.Root.displayName;\n\nconst Switch = Object.assign(SwitchRoot, {\n Thumb: SwitchThumb,\n});\n\nexport {Switch};\n"]}
@@ -2,6 +2,9 @@ import * as React from 'react';
2
2
  type TextareaProps = React.ComponentProps<'textarea'> & {
3
3
  autoResize?: boolean;
4
4
  };
5
+ /**
6
+ * Textarea component with optional auto-resize behavior.
7
+ */
5
8
  declare const Textarea: React.ForwardRefExoticComponent<Omit<TextareaProps, "ref"> & React.RefAttributes<HTMLTextAreaElement>>;
6
9
  export { Textarea };
7
10
  //# sourceMappingURL=textarea.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"textarea.d.ts","sourceRoot":"","sources":["../../src/components/textarea.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,KAAK,aAAa,GAAG,KAAK,CAAC,cAAc,CAAC,UAAU,CAAC,GAAG;IACtD,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF,QAAA,MAAM,QAAQ,wGA4Db,CAAC;AAGF,OAAO,EAAC,QAAQ,EAAC,CAAC"}
1
+ {"version":3,"file":"textarea.d.ts","sourceRoot":"","sources":["../../src/components/textarea.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,KAAK,aAAa,GAAG,KAAK,CAAC,cAAc,CAAC,UAAU,CAAC,GAAG;IACtD,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAmHF;;GAEG;AACH,QAAA,MAAM,QAAQ,wGAoDb,CAAC;AAGF,OAAO,EAAC,QAAQ,EAAC,CAAC"}
@@ -1,17 +1,26 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import * as React from 'react';
3
3
  import { cn } from '../lib/utils';
4
- const Textarea = React.forwardRef(({ className, autoResize = false, onInput, value, defaultValue, ...props }, ref) => {
5
- const localRef = React.useRef(null);
6
- React.useImperativeHandle(ref, () => localRef.current);
4
+ /**
5
+ * Uses layout effect in the browser and falls back to effect during SSR.
6
+ */
7
+ const useIsomorphicLayoutEffect = typeof window === 'undefined' ? React.useEffect : React.useLayoutEffect;
8
+ /**
9
+ * Keeps a textarea height synchronized with its content and container width.
10
+ *
11
+ * The resize path is intentionally triggered from multiple sources (input,
12
+ * value changes, and width changes) and then deduped per frame.
13
+ */
14
+ function useAutoResizeTextarea({ autoResize, textareaRef, value, defaultValue, }) {
7
15
  const [hasOverflow, setHasOverflow] = React.useState(false);
8
- const resizeToFitContent = React.useCallback(() => {
9
- const el = localRef.current;
10
- if (!el || !autoResize)
16
+ const lastMeasuredWidthRef = React.useRef(0);
17
+ const resizeFrameRef = React.useRef(null);
18
+ const applyResizeToFitContent = React.useCallback(() => {
19
+ const el = textareaRef.current;
20
+ if (!el || !autoResize || typeof window === 'undefined')
11
21
  return;
12
22
  el.style.height = 'auto';
13
23
  el.style.height = `${el.scrollHeight}px`;
14
- // Check if content exceeds the max-height constraint
15
24
  const computedStyle = window.getComputedStyle(el);
16
25
  const maxHeight = computedStyle.maxHeight;
17
26
  if (maxHeight && maxHeight !== 'none') {
@@ -21,11 +30,78 @@ const Textarea = React.forwardRef(({ className, autoResize = false, onInput, val
21
30
  else {
22
31
  setHasOverflow(false);
23
32
  }
24
- }, [autoResize]);
25
- React.useEffect(() => {
26
- // Trigger on mount and whenever the controlled value changes
33
+ }, [autoResize, textareaRef]);
34
+ const resizeToFitContent = React.useCallback(() => {
35
+ if (!autoResize || typeof window === 'undefined')
36
+ return;
37
+ // Keep input/effect-triggered resize paths for robustness, but collapse
38
+ // same-frame calls into one DOM measurement/write cycle.
39
+ if (resizeFrameRef.current !== null)
40
+ return;
41
+ resizeFrameRef.current = window.requestAnimationFrame(() => {
42
+ resizeFrameRef.current = null;
43
+ applyResizeToFitContent();
44
+ });
45
+ }, [autoResize, applyResizeToFitContent]);
46
+ useIsomorphicLayoutEffect(() => {
27
47
  resizeToFitContent();
28
48
  }, [resizeToFitContent, value, defaultValue]);
49
+ React.useEffect(() => {
50
+ if (!autoResize)
51
+ return;
52
+ const el = textareaRef.current;
53
+ if (!el || typeof window === 'undefined')
54
+ return;
55
+ // Re-measure after layout settles so hidden/collapsed mount states
56
+ // don't leave a stale oversized height.
57
+ resizeToFitContent();
58
+ if (typeof ResizeObserver === 'undefined') {
59
+ return;
60
+ }
61
+ lastMeasuredWidthRef.current = el.getBoundingClientRect().width;
62
+ const observer = new ResizeObserver((entries) => {
63
+ const entry = entries[0];
64
+ if (!entry)
65
+ return;
66
+ const nextWidth = entry.contentRect.width;
67
+ if (Math.abs(nextWidth - lastMeasuredWidthRef.current) < 1) {
68
+ return;
69
+ }
70
+ lastMeasuredWidthRef.current = nextWidth;
71
+ resizeToFitContent();
72
+ });
73
+ observer.observe(el);
74
+ return () => {
75
+ observer.disconnect();
76
+ };
77
+ }, [autoResize, resizeToFitContent, textareaRef]);
78
+ React.useEffect(() => {
79
+ if (typeof window === 'undefined')
80
+ return;
81
+ return () => {
82
+ if (resizeFrameRef.current !== null) {
83
+ window.cancelAnimationFrame(resizeFrameRef.current);
84
+ resizeFrameRef.current = null;
85
+ }
86
+ };
87
+ }, []);
88
+ return {
89
+ hasOverflow,
90
+ resizeToFitContent,
91
+ };
92
+ }
93
+ /**
94
+ * Textarea component with optional auto-resize behavior.
95
+ */
96
+ const Textarea = React.forwardRef(({ className, autoResize = false, onInput, value, defaultValue, rows, ...props }, ref) => {
97
+ const localRef = React.useRef(null);
98
+ React.useImperativeHandle(ref, () => localRef.current);
99
+ const { hasOverflow, resizeToFitContent } = useAutoResizeTextarea({
100
+ autoResize,
101
+ textareaRef: localRef,
102
+ value,
103
+ defaultValue,
104
+ });
29
105
  const handleInput = (e) => {
30
106
  if (autoResize)
31
107
  resizeToFitContent();
@@ -36,7 +112,7 @@ const Textarea = React.forwardRef(({ className, autoResize = false, onInput, val
36
112
  ? hasOverflow
37
113
  ? 'overflow-y-auto'
38
114
  : 'overflow-y-hidden'
39
- : undefined, className), ref: localRef, onInput: handleInput, value: value, defaultValue: defaultValue, ...props }));
115
+ : undefined, className), rows: rows ?? (autoResize ? 1 : undefined), ref: localRef, onInput: handleInput, value: value, defaultValue: defaultValue, ...props }));
40
116
  });
41
117
  Textarea.displayName = 'Textarea';
42
118
  export { Textarea };
@@ -1 +1 @@
1
- {"version":3,"file":"textarea.js","sourceRoot":"","sources":["../../src/components/textarea.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAC,EAAE,EAAC,MAAM,cAAc,CAAC;AAMhC,MAAM,QAAQ,GAAG,KAAK,CAAC,UAAU,CAC/B,CACE,EAAC,SAAS,EAAE,UAAU,GAAG,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,KAAK,EAAC,EACvE,GAAG,EACH,EAAE;IACF,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAsB,IAAI,CAAC,CAAC;IAEzD,KAAK,CAAC,mBAAmB,CACvB,GAAG,EACH,GAAG,EAAE,CAAC,QAAQ,CAAC,OAA8B,CAC9C,CAAC;IAEF,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAE5D,MAAM,kBAAkB,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE;QAChD,MAAM,EAAE,GAAG,QAAQ,CAAC,OAAO,CAAC;QAC5B,IAAI,CAAC,EAAE,IAAI,CAAC,UAAU;YAAE,OAAO;QAC/B,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC;QACzB,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,IAAI,CAAC;QAEzC,qDAAqD;QACrD,MAAM,aAAa,GAAG,MAAM,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC;QAClD,MAAM,SAAS,GAAG,aAAa,CAAC,SAAS,CAAC;QAC1C,IAAI,SAAS,IAAI,SAAS,KAAK,MAAM,EAAE,CAAC;YACtC,MAAM,cAAc,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;YAC7C,cAAc,CAAC,EAAE,CAAC,YAAY,GAAG,cAAc,CAAC,CAAC;QACnD,CAAC;aAAM,CAAC;YACN,cAAc,CAAC,KAAK,CAAC,CAAC;QACxB,CAAC;IACH,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;IAEjB,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,6DAA6D;QAC7D,kBAAkB,EAAE,CAAC;IACvB,CAAC,EAAE,CAAC,kBAAkB,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC;IAE9C,MAAM,WAAW,GAAG,CAAC,CAAuC,EAAE,EAAE;QAC9D,IAAI,UAAU;YAAE,kBAAkB,EAAE,CAAC;QACrC,IAAI,OAAO;YAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IAC1B,CAAC,CAAC;IAEF,OAAO,CACL,mBACE,SAAS,EAAE,EAAE,CACX,6QAA6Q,EAC7Q,UAAU;YACR,CAAC,CAAC,WAAW;gBACX,CAAC,CAAC,iBAAiB;gBACnB,CAAC,CAAC,mBAAmB;YACvB,CAAC,CAAC,SAAS,EACb,SAAS,CACV,EACD,GAAG,EAAE,QAAQ,EACb,OAAO,EAAE,WAAW,EACpB,KAAK,EAAE,KAAK,EACZ,YAAY,EAAE,YAAY,KACtB,KAAK,GACT,CACH,CAAC;AACJ,CAAC,CACF,CAAC;AACF,QAAQ,CAAC,WAAW,GAAG,UAAU,CAAC;AAElC,OAAO,EAAC,QAAQ,EAAC,CAAC","sourcesContent":["import * as React from 'react';\nimport {cn} from '../lib/utils';\n\ntype TextareaProps = React.ComponentProps<'textarea'> & {\n autoResize?: boolean;\n};\n\nconst Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(\n (\n {className, autoResize = false, onInput, value, defaultValue, ...props},\n ref,\n ) => {\n const localRef = React.useRef<HTMLTextAreaElement>(null);\n\n React.useImperativeHandle(\n ref,\n () => localRef.current as HTMLTextAreaElement,\n );\n\n const [hasOverflow, setHasOverflow] = React.useState(false);\n\n const resizeToFitContent = React.useCallback(() => {\n const el = localRef.current;\n if (!el || !autoResize) return;\n el.style.height = 'auto';\n el.style.height = `${el.scrollHeight}px`;\n\n // Check if content exceeds the max-height constraint\n const computedStyle = window.getComputedStyle(el);\n const maxHeight = computedStyle.maxHeight;\n if (maxHeight && maxHeight !== 'none') {\n const maxHeightValue = parseFloat(maxHeight);\n setHasOverflow(el.scrollHeight > maxHeightValue);\n } else {\n setHasOverflow(false);\n }\n }, [autoResize]);\n\n React.useEffect(() => {\n // Trigger on mount and whenever the controlled value changes\n resizeToFitContent();\n }, [resizeToFitContent, value, defaultValue]);\n\n const handleInput = (e: React.FormEvent<HTMLTextAreaElement>) => {\n if (autoResize) resizeToFitContent();\n if (onInput) onInput(e);\n };\n\n return (\n <textarea\n className={cn(\n 'border-input placeholder:text-muted-foreground focus-visible:ring-ring flex min-h-[60px] w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-sm focus-visible:ring-1 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',\n autoResize\n ? hasOverflow\n ? 'overflow-y-auto'\n : 'overflow-y-hidden'\n : undefined,\n className,\n )}\n ref={localRef}\n onInput={handleInput}\n value={value}\n defaultValue={defaultValue}\n {...props}\n />\n );\n },\n);\nTextarea.displayName = 'Textarea';\n\nexport {Textarea};\n"]}
1
+ {"version":3,"file":"textarea.js","sourceRoot":"","sources":["../../src/components/textarea.tsx"],"names":[],"mappings":"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","sourcesContent":["import * as React from 'react';\nimport {cn} from '../lib/utils';\n\ntype TextareaProps = React.ComponentProps<'textarea'> & {\n autoResize?: boolean;\n};\n\n/**\n * Uses layout effect in the browser and falls back to effect during SSR.\n */\nconst useIsomorphicLayoutEffect =\n typeof window === 'undefined' ? React.useEffect : React.useLayoutEffect;\n\n/**\n * Keeps a textarea height synchronized with its content and container width.\n *\n * The resize path is intentionally triggered from multiple sources (input,\n * value changes, and width changes) and then deduped per frame.\n */\nfunction useAutoResizeTextarea({\n autoResize,\n textareaRef,\n value,\n defaultValue,\n}: {\n autoResize: boolean;\n textareaRef: React.RefObject<HTMLTextAreaElement | null>;\n value: React.ComponentProps<'textarea'>['value'];\n defaultValue: React.ComponentProps<'textarea'>['defaultValue'];\n}) {\n const [hasOverflow, setHasOverflow] = React.useState(false);\n const lastMeasuredWidthRef = React.useRef<number>(0);\n const resizeFrameRef = React.useRef<number | null>(null);\n\n const applyResizeToFitContent = React.useCallback(() => {\n const el = textareaRef.current;\n if (!el || !autoResize || typeof window === 'undefined') return;\n\n el.style.height = 'auto';\n el.style.height = `${el.scrollHeight}px`;\n\n const computedStyle = window.getComputedStyle(el);\n const maxHeight = computedStyle.maxHeight;\n if (maxHeight && maxHeight !== 'none') {\n const maxHeightValue = parseFloat(maxHeight);\n setHasOverflow(el.scrollHeight > maxHeightValue);\n } else {\n setHasOverflow(false);\n }\n }, [autoResize, textareaRef]);\n\n const resizeToFitContent = React.useCallback(() => {\n if (!autoResize || typeof window === 'undefined') return;\n\n // Keep input/effect-triggered resize paths for robustness, but collapse\n // same-frame calls into one DOM measurement/write cycle.\n if (resizeFrameRef.current !== null) return;\n\n resizeFrameRef.current = window.requestAnimationFrame(() => {\n resizeFrameRef.current = null;\n applyResizeToFitContent();\n });\n }, [autoResize, applyResizeToFitContent]);\n\n useIsomorphicLayoutEffect(() => {\n resizeToFitContent();\n }, [resizeToFitContent, value, defaultValue]);\n\n React.useEffect(() => {\n if (!autoResize) return;\n\n const el = textareaRef.current;\n if (!el || typeof window === 'undefined') return;\n\n // Re-measure after layout settles so hidden/collapsed mount states\n // don't leave a stale oversized height.\n resizeToFitContent();\n\n if (typeof ResizeObserver === 'undefined') {\n return;\n }\n\n lastMeasuredWidthRef.current = el.getBoundingClientRect().width;\n const observer = new ResizeObserver((entries) => {\n const entry = entries[0];\n if (!entry) return;\n\n const nextWidth = entry.contentRect.width;\n if (Math.abs(nextWidth - lastMeasuredWidthRef.current) < 1) {\n return;\n }\n\n lastMeasuredWidthRef.current = nextWidth;\n resizeToFitContent();\n });\n\n observer.observe(el);\n\n return () => {\n observer.disconnect();\n };\n }, [autoResize, resizeToFitContent, textareaRef]);\n\n React.useEffect(() => {\n if (typeof window === 'undefined') return;\n\n return () => {\n if (resizeFrameRef.current !== null) {\n window.cancelAnimationFrame(resizeFrameRef.current);\n resizeFrameRef.current = null;\n }\n };\n }, []);\n\n return {\n hasOverflow,\n resizeToFitContent,\n };\n}\n\n/**\n * Textarea component with optional auto-resize behavior.\n */\nconst Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(\n (\n {\n className,\n autoResize = false,\n onInput,\n value,\n defaultValue,\n rows,\n ...props\n },\n ref,\n ) => {\n const localRef = React.useRef<HTMLTextAreaElement>(null);\n\n React.useImperativeHandle(\n ref,\n () => localRef.current as HTMLTextAreaElement,\n );\n\n const {hasOverflow, resizeToFitContent} = useAutoResizeTextarea({\n autoResize,\n textareaRef: localRef,\n value,\n defaultValue,\n });\n\n const handleInput = (e: React.FormEvent<HTMLTextAreaElement>) => {\n if (autoResize) resizeToFitContent();\n if (onInput) onInput(e);\n };\n\n return (\n <textarea\n className={cn(\n 'border-input placeholder:text-muted-foreground focus-visible:ring-ring flex min-h-[60px] w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-sm focus-visible:ring-1 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',\n autoResize\n ? hasOverflow\n ? 'overflow-y-auto'\n : 'overflow-y-hidden'\n : undefined,\n className,\n )}\n rows={rows ?? (autoResize ? 1 : undefined)}\n ref={localRef}\n onInput={handleInput}\n value={value}\n defaultValue={defaultValue}\n {...props}\n />\n );\n },\n);\nTextarea.displayName = 'Textarea';\n\nexport {Textarea};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"theme-switch.d.ts","sourceRoot":"","sources":["../../src/components/theme-switch.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAC,EAAE,EAAC,MAAM,OAAO,CAAC;AAIzB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,WAAW,EAAE,EAAE,CAAC;IAC3B,+DAA+D;IAC/D,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAwBA,CAAC"}
1
+ {"version":3,"file":"theme-switch.d.ts","sourceRoot":"","sources":["../../src/components/theme-switch.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAC,EAAE,EAAC,MAAM,OAAO,CAAC;AAKzB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,WAAW,EAAE,EAAE,CAAC;IAC3B,+DAA+D;IAC/D,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAiBA,CAAC"}
@@ -1,9 +1,9 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import * as SwitchPrimitives from '@radix-ui/react-switch';
4
3
  import { MoonIcon, SunIcon } from 'lucide-react';
5
4
  import { cn } from '../lib/utils';
6
5
  import { useTheme } from '../theme/theme-provider';
6
+ import { Switch } from './switch';
7
7
  /**
8
8
  * A theme toggle switch component that allows users to switch between light and dark themes.
9
9
  *
@@ -39,8 +39,8 @@ import { useTheme } from '../theme/theme-provider';
39
39
  */
40
40
  export const ThemeSwitch = ({ className }) => {
41
41
  const { theme, setTheme } = useTheme();
42
- return (_jsx(SwitchPrimitives.Root, { className: cn('focus-visible:ring-ring focus-visible:ring-offset-background data-[state=checked]:bg-primary/20 data-[state=unchecked]:bg-input peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50', className), checked: theme === 'dark', onCheckedChange: (checked) => {
42
+ return (_jsx(Switch, { className: cn('data-[state=checked]:bg-primary/20', className), checked: theme === 'dark', onCheckedChange: (checked) => {
43
43
  setTheme(checked ? 'dark' : 'light');
44
- }, children: _jsxs(SwitchPrimitives.Thumb, { className: cn('bg-background pointer-events-none flex h-4 w-4 items-center justify-center rounded-full shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0 dark:bg-zinc-900'), children: [_jsx(SunIcon, { className: "dark:text-primary h-2.5 w-2.5 scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90" }), _jsx(MoonIcon, { className: "dark:text-primary absolute h-2.5 w-2.5 scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0" })] }) }));
44
+ }, children: _jsxs(Switch.Thumb, { className: "bg-background flex items-center justify-center dark:bg-zinc-900", children: [_jsx(SunIcon, { className: "dark:text-primary h-2.5 w-2.5 scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90" }), _jsx(MoonIcon, { className: "dark:text-primary absolute h-2.5 w-2.5 scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0" })] }) }));
45
45
  };
46
46
  //# sourceMappingURL=theme-switch.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"theme-switch.js","sourceRoot":"","sources":["../../src/components/theme-switch.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,KAAK,gBAAgB,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAC,QAAQ,EAAE,OAAO,EAAC,MAAM,cAAc,CAAC;AAE/C,OAAO,EAAC,EAAE,EAAC,MAAM,cAAc,CAAC;AAChC,OAAO,EAAC,QAAQ,EAAC,MAAM,yBAAyB,CAAC;AAEjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,CAAC,MAAM,WAAW,GAGnB,CAAC,EAAC,SAAS,EAAC,EAAE,EAAE;IACnB,MAAM,EAAC,KAAK,EAAE,QAAQ,EAAC,GAAG,QAAQ,EAAE,CAAC;IAErC,OAAO,CACL,KAAC,gBAAgB,CAAC,IAAI,IACpB,SAAS,EAAE,EAAE,CACX,kYAAkY,EAClY,SAAS,CACV,EACD,OAAO,EAAE,KAAK,KAAK,MAAM,EACzB,eAAe,EAAE,CAAC,OAAO,EAAE,EAAE;YAC3B,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QACvC,CAAC,YAED,MAAC,gBAAgB,CAAC,KAAK,IACrB,SAAS,EAAE,EAAE,CACX,wNAAwN,CACzN,aAED,KAAC,OAAO,IAAC,SAAS,EAAC,8FAA8F,GAAG,EACpH,KAAC,QAAQ,IAAC,SAAS,EAAC,sGAAsG,GAAG,IACtG,GACH,CACzB,CAAC;AACJ,CAAC,CAAC","sourcesContent":["'use client';\n\nimport * as SwitchPrimitives from '@radix-ui/react-switch';\nimport {MoonIcon, SunIcon} from 'lucide-react';\nimport {FC} from 'react';\nimport {cn} from '../lib/utils';\nimport {useTheme} from '../theme/theme-provider';\n\n/**\n * A theme toggle switch component that allows users to switch between light and dark themes.\n *\n * This component provides a visually appealing switch with sun/moon icons that animate smoothly\n * during theme transitions. It integrates with the theme context to manage theme state.\n *\n * Features:\n * - Smooth icon animations\n * - Accessible keyboard navigation\n * - Focus and hover states\n * - Customizable via className prop\n *\n * @component\n * @example\n * ```tsx\n * // Basic usage\n * <ThemeSwitch />\n *\n * // With custom styling\n * <ThemeSwitch className=\"my-custom-class\" />\n *\n * // Within a theme provider\n * import { ThemeProvider } from '../theme/theme-provider';\n *\n * function App() {\n * return (\n * <ThemeProvider>\n * <ThemeSwitch />\n * </ThemeProvider>\n * );\n * }\n * ```\n */\nexport const ThemeSwitch: FC<{\n /** Optional CSS class name for styling the switch container */\n className?: string;\n}> = ({className}) => {\n const {theme, setTheme} = useTheme();\n\n return (\n <SwitchPrimitives.Root\n className={cn(\n 'focus-visible:ring-ring focus-visible:ring-offset-background data-[state=checked]:bg-primary/20 data-[state=unchecked]:bg-input peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n checked={theme === 'dark'}\n onCheckedChange={(checked) => {\n setTheme(checked ? 'dark' : 'light');\n }}\n >\n <SwitchPrimitives.Thumb\n className={cn(\n 'bg-background pointer-events-none flex h-4 w-4 items-center justify-center rounded-full shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0 dark:bg-zinc-900',\n )}\n >\n <SunIcon className=\"dark:text-primary h-2.5 w-2.5 scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90\" />\n <MoonIcon className=\"dark:text-primary absolute h-2.5 w-2.5 scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0\" />\n </SwitchPrimitives.Thumb>\n </SwitchPrimitives.Root>\n );\n};\n"]}
1
+ {"version":3,"file":"theme-switch.js","sourceRoot":"","sources":["../../src/components/theme-switch.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAC,QAAQ,EAAE,OAAO,EAAC,MAAM,cAAc,CAAC;AAE/C,OAAO,EAAC,EAAE,EAAC,MAAM,cAAc,CAAC;AAChC,OAAO,EAAC,QAAQ,EAAC,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAC,MAAM,EAAC,MAAM,UAAU,CAAC;AAEhC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,CAAC,MAAM,WAAW,GAGnB,CAAC,EAAC,SAAS,EAAC,EAAE,EAAE;IACnB,MAAM,EAAC,KAAK,EAAE,QAAQ,EAAC,GAAG,QAAQ,EAAE,CAAC;IAErC,OAAO,CACL,KAAC,MAAM,IACL,SAAS,EAAE,EAAE,CAAC,oCAAoC,EAAE,SAAS,CAAC,EAC9D,OAAO,EAAE,KAAK,KAAK,MAAM,EACzB,eAAe,EAAE,CAAC,OAAO,EAAE,EAAE;YAC3B,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QACvC,CAAC,YAED,MAAC,MAAM,CAAC,KAAK,IAAC,SAAS,EAAC,iEAAiE,aACvF,KAAC,OAAO,IAAC,SAAS,EAAC,8FAA8F,GAAG,EACpH,KAAC,QAAQ,IAAC,SAAS,EAAC,sGAAsG,GAAG,IAChH,GACR,CACV,CAAC;AACJ,CAAC,CAAC","sourcesContent":["'use client';\n\nimport {MoonIcon, SunIcon} from 'lucide-react';\nimport {FC} from 'react';\nimport {cn} from '../lib/utils';\nimport {useTheme} from '../theme/theme-provider';\nimport {Switch} from './switch';\n\n/**\n * A theme toggle switch component that allows users to switch between light and dark themes.\n *\n * This component provides a visually appealing switch with sun/moon icons that animate smoothly\n * during theme transitions. It integrates with the theme context to manage theme state.\n *\n * Features:\n * - Smooth icon animations\n * - Accessible keyboard navigation\n * - Focus and hover states\n * - Customizable via className prop\n *\n * @component\n * @example\n * ```tsx\n * // Basic usage\n * <ThemeSwitch />\n *\n * // With custom styling\n * <ThemeSwitch className=\"my-custom-class\" />\n *\n * // Within a theme provider\n * import { ThemeProvider } from '../theme/theme-provider';\n *\n * function App() {\n * return (\n * <ThemeProvider>\n * <ThemeSwitch />\n * </ThemeProvider>\n * );\n * }\n * ```\n */\nexport const ThemeSwitch: FC<{\n /** Optional CSS class name for styling the switch container */\n className?: string;\n}> = ({className}) => {\n const {theme, setTheme} = useTheme();\n\n return (\n <Switch\n className={cn('data-[state=checked]:bg-primary/20', className)}\n checked={theme === 'dark'}\n onCheckedChange={(checked) => {\n setTheme(checked ? 'dark' : 'light');\n }}\n >\n <Switch.Thumb className=\"bg-background flex items-center justify-center dark:bg-zinc-900\">\n <SunIcon className=\"dark:text-primary h-2.5 w-2.5 scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90\" />\n <MoonIcon className=\"dark:text-primary absolute h-2.5 w-2.5 scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0\" />\n </Switch.Thumb>\n </Switch>\n );\n};\n"]}
@@ -24,11 +24,11 @@ function TreeNode(props) {
24
24
  const hasChildren = Boolean(children?.length);
25
25
  const [isOpen, setIsOpen] = useState(Boolean(treeData.isInitialOpen));
26
26
  if (!hasChildren) {
27
- return (_jsxs("div", { className: "flex w-full items-center space-x-1", children: [_jsx("div", { className: "shrink-0", style: { width: DROPDOWN_ICON_PLACEHOLDER_WIDTH } }), renderNode(treeData, isOpen)] }));
27
+ return (_jsxs("div", { className: "flex w-full items-center space-x-1", children: [_jsx("div", { className: "mr-px ml-2 shrink-0", style: { width: DROPDOWN_ICON_PLACEHOLDER_WIDTH } }), renderNode(treeData, isOpen)] }));
28
28
  }
29
- return (_jsxs(Collapsible, { open: isOpen, onOpenChange: setIsOpen, children: [_jsx(CollapsibleTrigger, { className: "w-full", asChild: true, children: _jsxs("div", { className: "flex w-full cursor-pointer items-center space-x-1", children: [_jsx(ChevronRightIcon, { className: cn('shrink-0 text-gray-500', {
29
+ return (_jsxs(Collapsible, { open: isOpen, onOpenChange: setIsOpen, children: [_jsx(CollapsibleTrigger, { className: "w-full", asChild: true, children: _jsxs("div", { className: "flex w-full cursor-pointer items-center space-x-1", children: [_jsx(ChevronRightIcon, { className: cn('mr-px ml-2 shrink-0 text-gray-500', {
30
30
  'rotate-90 transform': isOpen,
31
- }), size: DROPDOWN_ICON_PLACEHOLDER_WIDTH }), renderNode(treeData, isOpen)] }) }), _jsx(CollapsibleContent, { className: "pl-4", children: isOpen
31
+ }), size: DROPDOWN_ICON_PLACEHOLDER_WIDTH }), renderNode(treeData, isOpen)] }) }), _jsx(CollapsibleContent, { className: "pl-2", children: isOpen
32
32
  ? children?.map((child) => (_jsx(TreeNode, { treeData: child, renderNode: renderNode }, child.key)))
33
33
  : null })] }));
34
34
  }
@@ -1 +1 @@
1
- {"version":3,"file":"tree.js","sourceRoot":"","sources":["../../src/components/tree.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAC,WAAW,EAAE,kBAAkB,EAAC,MAAM,6BAA6B,CAAC;AAC5E,OAAc,EAAC,QAAQ,EAAC,MAAM,OAAO,CAAC;AAEtC,OAAO,EAAC,gBAAgB,EAAC,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAC,EAAE,EAAC,MAAM,cAAc,CAAC;AAChC,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAEjD,MAAM,+BAA+B,GAAG,MAAM,CAAC;AAe/C;;;;GAIG;AACH,MAAM,UAAU,IAAI,CAAI,KAAmB;IACzC,MAAM,EAAC,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAC,GAAG,KAAK,CAAC;IAChD,OAAO,CACL,cAAK,SAAS,EAAE,EAAE,CAAC,eAAe,EAAE,SAAS,CAAC,YAC5C,KAAC,QAAQ,IAAI,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,GAAI,GACvD,CACP,CAAC;AACJ,CAAC;AAOD;;GAEG;AACH,SAAS,QAAQ,CAAI,KAAuB;IAC1C,MAAM,EAAC,QAAQ,EAAE,UAAU,EAAC,GAAG,KAAK,CAAC;IACrC,MAAM,EAAC,QAAQ,EAAC,GAAG,QAAQ,CAAC;IAC5B,MAAM,WAAW,GAAG,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC9C,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC;IACtE,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,CACL,eAAK,SAAS,EAAC,oCAAoC,aACjD,cACE,SAAS,EAAC,UAAU,EACpB,KAAK,EAAE,EAAC,KAAK,EAAE,+BAA+B,EAAC,GAC/C,EACD,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,IACzB,CACP,CAAC;IACJ,CAAC;IACD,OAAO,CACL,MAAC,WAAW,IAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,SAAS,aAChD,KAAC,kBAAkB,IAAC,SAAS,EAAC,QAAQ,EAAC,OAAO,kBAC5C,eAAK,SAAS,EAAC,mDAAmD,aAChE,KAAC,gBAAgB,IACf,SAAS,EAAE,EAAE,CAAC,wBAAwB,EAAE;gCACtC,qBAAqB,EAAE,MAAM;6BAC9B,CAAC,EACF,IAAI,EAAE,+BAA+B,GACrC,EACD,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,IACzB,GACa,EACrB,KAAC,kBAAkB,IAAC,SAAS,EAAC,MAAM,YACjC,MAAM;oBACL,CAAC,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CACvB,KAAC,QAAQ,IAEP,QAAQ,EAAE,KAAK,EACf,UAAU,EAAE,UAAU,IAFjB,KAAK,CAAC,GAAG,CAGd,CACH,CAAC;oBACJ,CAAC,CAAC,IAAI,GACW,IACT,CACf,CAAC;AACJ,CAAC","sourcesContent":["'use client';\n\nimport {Collapsible, CollapsibleContent} from '@radix-ui/react-collapsible';\nimport React, {useState} from 'react';\n\nimport {ChevronRightIcon} from 'lucide-react';\nimport {cn} from '../lib/utils';\nimport {CollapsibleTrigger} from './collapsible';\n\nconst DROPDOWN_ICON_PLACEHOLDER_WIDTH = '18px';\n\nexport type TreeNodeData<T> = {\n key: string;\n object: T;\n children?: TreeNodeData<T>[];\n isInitialOpen?: boolean;\n};\n\ntype TreeProps<T> = {\n className?: string;\n treeData: TreeNodeData<T>;\n renderNode: TreeNodeProps<T>['renderNode'];\n};\n\n/**\n * Component that renders a generic tree.\n * @param treeData - The tree data.\n * @param renderNode - A function that renders a tree node.\n */\nexport function Tree<T>(props: TreeProps<T>): React.ReactElement {\n const {className, treeData, renderNode} = props;\n return (\n <div className={cn('flex flex-col', className)}>\n <TreeNode<T> treeData={treeData} renderNode={renderNode} />\n </div>\n );\n}\n\ntype TreeNodeProps<T> = {\n treeData: TreeNodeData<T>;\n renderNode: (node: TreeNodeData<T>, isOpen: boolean) => React.ReactNode;\n};\n\n/**\n * Component that renders a tree node.\n */\nfunction TreeNode<T>(props: TreeNodeProps<T>): React.ReactElement | null {\n const {treeData, renderNode} = props;\n const {children} = treeData;\n const hasChildren = Boolean(children?.length);\n const [isOpen, setIsOpen] = useState(Boolean(treeData.isInitialOpen));\n if (!hasChildren) {\n return (\n <div className=\"flex w-full items-center space-x-1\">\n <div\n className=\"shrink-0\"\n style={{width: DROPDOWN_ICON_PLACEHOLDER_WIDTH}}\n />\n {renderNode(treeData, isOpen)}\n </div>\n );\n }\n return (\n <Collapsible open={isOpen} onOpenChange={setIsOpen}>\n <CollapsibleTrigger className=\"w-full\" asChild>\n <div className=\"flex w-full cursor-pointer items-center space-x-1\">\n <ChevronRightIcon\n className={cn('shrink-0 text-gray-500', {\n 'rotate-90 transform': isOpen,\n })}\n size={DROPDOWN_ICON_PLACEHOLDER_WIDTH}\n />\n {renderNode(treeData, isOpen)}\n </div>\n </CollapsibleTrigger>\n <CollapsibleContent className=\"pl-4\">\n {isOpen\n ? children?.map((child) => (\n <TreeNode<T>\n key={child.key}\n treeData={child}\n renderNode={renderNode}\n />\n ))\n : null}\n </CollapsibleContent>\n </Collapsible>\n );\n}\n"]}
1
+ {"version":3,"file":"tree.js","sourceRoot":"","sources":["../../src/components/tree.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAC,WAAW,EAAE,kBAAkB,EAAC,MAAM,6BAA6B,CAAC;AAC5E,OAAc,EAAC,QAAQ,EAAC,MAAM,OAAO,CAAC;AAEtC,OAAO,EAAC,gBAAgB,EAAC,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAC,EAAE,EAAC,MAAM,cAAc,CAAC;AAChC,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAEjD,MAAM,+BAA+B,GAAG,MAAM,CAAC;AAe/C;;;;GAIG;AACH,MAAM,UAAU,IAAI,CAAI,KAAmB;IACzC,MAAM,EAAC,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAC,GAAG,KAAK,CAAC;IAChD,OAAO,CACL,cAAK,SAAS,EAAE,EAAE,CAAC,eAAe,EAAE,SAAS,CAAC,YAC5C,KAAC,QAAQ,IAAI,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,GAAI,GACvD,CACP,CAAC;AACJ,CAAC;AAOD;;GAEG;AACH,SAAS,QAAQ,CAAI,KAAuB;IAC1C,MAAM,EAAC,QAAQ,EAAE,UAAU,EAAC,GAAG,KAAK,CAAC;IACrC,MAAM,EAAC,QAAQ,EAAC,GAAG,QAAQ,CAAC;IAC5B,MAAM,WAAW,GAAG,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC9C,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC;IACtE,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,CACL,eAAK,SAAS,EAAC,oCAAoC,aACjD,cACE,SAAS,EAAC,qBAAqB,EAC/B,KAAK,EAAE,EAAC,KAAK,EAAE,+BAA+B,EAAC,GAC/C,EACD,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,IACzB,CACP,CAAC;IACJ,CAAC;IACD,OAAO,CACL,MAAC,WAAW,IAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,SAAS,aAChD,KAAC,kBAAkB,IAAC,SAAS,EAAC,QAAQ,EAAC,OAAO,kBAC5C,eAAK,SAAS,EAAC,mDAAmD,aAChE,KAAC,gBAAgB,IACf,SAAS,EAAE,EAAE,CAAC,mCAAmC,EAAE;gCACjD,qBAAqB,EAAE,MAAM;6BAC9B,CAAC,EACF,IAAI,EAAE,+BAA+B,GACrC,EACD,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,IACzB,GACa,EACrB,KAAC,kBAAkB,IAAC,SAAS,EAAC,MAAM,YACjC,MAAM;oBACL,CAAC,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CACvB,KAAC,QAAQ,IAEP,QAAQ,EAAE,KAAK,EACf,UAAU,EAAE,UAAU,IAFjB,KAAK,CAAC,GAAG,CAGd,CACH,CAAC;oBACJ,CAAC,CAAC,IAAI,GACW,IACT,CACf,CAAC;AACJ,CAAC","sourcesContent":["'use client';\n\nimport {Collapsible, CollapsibleContent} from '@radix-ui/react-collapsible';\nimport React, {useState} from 'react';\n\nimport {ChevronRightIcon} from 'lucide-react';\nimport {cn} from '../lib/utils';\nimport {CollapsibleTrigger} from './collapsible';\n\nconst DROPDOWN_ICON_PLACEHOLDER_WIDTH = '18px';\n\nexport type TreeNodeData<T> = {\n key: string;\n object: T;\n children?: TreeNodeData<T>[];\n isInitialOpen?: boolean;\n};\n\ntype TreeProps<T> = {\n className?: string;\n treeData: TreeNodeData<T>;\n renderNode: TreeNodeProps<T>['renderNode'];\n};\n\n/**\n * Component that renders a generic tree.\n * @param treeData - The tree data.\n * @param renderNode - A function that renders a tree node.\n */\nexport function Tree<T>(props: TreeProps<T>): React.ReactElement {\n const {className, treeData, renderNode} = props;\n return (\n <div className={cn('flex flex-col', className)}>\n <TreeNode<T> treeData={treeData} renderNode={renderNode} />\n </div>\n );\n}\n\ntype TreeNodeProps<T> = {\n treeData: TreeNodeData<T>;\n renderNode: (node: TreeNodeData<T>, isOpen: boolean) => React.ReactNode;\n};\n\n/**\n * Component that renders a tree node.\n */\nfunction TreeNode<T>(props: TreeNodeProps<T>): React.ReactElement | null {\n const {treeData, renderNode} = props;\n const {children} = treeData;\n const hasChildren = Boolean(children?.length);\n const [isOpen, setIsOpen] = useState(Boolean(treeData.isInitialOpen));\n if (!hasChildren) {\n return (\n <div className=\"flex w-full items-center space-x-1\">\n <div\n className=\"mr-px ml-2 shrink-0\"\n style={{width: DROPDOWN_ICON_PLACEHOLDER_WIDTH}}\n />\n {renderNode(treeData, isOpen)}\n </div>\n );\n }\n return (\n <Collapsible open={isOpen} onOpenChange={setIsOpen}>\n <CollapsibleTrigger className=\"w-full\" asChild>\n <div className=\"flex w-full cursor-pointer items-center space-x-1\">\n <ChevronRightIcon\n className={cn('mr-px ml-2 shrink-0 text-gray-500', {\n 'rotate-90 transform': isOpen,\n })}\n size={DROPDOWN_ICON_PLACEHOLDER_WIDTH}\n />\n {renderNode(treeData, isOpen)}\n </div>\n </CollapsibleTrigger>\n <CollapsibleContent className=\"pl-2\">\n {isOpen\n ? children?.map((child) => (\n <TreeNode<T>\n key={child.key}\n treeData={child}\n renderNode={renderNode}\n />\n ))\n : null}\n </CollapsibleContent>\n </Collapsible>\n );\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sqlrooms/ui",
3
- "version": "0.29.0-rc.7",
3
+ "version": "0.29.0-rc.9",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/sqlrooms/sqlrooms.git"
@@ -71,5 +71,5 @@
71
71
  "publishConfig": {
72
72
  "access": "public"
73
73
  },
74
- "gitHead": "db298360fd66dc7839d4a14c15b99ac4a4cbf8c5"
74
+ "gitHead": "4a477560c0a6509ca00076d74eb3ce8f581c9e4f"
75
75
  }