@kushagradhawan/kookie-ui 0.1.41 → 0.1.43

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 (144) hide show
  1. package/README.md +257 -60
  2. package/components.css +398 -91
  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-menu.css +3 -8
  123. package/src/components/_internal/base-sidebar.css +1 -2
  124. package/src/components/schemas/base-button.schema.ts +339 -0
  125. package/src/components/schemas/button.schema.ts +198 -0
  126. package/src/components/schemas/icon-button.schema.ts +142 -0
  127. package/src/components/schemas/index.ts +68 -0
  128. package/src/components/schemas/toggle-button.schema.ts +122 -0
  129. package/src/components/schemas/toggle-icon-button.schema.ts +195 -0
  130. package/src/components/sheet.css +39 -19
  131. package/src/components/sheet.tsx +62 -3
  132. package/src/components/shell.css +510 -89
  133. package/src/components/shell.tsx +2055 -928
  134. package/src/components/sidebar.css +126 -65
  135. package/src/components/sidebar.tsx +5 -24
  136. package/src/components/theme.props.tsx +8 -0
  137. package/src/components/theme.tsx +16 -0
  138. package/src/helpers/font-config.ts +167 -0
  139. package/src/helpers/index.ts +1 -0
  140. package/src/styles/fonts.css +16 -13
  141. package/src/styles/tokens/typography.css +27 -4
  142. package/styles.css +410 -91
  143. package/tokens/base.css +12 -0
  144. package/tokens.css +12 -0
@@ -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
+ }
@@ -0,0 +1,195 @@
1
+ import { z } from 'zod';
2
+ import { BaseButtonSchema } from './base-button.schema.js';
3
+
4
+ /**
5
+ * ToggleIconButton Zod schema - Single source of truth for ToggleIconButton component props
6
+ *
7
+ * ToggleIconButton extends IconButton 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 IconButton component.
10
+ *
11
+ * Key features:
12
+ * - Required accessibility attributes (aria-label, aria-labelledby, or children)
13
+ * - Controlled and uncontrolled state management
14
+ * - Live accessibility announcements for screen readers
15
+ * - Tooltip support for better UX
16
+ * - Proper ARIA attributes for toggle functionality
17
+ *
18
+ * @example
19
+ * ```tsx
20
+ * // Uncontrolled toggle icon button
21
+ * const props = ToggleIconButtonSchema.parse({
22
+ * 'aria-label': 'Toggle sidebar',
23
+ * defaultPressed: false,
24
+ * variant: 'ghost'
25
+ * });
26
+ *
27
+ * // Controlled toggle icon button
28
+ * const controlledProps = ToggleIconButtonSchema.parse({
29
+ * 'aria-label': 'Toggle dark mode',
30
+ * pressed: true,
31
+ * onPressedChange: (pressed) => setDarkMode(pressed),
32
+ * variant: 'soft'
33
+ * });
34
+ *
35
+ * // Toggle icon button with tooltip
36
+ * const tooltipProps = ToggleIconButtonSchema.parse({
37
+ * 'aria-label': 'Toggle notifications',
38
+ * defaultPressed: false,
39
+ * tooltip: 'Toggle notification settings',
40
+ * tooltipSide: 'right'
41
+ * });
42
+ * ```
43
+ */
44
+ export const ToggleIconButtonSchema = BaseButtonSchema.extend({
45
+ /**
46
+ * Content to display in the tooltip on hover/focus
47
+ */
48
+ tooltip: z.string().optional().describe('Content to display in the tooltip on hover/focus'),
49
+
50
+ /**
51
+ * Side of the button where the tooltip should appear
52
+ * @default 'top'
53
+ */
54
+ tooltipSide: z
55
+ .enum(['top', 'right', 'bottom', 'left'])
56
+ .optional()
57
+ .default('top')
58
+ .describe('Side of the button where the tooltip should appear'),
59
+
60
+ /**
61
+ * Alignment of the tooltip relative to the button
62
+ * @default 'center'
63
+ */
64
+ tooltipAlign: z
65
+ .enum(['start', 'center', 'end'])
66
+ .optional()
67
+ .default('center')
68
+ .describe('Alignment of the tooltip relative to the button'),
69
+
70
+ /**
71
+ * Delay before showing the tooltip (in milliseconds)
72
+ */
73
+ tooltipDelayDuration: z
74
+ .number()
75
+ .optional()
76
+ .describe('Delay before showing the tooltip (in milliseconds)'),
77
+
78
+ /**
79
+ * Whether to disable hoverable content behavior
80
+ * @default false
81
+ */
82
+ tooltipDisableHoverableContent: z
83
+ .boolean()
84
+ .optional()
85
+ .default(false)
86
+ .describe('Whether to disable hoverable content behavior'),
87
+
88
+ /**
89
+ * ARIA label for accessibility (required if no aria-labelledby or children)
90
+ * Icon buttons must have an accessible name to meet WCAG guidelines
91
+ */
92
+ 'aria-label': z.string().optional().describe('ARIA label for accessibility'),
93
+
94
+ /**
95
+ * ARIA labelled by reference (required if no aria-label or children)
96
+ * Icon buttons must have an accessible name to meet WCAG guidelines
97
+ */
98
+ 'aria-labelledby': z.string().optional().describe('ARIA labelled by reference'),
99
+
100
+ /**
101
+ * Children elements (required if no aria-label or aria-labelledby)
102
+ * Icon buttons must have an accessible name to meet WCAG guidelines
103
+ */
104
+ children: z
105
+ .any()
106
+ .optional()
107
+ .describe('Children elements (required for accessibility if no aria-label)'),
108
+
109
+ /**
110
+ * Controlled pressed state
111
+ * When provided, the component is controlled and the pressed state is managed externally
112
+ */
113
+ pressed: z.boolean().optional().describe('Controlled pressed state'),
114
+
115
+ /**
116
+ * Callback when pressed state changes
117
+ * Called with the new pressed state when the toggle is activated
118
+ */
119
+ onPressedChange: z.function().optional().describe('Callback when pressed state changes'),
120
+
121
+ /**
122
+ * Default pressed state for uncontrolled usage
123
+ * Used as the initial pressed state when the component is uncontrolled
124
+ */
125
+ defaultPressed: z.boolean().optional().describe('Default pressed state for uncontrolled usage'),
126
+ })
127
+ .refine((data: any) => data['aria-label'] || data['aria-labelledby'] || data.children, {
128
+ message:
129
+ "ToggleIconButton must have either 'aria-label', 'aria-labelledby', or 'children' for accessibility",
130
+ path: ['aria-label', 'aria-labelledby', 'children'],
131
+ })
132
+ .refine(
133
+ (data: any) => {
134
+ // If pressed is provided, onPressedChange should also be provided for controlled usage
135
+ if (data.pressed !== undefined && data.onPressedChange === undefined) {
136
+ return false;
137
+ }
138
+ return true;
139
+ },
140
+ {
141
+ message: 'When using controlled mode (pressed prop), onPressedChange must also be provided',
142
+ path: ['onPressedChange'],
143
+ },
144
+ )
145
+ .refine(
146
+ (data: any) => {
147
+ // Cannot have both controlled and uncontrolled props
148
+ if (data.pressed !== undefined && data.defaultPressed !== undefined) {
149
+ return false;
150
+ }
151
+ return true;
152
+ },
153
+ {
154
+ message:
155
+ 'Cannot use both controlled (pressed) and uncontrolled (defaultPressed) props together',
156
+ path: ['pressed', 'defaultPressed'],
157
+ },
158
+ );
159
+
160
+ /**
161
+ * Type derived from ToggleIconButton Zod schema
162
+ * This ensures type safety and consistency with the schema
163
+ */
164
+ export type ToggleIconButtonProps = z.infer<typeof ToggleIconButtonSchema>;
165
+
166
+ /**
167
+ * Development-only helper to validate and normalize ToggleIconButton props
168
+ * This function should only be used in development mode
169
+ *
170
+ * @param props - Props to validate and normalize
171
+ * @returns Validated and normalized props
172
+ *
173
+ * @example
174
+ * ```tsx
175
+ * // In development, this will validate props and show helpful errors
176
+ * const invalidProps = parseToggleIconButtonProps({
177
+ * pressed: true,
178
+ * defaultPressed: false
179
+ * // Missing onPressedChange, conflicting controlled/uncontrolled, and missing accessibility
180
+ * });
181
+ * // Throws multiple validation errors
182
+ *
183
+ * const validProps = parseToggleIconButtonProps({
184
+ * 'aria-label': 'Toggle menu',
185
+ * pressed: true,
186
+ * onPressedChange: (pressed) => setMenuOpen(pressed)
187
+ * });
188
+ * ```
189
+ */
190
+ export function parseToggleIconButtonProps(props: unknown): ToggleIconButtonProps {
191
+ if (process.env.NODE_ENV === 'development') {
192
+ return ToggleIconButtonSchema.parse(props);
193
+ }
194
+ return props as ToggleIconButtonProps;
195
+ }
@@ -1,10 +1,10 @@
1
1
  :where(.rt-SheetContent) {
2
2
  position: fixed !important;
3
3
  /* Use physical properties to integrate with width/height responsive utilities */
4
- width: var(--width, 90vw) !important;
5
- max-width: var(--max-width, 100vw) !important;
6
- height: 100vh !important;
7
- max-height: 100vh !important;
4
+ width: var(--width, 90vw);
5
+ max-width: var(--max-width, 100vw);
6
+ height: 100vh;
7
+ max-height: 100vh;
8
8
  margin: 0 !important;
9
9
  border-radius: 0 !important;
10
10
  will-change: transform;
@@ -34,9 +34,9 @@
34
34
  left: 0 !important;
35
35
  right: 0 !important;
36
36
  bottom: auto !important;
37
- width: auto !important;
38
- max-width: none !important;
39
- height: var(--height, 75vh) !important;
37
+ width: auto;
38
+ max-width: none;
39
+ height: var(--height, 75vh);
40
40
  margin: 0 !important;
41
41
  border-start-start-radius: 0;
42
42
  border-start-end-radius: 0;
@@ -46,9 +46,9 @@
46
46
  left: 0 !important;
47
47
  right: 0 !important;
48
48
  top: auto !important;
49
- width: auto !important;
50
- max-width: none !important;
51
- height: var(--height, 75vh) !important;
49
+ width: auto;
50
+ max-width: none;
51
+ height: var(--height, 75vh);
52
52
  margin: 0 !important;
53
53
  border-end-start-radius: 0;
54
54
  border-end-end-radius: 0;
@@ -56,7 +56,6 @@
56
56
 
57
57
  /* Overlay adjustments: avoid double-fade jank from base dialog */
58
58
  .rt-SheetOverlay::before {
59
- opacity: 1 !important;
60
59
  backdrop-filter: var(--backdrop-filter-components) !important;
61
60
  }
62
61
 
@@ -83,31 +82,49 @@
83
82
  }
84
83
 
85
84
  .rt-SheetContent:where([data-state='open'][data-side='start']) {
86
- animation-name: rt-sheet-open-from-start, rt-fade-in !important;
85
+ /* OPEN: slide first (no fade yet) */
86
+ animation-name: rt-sheet-open-from-start !important;
87
87
  }
88
88
  .rt-SheetContent:where([data-state='closed'][data-side='start']) {
89
- animation-name: rt-sheet-close-to-start, rt-fade-out !important;
89
+ /* CLOSED: delay slide until content fade-out finishes */
90
+ animation-name: rt-sheet-close-to-start !important;
91
+ animation-delay: var(--motion-duration-small);
90
92
  }
91
93
 
92
94
  .rt-SheetContent:where([data-state='open'][data-side='end']) {
93
- animation-name: rt-sheet-open-from-end, rt-fade-in !important;
95
+ animation-name: rt-sheet-open-from-end !important;
94
96
  }
95
97
  .rt-SheetContent:where([data-state='closed'][data-side='end']) {
96
- animation-name: rt-sheet-close-to-end, rt-fade-out !important;
98
+ animation-name: rt-sheet-close-to-end !important;
99
+ animation-delay: var(--motion-duration-small);
97
100
  }
98
101
 
99
102
  .rt-SheetContent:where([data-state='open'][data-side='top']) {
100
- animation-name: rt-sheet-open-from-top, rt-fade-in !important;
103
+ animation-name: rt-sheet-open-from-top !important;
101
104
  }
102
105
  .rt-SheetContent:where([data-state='closed'][data-side='top']) {
103
- animation-name: rt-sheet-close-to-top, rt-fade-out !important;
106
+ animation-name: rt-sheet-close-to-top !important;
107
+ animation-delay: var(--motion-duration-small);
104
108
  }
105
109
 
106
110
  .rt-SheetContent:where([data-state='open'][data-side='bottom']) {
107
- animation-name: rt-sheet-open-from-bottom, rt-fade-in !important;
111
+ animation-name: rt-sheet-open-from-bottom !important;
108
112
  }
109
113
  .rt-SheetContent:where([data-state='closed'][data-side='bottom']) {
110
- animation-name: rt-sheet-close-to-bottom, rt-fade-out !important;
114
+ animation-name: rt-sheet-close-to-bottom !important;
115
+ animation-delay: var(--motion-duration-small);
116
+ }
117
+
118
+ /* OPEN: fade in inner content after slide completes */
119
+ .rt-SheetContent:where([data-state='open']) > * {
120
+ opacity: 0;
121
+ animation: rt-fade-in var(--motion-duration-small) var(--motion-spring-snappy) both;
122
+ animation-delay: var(--motion-duration-medium);
123
+ }
124
+
125
+ /* CLOSED: fade out inner content immediately, then container slides */
126
+ .rt-SheetContent:where([data-state='closed']) > * {
127
+ animation: rt-fade-out var(--motion-duration-small) var(--motion-spring-snappy) both;
111
128
  }
112
129
  }
113
130
 
@@ -115,4 +132,7 @@
115
132
  .rt-SheetContent {
116
133
  animation: none !important;
117
134
  }
135
+ .rt-SheetContent > * {
136
+ animation: none !important;
137
+ }
118
138
  }
@@ -42,6 +42,7 @@ import type { DialogContentOwnProps } from './dialog.props.js';
42
42
  import { Theme } from './theme.js';
43
43
  import { extractProps } from '../helpers/extract-props.js';
44
44
  import { requireReactElement } from '../helpers/require-react-element.js';
45
+ import { useBodyPointerEventsCleanup } from '../hooks/use-body-pointer-events-cleanup.js';
45
46
 
46
47
  import type { ComponentPropsWithout, RemovedProps } from '../helpers/component-props.js';
47
48
 
@@ -132,10 +133,10 @@ const Content = React.forwardRef<SheetContentElement, SheetContentProps>(
132
133
  );
133
134
 
134
135
  const materialValue = React.useMemo(() => {
135
- if (resolvedMaterial !== undefined) {
136
+ if (resolvedPanelBackground !== undefined) {
136
137
  if (process.env.NODE_ENV !== 'production') {
137
138
  console.warn(
138
- 'Warning: The `panelBackground` prop is deprecated and will be removed in a future version. Use `material` prop instead.',
139
+ 'Warning: The `panelBackground` prop is deprecated and will be removed in a future version. Use the `material` prop instead.',
139
140
  );
140
141
  }
141
142
  }
@@ -175,13 +176,65 @@ const Content = React.forwardRef<SheetContentElement, SheetContentProps>(
175
176
  }
176
177
  }
177
178
 
179
+ // Focus management and stuck pointer-events cleanup like Dialog
180
+ const contentRef = React.useRef<HTMLDivElement>(null);
181
+ const combinedRef = React.useMemo(
182
+ () => (node: HTMLDivElement | null) => {
183
+ contentRef.current = node;
184
+ if (typeof forwardedRef === 'function') {
185
+ forwardedRef(node);
186
+ } else if (forwardedRef) {
187
+ (forwardedRef as React.MutableRefObject<HTMLDivElement | null>).current = node;
188
+ }
189
+ },
190
+ [forwardedRef],
191
+ );
192
+
193
+ useBodyPointerEventsCleanup();
194
+
195
+ React.useEffect(() => {
196
+ if (typeof window === 'undefined') return;
197
+ const content = contentRef.current;
198
+ if (!content) return;
199
+
200
+ const focusableElements = content.querySelectorAll(
201
+ 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])',
202
+ );
203
+
204
+ if (focusableElements.length === 0) return;
205
+
206
+ const firstElement = focusableElements[0] as HTMLElement;
207
+ const lastElement = focusableElements[focusableElements.length - 1] as HTMLElement;
208
+
209
+ const handleKeyDown = (event: KeyboardEvent) => {
210
+ if (event.key === 'Tab') {
211
+ if (event.shiftKey) {
212
+ if (document.activeElement === firstElement) {
213
+ event.preventDefault();
214
+ lastElement.focus();
215
+ }
216
+ } else if (document.activeElement === lastElement) {
217
+ event.preventDefault();
218
+ firstElement.focus();
219
+ }
220
+ }
221
+ };
222
+
223
+ content.addEventListener('keydown', handleKeyDown);
224
+ firstElement.focus();
225
+
226
+ return () => {
227
+ content.removeEventListener('keydown', handleKeyDown);
228
+ };
229
+ }, []);
230
+
178
231
  return (
179
232
  <DialogPrimitive.Portal container={container} forceMount={forceMount}>
180
233
  <Theme asChild>
181
234
  <DialogPrimitive.Overlay className="rt-BaseDialogOverlay rt-DialogOverlay rt-SheetOverlay">
182
235
  <DialogPrimitive.Content
183
236
  {...contentProps}
184
- ref={forwardedRef}
237
+ ref={combinedRef}
185
238
  className={classNames(
186
239
  'rt-BaseDialogContent',
187
240
  'rt-SheetContent',
@@ -191,6 +244,9 @@ const Content = React.forwardRef<SheetContentElement, SheetContentProps>(
191
244
  data-side={normalizedSide}
192
245
  data-material={materialValue}
193
246
  data-panel-background={materialValue}
247
+ tabIndex={-1}
248
+ role="dialog"
249
+ aria-modal="true"
194
250
  />
195
251
  </DialogPrimitive.Overlay>
196
252
  </Theme>
@@ -244,4 +300,7 @@ export type {
244
300
  SheetRootProps as RootProps,
245
301
  SheetTriggerProps as TriggerProps,
246
302
  SheetContentProps as ContentProps,
303
+ SheetTitleProps as TitleProps,
304
+ SheetDescriptionProps as DescriptionProps,
305
+ SheetCloseProps as CloseProps,
247
306
  };