@dalshenekuda/candy-ui 2.0.1 → 2.1.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.
package/package.json CHANGED
@@ -1,7 +1,15 @@
1
1
  {
2
2
  "name": "@dalshenekuda/candy-ui",
3
- "version": "2.0.1",
3
+ "version": "2.1.0",
4
4
  "description": "A React UI components library with Tailwind CSS",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/dalshenekuda/CandyUI.git"
8
+ },
9
+ "homepage": "https://main--6ab56ef1aed13efbc107d427.chromatic.com/",
10
+ "bugs": {
11
+ "url": "https://github.com/dalshenekuda/CandyUI/issues"
12
+ },
5
13
  "type": "module",
6
14
  "main": "./build/ui-kit.js",
7
15
  "types": "./types/index.d.ts",
@@ -37,10 +45,11 @@
37
45
  "test:ui": "vitest --ui",
38
46
  "test:run": "vitest run",
39
47
  "test:coverage": "vitest run --coverage",
40
- "build:watch": "vite build --watch",
48
+ "build:watch": "VITE_BUILD_WATCH=true vite build --watch",
41
49
  "changeset": "changeset",
42
50
  "version-packages": "changeset version",
43
- "release": "npm run build && changeset publish"
51
+ "release": "npm run build && changeset publish",
52
+ "chromatic": "node --env-file-if-exists=.env.local ./node_modules/chromatic/dist/bin.js"
44
53
  },
45
54
  "keywords": [
46
55
  "react",
@@ -73,11 +82,14 @@
73
82
  "@eslint/js": "^10.0.1",
74
83
  "@storybook/addon-docs": "^10.3.6",
75
84
  "@storybook/react-vite": "^10.3.6",
85
+ "@testing-library/react": "^16.3.3",
86
+ "@testing-library/user-event": "^14.6.7",
76
87
  "@types/node": "^24.10.1",
77
88
  "@typescript-eslint/parser": "^8.0.0",
78
89
  "@vitejs/plugin-react": "^6.0.1",
79
90
  "@vitest/ui": "^4.0.14",
80
91
  "autoprefixer": "^10.4.22",
92
+ "chromatic": "^13.3.5",
81
93
  "concurrently": "^9.2.1",
82
94
  "eslint": "^10.0.2",
83
95
  "eslint-config-prettier": "^10.1.0",
@@ -1,12 +1,6 @@
1
1
  /**
2
- * Tailwind preset for candy-ui consumers.
3
- *
4
- * Import in your tailwind.config.js:
5
- * import uiKitPreset from 'candy-ui/tailwind.preset';
6
- * export default { presets: [uiKitPreset], content: [...] };
7
- *
8
- * All values reference CSS custom properties from src/tokens/*.css.
9
- * Import src/styles/style.css once in your app entry — tokens won't work without it.
2
+ * Tailwind preset for @dalshenekuda/candy-ui consumers.
3
+ * Import '@dalshenekuda/candy-ui/style.css' once in your app entry.
10
4
  */
11
5
 
12
6
  /** @type {import('tailwindcss').Config} */
@@ -20,7 +14,12 @@ export default {
20
14
  lg: '1024px',
21
15
  xl: '1280px',
22
16
  '2xl': '1536px',
23
- desktop: '992px', // matches --bp-desktop / typography breakpoint
17
+ desktop: '992px',
18
+ },
19
+
20
+ fontFamily: {
21
+ display: 'var(--font-display)',
22
+ body: 'var(--font-body)',
24
23
  },
25
24
 
26
25
  spacing: {
@@ -35,13 +34,16 @@ export default {
35
34
  '2xl': 'var(--spacing-2xl)',
36
35
  '3xl': 'var(--spacing-3xl)',
37
36
  '4xl': 'var(--spacing-4xl)',
37
+ '5xl': 'var(--spacing-5xl)',
38
+ '6xl': 'var(--spacing-6xl)',
39
+ '7xl': 'var(--spacing-7xl)',
38
40
  },
39
41
 
40
42
  colors: {
41
- // Semantic tokens — use these in components
42
43
  bg: 'var(--color-bg)',
43
44
  surface: 'var(--color-surface)',
44
45
  'surface-raised': 'var(--color-surface-raised)',
46
+ 'surface-sunken': 'var(--color-surface-sunken)',
45
47
 
46
48
  text: {
47
49
  DEFAULT: 'var(--color-text)',
@@ -52,6 +54,7 @@ export default {
52
54
 
53
55
  brand: {
54
56
  DEFAULT: 'var(--color-brand)',
57
+ hover: 'var(--color-brand-hover)',
55
58
  dark: 'var(--color-brand-dark)',
56
59
  light: 'var(--color-brand-light)',
57
60
  },
@@ -61,45 +64,62 @@ export default {
61
64
  dark: 'var(--color-accent-dark)',
62
65
  light: 'var(--color-accent-light)',
63
66
  warm: 'var(--color-accent-warm)',
67
+ alt: 'var(--color-accent-alt)',
64
68
  },
65
69
 
66
70
  border: {
67
71
  DEFAULT: 'var(--color-border)',
68
72
  subtle: 'var(--color-border-subtle)',
73
+ strong: 'var(--color-border-strong)',
74
+ },
75
+
76
+ tone: {
77
+ bg: 'var(--tone-bg)',
78
+ ink: 'var(--tone-ink)',
79
+ border: 'var(--tone-border)',
80
+ accent: 'var(--tone-accent)',
69
81
  },
70
82
 
71
83
  danger: 'var(--color-danger)',
72
84
  success: 'var(--color-success)',
73
85
  warning: 'var(--color-warning)',
74
86
 
75
- // Palette primitives — for Storybook / design token docs
76
87
  palette: {
77
- 'teal-900': 'var(--palette-teal-900)',
78
- 'teal-600': 'var(--palette-teal-600)',
79
- 'teal-400': 'var(--palette-teal-400)',
80
- 'teal-200': 'var(--palette-teal-200)',
81
- 'cream-ink': 'var(--palette-cream-ink)',
82
- 'cream-100': 'var(--palette-cream-100)',
83
- 'cream-50': 'var(--palette-cream-50)',
84
- 'grey-1000': 'var(--palette-grey-1000)',
85
- 'grey-900': 'var(--palette-grey-900)',
86
- 'grey-800': 'var(--palette-grey-800)',
87
- 'grey-700': 'var(--palette-grey-700)',
88
- 'grey-600': 'var(--palette-grey-600)',
89
- 'grey-500': 'var(--palette-grey-500)',
90
- 'grey-400': 'var(--palette-grey-400)',
91
- 'grey-300': 'var(--palette-grey-300)',
92
- 'grey-200': 'var(--palette-grey-200)',
93
- 'grey-100': 'var(--palette-grey-100)',
94
- 'coral-700': 'var(--palette-coral-700)',
95
- 'coral-500': 'var(--palette-coral-500)',
96
- 'coral-300': 'var(--palette-coral-300)',
97
- 'amber-500': 'var(--palette-amber-500)',
98
- 'olive-500': 'var(--palette-olive-500)',
99
- 'sage-500': 'var(--palette-sage-500)',
88
+ 'ink-1000': 'var(--palette-ink-1000)',
89
+ 'ink-900': 'var(--palette-ink-900)',
90
+ 'ink-800': 'var(--palette-ink-800)',
91
+ 'ink-600': 'var(--palette-ink-600)',
92
+ 'ink-500': 'var(--palette-ink-500)',
93
+ 'ink-300': 'var(--palette-ink-300)',
94
+ 'ink-200': 'var(--palette-ink-200)',
95
+ 'ink-100': 'var(--palette-ink-100)',
96
+ paper: 'var(--palette-paper)',
97
+ white: 'var(--palette-white)',
98
+ 'blueras-700': 'var(--palette-blueras-700)',
99
+ 'blueras-500': 'var(--palette-blueras-500)',
100
+ 'blueras-400': 'var(--palette-blueras-400)',
101
+ 'blueras-200': 'var(--palette-blueras-200)',
102
+ 'night-text': 'var(--palette-night-text)',
103
+ 'night-border-strong': 'var(--palette-night-border-strong)',
104
+ 'dark-base': 'var(--palette-dark-base)',
105
+ 'dark-surface': 'var(--palette-dark-surface)',
106
+ 'dark-raised': 'var(--palette-dark-raised)',
107
+ 'dark-border': 'var(--palette-dark-border)',
108
+ 'dark-border-subtle': 'var(--palette-dark-border-subtle)',
109
+ 'raspberry-700': 'var(--palette-raspberry-700)',
110
+ 'raspberry-600': 'var(--palette-raspberry-600)',
111
+ 'raspberry-200': 'var(--palette-raspberry-200)',
112
+ 'spearmint-700': 'var(--palette-spearmint-700)',
113
+ 'spearmint-500': 'var(--palette-spearmint-500)',
114
+ 'spearmint-200': 'var(--palette-spearmint-200)',
115
+ 'lemon-700': 'var(--palette-lemon-700)',
116
+ 'lemon-600': 'var(--palette-lemon-600)',
117
+ 'lemon-200': 'var(--palette-lemon-200)',
118
+ 'lime-700': 'var(--palette-lime-700)',
119
+ 'lime-500': 'var(--palette-lime-500)',
120
+ 'lime-200': 'var(--palette-lime-200)',
100
121
  },
101
122
 
102
- // White alpha scale
103
123
  'white-alpha': {
104
124
  10: 'var(--palette-white-10)',
105
125
  20: 'var(--palette-white-20)',
@@ -125,6 +145,10 @@ export default {
125
145
  full: 'var(--radius-full)',
126
146
  },
127
147
 
148
+ borderWidth: {
149
+ print: 'var(--border-print)',
150
+ },
151
+
128
152
  fontWeight: {
129
153
  light: 'var(--font-weight-light)',
130
154
  regular: 'var(--font-weight-regular)',
@@ -135,10 +159,13 @@ export default {
135
159
  },
136
160
 
137
161
  boxShadow: {
138
- sm: 'var(--shadow-sm)',
139
- md: 'var(--shadow-md)',
140
- lg: 'var(--shadow-lg)',
141
- xl: 'var(--shadow-xl)',
162
+ sm: 'var(--shadow-sm)',
163
+ md: 'var(--shadow-md)',
164
+ lg: 'var(--shadow-lg)',
165
+ xl: 'var(--shadow-xl)',
166
+ press: 'var(--shadow-press)',
167
+ hover: 'var(--shadow-hover)',
168
+ lift: 'var(--shadow-lift)',
142
169
  },
143
170
 
144
171
  transitionDuration: {
@@ -146,6 +173,11 @@ export default {
146
173
  base: 'var(--transition-base)',
147
174
  slow: 'var(--transition-slow)',
148
175
  },
176
+
177
+ transitionTimingFunction: {
178
+ 'out-quart': 'var(--ease-out-quart)',
179
+ spring: 'var(--ease-spring)',
180
+ },
149
181
  },
150
182
  },
151
183
  };
@@ -0,0 +1,19 @@
1
+ import * as React from 'react';
2
+ export type AddToCartStepperVariant = 'default' | 'compact' | 'compact-pill';
3
+ export interface AddToCartStepperProps {
4
+ quantity: number;
5
+ onAdd?: () => void;
6
+ onIncrease?: () => void;
7
+ onDecrease?: () => void;
8
+ addButton?: React.ReactNode;
9
+ decreaseButton?: React.ReactNode;
10
+ increaseButton?: React.ReactNode;
11
+ disabled?: boolean;
12
+ loading?: boolean;
13
+ addLabel?: string;
14
+ /** Height and max width for the default (full-width cart) layout; ignored for compact variants. */
15
+ size?: 'sm' | 'default';
16
+ variant?: AddToCartStepperVariant;
17
+ className?: string;
18
+ }
19
+ export declare function AddToCartStepper({ quantity, onAdd, onIncrease, onDecrease, addButton, decreaseButton, increaseButton, disabled, loading, addLabel, size, variant, className, }: AddToCartStepperProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,30 @@
1
+ import { VariantProps } from 'class-variance-authority';
2
+ import * as React from 'react';
3
+ import * as DialogPrimitive from '@radix-ui/react-dialog';
4
+ declare const Aside: React.FC<DialogPrimitive.DialogProps>;
5
+ declare const AsideTrigger: React.ForwardRefExoticComponent<DialogPrimitive.DialogTriggerProps & React.RefAttributes<HTMLButtonElement>>;
6
+ declare const AsidePortal: React.FC<DialogPrimitive.DialogPortalProps>;
7
+ declare const AsideClose: React.ForwardRefExoticComponent<DialogPrimitive.DialogCloseProps & React.RefAttributes<HTMLButtonElement>>;
8
+ declare const AsideOverlay: React.ForwardRefExoticComponent<Omit<DialogPrimitive.DialogOverlayProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
9
+ declare const asideContentVariants: (props?: ({
10
+ side?: "left" | "right" | null | undefined;
11
+ } & import('class-variance-authority/dist/types').ClassProp) | undefined) => string;
12
+ export interface AsideContentProps extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>, VariantProps<typeof asideContentVariants> {
13
+ }
14
+ declare const AsideContent: React.ForwardRefExoticComponent<AsideContentProps & React.RefAttributes<HTMLDivElement>>;
15
+ declare const AsideHeader: {
16
+ ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>): import("react/jsx-runtime").JSX.Element;
17
+ displayName: string;
18
+ };
19
+ declare const AsideBody: {
20
+ ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>): import("react/jsx-runtime").JSX.Element;
21
+ displayName: string;
22
+ };
23
+ declare const AsideFooter: {
24
+ ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>): import("react/jsx-runtime").JSX.Element;
25
+ displayName: string;
26
+ };
27
+ declare const AsideTitle: React.ForwardRefExoticComponent<Omit<DialogPrimitive.DialogTitleProps & React.RefAttributes<HTMLHeadingElement>, "ref"> & React.RefAttributes<HTMLHeadingElement>>;
28
+ declare const AsideDescription: React.ForwardRefExoticComponent<Omit<DialogPrimitive.DialogDescriptionProps & React.RefAttributes<HTMLParagraphElement>, "ref"> & React.RefAttributes<HTMLParagraphElement>>;
29
+ declare const AsideCloseButton: React.ForwardRefExoticComponent<Omit<DialogPrimitive.DialogCloseProps & React.RefAttributes<HTMLButtonElement>, "ref"> & React.RefAttributes<HTMLButtonElement>>;
30
+ export { Aside, AsidePortal, AsideOverlay, AsideTrigger, AsideClose, AsideContent, AsideHeader, AsideBody, AsideFooter, AsideTitle, AsideDescription, AsideCloseButton, };
@@ -1,9 +1,10 @@
1
1
  import { VariantProps } from 'class-variance-authority';
2
2
  import * as React from 'react';
3
3
  declare const badgeVariants: (props?: ({
4
- variant?: "default" | "destructive" | "outline" | "secondary" | "success" | "warning" | null | undefined;
4
+ variant?: "default" | "destructive" | "outline" | "secondary" | "tone" | "success" | "warning" | "sale" | "soldout" | "new" | "ink" | "print" | null | undefined;
5
+ rotate?: "none" | "left" | "right" | null | undefined;
5
6
  } & import('class-variance-authority/dist/types').ClassProp) | undefined) => string;
6
7
  export interface BadgeProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof badgeVariants> {
7
8
  }
8
- declare function Badge({ className, variant, ...props }: BadgeProps): import("react/jsx-runtime").JSX.Element;
9
+ declare function Badge({ className, variant, rotate, ...props }: BadgeProps): import("react/jsx-runtime").JSX.Element;
9
10
  export { Badge, badgeVariants };
@@ -1,11 +1,12 @@
1
1
  import { VariantProps } from 'class-variance-authority';
2
2
  import * as React from 'react';
3
3
  declare const buttonVariants: (props?: ({
4
- variant?: "link" | "default" | "destructive" | "outline" | "secondary" | "ghost" | null | undefined;
5
- size?: "default" | "icon" | "sm" | "lg" | null | undefined;
4
+ variant?: "link" | "default" | "destructive" | "outline" | "secondary" | "ghost" | "tone" | "cart" | null | undefined;
5
+ size?: "default" | "icon" | "sm" | "lg" | "xl" | "pill" | null | undefined;
6
6
  } & import('class-variance-authority/dist/types').ClassProp) | undefined) => string;
7
7
  export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
8
8
  asChild?: boolean;
9
+ loading?: boolean;
9
10
  }
10
11
  declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement>>;
11
12
  export { Button, buttonVariants };
@@ -0,0 +1,25 @@
1
+ import * as React from 'react';
2
+ export type ProductCardTone = 'blueras' | 'raspberry' | 'spearmint' | 'lemon' | 'lime';
3
+ export interface ProductCardProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'title'> {
4
+ imageSrc?: string;
5
+ imageAlt: string;
6
+ imageLoading?: 'eager' | 'lazy';
7
+ /** cover = fill frame; contain = cutout on tone field */
8
+ fit?: 'cover' | 'contain';
9
+ /** Flavor tone — vars resolve via data-tone-vars; fill on hover/focus (or rest when toneMode="rest") */
10
+ tone?: ProductCardTone | null;
11
+ /** hover = transparent rest + tone on group-hover/focus-within; rest = always filled (Storybook) */
12
+ toneMode?: 'hover' | 'rest';
13
+ title: React.ReactNode;
14
+ description?: React.ReactNode;
15
+ /** Meta line e.g. flavor label */
16
+ meta?: React.ReactNode;
17
+ /** Price label on media (top-left); page-colored field, print border on hover */
18
+ price?: React.ReactNode;
19
+ compareAtPrice?: React.ReactNode;
20
+ badgeTopLeft?: React.ReactNode;
21
+ badgeTopRight?: React.ReactNode;
22
+ footer?: React.ReactNode;
23
+ }
24
+ declare const ProductCard: React.ForwardRefExoticComponent<ProductCardProps & React.RefAttributes<HTMLDivElement>>;
25
+ export { ProductCard };
@@ -1,12 +1,14 @@
1
1
  import * as React from 'react';
2
- export type TextVariant = 'heading-xl' | 'heading-lg' | 'heading-md' | 'heading-sm' | 'subtitle-lg' | 'subtitle-md' | 'body-lg' | 'body-md' | 'body-sm' | 'caption-md' | 'caption-sm' | 'overline';
2
+ export type TextVariant = 'display-2xl' | 'display-xl' | 'display-lg' | 'heading-xl' | 'heading-lg' | 'heading-md' | 'heading-sm' | 'meta-md' | 'meta-sm' | 'subtitle-lg' | 'subtitle-md' | 'body-lg' | 'body-md' | 'body-sm' | 'caption-md' | 'caption-sm' | 'overline';
3
3
  export type FontWeight = 'light' | 'regular' | 'medium' | 'semibold' | 'bold' | 'black';
4
- export type TextColor = 'color-text' | 'color-text-muted' | 'color-text-subtle' | 'color-text-on-brand' | 'color-brand' | 'color-brand-dark' | 'color-brand-light' | 'color-accent' | 'color-accent-dark' | 'color-accent-light' | 'color-accent-warm' | 'color-danger' | 'color-success' | 'color-warning';
4
+ export type TextColor = 'color-text' | 'color-text-muted' | 'color-text-subtle' | 'color-text-on-brand' | 'color-brand' | 'color-brand-dark' | 'color-brand-light' | 'color-accent' | 'color-accent-dark' | 'color-accent-light' | 'color-accent-alt' | 'color-accent-warm' | 'color-danger' | 'color-success' | 'color-warning' | 'tone-ink' | 'tone-accent';
5
5
  export interface TextProps extends React.HTMLAttributes<HTMLElement> {
6
6
  variant?: TextVariant;
7
7
  as?: React.ElementType;
8
8
  weight?: FontWeight;
9
9
  color?: TextColor;
10
+ /** Applies text-wrap: balance for display headings */
11
+ balance?: boolean;
10
12
  }
11
13
  declare const Text: React.ForwardRefExoticComponent<TextProps & React.RefAttributes<HTMLElement>>;
12
14
  export { Text };
package/types/index.d.ts CHANGED
@@ -2,6 +2,7 @@ export * from './components/Text/Text';
2
2
  export * from './components/Button/Button';
3
3
  export * from './components/Badge/Badge';
4
4
  export * from './components/Card/Card';
5
+ export * from './components/ProductCard/ProductCard';
6
+ export * from './components/AddToCartStepper/AddToCartStepper';
5
7
  export * from './components/Dialog/Dialog';
6
- /** Alias for Button — consumed by my-account-proxy and other apps as ActionButton */
7
- export { Button as ActionButton } from './components/Button/Button';
8
+ export * from './components/Aside/Aside';
@@ -1,6 +0,0 @@
1
- /**
2
- * Valid semantic color token names from src/tokens/theme-light.css and theme-dark.css.
3
- * Use as: style.color = `var(--${color})` or color prop on Text component.
4
- * No hex values here — colors resolve at runtime via CSS custom properties.
5
- */
6
- export type TextColor = 'color-text' | 'color-text-muted' | 'color-text-subtle' | 'color-text-on-brand' | 'color-brand' | 'color-brand-dark' | 'color-brand-light' | 'color-accent' | 'color-accent-dark' | 'color-accent-light' | 'color-accent-warm' | 'color-danger' | 'color-success' | 'color-warning';
@@ -1,6 +0,0 @@
1
- /**
2
- * Spacing token names — match --spacing-* CSS custom properties
3
- * defined in src/tokens/spacing.css.
4
- * Usage: style.padding = `var(--spacing-${token})`
5
- */
6
- export type SpacingToken = 'none' | 'px' | '2xs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl';
@@ -1,6 +0,0 @@
1
- /**
2
- * Font weight token names — match --font-weight-* CSS custom properties
3
- * defined in src/tokens/typography-variables.scss.
4
- * Usage: style.fontWeight = `var(--font-weight-${weight})`
5
- */
6
- export type FontWeight = 'light' | 'regular' | 'medium' | 'semibold' | 'bold' | 'black';