@spear-ai/spectral 0.1.1 → 1.0.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.
Files changed (51) hide show
  1. package/README.md +7 -83
  2. package/dist/{components/Button/Button.d.ts → Button.d.ts} +10 -6
  3. package/dist/Button.js +98 -0
  4. package/dist/Card.css +4 -0
  5. package/dist/Card.d.ts +13 -0
  6. package/dist/Card.js +31 -0
  7. package/dist/Drawer.d.ts +14 -0
  8. package/dist/Drawer.js +42 -0
  9. package/dist/{components/Skeleton/Skeleton.d.ts → Skeleton.d.ts} +4 -1
  10. package/dist/Skeleton.js +14 -0
  11. package/dist/{components/Slider/Slider.d.ts → Slider.d.ts} +7 -4
  12. package/dist/Slider.js +79 -0
  13. package/dist/chunk-ZLENOYB4.js +12 -0
  14. package/dist/index.css +189 -0
  15. package/dist/index.d.ts +75 -22
  16. package/dist/index.js +276 -0
  17. package/package.json +66 -43
  18. package/src/styles/horizon.css +35 -0
  19. package/src/styles/main.css +34 -0
  20. package/dist/App.d.ts +0 -1
  21. package/dist/components/Accordion/Accordion.d.ts +0 -35
  22. package/dist/components/Card/Card.d.ts +0 -9
  23. package/dist/components/Checkbox/Checkbox.d.ts +0 -10
  24. package/dist/components/Input/Input.d.ts +0 -21
  25. package/dist/components/Input/InputUtils.d.ts +0 -10
  26. package/dist/components/InputOtp/InputOtp.d.ts +0 -29
  27. package/dist/components/Label/Label.d.ts +0 -3
  28. package/dist/components/RadioGroup/Label.d.ts +0 -4
  29. package/dist/components/RadioGroup/RadioGroup.d.ts +0 -38
  30. package/dist/components/Select/Select.d.ts +0 -24
  31. package/dist/components/Select/SelectList.d.ts +0 -17
  32. package/dist/components/Sidebar/Sidebar.d.ts +0 -1
  33. package/dist/components/Sidebar/SidebarBase.d.ts +0 -65
  34. package/dist/components/Switch/Switch.d.ts +0 -16
  35. package/dist/components/Textarea/Textarea.d.ts +0 -16
  36. package/dist/components/Textarea/TextareaUtils.d.ts +0 -44
  37. package/dist/favicon-invert.svg +0 -5
  38. package/dist/favicon.svg +0 -5
  39. package/dist/hooks/useAccordionAutoScroll.d.ts +0 -8
  40. package/dist/hooks/useOutsideClick.d.ts +0 -7
  41. package/dist/hooks/useTheme.d.ts +0 -7
  42. package/dist/logo/wordmark-dark-side-by-side.svg +0 -6
  43. package/dist/logo/wordmark-light-side-by-side.svg +0 -6
  44. package/dist/main.d.ts +0 -0
  45. package/dist/primitives/button.d.ts +0 -10
  46. package/dist/primitives/input.d.ts +0 -3
  47. package/dist/primitives/tooltip.d.ts +0 -7
  48. package/dist/spectral.cjs.js +0 -60
  49. package/dist/spectral.css +0 -1
  50. package/dist/spectral.es.js +0 -5531
  51. package/dist/utils/twUtils.d.ts +0 -2
package/README.md CHANGED
@@ -1,91 +1,15 @@
1
1
  # Spectral Component Library
2
2
 
3
- A modern React component library built with TypeScript, Tailwind CSS, and automated versioning with Changesets.
4
-
5
3
  ## Installation
6
4
 
7
5
  ```bash
8
- npm install @spear-ai/spectral
9
- ```
10
-
11
- ## Usage
12
-
13
- ```javascript
14
- import { Button, Card, cn } from '@spear-ai/spectral'
15
- import '@spear-ai/spectral/styles'
16
-
17
- function App() {
18
- return (
19
- <Card title="Welcome">
20
- <Button label="Click me" onClick={() => console.log('Hello!')} />
21
- </Card>
22
- )
23
- }
24
- ```
25
-
26
- ## Development
27
-
28
- ```bash
29
- # Install dependencies
30
- npm install
31
-
32
- # Start Storybook
33
- npm run storybook
34
-
35
- # Build library
36
- npm run build:lib
37
-
38
- # Format code (Prettier + OXC plugin)
39
- npm run format
40
-
41
- # Lint code (super fast with Oxlint!)
42
- npm run lint
43
-
44
- # Create changeset for your changes
45
- npm run changeset
46
- ```
47
-
48
- ## Components
49
-
50
- - Button
51
- - Card
52
- - Checkbox
53
- - Input
54
- - Label
55
- - RadioGroup
56
- - Select
57
- - Sidebar
58
- - Skeleton
59
- - Slider
60
- - Switch
61
- - Textarea
62
-
63
- ## Utilities
64
-
65
- - `cn` - Class name utility for merging Tailwind classes
66
-
67
- ## Hooks
68
-
69
- - `useTheme` - Theme management hook
70
-
71
- ## Contributing
72
-
73
- This project uses **Changesets** for version management and publishing.
74
-
75
- **Quick Start:**
76
- ```bash
77
- # Make changes, then:
78
- git add .
79
- npm run changeset # Create changeset describing your changes
80
- git commit -m "feat: add new component"
81
- git push origin feature-branch # Create PR
82
-
83
- # Changesets bot will create a "Version Packages" PR when ready to release
6
+ pnpm install @spear-ai/spectral
84
7
  ```
85
8
 
86
- **Change Types:**
87
- - `patch` → Bug fixes, small improvements (1.0.0 → 1.0.1)
88
- - `minor` → New features, new components (1.0.0 → 1.1.0)
89
- - `major` → Breaking changes (1.0.0 → 2.0.0)
90
9
 
91
- 📋 **See [CHANGESET_GUIDE.md](./CHANGESET_GUIDE.md) for complete workflow guide**
10
+ ### Development Stack
11
+ - **React 19** + **TypeScript 5.9**
12
+ - **Tailwind CSS v4** + **PostCSS**
13
+ - **Vite** for build optimization
14
+ - **Storybook 9** for component documentation
15
+ - **OXLint** for ultra-fast linting
@@ -1,10 +1,13 @@
1
+ import * as react from 'react';
2
+ import { ButtonHTMLAttributes, ReactNode, MouseEvent } from 'react';
3
+ import * as class_variance_authority_types from 'class-variance-authority/types';
1
4
  import { VariantProps } from 'class-variance-authority';
2
- import { ButtonHTMLAttributes, MouseEvent, ReactNode } from 'react';
5
+
3
6
  declare const buttonVariants: (props?: ({
4
7
  variant?: "primary" | "secondary" | "outline" | null | undefined;
5
8
  state?: "default" | "error" | "loading" | null | undefined;
6
- } & import('class-variance-authority/types').ClassProp) | undefined) => string;
7
- export interface ButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'color'>, VariantProps<typeof buttonVariants> {
9
+ } & class_variance_authority_types.ClassProp) | undefined) => string;
10
+ interface ButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'color'>, VariantProps<typeof buttonVariants> {
8
11
  errorMessage?: string | ReactNode;
9
12
  endIcon?: ReactNode;
10
13
  label: string;
@@ -14,7 +17,8 @@ export interface ButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement
14
17
  state?: 'loading' | 'error' | 'default';
15
18
  dataTestId?: string;
16
19
  onClick?: (event: MouseEvent<HTMLButtonElement>) => void;
17
- fullWidth?: boolean;
20
+ isFullWidth?: boolean;
18
21
  }
19
- export declare const Button: import('react').ForwardRefExoticComponent<ButtonProps & import('react').RefAttributes<HTMLButtonElement>>;
20
- export {};
22
+ declare const Button: react.ForwardRefExoticComponent<ButtonProps & react.RefAttributes<HTMLButtonElement>>;
23
+
24
+ export { Button, type ButtonProps };
package/dist/Button.js ADDED
@@ -0,0 +1,98 @@
1
+ "use client"
2
+ import {
3
+ cn
4
+ } from "./chunk-ZLENOYB4.js";
5
+
6
+ // src/components/Button/Button.tsx
7
+ import { cva } from "class-variance-authority";
8
+ import { Loader2 } from "lucide-react";
9
+ import { forwardRef } from "react";
10
+ import { jsx, jsxs } from "react/jsx-runtime";
11
+ var buttonVariants = cva(
12
+ `
13
+ flex relative items-center justify-center gap-2 whitespace-nowrap transition-colors cursor-pointer py-2 px-6 rounded-lg border font-semibold
14
+ focus:outline-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus:ring-2 focus:ring-ring focus:ring-offset-2
15
+ focus-visible:ring-offset-2 disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0
16
+ `,
17
+ {
18
+ variants: {
19
+ variant: {
20
+ primary: "bg-button-primary-bg text-button-primary-text border-button-primary-border disabled:bg-button-primary-bg--disabled disabled:text-button-primary-text--disabled disabled:border-button-primary-border--disabled",
21
+ secondary: "bg-button-secondary-bg border-button-secondary-border text-button-secondary-text disabled:bg-button-secondary-bg--disabled disabled:text-button-secondary-text--disabled disabled:border-button-secondary-border--disabled",
22
+ outline: "bg-button-outline-bg border-button-outline-border text-button-outline-text disabled:text-button-outline-text--disabled disabled:border-button-outline-border--disabled"
23
+ },
24
+ state: {
25
+ default: "",
26
+ error: "bg-button-danger text-button-primary-text transition pointer-events-none",
27
+ loading: "cursor-wait pointer-events-none"
28
+ }
29
+ },
30
+ defaultVariants: {
31
+ variant: "primary",
32
+ state: "default"
33
+ }
34
+ }
35
+ );
36
+ var Button = forwardRef(
37
+ ({
38
+ className,
39
+ variant,
40
+ label,
41
+ endIcon,
42
+ state,
43
+ errorMessage,
44
+ startIcon,
45
+ disabled,
46
+ type = "button",
47
+ dataTestId = `button-${variant}`,
48
+ isFullWidth,
49
+ ...props
50
+ }, ref) => {
51
+ const stateStyles = {
52
+ error: {
53
+ primary: "bg-button-danger border-button-danger text-button-primary-text pointer-events-none",
54
+ secondary: "bg-button-danger border-button-danger text-button-secondary-text pointer-events-none",
55
+ outline: "bg-transparent border-button-danger text-button-danger pointer-events-none"
56
+ },
57
+ loading: {
58
+ primary: "bg-button-primary-bg--disabled border-button-primary-border--disabled text-button-primary-text--disabled pointer-events-none",
59
+ secondary: "bg-button-secondary-bg--disabled border-button-secondary-border--disabled text-button-secondary-text--disabled pointer-events-none",
60
+ outline: "bg-button-outline-bg--disabled border-button-outline-border--disabled text-button-outline-text--disabled pointer-events-none"
61
+ }
62
+ };
63
+ const widthClass = isFullWidth ? "w-full" : "w-auto";
64
+ const classes = cn(
65
+ buttonVariants({ variant, state }),
66
+ state === "error" && stateStyles.error[variant || "primary"],
67
+ state === "loading" && stateStyles.loading[variant || "primary"],
68
+ widthClass,
69
+ className
70
+ );
71
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex justify-items-center", widthClass), children: [
72
+ /* @__PURE__ */ jsxs(
73
+ "button",
74
+ {
75
+ className: classes,
76
+ ref,
77
+ type,
78
+ "aria-disabled": disabled,
79
+ disabled,
80
+ "data-testid": dataTestId,
81
+ ...props,
82
+ "data-state": state,
83
+ children: [
84
+ startIcon && /* @__PURE__ */ jsx("span", { className: "flex pr-2", "aria-hidden": true, children: startIcon }),
85
+ label,
86
+ state === "loading" && /* @__PURE__ */ jsx(Loader2, { className: "ml-2 animate-spin", size: 16 }),
87
+ endIcon && state !== "loading" && /* @__PURE__ */ jsx("span", { className: "flex pl-2", "aria-hidden": true, children: endIcon })
88
+ ]
89
+ }
90
+ ),
91
+ state === "error" && errorMessage && /* @__PURE__ */ jsx("p", { className: "text-danger text-xs", role: "alert", "aria-live": "polite", children: errorMessage })
92
+ ] });
93
+ }
94
+ );
95
+ Button.displayName = "Button";
96
+ export {
97
+ Button
98
+ };
package/dist/Card.css ADDED
@@ -0,0 +1,4 @@
1
+ /* src/components/Card/main.css */
2
+ .card-loading-overlay {
3
+ backdrop-filter: blur(2px);
4
+ }
package/dist/Card.d.ts ADDED
@@ -0,0 +1,13 @@
1
+ import * as react from 'react';
2
+ import { HTMLAttributes, ReactNode } from 'react';
3
+
4
+ interface CardProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onClick'> {
5
+ title?: string;
6
+ icon?: ReactNode;
7
+ width?: 'full' | 'fit';
8
+ isLoading?: boolean;
9
+ children?: ReactNode;
10
+ }
11
+ declare const Card: react.ForwardRefExoticComponent<CardProps & react.RefAttributes<HTMLDivElement>>;
12
+
13
+ export { Card, type CardProps };
package/dist/Card.js ADDED
@@ -0,0 +1,31 @@
1
+ "use client"
2
+ import {
3
+ cn
4
+ } from "./chunk-ZLENOYB4.js";
5
+
6
+ // src/components/Card/Card.tsx
7
+ import { Loader2 } from "lucide-react";
8
+ import { forwardRef } from "react";
9
+ import { jsx, jsxs } from "react/jsx-runtime";
10
+ var Card = forwardRef(
11
+ ({ className, title, icon, width = "full", isLoading = false, children, ...props }, ref) => {
12
+ const hasHeader = title || icon;
13
+ const cardClasses = cn(
14
+ "relative bg-card-bg rounded-2xl p-4 focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
15
+ width === "full" ? "w-full" : "w-fit",
16
+ className
17
+ );
18
+ return /* @__PURE__ */ jsxs("div", { ref, className: cardClasses, ...props, children: [
19
+ isLoading && /* @__PURE__ */ jsx("div", { className: "bg-card-bg/50 absolute inset-0 z-10 flex items-center justify-center", children: /* @__PURE__ */ jsx(Loader2, { className: "text-muted-foreground animate-spin", size: 24 }) }),
20
+ hasHeader && /* @__PURE__ */ jsxs("div", { className: cn("flex items-center pb-4", title ? "justify-between" : "justify-end"), children: [
21
+ title && /* @__PURE__ */ jsx("h3", { className: "text-card-text truncate text-base font-semibold", children: title }),
22
+ icon && /* @__PURE__ */ jsx("div", { className: "flex-shrink-0", "aria-hidden": "true", children: icon })
23
+ ] }),
24
+ /* @__PURE__ */ jsx("div", { className: cn("min-h-40 p-4", hasHeader && "pt-0"), children })
25
+ ] });
26
+ }
27
+ );
28
+ Card.displayName = "Card";
29
+ export {
30
+ Card
31
+ };
@@ -0,0 +1,14 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+
4
+ type DrawerProps = {
5
+ title?: string;
6
+ trigger: ReactNode;
7
+ description?: string;
8
+ children?: ReactNode;
9
+ direction?: 'left' | 'right' | 'top' | 'bottom';
10
+ size?: string;
11
+ };
12
+ declare const Drawer: ({ trigger, title, description, children, direction, size }: DrawerProps) => react_jsx_runtime.JSX.Element;
13
+
14
+ export { Drawer, type DrawerProps };
package/dist/Drawer.js ADDED
@@ -0,0 +1,42 @@
1
+ "use client"
2
+
3
+ // src/components/Drawer/Drawer.tsx
4
+ import { Drawer as DrawerBase } from "vaul";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ var Drawer = ({ trigger, title, description, children, direction = "right", size = "320px" }) => {
7
+ const baseStyles = "fixed";
8
+ const directionStyles = {
9
+ left: {
10
+ className: `${baseStyles} top-0 bottom-0 left-0 shadow-[20px_0_20px_rgba(0,0,0,0.4)]`,
11
+ style: { width: size }
12
+ },
13
+ right: {
14
+ className: `${baseStyles} top-0 bottom-0 right-0 shadow-[-20px_0_20px_rgba(0,0,0,0.4)]`,
15
+ style: { width: size }
16
+ },
17
+ top: {
18
+ className: `${baseStyles} top-0 left-0 right-0 shadow-[0_20px_20px_rgba(0,0,0,0.4)]`,
19
+ style: { height: size }
20
+ },
21
+ bottom: {
22
+ className: `${baseStyles} bottom-0 left-0 right-0 shadow-[0_-20px_20px_rgba(0,0,0,0.4)]`,
23
+ style: { height: size }
24
+ }
25
+ };
26
+ const { className, style } = directionStyles[direction];
27
+ return /* @__PURE__ */ jsxs(DrawerBase.Root, { direction, children: [
28
+ /* @__PURE__ */ jsx(DrawerBase.Trigger, { asChild: true, children: trigger }),
29
+ /* @__PURE__ */ jsxs(DrawerBase.Portal, { children: [
30
+ /* @__PURE__ */ jsx(DrawerBase.Overlay, { className: "fixed inset-0 bg-transparent" }),
31
+ /* @__PURE__ */ jsxs(DrawerBase.Content, { className: `bg-drawer-bg z-10 flex flex-col p-4 outline-none ${className}`, style, children: [
32
+ /* @__PURE__ */ jsx(DrawerBase.Close, {}),
33
+ /* @__PURE__ */ jsx(DrawerBase.Title, { className: "text-text-primary mb-2 text-lg font-semibold", children: title }),
34
+ /* @__PURE__ */ jsx(DrawerBase.Description, { className: "!text-text-secondary mb-2 !text-xs uppercase", children: description }),
35
+ /* @__PURE__ */ jsx("div", { className: "pt-2", children })
36
+ ] })
37
+ ] })
38
+ ] });
39
+ };
40
+ export {
41
+ Drawer
42
+ };
@@ -1,3 +1,6 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
1
2
  import { ComponentProps } from 'react';
2
- declare function Skeleton({ className, ...props }: ComponentProps<'div'>): import("react/jsx-runtime").JSX.Element;
3
+
4
+ declare function Skeleton({ className, ...props }: ComponentProps<'div'>): react_jsx_runtime.JSX.Element;
5
+
3
6
  export { Skeleton };
@@ -0,0 +1,14 @@
1
+ "use client"
2
+ import {
3
+ cn
4
+ } from "./chunk-ZLENOYB4.js";
5
+
6
+ // src/components/Skeleton/Skeleton.tsx
7
+ import "react";
8
+ import { jsx } from "react/jsx-runtime";
9
+ function Skeleton({ className, ...props }) {
10
+ return /* @__PURE__ */ jsx("div", { "data-slot": "skeleton", className: cn("bg-accent animate-pulse rounded-md", className), ...props });
11
+ }
12
+ export {
13
+ Skeleton
14
+ };
@@ -1,6 +1,8 @@
1
- import { ComponentProps } from 'react';
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as SliderPrimitive from '@radix-ui/react-slider';
3
- export type SliderProps = ComponentProps<typeof SliderPrimitive.Root> & {
3
+ import { ComponentProps } from 'react';
4
+
5
+ type SliderProps = ComponentProps<typeof SliderPrimitive.Root> & {
4
6
  className?: string;
5
7
  defaultValue?: number[];
6
8
  value?: number[];
@@ -14,5 +16,6 @@ export type SliderProps = ComponentProps<typeof SliderPrimitive.Root> & {
14
16
  disabled?: boolean;
15
17
  name?: string;
16
18
  };
17
- declare function Slider({ className, defaultValue, value, min, max, step, minStepsBetweenThumbs, onValueChange, orientation, onValueCommit, disabled, name, ...props }: SliderProps): import("react/jsx-runtime").JSX.Element;
18
- export { Slider };
19
+ declare function Slider({ className, defaultValue, value, min, max, step, minStepsBetweenThumbs, onValueChange, orientation, onValueCommit, disabled, name, ...props }: SliderProps): react_jsx_runtime.JSX.Element;
20
+
21
+ export { Slider, type SliderProps };
package/dist/Slider.js ADDED
@@ -0,0 +1,79 @@
1
+ "use client"
2
+ import {
3
+ cn
4
+ } from "./chunk-ZLENOYB4.js";
5
+
6
+ // src/components/Slider/Slider.tsx
7
+ import * as SliderPrimitive from "@radix-ui/react-slider";
8
+ import "react";
9
+ import { jsx, jsxs } from "react/jsx-runtime";
10
+ function Slider({
11
+ className,
12
+ defaultValue,
13
+ value,
14
+ min = 0,
15
+ max = 100,
16
+ step = 1,
17
+ minStepsBetweenThumbs = 1,
18
+ onValueChange,
19
+ orientation = "horizontal",
20
+ onValueCommit,
21
+ disabled,
22
+ name,
23
+ ...props
24
+ }) {
25
+ const _values = value || defaultValue || [min];
26
+ return /* @__PURE__ */ jsxs(
27
+ SliderPrimitive.Root,
28
+ {
29
+ "data-slot": "slider",
30
+ defaultValue,
31
+ value,
32
+ min,
33
+ max,
34
+ step,
35
+ minStepsBetweenThumbs,
36
+ onValueChange,
37
+ orientation,
38
+ onValueCommit,
39
+ disabled,
40
+ name,
41
+ className: cn(
42
+ "relative flex w-full touch-none items-center select-none data-[disabled]:opacity-50 data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-44 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col",
43
+ className
44
+ ),
45
+ ...props,
46
+ children: [
47
+ /* @__PURE__ */ jsx(
48
+ SliderPrimitive.Track,
49
+ {
50
+ "data-slot": "slider-track",
51
+ className: cn(
52
+ "bg-slider-track relative grow overflow-hidden rounded-full data-[orientation=horizontal]:h-1.5 data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-1.5"
53
+ ),
54
+ children: /* @__PURE__ */ jsx(
55
+ SliderPrimitive.Range,
56
+ {
57
+ "data-slot": "slider-range",
58
+ className: cn(
59
+ "bg-slider-range absolute data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full"
60
+ )
61
+ }
62
+ )
63
+ }
64
+ ),
65
+ Array.from({ length: _values.length }, (_, index) => /* @__PURE__ */ jsx(
66
+ SliderPrimitive.Thumb,
67
+ {
68
+ "data-slot": "slider-thumb",
69
+ className: "border-slider-thumb-border bg-slider-thumb-bg ring-slider-thumb-ring/50 block size-4 shrink-0 rounded-full border shadow-sm transition-[color,box-shadow] hover:ring-4 focus-visible:ring-4 focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50"
70
+ },
71
+ index
72
+ ))
73
+ ]
74
+ }
75
+ );
76
+ }
77
+ export {
78
+ Slider
79
+ };
@@ -0,0 +1,12 @@
1
+ "use client"
2
+
3
+ // src/utils/twUtils.ts
4
+ import { clsx } from "clsx";
5
+ import { twMerge } from "tailwind-merge";
6
+ function cn(...inputs) {
7
+ return twMerge(clsx(inputs));
8
+ }
9
+
10
+ export {
11
+ cn
12
+ };