@kushagradhawan/kookie-ui 0.1.45 → 0.1.47

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.
@@ -530,6 +530,6 @@
530
530
  "title": "Button Component Props",
531
531
  "description": "Props schema for the button component in Kookie UI",
532
532
  "version": "1.0.0",
533
- "generatedAt": "2025-09-10T11:43:38.645Z",
533
+ "generatedAt": "2025-09-10T16:59:14.164Z",
534
534
  "source": "Zod schema"
535
535
  }
@@ -313,6 +313,6 @@
313
313
  "title": "Icon-button Component Props",
314
314
  "description": "Props schema for the icon-button component in Kookie UI",
315
315
  "version": "1.0.0",
316
- "generatedAt": "2025-09-10T11:43:38.646Z",
316
+ "generatedAt": "2025-09-10T16:59:14.185Z",
317
317
  "source": "Zod schema"
318
318
  }
@@ -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-10T11:43:38.648Z",
6
+ "generatedAt": "2025-09-10T16:59:14.189Z",
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-10T11:43:38.640Z",
290
+ "generatedAt": "2025-09-10T16:59:14.159Z",
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-10T11:43:38.645Z",
825
+ "generatedAt": "2025-09-10T16:59:14.164Z",
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-10T11:43:38.646Z",
1143
+ "generatedAt": "2025-09-10T16:59:14.185Z",
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-10T11:43:38.647Z",
1686
+ "generatedAt": "2025-09-10T16:59:14.187Z",
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-10T11:43:38.648Z",
2012
+ "generatedAt": "2025-09-10T16:59:14.188Z",
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-10T11:43:38.647Z",
541
+ "generatedAt": "2025-09-10T16:59:14.187Z",
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-10T11:43:38.648Z",
324
+ "generatedAt": "2025-09-10T16:59:14.188Z",
325
325
  "source": "Zod schema"
326
326
  }
@@ -335,6 +335,9 @@
335
335
 
336
336
  .rt-ShellBottom[data-mode='collapsed'] {
337
337
  height: 0px;
338
+ position: absolute;
339
+ inset-inline: 0;
340
+ inset-block-end: 0;
338
341
  }
339
342
 
340
343
  .rt-ShellBottomContent {
@@ -569,11 +572,10 @@
569
572
  width: var(--panel-size, 288px);
570
573
  }
571
574
 
572
- /* Sidebar peek: left edge; if collapsed, use fallback width */
575
+ /* Sidebar peek: left edge; preview next width (thin or expanded) */
573
576
  .rt-ShellSidebar[data-peek] {
574
577
  inset-block: 0;
575
578
  inset-inline-start: 0;
576
- /* Always use peek width when peeking */
577
579
  width: var(--peek-sidebar-width, var(--sidebar-size, 288px));
578
580
  }
579
581
 
@@ -1085,7 +1085,7 @@ type SidebarComponent = React.ForwardRefExoticComponent<
1085
1085
  defaultMode?: ResponsiveSidebarMode;
1086
1086
  onModeChange?: (mode: SidebarMode) => void;
1087
1087
  thinSize?: number;
1088
- toggleModes?: Array<'thin' | 'expanded'>;
1088
+ toggleModes?: 'both' | 'single';
1089
1089
  }) &
1090
1090
  React.RefAttributes<HTMLDivElement>
1091
1091
  > & { Handle: HandleComponent };
@@ -1294,7 +1294,7 @@ const Sidebar = React.forwardRef<
1294
1294
  defaultMode?: ResponsiveSidebarMode;
1295
1295
  onModeChange?: (mode: SidebarMode) => void;
1296
1296
  thinSize?: number;
1297
- toggleModes?: Array<'thin' | 'expanded'>;
1297
+ toggleModes?: 'both' | 'single';
1298
1298
  }
1299
1299
  >(
1300
1300
  (
@@ -1427,39 +1427,57 @@ const Sidebar = React.forwardRef<
1427
1427
  };
1428
1428
  }, [resizable, persistenceAdapter, onResize, isOverlay]);
1429
1429
 
1430
- // Register custom toggle behavior based on toggleModes
1430
+ // Always-follow responsive defaultMode for uncontrolled Sidebar (on breakpoint change only)
1431
+ const resolveResponsiveMode = React.useCallback((): SidebarMode => {
1432
+ if (typeof defaultMode === 'string') return defaultMode as SidebarMode;
1433
+ const dm = defaultMode as Partial<Record<Breakpoint, SidebarMode>> | undefined;
1434
+ if (dm && dm[shell.currentBreakpoint as Breakpoint]) {
1435
+ return dm[shell.currentBreakpoint as Breakpoint] as SidebarMode;
1436
+ }
1437
+ const bpKeys = Object.keys(BREAKPOINTS) as Array<keyof typeof BREAKPOINTS>;
1438
+ const order: Breakpoint[] = ([...bpKeys].reverse() as Breakpoint[]).concat(
1439
+ 'initial' as Breakpoint,
1440
+ );
1441
+ const startIdx = order.indexOf(shell.currentBreakpoint as Breakpoint);
1442
+ for (let i = startIdx + 1; i < order.length; i++) {
1443
+ const bp = order[i];
1444
+ if (dm && dm[bp]) return dm[bp] as SidebarMode;
1445
+ }
1446
+ return 'collapsed';
1447
+ }, [defaultMode, shell.currentBreakpoint]);
1448
+
1449
+ // Register custom toggle behavior based on toggleModes (both|single)
1431
1450
  const shellForToggle = useShell();
1451
+ const resolveDefaultSidebarMode = React.useCallback((): SidebarMode => {
1452
+ const resolved = resolveResponsiveMode();
1453
+ return resolved === 'thin' || resolved === 'expanded' ? resolved : 'expanded';
1454
+ }, [resolveResponsiveMode]);
1455
+
1432
1456
  React.useEffect(() => {
1433
1457
  if (!shellForToggle.setSidebarToggleComputer) return;
1434
- // Build cycle from provided modes (defaults to both)
1435
- const enabled = (
1436
- toggleModes && toggleModes.length > 0 ? toggleModes : (['thin', 'expanded'] as const)
1437
- ) as Array<'thin' | 'expanded'>;
1458
+ const strategy: 'both' | 'single' = toggleModes ?? 'both';
1438
1459
  const compute = (current: SidebarMode): SidebarMode => {
1439
- if (current === 'collapsed') return enabled[0] ?? 'expanded';
1440
- if (current === 'thin') {
1441
- // if thin not enabled, go to collapsed; else if expanded enabled go expanded; else collapsed
1442
- return enabled.includes('thin')
1443
- ? enabled.includes('expanded')
1444
- ? 'expanded'
1445
- : 'collapsed'
1446
- : 'collapsed';
1447
- }
1448
- // expanded
1449
- if (enabled.length === 2 && enabled.includes('thin') && enabled.includes('expanded')) {
1460
+ if (strategy === 'both') {
1461
+ // collapsed -> thin -> expanded -> collapsed
1462
+ if (current === 'collapsed') return 'thin';
1463
+ if (current === 'thin') return 'expanded';
1450
1464
  return 'collapsed';
1451
1465
  }
1452
- // if only expanded enabled, collapse next; if only thin enabled, go thin next
1453
- return enabled.includes('thin') && !enabled.includes('expanded') ? 'thin' : 'collapsed';
1466
+ // single: toggle between collapsed and resolved default mode
1467
+ const target = resolveDefaultSidebarMode();
1468
+ if (current === 'collapsed') return target;
1469
+ if (current === target) return 'collapsed';
1470
+ // if in the other non-collapsed state, jump to the target
1471
+ return target;
1454
1472
  };
1455
1473
  shellForToggle.setSidebarToggleComputer(compute);
1456
1474
  return () => {
1457
- // reset to default sequence when unmounting this Sidebar
1475
+ // default fallback sequence when unmounting
1458
1476
  shellForToggle.setSidebarToggleComputer?.((cur) =>
1459
1477
  cur === 'collapsed' ? 'thin' : cur === 'thin' ? 'expanded' : 'collapsed',
1460
1478
  );
1461
1479
  };
1462
- }, [shellForToggle, toggleModes]);
1480
+ }, [shellForToggle, toggleModes, resolveDefaultSidebarMode]);
1463
1481
 
1464
1482
  // Preserve last non-collapsed width for smooth overlay close animation
1465
1483
  const lastOverlayWidthRef = React.useRef<number>(expandedSize);
@@ -1471,24 +1489,7 @@ const Sidebar = React.forwardRef<
1471
1489
  }
1472
1490
  }, [shell.sidebarMode, thinSize, expandedSize]);
1473
1491
 
1474
- // Always-follow responsive defaultMode for uncontrolled Sidebar (on breakpoint change only)
1475
- const resolveResponsiveMode = React.useCallback((): SidebarMode => {
1476
- if (typeof defaultMode === 'string') return defaultMode as SidebarMode;
1477
- const dm = defaultMode as Partial<Record<Breakpoint, SidebarMode>> | undefined;
1478
- if (dm && dm[shell.currentBreakpoint as Breakpoint]) {
1479
- return dm[shell.currentBreakpoint as Breakpoint] as SidebarMode;
1480
- }
1481
- const bpKeys = Object.keys(BREAKPOINTS) as Array<keyof typeof BREAKPOINTS>;
1482
- const order: Breakpoint[] = ([...bpKeys].reverse() as Breakpoint[]).concat(
1483
- 'initial' as Breakpoint,
1484
- );
1485
- const startIdx = order.indexOf(shell.currentBreakpoint as Breakpoint);
1486
- for (let i = startIdx + 1; i < order.length; i++) {
1487
- const bp = order[i];
1488
- if (dm && dm[bp]) return dm[bp] as SidebarMode;
1489
- }
1490
- return 'collapsed';
1491
- }, [defaultMode, shell.currentBreakpoint]);
1492
+ // (moved above)
1492
1493
 
1493
1494
  const lastSidebarBpRef = React.useRef<Breakpoint | null>(null);
1494
1495
  React.useEffect(() => {
@@ -1563,7 +1564,7 @@ const Sidebar = React.forwardRef<
1563
1564
  <VisuallyHidden>
1564
1565
  <Sheet.Title>Sidebar</Sheet.Title>
1565
1566
  </VisuallyHidden>
1566
- {children}
1567
+ {contentChildren}
1567
1568
  </Sheet.Content>
1568
1569
  </Sheet.Root>
1569
1570
  );
@@ -1584,25 +1585,31 @@ const Sidebar = React.forwardRef<
1584
1585
  ['--sidebar-thin-size' as any]: `${thinSize}px`,
1585
1586
  ['--sidebar-min-size' as any]: `${minSize}px`,
1586
1587
  ['--sidebar-max-size' as any]: `${maxSize}px`,
1587
- // When peeking in fixed presentation, use the next toggle target's width (thin or expanded)
1588
- ...(shell.peekTarget === 'sidebar' && !isOverlay
1588
+ // When peeking in fixed presentation and collapsed, preview next state's width
1589
+ ...(shell.peekTarget === 'sidebar' && shell.sidebarMode === 'collapsed' && !isOverlay
1589
1590
  ? (() => {
1590
- const enabled = (
1591
- toggleModes && toggleModes.length > 0
1592
- ? toggleModes
1593
- : (['thin', 'expanded'] as const)
1594
- ) as Array<'thin' | 'expanded'>;
1591
+ const strategy: 'both' | 'single' = toggleModes ?? 'both';
1595
1592
  const current = shell.sidebarMode as SidebarMode;
1596
- let next: SidebarMode = 'collapsed';
1597
- if (current === 'collapsed') {
1598
- next = (enabled[0] ?? 'expanded') as SidebarMode;
1599
- } else if (current === 'thin') {
1600
- next = enabled.includes('expanded') ? 'expanded' : 'collapsed';
1593
+ let next: SidebarMode;
1594
+ if (strategy === 'both') {
1595
+ next =
1596
+ current === 'collapsed'
1597
+ ? 'thin'
1598
+ : current === 'thin'
1599
+ ? 'expanded'
1600
+ : 'collapsed';
1601
1601
  } else {
1602
- next = enabled.includes('thin') ? 'thin' : 'collapsed';
1602
+ const target = resolveDefaultSidebarMode();
1603
+ next = current === 'collapsed' ? target : 'collapsed';
1603
1604
  }
1604
- const peekWidth = next === 'thin' ? thinSize : expandedSize;
1605
- return { ['--peek-sidebar-width' as any]: `${peekWidth}px` } as React.CSSProperties;
1605
+ if (next === 'thin') {
1606
+ return {
1607
+ ['--peek-sidebar-width' as any]: `${thinSize}px`,
1608
+ } as React.CSSProperties;
1609
+ }
1610
+ return {
1611
+ ['--peek-sidebar-width' as any]: `var(--sidebar-size, ${expandedSize}px)`,
1612
+ } as React.CSSProperties;
1606
1613
  })()
1607
1614
  : {}),
1608
1615
  }}
@@ -1826,7 +1833,7 @@ const Inspector = React.forwardRef<HTMLDivElement, PaneProps>(
1826
1833
  <VisuallyHidden>
1827
1834
  <Sheet.Title>Inspector</Sheet.Title>
1828
1835
  </VisuallyHidden>
1829
- {children}
1836
+ {contentChildren}
1830
1837
  </Sheet.Content>
1831
1838
  </Sheet.Root>
1832
1839
  );
@@ -1910,17 +1917,60 @@ const Bottom = React.forwardRef<HTMLDivElement, PaneProps>(
1910
1917
  (el: React.ReactElement) => !(React.isValidElement(el) && el.type === BottomHandle),
1911
1918
  );
1912
1919
 
1913
- // Honor defaultMode on mount when uncontrolled
1920
+ // Resolve responsive defaultMode for uncontrolled Bottom (on mount and breakpoint change)
1921
+ const resolveResponsiveMode = React.useCallback((): PaneMode => {
1922
+ if (typeof defaultMode === 'string') return defaultMode as PaneMode;
1923
+ const dm = defaultMode as Partial<Record<Breakpoint, PaneMode>> | undefined;
1924
+ if (dm && dm[shell.currentBreakpoint as Breakpoint]) {
1925
+ return dm[shell.currentBreakpoint as Breakpoint] as PaneMode;
1926
+ }
1927
+ const bpKeys = Object.keys(BREAKPOINTS) as Array<keyof typeof BREAKPOINTS>;
1928
+ const order: Breakpoint[] = ([...bpKeys].reverse() as Breakpoint[]).concat(
1929
+ 'initial' as Breakpoint,
1930
+ );
1931
+ const startIdx = order.indexOf(shell.currentBreakpoint as Breakpoint);
1932
+ for (let i = startIdx + 1; i < order.length; i++) {
1933
+ const bp = order[i];
1934
+ if (dm && dm[bp]) {
1935
+ return dm[bp] as PaneMode;
1936
+ }
1937
+ }
1938
+ return 'collapsed';
1939
+ }, [defaultMode, shell.currentBreakpoint]);
1940
+
1941
+ // Honor defaultMode on mount when uncontrolled (including responsive objects)
1914
1942
  const didInitRef = React.useRef(false);
1915
1943
  React.useEffect(() => {
1916
1944
  if (didInitRef.current) return;
1917
1945
  didInitRef.current = true;
1918
- if (mode === undefined && shell.bottomMode !== (defaultMode as PaneMode)) {
1919
- shell.setBottomMode(defaultMode as PaneMode);
1946
+ if (mode === undefined) {
1947
+ const initial = resolveResponsiveMode();
1948
+ if (shell.bottomMode !== initial) shell.setBottomMode(initial);
1920
1949
  }
1921
1950
  // eslint-disable-next-line react-hooks/exhaustive-deps
1922
1951
  }, []);
1923
1952
 
1953
+ // Apply responsive defaultMode on breakpoint change when uncontrolled
1954
+ const lastBottomBpRef = React.useRef<Breakpoint | null>(null);
1955
+ const lastResolvedBottomRef = React.useRef<PaneMode | null>(null);
1956
+ React.useEffect(() => {
1957
+ if (mode !== undefined) return; // controlled wins
1958
+ if (!shell.currentBreakpointReady) return; // avoid SSR mismatch
1959
+ if (lastBottomBpRef.current === shell.currentBreakpoint) return; // only on bp change
1960
+ lastBottomBpRef.current = shell.currentBreakpoint as Breakpoint;
1961
+ const next = resolveResponsiveMode();
1962
+ if (lastResolvedBottomRef.current === next) return; // no-op transition
1963
+ lastResolvedBottomRef.current = next;
1964
+ if (next !== shell.bottomMode) shell.setBottomMode(next);
1965
+ }, [
1966
+ mode,
1967
+ shell.currentBreakpoint,
1968
+ shell.currentBreakpointReady,
1969
+ resolveResponsiveMode,
1970
+ shell.bottomMode,
1971
+ shell.setBottomMode,
1972
+ ]);
1973
+
1924
1974
  // Sync controlled mode
1925
1975
  React.useEffect(() => {
1926
1976
  if (mode !== undefined && shell.bottomMode !== mode) {
@@ -2032,7 +2082,7 @@ const Bottom = React.forwardRef<HTMLDivElement, PaneProps>(
2032
2082
  <VisuallyHidden>
2033
2083
  <Sheet.Title>Bottom panel</Sheet.Title>
2034
2084
  </VisuallyHidden>
2035
- {children}
2085
+ {contentChildren}
2036
2086
  </Sheet.Content>
2037
2087
  </Sheet.Root>
2038
2088
  );
@@ -2099,6 +2149,11 @@ const Trigger = React.forwardRef<HTMLButtonElement, TriggerProps>(
2099
2149
  (event: React.MouseEvent<HTMLButtonElement>) => {
2100
2150
  onClick?.(event);
2101
2151
 
2152
+ // Clear any active peek on this target before toggling to avoid sticky peek state
2153
+ if ((shell as any).peekTarget === target) {
2154
+ shell.clearPeek();
2155
+ }
2156
+
2102
2157
  switch (action) {
2103
2158
  case 'toggle':
2104
2159
  shell.togglePane(target);
package/styles.css CHANGED
@@ -20131,6 +20131,9 @@
20131
20131
  }
20132
20132
  .rt-ShellBottom[data-mode='collapsed']{
20133
20133
  height: 0px;
20134
+ position: absolute;
20135
+ inset-inline: 0;
20136
+ inset-block-end: 0;
20134
20137
  }
20135
20138
  .rt-ShellBottomContent{
20136
20139
  display: flex;