@kushagradhawan/kookie-ui 0.1.41 → 0.1.42

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 (142) hide show
  1. package/README.md +257 -60
  2. package/components.css +386 -79
  3. package/dist/cjs/components/schemas/base-button.schema.d.ts +319 -0
  4. package/dist/cjs/components/schemas/base-button.schema.d.ts.map +1 -0
  5. package/dist/cjs/components/schemas/base-button.schema.js +2 -0
  6. package/dist/cjs/components/schemas/base-button.schema.js.map +7 -0
  7. package/dist/cjs/components/schemas/button.schema.d.ts +686 -0
  8. package/dist/cjs/components/schemas/button.schema.d.ts.map +1 -0
  9. package/dist/cjs/components/schemas/button.schema.js +2 -0
  10. package/dist/cjs/components/schemas/button.schema.js.map +7 -0
  11. package/dist/cjs/components/schemas/icon-button.schema.d.ts +329 -0
  12. package/dist/cjs/components/schemas/icon-button.schema.d.ts.map +1 -0
  13. package/dist/cjs/components/schemas/icon-button.schema.js +2 -0
  14. package/dist/cjs/components/schemas/icon-button.schema.js.map +7 -0
  15. package/dist/cjs/components/schemas/index.d.ts +52 -0
  16. package/dist/cjs/components/schemas/index.d.ts.map +1 -0
  17. package/dist/cjs/components/schemas/index.js +2 -0
  18. package/dist/cjs/components/schemas/index.js.map +7 -0
  19. package/dist/cjs/components/schemas/toggle-button.schema.d.ts +1172 -0
  20. package/dist/cjs/components/schemas/toggle-button.schema.d.ts.map +1 -0
  21. package/dist/cjs/components/schemas/toggle-button.schema.js +2 -0
  22. package/dist/cjs/components/schemas/toggle-button.schema.js.map +7 -0
  23. package/dist/cjs/components/schemas/toggle-icon-button.schema.d.ts +563 -0
  24. package/dist/cjs/components/schemas/toggle-icon-button.schema.d.ts.map +1 -0
  25. package/dist/cjs/components/schemas/toggle-icon-button.schema.js +2 -0
  26. package/dist/cjs/components/schemas/toggle-icon-button.schema.js.map +7 -0
  27. package/dist/cjs/components/sheet.d.ts +1 -1
  28. package/dist/cjs/components/sheet.d.ts.map +1 -1
  29. package/dist/cjs/components/sheet.js +1 -1
  30. package/dist/cjs/components/sheet.js.map +3 -3
  31. package/dist/cjs/components/shell.d.ts +125 -164
  32. package/dist/cjs/components/shell.d.ts.map +1 -1
  33. package/dist/cjs/components/shell.js +1 -1
  34. package/dist/cjs/components/shell.js.map +3 -3
  35. package/dist/cjs/components/sidebar.d.ts +1 -7
  36. package/dist/cjs/components/sidebar.d.ts.map +1 -1
  37. package/dist/cjs/components/sidebar.js +1 -1
  38. package/dist/cjs/components/sidebar.js.map +3 -3
  39. package/dist/cjs/components/theme.d.ts +3 -0
  40. package/dist/cjs/components/theme.d.ts.map +1 -1
  41. package/dist/cjs/components/theme.js +1 -1
  42. package/dist/cjs/components/theme.js.map +3 -3
  43. package/dist/cjs/components/theme.props.d.ts +10 -0
  44. package/dist/cjs/components/theme.props.d.ts.map +1 -1
  45. package/dist/cjs/components/theme.props.js +1 -1
  46. package/dist/cjs/components/theme.props.js.map +3 -3
  47. package/dist/cjs/helpers/font-config.d.ts +96 -0
  48. package/dist/cjs/helpers/font-config.d.ts.map +1 -0
  49. package/dist/cjs/helpers/font-config.js +3 -0
  50. package/dist/cjs/helpers/font-config.js.map +7 -0
  51. package/dist/cjs/helpers/index.d.ts +1 -0
  52. package/dist/cjs/helpers/index.d.ts.map +1 -1
  53. package/dist/cjs/helpers/index.js +1 -1
  54. package/dist/cjs/helpers/index.js.map +2 -2
  55. package/dist/esm/components/schemas/base-button.schema.d.ts +319 -0
  56. package/dist/esm/components/schemas/base-button.schema.d.ts.map +1 -0
  57. package/dist/esm/components/schemas/base-button.schema.js +2 -0
  58. package/dist/esm/components/schemas/base-button.schema.js.map +7 -0
  59. package/dist/esm/components/schemas/button.schema.d.ts +686 -0
  60. package/dist/esm/components/schemas/button.schema.d.ts.map +1 -0
  61. package/dist/esm/components/schemas/button.schema.js +2 -0
  62. package/dist/esm/components/schemas/button.schema.js.map +7 -0
  63. package/dist/esm/components/schemas/icon-button.schema.d.ts +329 -0
  64. package/dist/esm/components/schemas/icon-button.schema.d.ts.map +1 -0
  65. package/dist/esm/components/schemas/icon-button.schema.js +2 -0
  66. package/dist/esm/components/schemas/icon-button.schema.js.map +7 -0
  67. package/dist/esm/components/schemas/index.d.ts +52 -0
  68. package/dist/esm/components/schemas/index.d.ts.map +1 -0
  69. package/dist/esm/components/schemas/index.js +2 -0
  70. package/dist/esm/components/schemas/index.js.map +7 -0
  71. package/dist/esm/components/schemas/toggle-button.schema.d.ts +1172 -0
  72. package/dist/esm/components/schemas/toggle-button.schema.d.ts.map +1 -0
  73. package/dist/esm/components/schemas/toggle-button.schema.js +2 -0
  74. package/dist/esm/components/schemas/toggle-button.schema.js.map +7 -0
  75. package/dist/esm/components/schemas/toggle-icon-button.schema.d.ts +563 -0
  76. package/dist/esm/components/schemas/toggle-icon-button.schema.d.ts.map +1 -0
  77. package/dist/esm/components/schemas/toggle-icon-button.schema.js +2 -0
  78. package/dist/esm/components/schemas/toggle-icon-button.schema.js.map +7 -0
  79. package/dist/esm/components/sheet.d.ts +1 -1
  80. package/dist/esm/components/sheet.d.ts.map +1 -1
  81. package/dist/esm/components/sheet.js +1 -1
  82. package/dist/esm/components/sheet.js.map +3 -3
  83. package/dist/esm/components/shell.d.ts +125 -164
  84. package/dist/esm/components/shell.d.ts.map +1 -1
  85. package/dist/esm/components/shell.js +1 -1
  86. package/dist/esm/components/shell.js.map +3 -3
  87. package/dist/esm/components/sidebar.d.ts +1 -7
  88. package/dist/esm/components/sidebar.d.ts.map +1 -1
  89. package/dist/esm/components/sidebar.js +1 -1
  90. package/dist/esm/components/sidebar.js.map +3 -3
  91. package/dist/esm/components/theme.d.ts +3 -0
  92. package/dist/esm/components/theme.d.ts.map +1 -1
  93. package/dist/esm/components/theme.js +1 -1
  94. package/dist/esm/components/theme.js.map +3 -3
  95. package/dist/esm/components/theme.props.d.ts +10 -0
  96. package/dist/esm/components/theme.props.d.ts.map +1 -1
  97. package/dist/esm/components/theme.props.js +1 -1
  98. package/dist/esm/components/theme.props.js.map +3 -3
  99. package/dist/esm/helpers/font-config.d.ts +96 -0
  100. package/dist/esm/helpers/font-config.d.ts.map +1 -0
  101. package/dist/esm/helpers/font-config.js +3 -0
  102. package/dist/esm/helpers/font-config.js.map +7 -0
  103. package/dist/esm/helpers/index.d.ts +1 -0
  104. package/dist/esm/helpers/index.d.ts.map +1 -1
  105. package/dist/esm/helpers/index.js +1 -1
  106. package/dist/esm/helpers/index.js.map +2 -2
  107. package/package.json +23 -3
  108. package/schemas/base-button.d.ts +2 -0
  109. package/schemas/base-button.json +284 -0
  110. package/schemas/button.d.ts +2 -0
  111. package/schemas/button.json +535 -0
  112. package/schemas/icon-button.d.ts +2 -0
  113. package/schemas/icon-button.json +318 -0
  114. package/schemas/index.d.ts +2 -0
  115. package/schemas/index.json +2016 -0
  116. package/schemas/schemas.d.ts +29 -0
  117. package/schemas/toggle-button.d.ts +2 -0
  118. package/schemas/toggle-button.json +543 -0
  119. package/schemas/toggle-icon-button.d.ts +2 -0
  120. package/schemas/toggle-icon-button.json +326 -0
  121. package/schemas-json.d.ts +12 -0
  122. package/src/components/_internal/base-sidebar.css +1 -2
  123. package/src/components/schemas/base-button.schema.ts +339 -0
  124. package/src/components/schemas/button.schema.ts +198 -0
  125. package/src/components/schemas/icon-button.schema.ts +142 -0
  126. package/src/components/schemas/index.ts +68 -0
  127. package/src/components/schemas/toggle-button.schema.ts +122 -0
  128. package/src/components/schemas/toggle-icon-button.schema.ts +195 -0
  129. package/src/components/sheet.css +39 -19
  130. package/src/components/sheet.tsx +62 -3
  131. package/src/components/shell.css +510 -89
  132. package/src/components/shell.tsx +2055 -928
  133. package/src/components/sidebar.tsx +3 -22
  134. package/src/components/theme.props.tsx +8 -0
  135. package/src/components/theme.tsx +16 -0
  136. package/src/helpers/font-config.ts +167 -0
  137. package/src/helpers/index.ts +1 -0
  138. package/src/styles/fonts.css +16 -13
  139. package/src/styles/tokens/typography.css +27 -4
  140. package/styles.css +398 -79
  141. package/tokens/base.css +12 -0
  142. package/tokens.css +12 -0
@@ -0,0 +1,198 @@
1
+ import { z } from 'zod';
2
+ import { BaseButtonSchema } from './base-button.schema.js';
3
+
4
+ /**
5
+ * Button Zod schema - Single source of truth for Button component props
6
+ *
7
+ * The Button component is the primary interactive element in the Kookie User Interface.
8
+ * It provides six visual variants, four sizes, comprehensive color options, and built-in
9
+ * tooltip support. The component automatically handles icon sizing, supports responsive
10
+ * layouts, and provides accessibility compliance out of the box.
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * // Basic button validation
15
+ * const props = ButtonSchema.parse({ variant: 'solid', size: '2' });
16
+ *
17
+ * // Button with tooltip
18
+ * const tooltipProps = ButtonSchema.parse({
19
+ * tooltip: 'Save your progress',
20
+ * tooltipSide: 'top'
21
+ * });
22
+ *
23
+ * // Polymorphic button as link
24
+ * const linkProps = ButtonSchema.parse({
25
+ * as: 'a',
26
+ * href: '/dashboard',
27
+ * children: 'Go to Dashboard'
28
+ * });
29
+ * ```
30
+ */
31
+ export const ButtonSchema = BaseButtonSchema.extend({
32
+ /**
33
+ * Content to display in the tooltip on hover/focus
34
+ */
35
+ tooltip: z.string().optional().describe('Content to display in the tooltip on hover/focus'),
36
+
37
+ /**
38
+ * Side of the button where the tooltip should appear
39
+ * @default 'top'
40
+ */
41
+ tooltipSide: z
42
+ .enum(['top', 'right', 'bottom', 'left'])
43
+ .optional()
44
+ .default('top')
45
+ .describe('Side of the button where the tooltip should appear'),
46
+
47
+ /**
48
+ * Alignment of the tooltip relative to the button
49
+ * @default 'center'
50
+ */
51
+ tooltipAlign: z
52
+ .enum(['start', 'center', 'end'])
53
+ .optional()
54
+ .default('center')
55
+ .describe('Alignment of the tooltip relative to the button'),
56
+
57
+ /**
58
+ * Delay before showing the tooltip (in milliseconds)
59
+ */
60
+ tooltipDelayDuration: z
61
+ .number()
62
+ .optional()
63
+ .describe('Delay before showing the tooltip (in milliseconds)'),
64
+
65
+ /**
66
+ * Whether to disable hoverable content behavior
67
+ * @default false
68
+ */
69
+ tooltipDisableHoverableContent: z
70
+ .boolean()
71
+ .optional()
72
+ .default(false)
73
+ .describe('Whether to disable hoverable content behavior'),
74
+
75
+ /**
76
+ * Override styles for different interaction states
77
+ */
78
+ overrideStyles: z
79
+ .object({
80
+ /** Default/idle state styles */
81
+ normal: z
82
+ .object({
83
+ color: z.string().optional(),
84
+ background: z.string().optional(),
85
+ backgroundColor: z.string().optional(),
86
+ boxShadow: z.string().optional(),
87
+ filter: z.string().optional(),
88
+ outline: z.string().optional(),
89
+ outlineOffset: z.string().optional(),
90
+ opacity: z.union([z.string(), z.number()]).optional(),
91
+ })
92
+ .optional(),
93
+ /** Hover state styles */
94
+ hover: z
95
+ .object({
96
+ color: z.string().optional(),
97
+ background: z.string().optional(),
98
+ backgroundColor: z.string().optional(),
99
+ boxShadow: z.string().optional(),
100
+ filter: z.string().optional(),
101
+ outline: z.string().optional(),
102
+ outlineOffset: z.string().optional(),
103
+ opacity: z.union([z.string(), z.number()]).optional(),
104
+ })
105
+ .optional(),
106
+ /** Active (mouse down) state styles */
107
+ active: z
108
+ .object({
109
+ color: z.string().optional(),
110
+ background: z.string().optional(),
111
+ backgroundColor: z.string().optional(),
112
+ boxShadow: z.string().optional(),
113
+ filter: z.string().optional(),
114
+ outline: z.string().optional(),
115
+ outlineOffset: z.string().optional(),
116
+ opacity: z.union([z.string(), z.number()]).optional(),
117
+ })
118
+ .optional(),
119
+ /** Toggle pressed state styles (data-state="on") */
120
+ pressed: z
121
+ .object({
122
+ color: z.string().optional(),
123
+ background: z.string().optional(),
124
+ backgroundColor: z.string().optional(),
125
+ boxShadow: z.string().optional(),
126
+ filter: z.string().optional(),
127
+ outline: z.string().optional(),
128
+ outlineOffset: z.string().optional(),
129
+ opacity: z.union([z.string(), z.number()]).optional(),
130
+ })
131
+ .optional(),
132
+ /** Open state styles (e.g., when used as a trigger) */
133
+ open: z
134
+ .object({
135
+ color: z.string().optional(),
136
+ background: z.string().optional(),
137
+ backgroundColor: z.string().optional(),
138
+ boxShadow: z.string().optional(),
139
+ filter: z.string().optional(),
140
+ outline: z.string().optional(),
141
+ outlineOffset: z.string().optional(),
142
+ opacity: z.union([z.string(), z.number()]).optional(),
143
+ })
144
+ .optional(),
145
+ /** Disabled state styles */
146
+ disabled: z
147
+ .object({
148
+ color: z.string().optional(),
149
+ background: z.string().optional(),
150
+ backgroundColor: z.string().optional(),
151
+ boxShadow: z.string().optional(),
152
+ filter: z.string().optional(),
153
+ outline: z.string().optional(),
154
+ outlineOffset: z.string().optional(),
155
+ opacity: z.union([z.string(), z.number()]).optional(),
156
+ })
157
+ .optional(),
158
+ /** Focus-visible outline styles */
159
+ focus: z
160
+ .object({
161
+ outline: z.string().optional(),
162
+ outlineOffset: z.string().optional(),
163
+ })
164
+ .optional(),
165
+ })
166
+ .optional()
167
+ .describe('Override styles for different interaction states'),
168
+ }).strict();
169
+
170
+ /**
171
+ * Type derived from Button Zod schema
172
+ * This ensures type safety and consistency with the schema
173
+ */
174
+ export type ButtonProps = z.infer<typeof ButtonSchema>;
175
+
176
+ /**
177
+ * Development-only helper to validate and normalize Button props
178
+ * This function should only be used in development mode
179
+ *
180
+ * @param props - Props to validate and normalize
181
+ * @returns Validated and normalized props
182
+ *
183
+ * @example
184
+ * ```tsx
185
+ * // In development, this will validate props and show helpful errors
186
+ * const validatedProps = parseButtonProps({
187
+ * variant: 'invalid',
188
+ * tooltipSide: 'invalid'
189
+ * });
190
+ * // Throws validation errors for invalid enum values
191
+ * ```
192
+ */
193
+ export function parseButtonProps(props: unknown): ButtonProps {
194
+ if (process.env.NODE_ENV === 'development') {
195
+ return ButtonSchema.parse(props);
196
+ }
197
+ return props as ButtonProps;
198
+ }
@@ -0,0 +1,142 @@
1
+ import { z } from 'zod';
2
+ import { BaseButtonSchema } from './base-button.schema.js';
3
+
4
+ /**
5
+ * IconButton Zod schema - Single source of truth for IconButton component props
6
+ *
7
+ * IconButton is a specialized button component designed for icon-only interactions.
8
+ * It requires proper accessibility attributes to meet WCAG guidelines and provides
9
+ * comprehensive tooltip support for better user experience.
10
+ *
11
+ * Key features:
12
+ * - Required accessibility attributes (aria-label, aria-labelledby, or children)
13
+ * - Tooltip support for better UX
14
+ * - Inherits all BaseButton functionality
15
+ * - Optimized for icon-only interactions
16
+ *
17
+ * @example
18
+ * ```tsx
19
+ * // Basic icon button with aria-label
20
+ * const props = IconButtonSchema.parse({
21
+ * 'aria-label': 'Close dialog',
22
+ * variant: 'ghost'
23
+ * });
24
+ *
25
+ * // Icon button with tooltip
26
+ * const tooltipProps = IconButtonSchema.parse({
27
+ * 'aria-label': 'Settings',
28
+ * tooltip: 'Open settings menu',
29
+ * tooltipSide: 'right'
30
+ * });
31
+ *
32
+ * // Icon button with children (fallback accessibility)
33
+ * const childrenProps = IconButtonSchema.parse({
34
+ * children: <SettingsIcon />,
35
+ * variant: 'soft'
36
+ * });
37
+ * ```
38
+ */
39
+ export const IconButtonSchema = BaseButtonSchema.extend({
40
+ /**
41
+ * Content to display in the tooltip on hover/focus
42
+ */
43
+ tooltip: z.string().optional().describe('Content to display in the tooltip on hover/focus'),
44
+
45
+ /**
46
+ * Side of the button where the tooltip should appear
47
+ * @default 'top'
48
+ */
49
+ tooltipSide: z
50
+ .enum(['top', 'right', 'bottom', 'left'])
51
+ .optional()
52
+ .default('top')
53
+ .describe('Side of the button where the tooltip should appear'),
54
+
55
+ /**
56
+ * Alignment of the tooltip relative to the button
57
+ * @default 'center'
58
+ */
59
+ tooltipAlign: z
60
+ .enum(['start', 'center', 'end'])
61
+ .optional()
62
+ .default('center')
63
+ .describe('Alignment of the tooltip relative to the button'),
64
+
65
+ /**
66
+ * Delay before showing the tooltip (in milliseconds)
67
+ */
68
+ tooltipDelayDuration: z
69
+ .number()
70
+ .optional()
71
+ .describe('Delay before showing the tooltip (in milliseconds)'),
72
+
73
+ /**
74
+ * Whether to disable hoverable content behavior
75
+ * @default false
76
+ */
77
+ tooltipDisableHoverableContent: z
78
+ .boolean()
79
+ .optional()
80
+ .default(false)
81
+ .describe('Whether to disable hoverable content behavior'),
82
+
83
+ /**
84
+ * ARIA label for accessibility (required if no aria-labelledby or children)
85
+ * Icon buttons must have an accessible name to meet WCAG guidelines
86
+ */
87
+ 'aria-label': z.string().optional().describe('ARIA label for accessibility'),
88
+
89
+ /**
90
+ * ARIA labelled by reference (required if no aria-label or children)
91
+ * Icon buttons must have an accessible name to meet WCAG guidelines
92
+ */
93
+ 'aria-labelledby': z.string().optional().describe('ARIA labelled by reference'),
94
+
95
+ /**
96
+ * Children elements (required if no aria-label or aria-labelledby)
97
+ * Icon buttons must have an accessible name to meet WCAG guidelines
98
+ */
99
+ children: z
100
+ .any()
101
+ .optional()
102
+ .describe('Children elements (required for accessibility if no aria-label)'),
103
+ }).refine((data) => data['aria-label'] || data['aria-labelledby'] || data.children, {
104
+ message:
105
+ "IconButton must have either 'aria-label', 'aria-labelledby', or 'children' for accessibility",
106
+ path: ['aria-label', 'aria-labelledby', 'children'],
107
+ });
108
+
109
+ /**
110
+ * Type derived from IconButton Zod schema
111
+ * This ensures type safety and consistency with the schema
112
+ */
113
+ export type IconButtonProps = z.infer<typeof IconButtonSchema>;
114
+
115
+ /**
116
+ * Development-only helper to validate and normalize IconButton props
117
+ * This function should only be used in development mode
118
+ *
119
+ * @param props - Props to validate and normalize
120
+ * @returns Validated and normalized props
121
+ *
122
+ * @example
123
+ * ```tsx
124
+ * // In development, this will validate props and show helpful errors
125
+ * const validatedProps = parseIconButtonProps({
126
+ * variant: 'ghost'
127
+ * // Missing accessibility - will throw error
128
+ * });
129
+ * // Throws: "IconButton must have either 'aria-label', 'aria-labelledby', or 'children' for accessibility"
130
+ *
131
+ * const validProps = parseIconButtonProps({
132
+ * 'aria-label': 'Close',
133
+ * variant: 'ghost'
134
+ * });
135
+ * ```
136
+ */
137
+ export function parseIconButtonProps(props: unknown): IconButtonProps {
138
+ if (process.env.NODE_ENV === 'development') {
139
+ return IconButtonSchema.parse(props);
140
+ }
141
+ return props as IconButtonProps;
142
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Button component schemas - Single source of truth for all button-related components
3
+ *
4
+ * This module exports Zod schemas for all button components, providing:
5
+ * - Type-safe prop validation
6
+ * - Machine-readable JSON schema generation
7
+ * - Development-time prop validation
8
+ * - Consistent API across all button variants
9
+ *
10
+ * @example
11
+ * ```tsx
12
+ * import { ButtonSchema, parseButtonProps } from './schemas';
13
+ *
14
+ * // Type-safe prop validation
15
+ * const props = ButtonSchema.parse({ variant: 'solid', size: '2' });
16
+ *
17
+ * // Development-time validation
18
+ * const validatedProps = parseButtonProps(userProps);
19
+ * ```
20
+ */
21
+
22
+ // Base schemas
23
+ export { BaseButtonSchema, parseBaseButtonProps } from './base-button.schema.js';
24
+ export type { BaseButtonProps } from './base-button.schema.js';
25
+
26
+ // Button schemas
27
+ export { ButtonSchema, parseButtonProps } from './button.schema.js';
28
+ export type { ButtonProps } from './button.schema.js';
29
+
30
+ // IconButton schemas
31
+ export { IconButtonSchema, parseIconButtonProps } from './icon-button.schema.js';
32
+ export type { IconButtonProps } from './icon-button.schema.js';
33
+
34
+ // ToggleButton schemas
35
+ export { ToggleButtonSchema, parseToggleButtonProps } from './toggle-button.schema.js';
36
+ export type { ToggleButtonProps } from './toggle-button.schema.js';
37
+
38
+ // ToggleIconButton schemas
39
+ export { ToggleIconButtonSchema, parseToggleIconButtonProps } from './toggle-icon-button.schema.js';
40
+ export type { ToggleIconButtonProps } from './toggle-icon-button.schema.js';
41
+
42
+ /**
43
+ * Generic parseProps helper for development-time validation
44
+ *
45
+ * This function provides a type-safe way to validate props in development mode.
46
+ * It should only be used in development as it adds runtime overhead.
47
+ *
48
+ * @param schema - Zod schema to validate against
49
+ * @param props - Props to validate
50
+ * @returns Validated and normalized props
51
+ *
52
+ * @example
53
+ * ```tsx
54
+ * import { parseProps } from './schemas';
55
+ * import { ButtonSchema } from './schemas';
56
+ *
57
+ * // In development, this will validate props and show helpful errors
58
+ * const validatedProps = parseProps(ButtonSchema, userProps);
59
+ * ```
60
+ */
61
+ export function parseProps<T>(schema: z.ZodSchema<T>, props: unknown): T {
62
+ if (process.env.NODE_ENV === 'development') {
63
+ return schema.parse(props);
64
+ }
65
+ return props as T;
66
+ }
67
+
68
+ import { z } from 'zod';
@@ -0,0 +1,122 @@
1
+ import { z } from 'zod';
2
+ import { ButtonSchema } from './button.schema.js';
3
+
4
+ /**
5
+ * ToggleButton Zod schema - Single source of truth for ToggleButton component props
6
+ *
7
+ * ToggleButton extends Button with toggle functionality using Radix UI's Toggle primitive.
8
+ * It provides proper accessibility announcements, controlled/uncontrolled state management,
9
+ * and seamless integration with the existing Button component.
10
+ *
11
+ * Key features:
12
+ * - Controlled and uncontrolled state management
13
+ * - Live accessibility announcements for screen readers
14
+ * - Automatic state validation and warnings
15
+ * - Seamless integration with Button props and styling
16
+ * - Proper ARIA attributes for toggle functionality
17
+ *
18
+ * @example
19
+ * ```tsx
20
+ * // Uncontrolled toggle button
21
+ * const props = ToggleButtonSchema.parse({
22
+ * defaultPressed: false,
23
+ * variant: 'outline'
24
+ * });
25
+ *
26
+ * // Controlled toggle button
27
+ * const controlledProps = ToggleButtonSchema.parse({
28
+ * pressed: true,
29
+ * onPressedChange: (pressed) => console.log(pressed),
30
+ * variant: 'soft'
31
+ * });
32
+ *
33
+ * // Toggle button with tooltip
34
+ * const tooltipProps = ToggleButtonSchema.parse({
35
+ * defaultPressed: false,
36
+ * tooltip: 'Toggle dark mode',
37
+ * children: 'Dark Mode'
38
+ * });
39
+ * ```
40
+ */
41
+ export const ToggleButtonSchema = ButtonSchema.extend({
42
+ /**
43
+ * Controlled pressed state
44
+ * When provided, the component is controlled and the pressed state is managed externally
45
+ */
46
+ pressed: z.boolean().optional().describe('Controlled pressed state'),
47
+
48
+ /**
49
+ * Callback when pressed state changes
50
+ * Called with the new pressed state when the toggle is activated
51
+ */
52
+ onPressedChange: z.function().optional().describe('Callback when pressed state changes'),
53
+
54
+ /**
55
+ * Default pressed state for uncontrolled usage
56
+ * Used as the initial pressed state when the component is uncontrolled
57
+ */
58
+ defaultPressed: z.boolean().optional().describe('Default pressed state for uncontrolled usage'),
59
+ })
60
+ .refine(
61
+ (data) => {
62
+ // If pressed is provided, onPressedChange should also be provided for controlled usage
63
+ if (data.pressed !== undefined && data.onPressedChange === undefined) {
64
+ return false;
65
+ }
66
+ return true;
67
+ },
68
+ {
69
+ message: 'When using controlled mode (pressed prop), onPressedChange must also be provided',
70
+ path: ['onPressedChange'],
71
+ },
72
+ )
73
+ .refine(
74
+ (data) => {
75
+ // Cannot have both controlled and uncontrolled props
76
+ if (data.pressed !== undefined && data.defaultPressed !== undefined) {
77
+ return false;
78
+ }
79
+ return true;
80
+ },
81
+ {
82
+ message:
83
+ 'Cannot use both controlled (pressed) and uncontrolled (defaultPressed) props together',
84
+ path: ['pressed', 'defaultPressed'],
85
+ },
86
+ );
87
+
88
+ /**
89
+ * Type derived from ToggleButton Zod schema
90
+ * This ensures type safety and consistency with the schema
91
+ */
92
+ export type ToggleButtonProps = z.infer<typeof ToggleButtonSchema>;
93
+
94
+ /**
95
+ * Development-only helper to validate and normalize ToggleButton props
96
+ * This function should only be used in development mode
97
+ *
98
+ * @param props - Props to validate and normalize
99
+ * @returns Validated and normalized props
100
+ *
101
+ * @example
102
+ * ```tsx
103
+ * // In development, this will validate props and show helpful errors
104
+ * const invalidProps = parseToggleButtonProps({
105
+ * pressed: true,
106
+ * defaultPressed: false
107
+ * // Missing onPressedChange and conflicting controlled/uncontrolled
108
+ * });
109
+ * // Throws: "Cannot use both controlled (pressed) and uncontrolled (defaultPressed) props together"
110
+ *
111
+ * const validProps = parseToggleButtonProps({
112
+ * pressed: true,
113
+ * onPressedChange: (pressed) => setPressed(pressed)
114
+ * });
115
+ * ```
116
+ */
117
+ export function parseToggleButtonProps(props: unknown): ToggleButtonProps {
118
+ if (process.env.NODE_ENV === 'development') {
119
+ return ToggleButtonSchema.parse(props);
120
+ }
121
+ return props as ToggleButtonProps;
122
+ }