@kushagradhawan/kookie-ui 0.1.49 → 0.1.50

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 (45) hide show
  1. package/components.css +235 -64
  2. package/dist/cjs/components/_internal/shell-sidebar.d.ts.map +1 -1
  3. package/dist/cjs/components/_internal/shell-sidebar.js +1 -1
  4. package/dist/cjs/components/_internal/shell-sidebar.js.map +3 -3
  5. package/dist/cjs/components/shell.context.d.ts +1 -0
  6. package/dist/cjs/components/shell.context.d.ts.map +1 -1
  7. package/dist/cjs/components/shell.context.js +1 -1
  8. package/dist/cjs/components/shell.context.js.map +2 -2
  9. package/dist/cjs/components/shell.d.ts.map +1 -1
  10. package/dist/cjs/components/shell.js +1 -1
  11. package/dist/cjs/components/shell.js.map +3 -3
  12. package/dist/cjs/components/sidebar.d.ts +7 -1
  13. package/dist/cjs/components/sidebar.d.ts.map +1 -1
  14. package/dist/cjs/components/sidebar.js +1 -1
  15. package/dist/cjs/components/sidebar.js.map +3 -3
  16. package/dist/esm/components/_internal/shell-sidebar.d.ts.map +1 -1
  17. package/dist/esm/components/_internal/shell-sidebar.js +1 -1
  18. package/dist/esm/components/_internal/shell-sidebar.js.map +3 -3
  19. package/dist/esm/components/shell.context.d.ts +1 -0
  20. package/dist/esm/components/shell.context.d.ts.map +1 -1
  21. package/dist/esm/components/shell.context.js.map +2 -2
  22. package/dist/esm/components/shell.d.ts.map +1 -1
  23. package/dist/esm/components/shell.js +1 -1
  24. package/dist/esm/components/shell.js.map +3 -3
  25. package/dist/esm/components/sidebar.d.ts +7 -1
  26. package/dist/esm/components/sidebar.d.ts.map +1 -1
  27. package/dist/esm/components/sidebar.js +1 -1
  28. package/dist/esm/components/sidebar.js.map +3 -3
  29. package/package.json +1 -1
  30. package/schemas/base-button.json +1 -1
  31. package/schemas/button.json +1 -1
  32. package/schemas/icon-button.json +1 -1
  33. package/schemas/index.json +6 -6
  34. package/schemas/toggle-button.json +1 -1
  35. package/schemas/toggle-icon-button.json +1 -1
  36. package/src/components/_internal/base-menu.css +4 -5
  37. package/src/components/_internal/base-sidebar-menu.css +0 -1
  38. package/src/components/_internal/base-sidebar.css +7 -0
  39. package/src/components/_internal/shell-sidebar.tsx +24 -1
  40. package/src/components/shell.context.tsx +3 -0
  41. package/src/components/shell.css +28 -1
  42. package/src/components/shell.tsx +24 -3
  43. package/src/components/sidebar.css +233 -33
  44. package/src/components/sidebar.tsx +247 -213
  45. package/styles.css +235 -64
@@ -3,7 +3,7 @@
3
3
  "title": "Kookie UI Button Components",
4
4
  "description": "Complete JSON Schema collection for all button components in Kookie UI",
5
5
  "version": "1.0.0",
6
- "generatedAt": "2025-09-11T22:13:16.362Z",
6
+ "generatedAt": "2025-09-12T18:14:42.772Z",
7
7
  "source": "Zod schemas",
8
8
  "components": {
9
9
  "base-button": {
@@ -287,7 +287,7 @@
287
287
  "title": "Base-button Component Props",
288
288
  "description": "Props schema for the base-button component in Kookie UI",
289
289
  "version": "1.0.0",
290
- "generatedAt": "2025-09-11T22:13:16.352Z",
290
+ "generatedAt": "2025-09-12T18:14:42.763Z",
291
291
  "source": "Zod schema"
292
292
  },
293
293
  "button": {
@@ -822,7 +822,7 @@
822
822
  "title": "Button Component Props",
823
823
  "description": "Props schema for the button component in Kookie UI",
824
824
  "version": "1.0.0",
825
- "generatedAt": "2025-09-11T22:13:16.358Z",
825
+ "generatedAt": "2025-09-12T18:14:42.768Z",
826
826
  "source": "Zod schema"
827
827
  },
828
828
  "icon-button": {
@@ -1140,7 +1140,7 @@
1140
1140
  "title": "Icon-button Component Props",
1141
1141
  "description": "Props schema for the icon-button component in Kookie UI",
1142
1142
  "version": "1.0.0",
1143
- "generatedAt": "2025-09-11T22:13:16.359Z",
1143
+ "generatedAt": "2025-09-12T18:14:42.770Z",
1144
1144
  "source": "Zod schema"
1145
1145
  },
1146
1146
  "toggle-button": {
@@ -1683,7 +1683,7 @@
1683
1683
  "title": "Toggle-button Component Props",
1684
1684
  "description": "Props schema for the toggle-button component in Kookie UI",
1685
1685
  "version": "1.0.0",
1686
- "generatedAt": "2025-09-11T22:13:16.360Z",
1686
+ "generatedAt": "2025-09-12T18:14:42.771Z",
1687
1687
  "source": "Zod schema"
1688
1688
  },
1689
1689
  "toggle-icon-button": {
@@ -2009,7 +2009,7 @@
2009
2009
  "title": "Toggle-icon-button Component Props",
2010
2010
  "description": "Props schema for the toggle-icon-button component in Kookie UI",
2011
2011
  "version": "1.0.0",
2012
- "generatedAt": "2025-09-11T22:13:16.361Z",
2012
+ "generatedAt": "2025-09-12T18:14:42.772Z",
2013
2013
  "source": "Zod schema"
2014
2014
  }
2015
2015
  }
@@ -538,6 +538,6 @@
538
538
  "title": "Toggle-button Component Props",
539
539
  "description": "Props schema for the toggle-button component in Kookie UI",
540
540
  "version": "1.0.0",
541
- "generatedAt": "2025-09-11T22:13:16.360Z",
541
+ "generatedAt": "2025-09-12T18:14:42.771Z",
542
542
  "source": "Zod schema"
543
543
  }
@@ -321,6 +321,6 @@
321
321
  "title": "Toggle-icon-button Component Props",
322
322
  "description": "Props schema for the toggle-icon-button component in Kookie UI",
323
323
  "version": "1.0.0",
324
- "generatedAt": "2025-09-11T22:13:16.361Z",
324
+ "generatedAt": "2025-09-12T18:14:42.772Z",
325
325
  "source": "Zod schema"
326
326
  }
@@ -165,7 +165,7 @@
165
165
  --base-menu-content-padding: var(--space-2);
166
166
  --base-menu-item-padding-left: calc(var(--space-5) / 1.2);
167
167
  --base-menu-item-padding-right: var(--space-2);
168
- --base-menu-item-padding-y: calc(var(--space-1) * 0.75);
168
+ --base-menu-item-padding-y: var(--space-2);
169
169
  --base-menu-item-height: var(--space-5);
170
170
  border-radius: var(--radius-3);
171
171
 
@@ -209,7 +209,7 @@
209
209
  --base-menu-content-padding: var(--space-3);
210
210
  --base-menu-item-padding-left: var(--space-3);
211
211
  --base-menu-item-padding-right: var(--space-3);
212
- --base-menu-item-padding-y: var(--space-1);
212
+ --base-menu-item-padding-y: var(--space-2);
213
213
  --base-menu-item-height: var(--space-6);
214
214
  border-radius: var(--radius-5);
215
215
 
@@ -253,7 +253,7 @@
253
253
  --base-menu-content-padding: var(--space-3);
254
254
  --base-menu-item-padding-left: var(--space-3);
255
255
  --base-menu-item-padding-right: var(--space-3);
256
- --base-menu-item-padding-y: var(--space-1);
256
+ --base-menu-item-padding-y: var(--space-2);
257
257
  --base-menu-item-height: var(--space-6);
258
258
  border-radius: var(--radius-6);
259
259
 
@@ -311,8 +311,7 @@
311
311
  }
312
312
 
313
313
  /* Ensure gray text appears muted in non-highlighted state */
314
- .rt-BaseMenuItem
315
- :where(.rt-Text[data-accent-color='gray'], [data-accent-color='gray']:not(.rt-Badge)) {
314
+ .rt-BaseMenuItem :where(.rt-Text[data-accent-color='gray'], [data-accent-color='gray']:not(.rt-Badge)) {
316
315
  color: var(--gray-a10);
317
316
  }
318
317
  .rt-BaseMenuItem:where([data-disabled], [data-highlighted]),
@@ -10,7 +10,6 @@
10
10
  flex: 1;
11
11
  display: flex;
12
12
  flex-direction: column;
13
- padding-bottom: var(--base-menu-content-padding);
14
13
  box-sizing: border-box;
15
14
  list-style: none;
16
15
  margin: 0;
@@ -78,6 +78,13 @@
78
78
  box-shadow: none !important;
79
79
  border-radius: 0 !important;
80
80
 
81
+ /* Add gap between groups using flex */
82
+ /* stylelint-disable-next-line selector-max-specificity */
83
+ & .rt-BaseMenuViewport {
84
+ /* gap: var(--base-menu-content-padding); */
85
+ gap: var(--space-5);
86
+ }
87
+
81
88
  /* Ensure ScrollArea takes full height within SidebarContent */
82
89
  & :where(.rt-ScrollAreaRoot) {
83
90
  flex: 1;
@@ -86,6 +86,29 @@ export const Sidebar = React.forwardRef<
86
86
  const resolvedPresentation = useResponsivePresentation(presentation);
87
87
  const isOverlay = resolvedPresentation === 'overlay';
88
88
  const isStacked = resolvedPresentation === 'stacked';
89
+ // Use library-managed phase for thin ↔ expanded sequencing
90
+ const transitionPhase = (shell as any).sidebarPhase as 'idle' | 'hiding' | 'resizing' | 'showing' | undefined;
91
+ React.useLayoutEffect(() => {
92
+ if (isOverlay) return;
93
+ const containerEl = localRef.current;
94
+ if (!containerEl) return;
95
+ if (transitionPhase === 'hiding') {
96
+ // Freeze width while we fade out
97
+ try {
98
+ const rect = containerEl.getBoundingClientRect();
99
+ containerEl.style.width = `${Math.round(rect.width)}px`;
100
+ } catch {}
101
+ } else if (transitionPhase === 'resizing') {
102
+ // Release width so the CSS width transition happens
103
+ try {
104
+ containerEl.style.removeProperty('width');
105
+ } catch {}
106
+ } else if (transitionPhase === 'idle') {
107
+ try {
108
+ containerEl.style.removeProperty('width');
109
+ } catch {}
110
+ }
111
+ }, [transitionPhase, isOverlay]);
89
112
  const localRef = React.useRef<HTMLDivElement | null>(null);
90
113
  const setRef = React.useCallback(
91
114
  (node: HTMLDivElement | null) => {
@@ -334,7 +357,7 @@ export const Sidebar = React.forwardRef<
334
357
  : {}),
335
358
  }}
336
359
  >
337
- <div className="rt-ShellSidebarContent" data-visible={isContentVisible || undefined}>
360
+ <div className="rt-ShellSidebarContent" data-visible={isContentVisible || undefined} data-phase={transitionPhase && transitionPhase !== 'idle' ? transitionPhase : undefined}>
338
361
  {contentChildren}
339
362
  </div>
340
363
  {handleEl}
@@ -20,6 +20,9 @@ export interface ShellContextValue {
20
20
  peekPane: (target: PaneTarget) => void;
21
21
  clearPeek: () => void;
22
22
 
23
+ // Sidebar presentation sequencing phase (library-managed)
24
+ sidebarPhase?: 'idle' | 'hiding' | 'resizing' | 'showing';
25
+
23
26
  // Composition detection
24
27
  hasLeft: boolean;
25
28
  setHasLeft: (has: boolean) => void;
@@ -74,6 +74,8 @@
74
74
 
75
75
  .rt-ShellRail[data-mode='collapsed'] {
76
76
  width: 0px;
77
+ /* Delay container collapse until content fade completes */
78
+ transition-delay: var(--motion-duration-small);
77
79
  }
78
80
 
79
81
  /* Keep collapsed panes out of flow to avoid layout blips when exiting peek */
@@ -128,6 +130,8 @@
128
130
 
129
131
  .rt-ShellPanel:not([data-visible]) {
130
132
  width: 0px;
133
+ /* Delay container collapse until content fade completes */
134
+ transition-delay: var(--motion-duration-small);
131
135
  }
132
136
 
133
137
  /* Keep collapsed panel out of flow to avoid layout blips when exiting peek */
@@ -188,6 +192,8 @@
188
192
 
189
193
  .rt-ShellSidebar[data-mode='collapsed'] {
190
194
  width: 0px;
195
+ /* Delay container collapse until content fade completes */
196
+ transition-delay: var(--motion-duration-small);
191
197
  }
192
198
 
193
199
  /* Keep collapsed sidebar out of flow to avoid layout blips when exiting peek */
@@ -218,6 +224,22 @@
218
224
  opacity: 1;
219
225
  }
220
226
 
227
+ /* Sidebar presentation switch sequencing (thin ↔ expanded) */
228
+ .rt-ShellSidebarContent[data-phase='hiding'] {
229
+ /* Immediately fade out */
230
+ opacity: 0;
231
+ transition: opacity var(--motion-duration-small) var(--motion-ease-standard);
232
+ }
233
+ .rt-ShellSidebarContent[data-phase='resizing'] {
234
+ /* Keep hidden during width transition */
235
+ opacity: 0;
236
+ }
237
+ .rt-ShellSidebarContent[data-phase='showing'] {
238
+ /* Fade back in after width settles */
239
+ opacity: 1;
240
+ transition: opacity var(--motion-duration-small) var(--motion-ease-standard);
241
+ }
242
+
221
243
  .rt-ShellSidebar[data-mode='collapsed'] .rt-ShellSidebarContent {
222
244
  /* Exit animation: fade out content first */
223
245
  opacity: 0;
@@ -274,6 +296,8 @@
274
296
 
275
297
  .rt-ShellInspector[data-mode='collapsed'] {
276
298
  width: 0px;
299
+ /* Delay container collapse until content fade completes */
300
+ transition-delay: var(--motion-duration-small);
277
301
  }
278
302
 
279
303
  .rt-ShellInspector[data-mode='collapsed'] {
@@ -327,6 +351,8 @@
327
351
  position: absolute;
328
352
  inset-inline: 0;
329
353
  inset-block-end: 0;
354
+ /* Delay container collapse until content fade completes */
355
+ transition-delay: var(--motion-duration-small);
330
356
  }
331
357
 
332
358
  .rt-ShellBottomContent {
@@ -537,13 +563,14 @@
537
563
  box-shadow: 0 -4px 8px -4px rgba(0, 0, 0, 0.15);
538
564
  }
539
565
 
540
- /* Force content visible during peek */
566
+ /* Peek: expand container first, then fade content in */
541
567
  .rt-ShellRail[data-peek] .rt-ShellRailContent,
542
568
  .rt-ShellPanel[data-peek] .rt-ShellPanelContent,
543
569
  .rt-ShellSidebar[data-peek] .rt-ShellSidebarContent,
544
570
  .rt-ShellInspector[data-peek] .rt-ShellInspectorContent,
545
571
  .rt-ShellBottom[data-peek] .rt-ShellBottomContent {
546
572
  opacity: 1;
573
+ transition-delay: var(--motion-duration-small);
547
574
  }
548
575
 
549
576
  /* Rail peek: left edge */
@@ -99,6 +99,8 @@ const Root = React.forwardRef<HTMLDivElement, ShellRootProps>(({ className, chil
99
99
  const [leftMode, setLeftMode] = React.useState<PaneMode>('collapsed');
100
100
  const [panelMode, setPanelMode] = React.useState<PaneMode>('collapsed');
101
101
  const [sidebarMode, setSidebarMode] = React.useState<SidebarMode>('expanded');
102
+ // Library-managed phase for sidebar presentation changes (thin ↔ expanded)
103
+ const [sidebarPhase, setSidebarPhase] = React.useState<'idle' | 'hiding' | 'resizing' | 'showing'>('idle');
102
104
  const [inspectorMode, setInspectorMode] = React.useState<PaneMode>('collapsed');
103
105
  const [bottomMode, setBottomMode] = React.useState<PaneMode>('collapsed');
104
106
 
@@ -169,9 +171,26 @@ const Root = React.forwardRef<HTMLDivElement, ShellRootProps>(({ className, chil
169
171
  setPanelMode((prev) => (prev === 'expanded' ? 'collapsed' : 'expanded'));
170
172
  }
171
173
  break;
172
- case 'sidebar':
173
- setSidebarMode((prev) => sidebarToggleComputerRef.current(prev as SidebarMode));
174
+ case 'sidebar': {
175
+ // Orchestrate thin expanded sequencing: fade out → change mode → fade in
176
+ const next = sidebarToggleComputerRef.current(sidebarMode as SidebarMode);
177
+ const isWidthOnlyChange = sidebarMode !== next && sidebarMode !== 'collapsed' && next !== 'collapsed';
178
+ if (!isWidthOnlyChange) {
179
+ setSidebarMode(next);
180
+ break;
181
+ }
182
+ const SMALL_MS = 150;
183
+ setSidebarPhase('hiding');
184
+ window.setTimeout(() => {
185
+ setSidebarPhase('resizing');
186
+ setSidebarMode(next);
187
+ window.setTimeout(() => {
188
+ setSidebarPhase('showing');
189
+ window.setTimeout(() => setSidebarPhase('idle'), SMALL_MS);
190
+ }, SMALL_MS);
191
+ }, SMALL_MS);
174
192
  break;
193
+ }
175
194
  case 'inspector':
176
195
  setInspectorMode((prev) => (prev === 'expanded' ? 'collapsed' : 'expanded'));
177
196
  break;
@@ -180,7 +199,7 @@ const Root = React.forwardRef<HTMLDivElement, ShellRootProps>(({ className, chil
180
199
  break;
181
200
  }
182
201
  },
183
- [leftMode],
202
+ [leftMode, sidebarMode],
184
203
  );
185
204
 
186
205
  const expandPane = React.useCallback((target: PaneTarget) => {
@@ -238,6 +257,7 @@ const Root = React.forwardRef<HTMLDivElement, ShellRootProps>(({ className, chil
238
257
  setInspectorMode,
239
258
  bottomMode,
240
259
  setBottomMode,
260
+ sidebarPhase,
241
261
  hasLeft,
242
262
  setHasLeft,
243
263
  hasSidebar,
@@ -259,6 +279,7 @@ const Root = React.forwardRef<HTMLDivElement, ShellRootProps>(({ className, chil
259
279
  sidebarMode,
260
280
  inspectorMode,
261
281
  bottomMode,
282
+ sidebarPhase,
262
283
  hasLeft,
263
284
  hasSidebar,
264
285
  currentBreakpoint,
@@ -19,55 +19,252 @@
19
19
  */
20
20
 
21
21
  /* Rail Layout Styling */
22
- :where(.rt-SidebarContainer.rt-layout-rail .rt-SidebarContent),
23
- .rt-ShellSidebarRail :where(.rt-SidebarContent),
24
- :where(.rt-ShellSidebar[data-state='rail'] .rt-SidebarContent) {
22
+ :where(.rt-SidebarContainer[data-presentation='thin'] .rt-SidebarContent) {
25
23
  padding: var(--space-2);
26
24
  }
27
25
 
28
- :where(.rt-SidebarContainer.rt-layout-rail .rt-SidebarMenuButton),
29
- .rt-ShellSidebarRail :where(.rt-SidebarMenuButton),
30
- :where(.rt-ShellSidebar[data-state='rail'] .rt-SidebarMenuButton) {
31
- justify-content: center;
26
+ :where(.rt-SidebarContainer[data-presentation='thin'] .rt-BaseMenuViewport) {
27
+ padding: var(--space-2) !important;
28
+ }
29
+
30
+ /* Enforce vertical stack and compact typography for all buttons in thin mode */
31
+ :where(.rt-SidebarContainer[data-presentation='thin'] .rt-SidebarContent) :where(.rt-SidebarMenuButton, .rt-SidebarMenuSubTrigger) {
32
+ justify-content: center !important;
33
+ align-items: center !important;
34
+ flex-direction: column !important;
35
+ gap: var(--space-1) !important;
36
+ text-align: center !important;
37
+ font-size: var(--font-size-0) !important;
38
+ line-height: var(--line-height-0) !important;
39
+ padding-top: var(--space-2) !important;
40
+ padding-bottom: var(--space-2) !important;
41
+ padding-left: var(--space-1) !important;
42
+ padding-right: var(--space-1) !important;
43
+ }
44
+
45
+ /* Consolidated thin mode size blocks */
46
+ :where(.rt-SidebarContainer[data-presentation='thin'] .rt-SidebarContent.rt-r-size-1) {
47
+ /* Horizontal padding tokens to free space for text */
48
+ --base-menu-item-padding-left: var(--space-1) !important;
49
+ --base-menu-item-padding-right: var(--space-1) !important;
50
+ /* Unify vertical padding via tokens (used by BaseMenuItem) */
51
+ --base-menu-item-padding-y: var(--space-2) !important;
52
+
53
+ /* Override BaseMenu left padding resets */
54
+ &:where(:not(:has(.rt-BaseMenuCheckboxItem, .rt-BaseMenuRadioItem))) {
55
+ --base-menu-item-padding-left: var(--space-1) !important;
56
+ }
57
+ &:where(:has(.rt-BaseMenuCheckboxItem, .rt-BaseMenuRadioItem)) {
58
+ --base-menu-item-padding-left: var(--space-1) !important;
59
+ }
60
+
61
+ /* Button and subtrigger layout */
62
+ :where(.rt-SidebarMenuButton, .rt-SidebarMenuSubTrigger) {
63
+ justify-content: center;
64
+ align-items: center;
65
+ flex-direction: column;
66
+ gap: var(--space-1);
67
+ text-align: center;
68
+ font-size: var(--font-size-0);
69
+ line-height: var(--line-height-0);
70
+ white-space: nowrap;
71
+ overflow: hidden;
72
+ text-overflow: ellipsis;
73
+ max-width: 100%;
74
+ min-width: 0;
75
+ }
76
+
77
+ /* Icon sizing */
78
+ /* stylelint-disable-next-line selector-max-type */
79
+ :where(.rt-SidebarMenuButton, .rt-SidebarMenuSubTrigger) :where(svg) {
80
+ width: var(--content-icon-size-3);
81
+ height: var(--content-icon-size-3);
82
+ }
83
+ }
84
+
85
+ :where(.rt-SidebarContainer[data-presentation='thin'] .rt-SidebarContent.rt-r-size-2) {
86
+ --base-menu-item-padding-left: var(--space-1) !important;
87
+ --base-menu-item-padding-right: var(--space-1) !important;
88
+ --base-menu-item-padding-y: var(--space-2) !important;
89
+
90
+ &:where(:not(:has(.rt-BaseMenuCheckboxItem, .rt-BaseMenuRadioItem))) {
91
+ --base-menu-item-padding-left: var(--space-1) !important;
92
+ }
93
+ &:where(:has(.rt-BaseMenuCheckboxItem, .rt-BaseMenuRadioItem)) {
94
+ --base-menu-item-padding-left: var(--space-1) !important;
95
+ }
96
+
97
+ :where(.rt-SidebarMenuButton, .rt-SidebarMenuSubTrigger) {
98
+ justify-content: center;
99
+ align-items: center;
100
+ flex-direction: column;
101
+ gap: var(--space-1);
102
+ text-align: center;
103
+ font-size: var(--font-size-0);
104
+ line-height: var(--line-height-0);
105
+ white-space: nowrap;
106
+ overflow: hidden;
107
+ text-overflow: ellipsis;
108
+ max-width: 100%;
109
+ min-width: 0;
110
+ }
111
+
112
+ /* stylelint-disable-next-line selector-max-type */
113
+ :where(.rt-SidebarMenuButton, .rt-SidebarMenuSubTrigger) :where(svg) {
114
+ width: var(--content-icon-size-4);
115
+ height: var(--content-icon-size-4);
116
+ }
117
+ }
118
+
119
+ :where(.rt-SidebarContainer[data-presentation='thin'] .rt-SidebarContent.rt-r-size-3) {
120
+ --base-menu-item-padding-left: var(--space-1) !important;
121
+ --base-menu-item-padding-right: var(--space-1) !important;
122
+ --base-menu-item-padding-y: var(--space-2) !important;
123
+
124
+ &:where(:not(:has(.rt-BaseMenuCheckboxItem, .rt-BaseMenuRadioItem))) {
125
+ --base-menu-item-padding-left: var(--space-1) !important;
126
+ }
127
+ &:where(:has(.rt-BaseMenuCheckboxItem, .rt-BaseMenuRadioItem)) {
128
+ --base-menu-item-padding-left: var(--space-1) !important;
129
+ }
130
+
131
+ :where(.rt-SidebarMenuButton, .rt-SidebarMenuSubTrigger) {
132
+ justify-content: center;
133
+ align-items: center;
134
+ flex-direction: column;
135
+ gap: var(--space-1);
136
+ text-align: center;
137
+ font-size: var(--font-size-0);
138
+ line-height: var(--line-height-0);
139
+ white-space: nowrap;
140
+ overflow: hidden;
141
+ text-overflow: ellipsis;
142
+ max-width: 100%;
143
+ min-width: 0;
144
+ }
145
+
146
+ /* stylelint-disable-next-line selector-max-type */
147
+ :where(.rt-SidebarMenuButton, .rt-SidebarMenuSubTrigger) :where(svg) {
148
+ width: var(--content-icon-size-5);
149
+ height: var(--content-icon-size-5);
150
+ }
151
+ }
152
+
153
+ /* Ellipsis on root child content when using asChild (e.g., Next.js Link) */
154
+ :where(.rt-SidebarContainer[data-presentation='thin'] .rt-SidebarMenuButton > *) {
155
+ display: flex;
156
+ flex-direction: column;
32
157
  align-items: center;
158
+ white-space: nowrap;
159
+ overflow: hidden;
160
+ text-overflow: ellipsis;
161
+ width: 100%;
162
+ min-width: 0;
163
+ }
164
+
165
+ /* Ensure submenu trigger asChild containers also stack vertically */
166
+ :where(.rt-SidebarContainer[data-presentation='thin'] .rt-SidebarMenuSubTrigger > *) {
167
+ display: flex;
33
168
  flex-direction: column;
34
- gap: var(--space-1);
35
- padding: var(--space-2) var(--space-1);
169
+ align-items: center;
170
+ width: 100%;
171
+ min-width: 0;
172
+ }
173
+
174
+ /* stylelint-disable-next-line selector-max-type */
175
+ :where(.rt-SidebarContainer[data-presentation='thin'] .rt-SidebarMenuButton > * > svg) {
176
+ flex-shrink: 0;
36
177
  }
37
178
 
38
- :where(.rt-SidebarContainer.rt-layout-rail .rt-SidebarMenuBadge),
39
- :where(.rt-SidebarContainer.rt-layout-rail .rt-SidebarMenuShortcut),
40
- .rt-ShellSidebarRail :where(.rt-SidebarMenuBadge),
41
- .rt-ShellSidebarRail :where(.rt-SidebarMenuShortcut),
42
- :where(.rt-ShellSidebar[data-state='rail'] .rt-SidebarMenuBadge),
43
- :where(.rt-ShellSidebar[data-state='rail'] .rt-SidebarMenuShortcut) {
44
- display: none;
179
+ /* Ensure submenu anchors also truncate */
180
+ :where(.rt-SidebarContainer[data-presentation='thin'] .rt-SidebarMenuSubContent .rt-SidebarMenuButton > *) {
181
+ display: flex;
182
+ flex-direction: column;
183
+ align-items: center;
184
+ white-space: nowrap;
185
+ overflow: hidden;
186
+ text-overflow: ellipsis;
187
+ width: 100%;
188
+ min-width: 0;
189
+ }
190
+
191
+ /* Ensure icons remain visible at their token sizes in thin mode */
192
+ /* stylelint-disable-next-line selector-max-type */
193
+ :where(.rt-SidebarContainer[data-presentation='thin'] .rt-SidebarMenuButton) :where(svg) {
194
+ /* svg size is already controlled by tokens; this ensures layout stability */
195
+ display: block;
45
196
  }
46
197
 
47
- :where(.rt-SidebarContainer.rt-layout-rail .rt-SidebarGroupLabel),
48
- .rt-ShellSidebarRail :where(.rt-SidebarGroupLabel),
49
- :where(.rt-ShellSidebar[data-state='rail'] .rt-SidebarGroupLabel) {
198
+ /* Truncate labels inside an explicit label span */
199
+ :where(.rt-SidebarContainer[data-presentation='thin'] .rt-SidebarMenuButton .rt-SidebarMenuLabel) {
50
200
  display: block;
201
+ max-width: 100%;
202
+ min-width: 0;
203
+ overflow: hidden;
204
+ text-overflow: ellipsis;
205
+ white-space: nowrap;
51
206
  text-align: center;
207
+ color: var(--accent-11);
52
208
  font-size: var(--font-size-0);
53
209
  line-height: var(--line-height-0);
54
- color: var(--gray-a9);
55
- font-weight: var(--font-weight-medium);
210
+ }
211
+
212
+ :where(.rt-SidebarContainer[data-presentation='thin'] .rt-SidebarMenuBadge),
213
+ :where(.rt-SidebarContainer[data-presentation='thin'] .rt-SidebarMenuShortcut),
214
+ :where(.rt-SidebarContainer[data-presentation='thin'] .rt-Badge),
215
+ :where(.rt-SidebarContainer[data-presentation='thin'] .rt-Kbd) {
216
+ display: none !important;
217
+ }
218
+
219
+ :where(.rt-SidebarContainer[data-presentation='thin'] .rt-SidebarGroupLabel) {
220
+ display: none !important;
56
221
  }
57
222
 
58
223
  /* Hide submenu chevrons and flatten sublists in rail */
59
- :where(.rt-SidebarContainer.rt-layout-rail .rt-SidebarMenuSubTriggerIcon),
60
- .rt-ShellSidebarRail :where(.rt-SidebarMenuSubTriggerIcon),
61
- :where(.rt-ShellSidebar[data-state='rail'] .rt-SidebarMenuSubTriggerIcon) {
62
- display: none;
224
+ :where(.rt-SidebarContainer[data-presentation='thin'] .rt-SidebarMenuSubTriggerIcon),
225
+ :where(.rt-SidebarContainer[data-presentation='thin'] .rt-BaseMenuSubTriggerIcon) {
226
+ display: none !important;
227
+ }
228
+
229
+ :where(.rt-SidebarContainer[data-presentation='thin'] .rt-SidebarMenuSubList),
230
+ :where(.rt-SidebarContainer[data-presentation='thin'] .rt-BaseMenuSubList) {
231
+ padding-left: 0 !important;
232
+ margin-left: 0 !important;
233
+ border-left: 0 !important;
234
+ border-top: 0 !important;
235
+ border-bottom: 0 !important;
236
+ margin-top: 0 !important;
237
+ margin-bottom: 0 !important;
238
+ }
239
+
240
+ /* Also remove any decorative rule on the submenu list in thin mode */
241
+ :where(.rt-SidebarContainer[data-presentation='thin'] .rt-SidebarMenuSubList::before),
242
+ :where(.rt-SidebarContainer[data-presentation='thin'] .rt-BaseMenuSubList::before) {
243
+ content: none !important;
244
+ display: none !important;
245
+ }
246
+
247
+ /* Ensure the Accordion content wrapper doesn't add indentation */
248
+ :where(.rt-SidebarContainer[data-presentation='thin'] .rt-SidebarMenuSubContent) {
249
+ padding-left: 0 !important;
250
+ margin-left: 0 !important;
251
+ border-left: 0 !important;
252
+ border-top: 1px solid var(--gray-a6) !important;
253
+ border-bottom: 1px solid var(--gray-a6) !important;
254
+ margin-top: var(--space-2) !important;
255
+ margin-bottom: var(--space-2) !important;
256
+ /* background-color: var(--accent-3); */
63
257
  }
64
258
 
65
- :where(.rt-SidebarContainer.rt-layout-rail .rt-SidebarMenuSubList),
66
- .rt-ShellSidebarRail :where(.rt-SidebarMenuSubList),
67
- :where(.rt-ShellSidebar[data-state='rail'] .rt-SidebarMenuSubList) {
68
- padding-left: 0;
69
- border-left: none;
70
- margin-left: 0;
259
+ /* Remove vertical connector in thin mode */
260
+ /* (intentionally no ::before) */
261
+
262
+ /* Ensure submenu buttons also truncate */
263
+ :where(.rt-SidebarContainer[data-presentation='thin'] .rt-SidebarMenuSubContent .rt-SidebarMenuButton) {
264
+ white-space: nowrap;
265
+ overflow: hidden;
266
+ text-overflow: ellipsis;
267
+ max-width: 100%;
71
268
  }
72
269
 
73
270
  /* Panel Layout Styling (default) - inherits existing styles */
@@ -347,7 +544,7 @@
347
544
  line-height: var(--line-height-1);
348
545
  letter-spacing: var(--letter-spacing-1);
349
546
  border-radius: var(--radius-1);
350
- font-weight: var(--font-weight-medium);
547
+ font-weight: var(--font-weight-regular);
351
548
 
352
549
  /* stylelint-disable-next-line selector-max-type */
353
550
  & :where(svg) {
@@ -373,7 +570,7 @@
373
570
  line-height: var(--line-height-2);
374
571
  letter-spacing: var(--letter-spacing-2);
375
572
  border-radius: var(--radius-2);
376
- font-weight: var(--font-weight-medium);
573
+ font-weight: var(--font-weight-regular);
377
574
 
378
575
  /* stylelint-disable-next-line selector-max-type */
379
576
  & :where(svg) {
@@ -482,6 +679,7 @@
482
679
  & :where(.rt-SidebarMenuButton[data-active]) {
483
680
  background-color: var(--accent-9);
484
681
  color: var(--accent-contrast);
682
+ font-weight: var(--font-weight-medium);
485
683
 
486
684
  /* Force all text elements to inherit active color */
487
685
  & :where(.rt-Text) {
@@ -547,6 +745,7 @@
547
745
  & :where(.rt-SidebarMenuButton[data-active]) {
548
746
  background-color: var(--accent-12);
549
747
  color: var(--accent-1);
748
+ font-weight: var(--font-weight-medium);
550
749
 
551
750
  & :where(.rt-Text) {
552
751
  color: inherit !important;
@@ -667,6 +866,7 @@
667
866
  /* Base state: solid accent for solid panels */
668
867
  background-color: var(--accent-3);
669
868
  color: var(--accent-12);
869
+ font-weight: var(--font-weight-medium);
670
870
 
671
871
  /* Theme-level translucent override */
672
872
  :where([data-panel-background='translucent']) & {