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

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.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
  };
@@ -244,7 +244,9 @@ var buttonBase = {
244
244
  width: 32,
245
245
  height: 32,
246
246
  borderRadius: "var(--admin-radius-sm)",
247
- border: "1px solid var(--admin-border)",
247
+ borderWidth: 1,
248
+ borderStyle: "solid",
249
+ borderColor: "var(--admin-border)",
248
250
  background: "var(--admin-surface)",
249
251
  color: "var(--admin-text-secondary)",
250
252
  cursor: "pointer",
@@ -258,7 +260,9 @@ var buttonActive = {
258
260
  color: "var(--admin-accent)"
259
261
  };
260
262
  function ThemeSwitcher() {
261
- const { isDark, isBrand, toggleDarkMode, toggleBrandMode } = useTheme();
263
+ const { isDark, isBrand, hasMounted, toggleDarkMode, toggleBrandMode } = useTheme();
264
+ const showDark = hasMounted && isDark;
265
+ const showBrand = hasMounted && isBrand;
262
266
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
263
267
  "div",
264
268
  {
@@ -274,10 +278,10 @@ function ThemeSwitcher() {
274
278
  {
275
279
  type: "button",
276
280
  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, {})
281
+ style: showDark ? buttonActive : buttonBase,
282
+ title: showDark ? "Switch to light mode" : "Switch to dark mode",
283
+ "aria-label": showDark ? "Switch to light mode" : "Switch to dark mode",
284
+ children: showDark ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MoonIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SunIcon, {})
281
285
  }
282
286
  ),
283
287
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
@@ -285,9 +289,9 @@ function ThemeSwitcher() {
285
289
  {
286
290
  type: "button",
287
291
  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",
292
+ style: showBrand ? buttonActive : buttonBase,
293
+ title: showBrand ? "Switch to standard colors" : "Switch to brand colors",
294
+ "aria-label": showBrand ? "Switch to standard colors" : "Switch to brand colors",
291
295
  children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PaletteIcon, {})
292
296
  }
293
297
  )
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
  };
@@ -208,7 +208,9 @@ var buttonBase = {
208
208
  width: 32,
209
209
  height: 32,
210
210
  borderRadius: "var(--admin-radius-sm)",
211
- border: "1px solid var(--admin-border)",
211
+ borderWidth: 1,
212
+ borderStyle: "solid",
213
+ borderColor: "var(--admin-border)",
212
214
  background: "var(--admin-surface)",
213
215
  color: "var(--admin-text-secondary)",
214
216
  cursor: "pointer",
@@ -222,7 +224,9 @@ var buttonActive = {
222
224
  color: "var(--admin-accent)"
223
225
  };
224
226
  function ThemeSwitcher() {
225
- const { isDark, isBrand, toggleDarkMode, toggleBrandMode } = useTheme();
227
+ const { isDark, isBrand, hasMounted, toggleDarkMode, toggleBrandMode } = useTheme();
228
+ const showDark = hasMounted && isDark;
229
+ const showBrand = hasMounted && isBrand;
226
230
  return /* @__PURE__ */ jsxs3(
227
231
  "div",
228
232
  {
@@ -238,10 +242,10 @@ function ThemeSwitcher() {
238
242
  {
239
243
  type: "button",
240
244
  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, {})
245
+ style: showDark ? buttonActive : buttonBase,
246
+ title: showDark ? "Switch to light mode" : "Switch to dark mode",
247
+ "aria-label": showDark ? "Switch to light mode" : "Switch to dark mode",
248
+ children: showDark ? /* @__PURE__ */ jsx3(MoonIcon, {}) : /* @__PURE__ */ jsx3(SunIcon, {})
245
249
  }
246
250
  ),
247
251
  /* @__PURE__ */ jsx3(
@@ -249,9 +253,9 @@ function ThemeSwitcher() {
249
253
  {
250
254
  type: "button",
251
255
  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",
256
+ style: showBrand ? buttonActive : buttonBase,
257
+ title: showBrand ? "Switch to standard colors" : "Switch to brand colors",
258
+ "aria-label": showBrand ? "Switch to standard colors" : "Switch to brand colors",
255
259
  children: /* @__PURE__ */ jsx3(PaletteIcon, {})
256
260
  }
257
261
  )
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
  };
@@ -407,7 +407,9 @@ var buttonBase = {
407
407
  width: 32,
408
408
  height: 32,
409
409
  borderRadius: "var(--admin-radius-sm)",
410
- border: "1px solid var(--admin-border)",
410
+ borderWidth: 1,
411
+ borderStyle: "solid",
412
+ borderColor: "var(--admin-border)",
411
413
  background: "var(--admin-surface)",
412
414
  color: "var(--admin-text-secondary)",
413
415
  cursor: "pointer",
@@ -421,7 +423,9 @@ var buttonActive = {
421
423
  color: "var(--admin-accent)"
422
424
  };
423
425
  function ThemeSwitcher() {
424
- const { isDark, isBrand, toggleDarkMode, toggleBrandMode } = useTheme();
426
+ const { isDark, isBrand, hasMounted, toggleDarkMode, toggleBrandMode } = useTheme();
427
+ const showDark = hasMounted && isDark;
428
+ const showBrand = hasMounted && isBrand;
425
429
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
426
430
  "div",
427
431
  {
@@ -437,10 +441,10 @@ function ThemeSwitcher() {
437
441
  {
438
442
  type: "button",
439
443
  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, {})
444
+ style: showDark ? buttonActive : buttonBase,
445
+ title: showDark ? "Switch to light mode" : "Switch to dark mode",
446
+ "aria-label": showDark ? "Switch to light mode" : "Switch to dark mode",
447
+ children: showDark ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MoonIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SunIcon, {})
444
448
  }
445
449
  ),
446
450
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
@@ -448,9 +452,9 @@ function ThemeSwitcher() {
448
452
  {
449
453
  type: "button",
450
454
  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",
455
+ style: showBrand ? buttonActive : buttonBase,
456
+ title: showBrand ? "Switch to standard colors" : "Switch to brand colors",
457
+ "aria-label": showBrand ? "Switch to standard colors" : "Switch to brand colors",
454
458
  children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PaletteIcon, {})
455
459
  }
456
460
  )
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
  };
@@ -367,7 +367,9 @@ var buttonBase = {
367
367
  width: 32,
368
368
  height: 32,
369
369
  borderRadius: "var(--admin-radius-sm)",
370
- border: "1px solid var(--admin-border)",
370
+ borderWidth: 1,
371
+ borderStyle: "solid",
372
+ borderColor: "var(--admin-border)",
371
373
  background: "var(--admin-surface)",
372
374
  color: "var(--admin-text-secondary)",
373
375
  cursor: "pointer",
@@ -381,7 +383,9 @@ var buttonActive = {
381
383
  color: "var(--admin-accent)"
382
384
  };
383
385
  function ThemeSwitcher() {
384
- const { isDark, isBrand, toggleDarkMode, toggleBrandMode } = useTheme();
386
+ const { isDark, isBrand, hasMounted, toggleDarkMode, toggleBrandMode } = useTheme();
387
+ const showDark = hasMounted && isDark;
388
+ const showBrand = hasMounted && isBrand;
385
389
  return /* @__PURE__ */ jsxs3(
386
390
  "div",
387
391
  {
@@ -397,10 +401,10 @@ function ThemeSwitcher() {
397
401
  {
398
402
  type: "button",
399
403
  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, {})
404
+ style: showDark ? buttonActive : buttonBase,
405
+ title: showDark ? "Switch to light mode" : "Switch to dark mode",
406
+ "aria-label": showDark ? "Switch to light mode" : "Switch to dark mode",
407
+ children: showDark ? /* @__PURE__ */ jsx3(MoonIcon, {}) : /* @__PURE__ */ jsx3(SunIcon, {})
404
408
  }
405
409
  ),
406
410
  /* @__PURE__ */ jsx3(
@@ -408,9 +412,9 @@ function ThemeSwitcher() {
408
412
  {
409
413
  type: "button",
410
414
  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",
415
+ style: showBrand ? buttonActive : buttonBase,
416
+ title: showBrand ? "Switch to standard colors" : "Switch to brand colors",
417
+ "aria-label": showBrand ? "Switch to standard colors" : "Switch to brand colors",
414
418
  children: /* @__PURE__ */ jsx3(PaletteIcon, {})
415
419
  }
416
420
  )
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.4",
4
4
  "description": "Custom admin UI components for Payload CMS",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -23,7 +23,7 @@
23
23
  "src"
24
24
  ],
25
25
  "scripts": {
26
- "build": "tsup && node -e \"const fs=require('fs'),path=require('path');function copyDir(s,d){fs.mkdirSync(d,{recursive:true});for(const f of fs.readdirSync(s)){const sp=path.join(s,f),dp=path.join(d,f);fs.statSync(sp).isDirectory()?copyDir(sp,dp):fs.copyFileSync(sp,dp)}}copyDir('src/styles','dist/styles');fs.copyFileSync('src/styles/admin.css','dist/admin.css')\"",
26
+ "build": "tsup && node -e \"require('fs').copyFileSync('src/styles/admin.css','dist/admin.css')\"",
27
27
  "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
28
28
  "typecheck": "tsc --noEmit"
29
29
  },
@@ -48,7 +48,9 @@ const buttonBase: React.CSSProperties = {
48
48
  width: 32,
49
49
  height: 32,
50
50
  borderRadius: 'var(--admin-radius-sm)',
51
- border: '1px solid var(--admin-border)',
51
+ borderWidth: 1,
52
+ borderStyle: 'solid',
53
+ borderColor: 'var(--admin-border)',
52
54
  background: 'var(--admin-surface)',
53
55
  color: 'var(--admin-text-secondary)',
54
56
  cursor: 'pointer',
@@ -64,7 +66,13 @@ const buttonActive: React.CSSProperties = {
64
66
  }
65
67
 
66
68
  export function ThemeSwitcher() {
67
- const { isDark, isBrand, toggleDarkMode, toggleBrandMode } = useTheme()
69
+ const { isDark, isBrand, hasMounted, toggleDarkMode, toggleBrandMode } = useTheme()
70
+
71
+ // Before mount, render the default (light) state to match server HTML and avoid hydration mismatch.
72
+ // The ThemeProvider applies the cached theme to the document immediately on mount,
73
+ // so the visual flash is minimal.
74
+ const showDark = hasMounted && isDark
75
+ const showBrand = hasMounted && isBrand
68
76
 
69
77
  return (
70
78
  <div
@@ -78,18 +86,18 @@ export function ThemeSwitcher() {
78
86
  <button
79
87
  type="button"
80
88
  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'}
89
+ style={showDark ? buttonActive : buttonBase}
90
+ title={showDark ? 'Switch to light mode' : 'Switch to dark mode'}
91
+ aria-label={showDark ? 'Switch to light mode' : 'Switch to dark mode'}
84
92
  >
85
- {isDark ? <MoonIcon /> : <SunIcon />}
93
+ {showDark ? <MoonIcon /> : <SunIcon />}
86
94
  </button>
87
95
  <button
88
96
  type="button"
89
97
  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'}
98
+ style={showBrand ? buttonActive : buttonBase}
99
+ title={showBrand ? 'Switch to standard colors' : 'Switch to brand colors'}
100
+ aria-label={showBrand ? 'Switch to standard colors' : 'Switch to brand colors'}
93
101
  >
94
102
  <PaletteIcon />
95
103
  </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
  }