@cntyclub/ui-react 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cntyclub/ui-react",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "React component library for the Country Club UI Kit — Base UI primitives styled with the Country Club design system (Tailwind CSS v4)",
5
5
  "type": "module",
6
6
  "sideEffects": [
@@ -58,6 +58,7 @@ function SidebarProvider({
58
58
  defaultOpen = true,
59
59
  open: openProp,
60
60
  onOpenChange: setOpenProp,
61
+ persistKey,
61
62
  className,
62
63
  style,
63
64
  children,
@@ -66,6 +67,14 @@ function SidebarProvider({
66
67
  defaultOpen?: boolean;
67
68
  open?: boolean;
68
69
  onOpenChange?: (open: boolean) => void;
70
+ /**
71
+ * Remember the expanded/collapsed state in `localStorage` under this key and
72
+ * restore it on the next load (desktop rail only; the mobile sheet is always
73
+ * closed on load). Opt-in — omit to keep the sidebar un-persisted. Ignored in
74
+ * controlled mode (when `open` is provided). The restore runs before first
75
+ * paint, so there's no expand→collapse flash.
76
+ */
77
+ persistKey?: string;
69
78
  }) {
70
79
  // Self-contained breakpoint check (md = 48rem). Resolved in a layout effect
71
80
  // before the first paint so the sidebar never flashes from mobile to desktop.
@@ -93,16 +102,38 @@ function SidebarProvider({
93
102
  }
94
103
 
95
104
  // Persist the sidebar state. document.cookie works in every browser
96
- // (cookieStore is Chromium-only and throws elsewhere).
105
+ // (cookieStore is Chromium-only and throws elsewhere). When `persistKey`
106
+ // is set we also mirror it to localStorage so a client-only app (no SSR
107
+ // cookie read) can restore it on load.
97
108
  try {
98
109
  document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
110
+ if (persistKey) {
111
+ window.localStorage.setItem(persistKey, openState ? "true" : "false");
112
+ }
99
113
  } catch {
100
114
  // Ignore — persistence is best-effort.
101
115
  }
102
116
  },
103
- [setOpenProp, open],
117
+ [setOpenProp, open, persistKey],
104
118
  );
105
119
 
120
+ // Restore the persisted (localStorage) open state on mount — uncontrolled use
121
+ // only. Runs in a layout effect so the restore lands before first paint (no
122
+ // expand→collapse flash). SSR renders `defaultOpen` and the client's first
123
+ // render matches it, so this reconciles afterwards without a hydration
124
+ // mismatch.
125
+ useIsomorphicLayoutEffect(() => {
126
+ if (!persistKey || openProp !== undefined) return;
127
+ try {
128
+ const stored = window.localStorage.getItem(persistKey);
129
+ if (stored === "true" || stored === "false") {
130
+ _setOpen(stored === "true");
131
+ }
132
+ } catch {
133
+ // Ignore — restore is best-effort.
134
+ }
135
+ }, [persistKey, openProp]);
136
+
106
137
  // Helper to toggle the sidebar.
107
138
  const toggleSidebar = React.useCallback(() => {
108
139
  return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open);