@orion-studios/payload-admin-components 0.2.0-beta.2 → 0.2.0-beta.3

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/dist/client.d.mts CHANGED
@@ -67,6 +67,7 @@ declare function useTheme(): {
67
67
  isDark: boolean;
68
68
  isBrand: boolean;
69
69
  isLoading: boolean;
70
+ hasMounted: boolean;
70
71
  toggleDarkMode: () => void;
71
72
  toggleBrandMode: () => void;
72
73
  };
package/dist/client.d.ts CHANGED
@@ -67,6 +67,7 @@ declare function useTheme(): {
67
67
  isDark: boolean;
68
68
  isBrand: boolean;
69
69
  isLoading: boolean;
70
+ hasMounted: boolean;
70
71
  toggleDarkMode: () => void;
71
72
  toggleBrandMode: () => void;
72
73
  };
package/dist/client.js CHANGED
@@ -132,14 +132,13 @@ function cacheTheme(theme) {
132
132
  }
133
133
  }
134
134
  function useTheme() {
135
- const [theme, setThemeState] = (0, import_react.useState)(() => {
136
- if (typeof window === "undefined") return DEFAULT_THEME;
137
- return getCachedTheme() || DEFAULT_THEME;
138
- });
135
+ const [theme, setThemeState] = (0, import_react.useState)(DEFAULT_THEME);
139
136
  const [isLoading, setIsLoading] = (0, import_react.useState)(true);
137
+ const [hasMounted, setHasMounted] = (0, import_react.useState)(false);
140
138
  const debounceRef = (0, import_react.useRef)(null);
141
139
  const userIdRef = (0, import_react.useRef)(null);
142
140
  (0, import_react.useEffect)(() => {
141
+ setHasMounted(true);
143
142
  const cached = getCachedTheme();
144
143
  if (cached) {
145
144
  applyTheme(cached);
@@ -204,6 +203,7 @@ function useTheme() {
204
203
  isDark,
205
204
  isBrand,
206
205
  isLoading,
206
+ hasMounted,
207
207
  toggleDarkMode,
208
208
  toggleBrandMode
209
209
  };
@@ -258,7 +258,9 @@ var buttonActive = {
258
258
  color: "var(--admin-accent)"
259
259
  };
260
260
  function ThemeSwitcher() {
261
- const { isDark, isBrand, toggleDarkMode, toggleBrandMode } = useTheme();
261
+ const { isDark, isBrand, hasMounted, toggleDarkMode, toggleBrandMode } = useTheme();
262
+ const showDark = hasMounted && isDark;
263
+ const showBrand = hasMounted && isBrand;
262
264
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
263
265
  "div",
264
266
  {
@@ -274,10 +276,10 @@ function ThemeSwitcher() {
274
276
  {
275
277
  type: "button",
276
278
  onClick: toggleDarkMode,
277
- style: isDark ? buttonActive : buttonBase,
278
- title: isDark ? "Switch to light mode" : "Switch to dark mode",
279
- "aria-label": isDark ? "Switch to light mode" : "Switch to dark mode",
280
- children: isDark ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MoonIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SunIcon, {})
279
+ style: showDark ? buttonActive : buttonBase,
280
+ title: showDark ? "Switch to light mode" : "Switch to dark mode",
281
+ "aria-label": showDark ? "Switch to light mode" : "Switch to dark mode",
282
+ children: showDark ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MoonIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SunIcon, {})
281
283
  }
282
284
  ),
283
285
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
@@ -285,9 +287,9 @@ function ThemeSwitcher() {
285
287
  {
286
288
  type: "button",
287
289
  onClick: toggleBrandMode,
288
- style: isBrand ? buttonActive : buttonBase,
289
- title: isBrand ? "Switch to standard colors" : "Switch to brand colors",
290
- "aria-label": isBrand ? "Switch to standard colors" : "Switch to brand colors",
290
+ style: showBrand ? buttonActive : buttonBase,
291
+ title: showBrand ? "Switch to standard colors" : "Switch to brand colors",
292
+ "aria-label": showBrand ? "Switch to standard colors" : "Switch to brand colors",
291
293
  children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PaletteIcon, {})
292
294
  }
293
295
  )
package/dist/client.mjs CHANGED
@@ -96,14 +96,13 @@ function cacheTheme(theme) {
96
96
  }
97
97
  }
98
98
  function useTheme() {
99
- const [theme, setThemeState] = useState(() => {
100
- if (typeof window === "undefined") return DEFAULT_THEME;
101
- return getCachedTheme() || DEFAULT_THEME;
102
- });
99
+ const [theme, setThemeState] = useState(DEFAULT_THEME);
103
100
  const [isLoading, setIsLoading] = useState(true);
101
+ const [hasMounted, setHasMounted] = useState(false);
104
102
  const debounceRef = useRef(null);
105
103
  const userIdRef = useRef(null);
106
104
  useEffect(() => {
105
+ setHasMounted(true);
107
106
  const cached = getCachedTheme();
108
107
  if (cached) {
109
108
  applyTheme(cached);
@@ -168,6 +167,7 @@ function useTheme() {
168
167
  isDark,
169
168
  isBrand,
170
169
  isLoading,
170
+ hasMounted,
171
171
  toggleDarkMode,
172
172
  toggleBrandMode
173
173
  };
@@ -222,7 +222,9 @@ var buttonActive = {
222
222
  color: "var(--admin-accent)"
223
223
  };
224
224
  function ThemeSwitcher() {
225
- const { isDark, isBrand, toggleDarkMode, toggleBrandMode } = useTheme();
225
+ const { isDark, isBrand, hasMounted, toggleDarkMode, toggleBrandMode } = useTheme();
226
+ const showDark = hasMounted && isDark;
227
+ const showBrand = hasMounted && isBrand;
226
228
  return /* @__PURE__ */ jsxs3(
227
229
  "div",
228
230
  {
@@ -238,10 +240,10 @@ function ThemeSwitcher() {
238
240
  {
239
241
  type: "button",
240
242
  onClick: toggleDarkMode,
241
- style: isDark ? buttonActive : buttonBase,
242
- title: isDark ? "Switch to light mode" : "Switch to dark mode",
243
- "aria-label": isDark ? "Switch to light mode" : "Switch to dark mode",
244
- children: isDark ? /* @__PURE__ */ jsx3(MoonIcon, {}) : /* @__PURE__ */ jsx3(SunIcon, {})
243
+ style: showDark ? buttonActive : buttonBase,
244
+ title: showDark ? "Switch to light mode" : "Switch to dark mode",
245
+ "aria-label": showDark ? "Switch to light mode" : "Switch to dark mode",
246
+ children: showDark ? /* @__PURE__ */ jsx3(MoonIcon, {}) : /* @__PURE__ */ jsx3(SunIcon, {})
245
247
  }
246
248
  ),
247
249
  /* @__PURE__ */ jsx3(
@@ -249,9 +251,9 @@ function ThemeSwitcher() {
249
251
  {
250
252
  type: "button",
251
253
  onClick: toggleBrandMode,
252
- style: isBrand ? buttonActive : buttonBase,
253
- title: isBrand ? "Switch to standard colors" : "Switch to brand colors",
254
- "aria-label": isBrand ? "Switch to standard colors" : "Switch to brand colors",
254
+ style: showBrand ? buttonActive : buttonBase,
255
+ title: showBrand ? "Switch to standard colors" : "Switch to brand colors",
256
+ "aria-label": showBrand ? "Switch to standard colors" : "Switch to brand colors",
255
257
  children: /* @__PURE__ */ jsx3(PaletteIcon, {})
256
258
  }
257
259
  )
package/dist/index.d.mts CHANGED
@@ -120,6 +120,7 @@ declare function useTheme(): {
120
120
  isDark: boolean;
121
121
  isBrand: boolean;
122
122
  isLoading: boolean;
123
+ hasMounted: boolean;
123
124
  toggleDarkMode: () => void;
124
125
  toggleBrandMode: () => void;
125
126
  };
package/dist/index.d.ts CHANGED
@@ -120,6 +120,7 @@ declare function useTheme(): {
120
120
  isDark: boolean;
121
121
  isBrand: boolean;
122
122
  isLoading: boolean;
123
+ hasMounted: boolean;
123
124
  toggleDarkMode: () => void;
124
125
  toggleBrandMode: () => void;
125
126
  };
package/dist/index.js CHANGED
@@ -295,14 +295,13 @@ function cacheTheme(theme) {
295
295
  }
296
296
  }
297
297
  function useTheme() {
298
- const [theme, setThemeState] = (0, import_react.useState)(() => {
299
- if (typeof window === "undefined") return DEFAULT_THEME;
300
- return getCachedTheme() || DEFAULT_THEME;
301
- });
298
+ const [theme, setThemeState] = (0, import_react.useState)(DEFAULT_THEME);
302
299
  const [isLoading, setIsLoading] = (0, import_react.useState)(true);
300
+ const [hasMounted, setHasMounted] = (0, import_react.useState)(false);
303
301
  const debounceRef = (0, import_react.useRef)(null);
304
302
  const userIdRef = (0, import_react.useRef)(null);
305
303
  (0, import_react.useEffect)(() => {
304
+ setHasMounted(true);
306
305
  const cached = getCachedTheme();
307
306
  if (cached) {
308
307
  applyTheme(cached);
@@ -367,6 +366,7 @@ function useTheme() {
367
366
  isDark,
368
367
  isBrand,
369
368
  isLoading,
369
+ hasMounted,
370
370
  toggleDarkMode,
371
371
  toggleBrandMode
372
372
  };
@@ -421,7 +421,9 @@ var buttonActive = {
421
421
  color: "var(--admin-accent)"
422
422
  };
423
423
  function ThemeSwitcher() {
424
- const { isDark, isBrand, toggleDarkMode, toggleBrandMode } = useTheme();
424
+ const { isDark, isBrand, hasMounted, toggleDarkMode, toggleBrandMode } = useTheme();
425
+ const showDark = hasMounted && isDark;
426
+ const showBrand = hasMounted && isBrand;
425
427
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
426
428
  "div",
427
429
  {
@@ -437,10 +439,10 @@ function ThemeSwitcher() {
437
439
  {
438
440
  type: "button",
439
441
  onClick: toggleDarkMode,
440
- style: isDark ? buttonActive : buttonBase,
441
- title: isDark ? "Switch to light mode" : "Switch to dark mode",
442
- "aria-label": isDark ? "Switch to light mode" : "Switch to dark mode",
443
- children: isDark ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MoonIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SunIcon, {})
442
+ style: showDark ? buttonActive : buttonBase,
443
+ title: showDark ? "Switch to light mode" : "Switch to dark mode",
444
+ "aria-label": showDark ? "Switch to light mode" : "Switch to dark mode",
445
+ children: showDark ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MoonIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SunIcon, {})
444
446
  }
445
447
  ),
446
448
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
@@ -448,9 +450,9 @@ function ThemeSwitcher() {
448
450
  {
449
451
  type: "button",
450
452
  onClick: toggleBrandMode,
451
- style: isBrand ? buttonActive : buttonBase,
452
- title: isBrand ? "Switch to standard colors" : "Switch to brand colors",
453
- "aria-label": isBrand ? "Switch to standard colors" : "Switch to brand colors",
453
+ style: showBrand ? buttonActive : buttonBase,
454
+ title: showBrand ? "Switch to standard colors" : "Switch to brand colors",
455
+ "aria-label": showBrand ? "Switch to standard colors" : "Switch to brand colors",
454
456
  children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PaletteIcon, {})
455
457
  }
456
458
  )
package/dist/index.mjs CHANGED
@@ -255,14 +255,13 @@ function cacheTheme(theme) {
255
255
  }
256
256
  }
257
257
  function useTheme() {
258
- const [theme, setThemeState] = useState(() => {
259
- if (typeof window === "undefined") return DEFAULT_THEME;
260
- return getCachedTheme() || DEFAULT_THEME;
261
- });
258
+ const [theme, setThemeState] = useState(DEFAULT_THEME);
262
259
  const [isLoading, setIsLoading] = useState(true);
260
+ const [hasMounted, setHasMounted] = useState(false);
263
261
  const debounceRef = useRef(null);
264
262
  const userIdRef = useRef(null);
265
263
  useEffect(() => {
264
+ setHasMounted(true);
266
265
  const cached = getCachedTheme();
267
266
  if (cached) {
268
267
  applyTheme(cached);
@@ -327,6 +326,7 @@ function useTheme() {
327
326
  isDark,
328
327
  isBrand,
329
328
  isLoading,
329
+ hasMounted,
330
330
  toggleDarkMode,
331
331
  toggleBrandMode
332
332
  };
@@ -381,7 +381,9 @@ var buttonActive = {
381
381
  color: "var(--admin-accent)"
382
382
  };
383
383
  function ThemeSwitcher() {
384
- const { isDark, isBrand, toggleDarkMode, toggleBrandMode } = useTheme();
384
+ const { isDark, isBrand, hasMounted, toggleDarkMode, toggleBrandMode } = useTheme();
385
+ const showDark = hasMounted && isDark;
386
+ const showBrand = hasMounted && isBrand;
385
387
  return /* @__PURE__ */ jsxs3(
386
388
  "div",
387
389
  {
@@ -397,10 +399,10 @@ function ThemeSwitcher() {
397
399
  {
398
400
  type: "button",
399
401
  onClick: toggleDarkMode,
400
- style: isDark ? buttonActive : buttonBase,
401
- title: isDark ? "Switch to light mode" : "Switch to dark mode",
402
- "aria-label": isDark ? "Switch to light mode" : "Switch to dark mode",
403
- children: isDark ? /* @__PURE__ */ jsx3(MoonIcon, {}) : /* @__PURE__ */ jsx3(SunIcon, {})
402
+ style: showDark ? buttonActive : buttonBase,
403
+ title: showDark ? "Switch to light mode" : "Switch to dark mode",
404
+ "aria-label": showDark ? "Switch to light mode" : "Switch to dark mode",
405
+ children: showDark ? /* @__PURE__ */ jsx3(MoonIcon, {}) : /* @__PURE__ */ jsx3(SunIcon, {})
404
406
  }
405
407
  ),
406
408
  /* @__PURE__ */ jsx3(
@@ -408,9 +410,9 @@ function ThemeSwitcher() {
408
410
  {
409
411
  type: "button",
410
412
  onClick: toggleBrandMode,
411
- style: isBrand ? buttonActive : buttonBase,
412
- title: isBrand ? "Switch to standard colors" : "Switch to brand colors",
413
- "aria-label": isBrand ? "Switch to standard colors" : "Switch to brand colors",
413
+ style: showBrand ? buttonActive : buttonBase,
414
+ title: showBrand ? "Switch to standard colors" : "Switch to brand colors",
415
+ "aria-label": showBrand ? "Switch to standard colors" : "Switch to brand colors",
414
416
  children: /* @__PURE__ */ jsx3(PaletteIcon, {})
415
417
  }
416
418
  )
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orion-studios/payload-admin-components",
3
- "version": "0.2.0-beta.2",
3
+ "version": "0.2.0-beta.3",
4
4
  "description": "Custom admin UI components for Payload CMS",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -64,7 +64,13 @@ const buttonActive: React.CSSProperties = {
64
64
  }
65
65
 
66
66
  export function ThemeSwitcher() {
67
- const { isDark, isBrand, toggleDarkMode, toggleBrandMode } = useTheme()
67
+ const { isDark, isBrand, hasMounted, toggleDarkMode, toggleBrandMode } = useTheme()
68
+
69
+ // Before mount, render the default (light) state to match server HTML and avoid hydration mismatch.
70
+ // The ThemeProvider applies the cached theme to the document immediately on mount,
71
+ // so the visual flash is minimal.
72
+ const showDark = hasMounted && isDark
73
+ const showBrand = hasMounted && isBrand
68
74
 
69
75
  return (
70
76
  <div
@@ -78,18 +84,18 @@ export function ThemeSwitcher() {
78
84
  <button
79
85
  type="button"
80
86
  onClick={toggleDarkMode}
81
- style={isDark ? buttonActive : buttonBase}
82
- title={isDark ? 'Switch to light mode' : 'Switch to dark mode'}
83
- aria-label={isDark ? 'Switch to light mode' : 'Switch to dark mode'}
87
+ style={showDark ? buttonActive : buttonBase}
88
+ title={showDark ? 'Switch to light mode' : 'Switch to dark mode'}
89
+ aria-label={showDark ? 'Switch to light mode' : 'Switch to dark mode'}
84
90
  >
85
- {isDark ? <MoonIcon /> : <SunIcon />}
91
+ {showDark ? <MoonIcon /> : <SunIcon />}
86
92
  </button>
87
93
  <button
88
94
  type="button"
89
95
  onClick={toggleBrandMode}
90
- style={isBrand ? buttonActive : buttonBase}
91
- title={isBrand ? 'Switch to standard colors' : 'Switch to brand colors'}
92
- aria-label={isBrand ? 'Switch to standard colors' : 'Switch to brand colors'}
96
+ style={showBrand ? buttonActive : buttonBase}
97
+ title={showBrand ? 'Switch to standard colors' : 'Switch to brand colors'}
98
+ aria-label={showBrand ? 'Switch to standard colors' : 'Switch to brand colors'}
93
99
  >
94
100
  <PaletteIcon />
95
101
  </button>
@@ -32,16 +32,17 @@ function cacheTheme(theme: ThemeOption) {
32
32
  }
33
33
 
34
34
  export function useTheme() {
35
- const [theme, setThemeState] = useState<ThemeOption>(() => {
36
- if (typeof window === 'undefined') return DEFAULT_THEME
37
- return getCachedTheme() || DEFAULT_THEME
38
- })
35
+ // Always initialize with DEFAULT_THEME to avoid hydration mismatch.
36
+ // The real theme is applied in useEffect after mount.
37
+ const [theme, setThemeState] = useState<ThemeOption>(DEFAULT_THEME)
39
38
  const [isLoading, setIsLoading] = useState(true)
39
+ const [hasMounted, setHasMounted] = useState(false)
40
40
  const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null)
41
41
  const userIdRef = useRef<string | null>(null)
42
42
 
43
43
  // On mount: apply cached theme immediately, then sync from DB
44
44
  useEffect(() => {
45
+ setHasMounted(true)
45
46
  const cached = getCachedTheme()
46
47
  if (cached) {
47
48
  applyTheme(cached)
@@ -122,6 +123,7 @@ export function useTheme() {
122
123
  isDark,
123
124
  isBrand,
124
125
  isLoading,
126
+ hasMounted,
125
127
  toggleDarkMode,
126
128
  toggleBrandMode,
127
129
  }