@korioinc/next-core 2.0.31 → 2.0.34

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/README.md CHANGED
@@ -49,6 +49,15 @@ export default function middleware(request: NextRequest) {
49
49
 
50
50
  ```typescript
51
51
  import { ThemeSwitcher, LocaleSwitcher } from '@korioinc/next-core/components';
52
+ import { ThemeProvider } from '@korioinc/next-core/theme/server';
53
+
54
+ export function Layout({ children }: { children: React.ReactNode }) {
55
+ return (
56
+ <ThemeProvider attribute="class" enableSystem defaultTheme="system">
57
+ {children}
58
+ </ThemeProvider>
59
+ );
60
+ }
52
61
 
53
62
  export function Header() {
54
63
  return (
@@ -87,4 +96,4 @@ MIT
87
96
 
88
97
  ## Contributing
89
98
 
90
- Contributions are welcome! Please feel free to submit a Pull Request.
99
+ Contributions are welcome! Please feel free to submit a Pull Request.
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import * as React from 'react';
4
- import { useTheme } from 'next-themes';
4
+ import { useTheme } from '../../theme';
5
5
  const FALLBACK_THEME_ORDER = ['light', 'dark'];
6
6
  const isThemeMode = (value) => value === 'light' || value === 'dark' || value === 'system';
7
7
  const getThemeOrder = (themes) => {
@@ -0,0 +1,5 @@
1
+ import * as React from 'react';
2
+ import type { UseThemeProps } from './types';
3
+ export declare const ThemeContext: React.Context<UseThemeProps | undefined>;
4
+ export declare function useTheme(): UseThemeProps;
5
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/theme/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE7C,eAAO,MAAM,YAAY,0CAA4D,CAAC;AAOtF,wBAAgB,QAAQ,kBAEvB"}
@@ -0,0 +1,9 @@
1
+ import * as React from 'react';
2
+ export const ThemeContext = React.createContext(undefined);
3
+ const DEFAULT_CONTEXT = {
4
+ setTheme: () => undefined,
5
+ themes: [],
6
+ };
7
+ export function useTheme() {
8
+ return React.useContext(ThemeContext) ?? DEFAULT_CONTEXT;
9
+ }
@@ -0,0 +1,3 @@
1
+ export { ThemeProvider, useTheme } from './theme-provider.client';
2
+ export type { ThemeProviderProps, ThemeStorage, ThemeValueMap, UseThemeProps } from './types';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/theme/index.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAClE,YAAY,EAAE,kBAAkB,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC"}
@@ -0,0 +1,2 @@
1
+ 'use client';
2
+ export { ThemeProvider, useTheme } from './theme-provider.client';
@@ -0,0 +1,4 @@
1
+ import type { ThemeProviderProps, ThemeStorage, ThemeValueMap, UseThemeProps } from './types';
2
+ export declare function ThemeProvider(props: ThemeProviderProps): Promise<import("react/jsx-runtime").JSX.Element>;
3
+ export type { ThemeProviderProps, ThemeStorage, ThemeValueMap, UseThemeProps };
4
+ //# sourceMappingURL=index.server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.server.d.ts","sourceRoot":"","sources":["../../src/theme/index.server.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,kBAAkB,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE9F,wBAAsB,aAAa,CAAC,KAAK,EAAE,kBAAkB,oDAkB5D;AAED,YAAY,EAAE,kBAAkB,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { cookies } from 'next/headers';
3
+ import { getCookieStorageKey, isValidTheme, normalizeThemeProviderProps } from './shared';
4
+ import { ThemeProvider as ClientThemeProvider } from './theme-provider.client';
5
+ export async function ThemeProvider(props) {
6
+ const normalizedProps = normalizeThemeProviderProps(props);
7
+ let initialTheme = props.initialTheme;
8
+ if (!initialTheme && normalizedProps.storage === 'cookie') {
9
+ try {
10
+ const cookieStore = await cookies();
11
+ const storedTheme = cookieStore.get(getCookieStorageKey(normalizedProps.storageKey))?.value;
12
+ if (isValidTheme(storedTheme, normalizedProps.themes, normalizedProps.enableSystem)) {
13
+ initialTheme = storedTheme;
14
+ }
15
+ }
16
+ catch {
17
+ // Ignore missing request context and let the client resolve its own theme.
18
+ }
19
+ }
20
+ return _jsx(ClientThemeProvider, { ...props, initialTheme: initialTheme });
21
+ }
@@ -0,0 +1,2 @@
1
+ export declare function themeScript(attribute: 'class' | `data-${string}` | Array<'class' | `data-${string}`>, storageKey: string, defaultTheme: string, forcedTheme: string | undefined, themes: string[], value: Record<string, string> | undefined, enableSystem: boolean, enableColorScheme: boolean, storage: 'localStorage' | 'sessionStorage' | 'cookie' | 'none', initialTheme: string | undefined, disableTransitionOnChange: boolean): void;
2
+ //# sourceMappingURL=script.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"script.d.ts","sourceRoot":"","sources":["../../src/theme/script.ts"],"names":[],"mappings":"AAAA,wBAAgB,WAAW,CACzB,SAAS,EAAE,OAAO,GAAG,QAAQ,MAAM,EAAE,GAAG,KAAK,CAAC,OAAO,GAAG,QAAQ,MAAM,EAAE,CAAC,EACzE,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,MAAM,EAAE,MAAM,EAAE,EAChB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,EACzC,YAAY,EAAE,OAAO,EACrB,iBAAiB,EAAE,OAAO,EAC1B,OAAO,EAAE,cAAc,GAAG,gBAAgB,GAAG,QAAQ,GAAG,MAAM,EAC9D,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,yBAAyB,EAAE,OAAO,QAyHnC"}
@@ -0,0 +1,92 @@
1
+ export function themeScript(attribute, storageKey, defaultTheme, forcedTheme, themes, value, enableSystem, enableColorScheme, storage, initialTheme, disableTransitionOnChange) {
2
+ const root = document.documentElement;
3
+ const colorSchemes = ['light', 'dark'];
4
+ function resolveValue(theme) {
5
+ return value && value[theme] ? value[theme] : theme;
6
+ }
7
+ function getThemeTokens(themeValue) {
8
+ return themeValue.split(/\s+/).filter(Boolean);
9
+ }
10
+ function isValidTheme(theme) {
11
+ if (!theme) {
12
+ return false;
13
+ }
14
+ if (themes.includes(theme)) {
15
+ return true;
16
+ }
17
+ return enableSystem && theme === 'system';
18
+ }
19
+ function getCookieStorageKey() {
20
+ return encodeURIComponent(storageKey);
21
+ }
22
+ function readThemeFromCookie() {
23
+ const match = document.cookie.match(new RegExp(`(?:^|;\\s*)${getCookieStorageKey().replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}=([^;]*)`));
24
+ return match?.[1] != null ? decodeURIComponent(match[1]) : null;
25
+ }
26
+ function readStoredTheme() {
27
+ if (storage === 'none') {
28
+ return null;
29
+ }
30
+ if (storage === 'cookie') {
31
+ return readThemeFromCookie();
32
+ }
33
+ if (storage === 'sessionStorage') {
34
+ return sessionStorage.getItem(storageKey);
35
+ }
36
+ return localStorage.getItem(storageKey);
37
+ }
38
+ function disableTransitions() {
39
+ if (!disableTransitionOnChange) {
40
+ return;
41
+ }
42
+ const style = document.createElement('style');
43
+ style.textContent =
44
+ '*,*::before,*::after{-webkit-transition:none!important;-moz-transition:none!important;-o-transition:none!important;-ms-transition:none!important;transition:none!important}';
45
+ document.head.appendChild(style);
46
+ const scheduleFrame = typeof window.requestAnimationFrame === 'function'
47
+ ? window.requestAnimationFrame.bind(window)
48
+ : (callback) => window.setTimeout(() => callback(0), 0);
49
+ scheduleFrame(() => {
50
+ scheduleFrame(() => {
51
+ style.remove();
52
+ });
53
+ });
54
+ }
55
+ function applyTheme(theme) {
56
+ if (!theme) {
57
+ return;
58
+ }
59
+ disableTransitions();
60
+ const nextTheme = resolveValue(theme);
61
+ const attributes = Array.isArray(attribute) ? attribute : [attribute];
62
+ attributes.forEach((currentAttribute) => {
63
+ if (currentAttribute === 'class') {
64
+ const classes = themes.flatMap((currentTheme) => getThemeTokens(resolveValue(currentTheme)));
65
+ root.classList.remove(...classes);
66
+ root.classList.add(...getThemeTokens(nextTheme));
67
+ return;
68
+ }
69
+ root.setAttribute(currentAttribute, nextTheme);
70
+ });
71
+ if (enableColorScheme) {
72
+ const fallbackColorScheme = colorSchemes.includes(defaultTheme) ? defaultTheme : null;
73
+ const colorScheme = colorSchemes.includes(theme) ? theme : fallbackColorScheme;
74
+ root.style.colorScheme = colorScheme || '';
75
+ }
76
+ }
77
+ function getSystemTheme() {
78
+ return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
79
+ }
80
+ try {
81
+ const storedTheme = isValidTheme(initialTheme) ? initialTheme : readStoredTheme();
82
+ const selectedStoredTheme = isValidTheme(storedTheme ?? undefined) ? (storedTheme ?? defaultTheme) : defaultTheme;
83
+ const selectedTheme = forcedTheme || selectedStoredTheme;
84
+ const resolvedTheme = selectedTheme === 'system' && enableSystem ? getSystemTheme() : selectedTheme;
85
+ applyTheme(resolvedTheme);
86
+ }
87
+ catch {
88
+ const fallbackTheme = forcedTheme || defaultTheme;
89
+ const resolvedTheme = fallbackTheme === 'system' && enableSystem ? getSystemTheme() : fallbackTheme;
90
+ applyTheme(resolvedTheme);
91
+ }
92
+ }
@@ -0,0 +1,44 @@
1
+ import type { ThemeAttribute, ThemeProviderProps, ThemeStorage, ThemeValueMap } from './types';
2
+ export declare const DEFAULT_THEMES: string[];
3
+ export declare const DEFAULT_STORAGE_KEY = "theme";
4
+ export declare const DEFAULT_STORAGE: ThemeStorage;
5
+ export declare const MEDIA_QUERY = "(prefers-color-scheme: dark)";
6
+ type NormalizedThemeProviderProps = Omit<ThemeProviderProps, 'children'> & {
7
+ attribute: ThemeAttribute | ThemeAttribute[];
8
+ defaultTheme: string;
9
+ disableTransitionOnChange: boolean;
10
+ enableColorScheme: boolean;
11
+ enableSystem: boolean;
12
+ storage: ThemeStorage;
13
+ storageKey: string;
14
+ themes: string[];
15
+ };
16
+ type ApplyThemeOptions = Pick<NormalizedThemeProviderProps, 'attribute' | 'defaultTheme' | 'disableTransitionOnChange' | 'enableColorScheme' | 'themes' | 'value'> & {
17
+ resolvedTheme: string;
18
+ };
19
+ export declare function getCookieStorageKey(storageKey: string): string;
20
+ export declare function normalizeThemeProviderProps(props: ThemeProviderProps): NormalizedThemeProviderProps;
21
+ export declare function isValidTheme(theme: string | undefined, themes: string[], enableSystem: boolean): boolean;
22
+ export declare function getStoredTheme({ defaultTheme, enableSystem, storage, storageKey, themes, }: {
23
+ defaultTheme: string;
24
+ enableSystem: boolean;
25
+ storage: ThemeStorage;
26
+ storageKey: string;
27
+ themes: string[];
28
+ }): string;
29
+ export declare function saveTheme(storage: ThemeStorage, storageKey: string, value: string): void;
30
+ export declare function getServerThemeFromCookieString({ cookieString, defaultTheme, enableSystem, storageKey, themes, }: {
31
+ cookieString: string;
32
+ defaultTheme: string;
33
+ enableSystem: boolean;
34
+ storageKey: string;
35
+ themes: string[];
36
+ }): string;
37
+ export declare function getSystemTheme(mediaQueryList?: MediaQueryList | MediaQueryListEvent): "light" | "dark" | undefined;
38
+ export declare function resolveThemeValue(theme: string, value?: ThemeValueMap): string;
39
+ export declare function splitThemeValueTokens(themeValue: string): string[];
40
+ export declare function getThemeClassValues(themes: string[], value?: ThemeValueMap): string[];
41
+ export declare function resolveActiveTheme(theme: string | undefined, enableSystem: boolean, systemTheme?: string): string | undefined;
42
+ export declare function applyThemeToDocument({ attribute, defaultTheme, disableTransitionOnChange, enableColorScheme, resolvedTheme, themes, value, }: ApplyThemeOptions): void;
43
+ export {};
44
+ //# sourceMappingURL=shared.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/theme/shared.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,kBAAkB,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE/F,eAAO,MAAM,cAAc,UAAoB,CAAC;AAChD,eAAO,MAAM,mBAAmB,UAAU,CAAC;AAC3C,eAAO,MAAM,eAAe,EAAE,YAA6B,CAAC;AAC5D,eAAO,MAAM,WAAW,iCAAiC,CAAC;AAE1D,KAAK,4BAA4B,GAAG,IAAI,CAAC,kBAAkB,EAAE,UAAU,CAAC,GAAG;IACzE,SAAS,EAAE,cAAc,GAAG,cAAc,EAAE,CAAC;IAC7C,YAAY,EAAE,MAAM,CAAC;IACrB,yBAAyB,EAAE,OAAO,CAAC;IACnC,iBAAiB,EAAE,OAAO,CAAC;IAC3B,YAAY,EAAE,OAAO,CAAC;IACtB,OAAO,EAAE,YAAY,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC;AAEF,KAAK,iBAAiB,GAAG,IAAI,CAC3B,4BAA4B,EAC5B,WAAW,GAAG,cAAc,GAAG,2BAA2B,GAAG,mBAAmB,GAAG,QAAQ,GAAG,OAAO,CACtG,GAAG;IACF,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAIF,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,UAErD;AAED,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,kBAAkB,GAAG,4BAA4B,CAgCnG;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,YAAY,EAAE,OAAO,WAU9F;AAwBD,wBAAgB,cAAc,CAAC,EAC7B,YAAY,EACZ,YAAY,EACZ,OAAO,EACP,UAAU,EACV,MAAM,GACP,EAAE;IACD,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,OAAO,CAAC;IACtB,OAAO,EAAE,YAAY,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,UAYA;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAkBjF;AAED,wBAAgB,8BAA8B,CAAC,EAC7C,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,MAAM,GACP,EAAE;IACD,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,OAAO,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,UAIA;AAED,wBAAgB,cAAc,CAAC,cAAc,CAAC,EAAE,cAAc,GAAG,mBAAmB,gCAQnF;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,aAAa,UAErE;AAED,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,YAEvD;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,KAAK,CAAC,EAAE,aAAa,YAE1E;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,WAAW,CAAC,EAAE,MAAM,sBAUxG;AAED,wBAAgB,oBAAoB,CAAC,EACnC,SAAS,EACT,YAAY,EACZ,yBAAyB,EACzB,iBAAiB,EACjB,aAAa,EACb,MAAM,EACN,KAAK,GACN,EAAE,iBAAiB,QA6BnB"}
@@ -0,0 +1,153 @@
1
+ export const DEFAULT_THEMES = ['light', 'dark'];
2
+ export const DEFAULT_STORAGE_KEY = 'theme';
3
+ export const DEFAULT_STORAGE = 'localStorage';
4
+ export const MEDIA_QUERY = '(prefers-color-scheme: dark)';
5
+ const COLOR_SCHEMES = new Set(['light', 'dark']);
6
+ export function getCookieStorageKey(storageKey) {
7
+ return encodeURIComponent(storageKey);
8
+ }
9
+ export function normalizeThemeProviderProps(props) {
10
+ const { attribute = 'data-theme', defaultTheme, disableTransitionOnChange = false, enableColorScheme = true, enableSystem = true, forcedTheme, initialTheme, nonce, scriptProps, storage = DEFAULT_STORAGE, storageKey = DEFAULT_STORAGE_KEY, themes = DEFAULT_THEMES, value, } = props;
11
+ return {
12
+ attribute,
13
+ defaultTheme: defaultTheme ?? (enableSystem ? 'system' : 'light'),
14
+ disableTransitionOnChange,
15
+ enableColorScheme,
16
+ enableSystem,
17
+ forcedTheme,
18
+ initialTheme,
19
+ nonce,
20
+ scriptProps,
21
+ storage,
22
+ storageKey,
23
+ themes,
24
+ value,
25
+ };
26
+ }
27
+ export function isValidTheme(theme, themes, enableSystem) {
28
+ if (!theme) {
29
+ return false;
30
+ }
31
+ if (themes.includes(theme)) {
32
+ return true;
33
+ }
34
+ return enableSystem && theme === 'system';
35
+ }
36
+ function readThemeFromCookieString(cookieString, storageKey) {
37
+ const match = cookieString.match(new RegExp(`(?:^|;\\s*)${escapeRegExp(getCookieStorageKey(storageKey))}=([^;]*)`));
38
+ return match?.[1] != null ? decodeURIComponent(match[1]) : null;
39
+ }
40
+ function readThemeFromStorageArea(storage, storageKey) {
41
+ if (typeof window === 'undefined') {
42
+ return null;
43
+ }
44
+ if (storage === 'cookie') {
45
+ return readThemeFromCookieString(document.cookie, storageKey);
46
+ }
47
+ if (storage === 'sessionStorage') {
48
+ return sessionStorage.getItem(storageKey);
49
+ }
50
+ return localStorage.getItem(storageKey);
51
+ }
52
+ export function getStoredTheme({ defaultTheme, enableSystem, storage, storageKey, themes, }) {
53
+ if (typeof window === 'undefined' || storage === 'none') {
54
+ return defaultTheme;
55
+ }
56
+ try {
57
+ const storedTheme = readThemeFromStorageArea(storage, storageKey);
58
+ return isValidTheme(storedTheme ?? undefined, themes, enableSystem) ? (storedTheme ?? defaultTheme) : defaultTheme;
59
+ }
60
+ catch {
61
+ return defaultTheme;
62
+ }
63
+ }
64
+ export function saveTheme(storage, storageKey, value) {
65
+ try {
66
+ if (storage === 'none') {
67
+ return;
68
+ }
69
+ if (storage === 'cookie') {
70
+ const secureAttribute = typeof location !== 'undefined' && location.protocol === 'https:' ? '; Secure' : '';
71
+ document.cookie = `${getCookieStorageKey(storageKey)}=${encodeURIComponent(value)}; path=/; max-age=31536000; SameSite=Lax${secureAttribute}`;
72
+ return;
73
+ }
74
+ const storageArea = storage === 'sessionStorage' ? sessionStorage : localStorage;
75
+ storageArea.setItem(storageKey, value);
76
+ }
77
+ catch {
78
+ // Ignore storage failures in unsupported or restricted environments.
79
+ }
80
+ }
81
+ export function getServerThemeFromCookieString({ cookieString, defaultTheme, enableSystem, storageKey, themes, }) {
82
+ const storedTheme = readThemeFromCookieString(cookieString, storageKey);
83
+ return isValidTheme(storedTheme ?? undefined, themes, enableSystem) ? (storedTheme ?? defaultTheme) : defaultTheme;
84
+ }
85
+ export function getSystemTheme(mediaQueryList) {
86
+ if (typeof window === 'undefined') {
87
+ return undefined;
88
+ }
89
+ const query = mediaQueryList ?? window.matchMedia(MEDIA_QUERY);
90
+ return query.matches ? 'dark' : 'light';
91
+ }
92
+ export function resolveThemeValue(theme, value) {
93
+ return value?.[theme] ?? theme;
94
+ }
95
+ export function splitThemeValueTokens(themeValue) {
96
+ return themeValue.split(/\s+/).filter(Boolean);
97
+ }
98
+ export function getThemeClassValues(themes, value) {
99
+ return themes.flatMap((theme) => splitThemeValueTokens(resolveThemeValue(theme, value)));
100
+ }
101
+ export function resolveActiveTheme(theme, enableSystem, systemTheme) {
102
+ if (!theme) {
103
+ return undefined;
104
+ }
105
+ if (theme === 'system' && enableSystem) {
106
+ return systemTheme ?? 'light';
107
+ }
108
+ return theme;
109
+ }
110
+ export function applyThemeToDocument({ attribute, defaultTheme, disableTransitionOnChange, enableColorScheme, resolvedTheme, themes, value, }) {
111
+ if (typeof document === 'undefined' || !resolvedTheme) {
112
+ return;
113
+ }
114
+ const cleanupTransitions = disableTransitionOnChange ? disableTransitions() : null;
115
+ const root = document.documentElement;
116
+ const nextValue = resolveThemeValue(resolvedTheme, value);
117
+ const attributes = Array.isArray(attribute) ? attribute : [attribute];
118
+ attributes.forEach((currentAttribute) => {
119
+ if (currentAttribute === 'class') {
120
+ root.classList.remove(...getThemeClassValues(themes, value));
121
+ root.classList.add(...splitThemeValueTokens(nextValue));
122
+ return;
123
+ }
124
+ root.setAttribute(currentAttribute, nextValue);
125
+ });
126
+ if (enableColorScheme) {
127
+ const fallbackColorScheme = COLOR_SCHEMES.has(defaultTheme) ? defaultTheme : null;
128
+ const colorScheme = COLOR_SCHEMES.has(resolvedTheme) ? resolvedTheme : fallbackColorScheme;
129
+ root.style.colorScheme = colorScheme ?? '';
130
+ }
131
+ cleanupTransitions?.();
132
+ }
133
+ function disableTransitions() {
134
+ if (typeof document === 'undefined') {
135
+ return undefined;
136
+ }
137
+ const style = document.createElement('style');
138
+ style.appendChild(document.createTextNode('*,*::before,*::after{-webkit-transition:none!important;-moz-transition:none!important;-o-transition:none!important;-ms-transition:none!important;transition:none!important}'));
139
+ document.head.appendChild(style);
140
+ return () => {
141
+ const scheduleFrame = typeof window.requestAnimationFrame === 'function'
142
+ ? window.requestAnimationFrame.bind(window)
143
+ : (callback) => window.setTimeout(() => callback(0), 0);
144
+ scheduleFrame(() => {
145
+ scheduleFrame(() => {
146
+ style.remove();
147
+ });
148
+ });
149
+ };
150
+ }
151
+ function escapeRegExp(value) {
152
+ return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
153
+ }
@@ -0,0 +1,13 @@
1
+ export interface ThemeState {
2
+ theme?: string;
3
+ systemTheme?: 'light' | 'dark';
4
+ }
5
+ export interface ThemeStore {
6
+ subscribe(listener: () => void): () => void;
7
+ getSnapshot(): ThemeState;
8
+ getServerSnapshot(): ThemeState;
9
+ setTheme(theme: string | undefined): void;
10
+ setSystemTheme(systemTheme: 'light' | 'dark' | undefined): void;
11
+ }
12
+ export declare function createThemeStore(initialState?: ThemeState): ThemeStore;
13
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/theme/store.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC;IAC5C,WAAW,IAAI,UAAU,CAAC;IAC1B,iBAAiB,IAAI,UAAU,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC;IAC1C,cAAc,CAAC,WAAW,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC;CACjE;AAOD,wBAAgB,gBAAgB,CAAC,YAAY,GAAE,UAA4B,GAAG,UAAU,CA+CvF"}
@@ -0,0 +1,47 @@
1
+ const SERVER_SNAPSHOT = {
2
+ systemTheme: undefined,
3
+ theme: undefined,
4
+ };
5
+ export function createThemeStore(initialState = SERVER_SNAPSHOT) {
6
+ let state = initialState;
7
+ const listeners = new Set();
8
+ const emit = () => {
9
+ for (const listener of listeners) {
10
+ listener();
11
+ }
12
+ };
13
+ return {
14
+ subscribe(listener) {
15
+ listeners.add(listener);
16
+ return () => {
17
+ listeners.delete(listener);
18
+ };
19
+ },
20
+ getSnapshot() {
21
+ return state;
22
+ },
23
+ getServerSnapshot() {
24
+ return SERVER_SNAPSHOT;
25
+ },
26
+ setTheme(theme) {
27
+ if (state.theme === theme) {
28
+ return;
29
+ }
30
+ state = {
31
+ ...state,
32
+ theme,
33
+ };
34
+ emit();
35
+ },
36
+ setSystemTheme(systemTheme) {
37
+ if (state.systemTheme === systemTheme) {
38
+ return;
39
+ }
40
+ state = {
41
+ ...state,
42
+ systemTheme,
43
+ };
44
+ emit();
45
+ },
46
+ };
47
+ }
@@ -0,0 +1,5 @@
1
+ import { useTheme } from './context';
2
+ import type { ThemeProviderProps } from './types';
3
+ export { useTheme };
4
+ export declare function ThemeProvider(props: ThemeProviderProps): import("react/jsx-runtime").JSX.Element;
5
+ //# sourceMappingURL=theme-provider.client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme-provider.client.d.ts","sourceRoot":"","sources":["../../src/theme/theme-provider.client.tsx"],"names":[],"mappings":"AAMA,OAAO,EAAgB,QAAQ,EAAE,MAAM,WAAW,CAAC;AAanD,OAAO,KAAK,EAAE,kBAAkB,EAAiB,MAAM,SAAS,CAAC;AAEjE,OAAO,EAAE,QAAQ,EAAE,CAAC;AAEpB,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,2CAQtD"}
@@ -0,0 +1,130 @@
1
+ 'use client';
2
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
3
+ import * as React from 'react';
4
+ import { useServerInsertedHTML } from 'next/navigation';
5
+ import { ThemeContext, useTheme } from './context';
6
+ import { MEDIA_QUERY, applyThemeToDocument, getStoredTheme, getSystemTheme, isValidTheme, normalizeThemeProviderProps, resolveActiveTheme, saveTheme, } from './shared';
7
+ import { createThemeStore } from './store';
8
+ import { ThemeScript } from './theme-script';
9
+ export { useTheme };
10
+ export function ThemeProvider(props) {
11
+ const context = React.useContext(ThemeContext);
12
+ if (context) {
13
+ return _jsx(_Fragment, { children: props.children });
14
+ }
15
+ return _jsx(ThemeProviderInner, { ...props });
16
+ }
17
+ function ThemeProviderInner(props) {
18
+ const { attribute, defaultTheme, disableTransitionOnChange, enableColorScheme, enableSystem, forcedTheme, initialTheme, nonce, scriptProps, storage, storageKey, themes, value, } = normalizeThemeProviderProps(props);
19
+ useServerInsertedHTML(() => (_jsx(ThemeScript, { attribute: attribute, defaultTheme: defaultTheme, disableTransitionOnChange: disableTransitionOnChange, enableColorScheme: enableColorScheme, enableSystem: enableSystem, forcedTheme: forcedTheme, initialTheme: initialTheme, nonce: nonce, scriptProps: scriptProps, storage: storage, storageKey: storageKey, themes: themes, value: value })));
20
+ const storeRef = React.useRef(createThemeStore({
21
+ systemTheme: getSystemTheme(),
22
+ theme: isValidTheme(initialTheme, themes, enableSystem)
23
+ ? initialTheme
24
+ : getStoredTheme({
25
+ defaultTheme,
26
+ enableSystem,
27
+ storage,
28
+ storageKey,
29
+ themes,
30
+ }),
31
+ }));
32
+ const store = storeRef.current;
33
+ const { systemTheme, theme } = React.useSyncExternalStore(store.subscribe, store.getSnapshot, store.getServerSnapshot);
34
+ const applyResolvedTheme = React.useCallback((selectedTheme) => {
35
+ const resolvedTheme = resolveActiveTheme(selectedTheme, enableSystem, store.getSnapshot().systemTheme);
36
+ if (!resolvedTheme) {
37
+ return;
38
+ }
39
+ applyThemeToDocument({
40
+ attribute,
41
+ defaultTheme,
42
+ disableTransitionOnChange,
43
+ enableColorScheme,
44
+ resolvedTheme,
45
+ themes,
46
+ value,
47
+ });
48
+ }, [attribute, defaultTheme, disableTransitionOnChange, enableColorScheme, enableSystem, store, themes, value]);
49
+ const setTheme = React.useCallback((nextTheme) => {
50
+ if (forcedTheme) {
51
+ return;
52
+ }
53
+ const currentTheme = store.getSnapshot().theme ?? defaultTheme;
54
+ const selectedTheme = typeof nextTheme === 'function' ? nextTheme(currentTheme) : nextTheme;
55
+ store.setTheme(selectedTheme);
56
+ saveTheme(storage, storageKey, selectedTheme);
57
+ }, [defaultTheme, forcedTheme, storage, storageKey, store]);
58
+ React.useEffect(() => {
59
+ const mediaQueryList = window.matchMedia(MEDIA_QUERY);
60
+ const handleMediaQueryChange = (event) => {
61
+ store.setSystemTheme(getSystemTheme(event));
62
+ };
63
+ if (typeof mediaQueryList.addEventListener === 'function') {
64
+ mediaQueryList.addEventListener('change', handleMediaQueryChange);
65
+ }
66
+ else {
67
+ mediaQueryList.addListener(handleMediaQueryChange);
68
+ }
69
+ handleMediaQueryChange(mediaQueryList);
70
+ return () => {
71
+ if (typeof mediaQueryList.removeEventListener === 'function') {
72
+ mediaQueryList.removeEventListener('change', handleMediaQueryChange);
73
+ }
74
+ else {
75
+ mediaQueryList.removeListener(handleMediaQueryChange);
76
+ }
77
+ };
78
+ }, [store]);
79
+ React.useEffect(() => {
80
+ if (initialTheme && isValidTheme(initialTheme, themes, enableSystem)) {
81
+ store.setTheme(initialTheme);
82
+ saveTheme(storage, storageKey, initialTheme);
83
+ return;
84
+ }
85
+ const nextTheme = getStoredTheme({
86
+ defaultTheme,
87
+ enableSystem,
88
+ storage,
89
+ storageKey,
90
+ themes,
91
+ });
92
+ store.setTheme(nextTheme);
93
+ }, [defaultTheme, enableSystem, initialTheme, storage, storageKey, store, themes]);
94
+ React.useEffect(() => {
95
+ if (storage !== 'localStorage') {
96
+ return;
97
+ }
98
+ const handleStorage = (event) => {
99
+ if (event.key !== storageKey) {
100
+ return;
101
+ }
102
+ if (event.storageArea && event.storageArea !== localStorage) {
103
+ return;
104
+ }
105
+ if (!event.newValue) {
106
+ store.setTheme(defaultTheme);
107
+ return;
108
+ }
109
+ if (!isValidTheme(event.newValue, themes, enableSystem)) {
110
+ store.setTheme(defaultTheme);
111
+ return;
112
+ }
113
+ store.setTheme(event.newValue);
114
+ };
115
+ window.addEventListener('storage', handleStorage);
116
+ return () => window.removeEventListener('storage', handleStorage);
117
+ }, [defaultTheme, enableSystem, storage, storageKey, store, themes]);
118
+ React.useEffect(() => {
119
+ applyResolvedTheme(forcedTheme ?? theme);
120
+ }, [applyResolvedTheme, forcedTheme, theme]);
121
+ const contextValue = React.useMemo(() => ({
122
+ forcedTheme,
123
+ resolvedTheme: theme === 'system' ? systemTheme : theme,
124
+ setTheme,
125
+ systemTheme: enableSystem ? systemTheme : undefined,
126
+ theme,
127
+ themes: enableSystem ? [...themes, 'system'] : themes,
128
+ }), [enableSystem, forcedTheme, setTheme, systemTheme, theme, themes]);
129
+ return _jsx(ThemeContext.Provider, { value: contextValue, children: props.children });
130
+ }
@@ -0,0 +1,3 @@
1
+ import type { ThemeProviderProps } from './types';
2
+ export declare function ThemeScript(props: Omit<ThemeProviderProps, 'children'>): import("react/jsx-runtime").JSX.Element;
3
+ //# sourceMappingURL=theme-script.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme-script.d.ts","sourceRoot":"","sources":["../../src/theme/theme-script.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAElD,wBAAgB,WAAW,CAAC,KAAK,EAAE,IAAI,CAAC,kBAAkB,EAAE,UAAU,CAAC,2CAyCtE"}
@@ -0,0 +1,22 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { themeScript } from './script';
3
+ import { normalizeThemeProviderProps } from './shared';
4
+ export function ThemeScript(props) {
5
+ const { attribute, defaultTheme, disableTransitionOnChange, enableColorScheme, enableSystem, forcedTheme, initialTheme, nonce, scriptProps, storage, storageKey, themes, value, } = normalizeThemeProviderProps(props);
6
+ const scriptArguments = JSON.stringify([
7
+ attribute,
8
+ storageKey,
9
+ defaultTheme,
10
+ forcedTheme,
11
+ themes,
12
+ value,
13
+ enableSystem,
14
+ enableColorScheme,
15
+ storage,
16
+ initialTheme,
17
+ disableTransitionOnChange,
18
+ ]).slice(1, -1);
19
+ return (_jsx("script", { ...scriptProps, suppressHydrationWarning: true, nonce: nonce, dangerouslySetInnerHTML: {
20
+ __html: `(${themeScript.toString()})(${scriptArguments})`,
21
+ } }));
22
+ }
@@ -0,0 +1,32 @@
1
+ import type * as React from 'react';
2
+ export type ThemeAttribute = 'class' | `data-${string}`;
3
+ export type ThemeValueMap = Record<string, string>;
4
+ export type ThemeStorage = 'localStorage' | 'sessionStorage' | 'cookie' | 'none';
5
+ export interface ThemeScriptProps extends React.DetailedHTMLProps<React.ScriptHTMLAttributes<HTMLScriptElement>, HTMLScriptElement> {
6
+ [dataAttribute: `data-${string}`]: unknown;
7
+ }
8
+ export type SetThemeValue = React.SetStateAction<string>;
9
+ export interface UseThemeProps {
10
+ themes: string[];
11
+ forcedTheme?: string;
12
+ setTheme: React.Dispatch<SetThemeValue>;
13
+ theme?: string;
14
+ resolvedTheme?: string;
15
+ systemTheme?: 'light' | 'dark';
16
+ }
17
+ export interface ThemeProviderProps extends React.PropsWithChildren {
18
+ themes?: string[];
19
+ forcedTheme?: string;
20
+ enableSystem?: boolean;
21
+ disableTransitionOnChange?: boolean;
22
+ enableColorScheme?: boolean;
23
+ storageKey?: string;
24
+ defaultTheme?: string;
25
+ attribute?: ThemeAttribute | ThemeAttribute[];
26
+ value?: ThemeValueMap;
27
+ storage?: ThemeStorage;
28
+ initialTheme?: string;
29
+ nonce?: string;
30
+ scriptProps?: ThemeScriptProps;
31
+ }
32
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/theme/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AAEpC,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,QAAQ,MAAM,EAAE,CAAC;AAExD,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACnD,MAAM,MAAM,YAAY,GAAG,cAAc,GAAG,gBAAgB,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEjF,MAAM,WAAW,gBAAiB,SAAQ,KAAK,CAAC,iBAAiB,CAC/D,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAC7C,iBAAiB,CAClB;IACC,CAAC,aAAa,EAAE,QAAQ,MAAM,EAAE,GAAG,OAAO,CAAC;CAC5C;AAED,MAAM,MAAM,aAAa,GAAG,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;AAEzD,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,kBAAmB,SAAQ,KAAK,CAAC,iBAAiB;IACjE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,cAAc,GAAG,cAAc,EAAE,CAAC;IAC9C,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,gBAAgB,CAAC;CAChC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -1,3 +1,5 @@
1
+ /// <reference types="next" />
2
+
1
3
  /**
2
4
  * This file contains global type definitions for the package.
3
5
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@korioinc/next-core",
3
- "version": "2.0.31",
3
+ "version": "2.0.34",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "./ads": {
@@ -53,6 +53,16 @@
53
53
  "import": "./dist/components/index.js",
54
54
  "default": "./dist/components/index.js"
55
55
  },
56
+ "./theme": {
57
+ "types": "./dist/theme/index.d.ts",
58
+ "import": "./dist/theme/index.js",
59
+ "default": "./dist/theme/index.js"
60
+ },
61
+ "./theme/server": {
62
+ "types": "./dist/theme/index.server.d.ts",
63
+ "import": "./dist/theme/index.server.js",
64
+ "default": "./dist/theme/index.server.js"
65
+ },
56
66
  "./styles/*": "./dist/styles/*",
57
67
  "./types/*": "./dist/types/*"
58
68
  },
@@ -63,24 +73,24 @@
63
73
  ],
64
74
  "devDependencies": {
65
75
  "@headlessui/react": "^2.2.9",
66
- "@lingui/conf": "^5.9.3",
67
- "@lingui/core": "^5.9.3",
68
- "@lingui/react": "^5.9.3",
76
+ "@lingui/conf": "^5.9.4",
77
+ "@lingui/core": "^5.9.4",
78
+ "@lingui/react": "^5.9.4",
69
79
  "@tailwindcss/typography": "^0.5.19",
70
80
  "@types/negotiator": "^0.6.4",
71
81
  "@types/node": "^25.5.0",
72
82
  "@types/react": "^19.2.14",
73
83
  "@types/react-dom": "^19.2.3",
74
84
  "eslint": "^10.1.0",
75
- "next-themes": "^0.4.6",
85
+ "jsdom": "^29.0.1",
76
86
  "react": "^19.2.4",
77
87
  "react-dom": "^19.2.4",
78
88
  "tailwindcss": "^4.2.2",
79
89
  "tsc-alias": "^1.8.16",
80
90
  "tw-animate-css": "^1.4.0",
81
- "typescript": "^5.9.3",
91
+ "typescript": "^6.0.2",
82
92
  "vitest": "^4.1.2",
83
- "@korioinc/next-configs": "2.0.31"
93
+ "@korioinc/next-configs": "2.0.34"
84
94
  },
85
95
  "dependencies": {
86
96
  "@floating-ui/react": "^0.27.19",
@@ -95,7 +105,7 @@
95
105
  "schema-dts": "^2.0.0",
96
106
  "tailwind-merge": "^3.5.0",
97
107
  "valtio": "^2.3.1",
98
- "@korioinc/next-conf": "2.0.31"
108
+ "@korioinc/next-conf": "2.0.34"
99
109
  },
100
110
  "publishConfig": {
101
111
  "access": "public",
@@ -109,10 +119,9 @@
109
119
  "author": "Korio Inc.",
110
120
  "peerDependencies": {
111
121
  "@headlessui/react": ">=2.2.0",
112
- "@lingui/core": ">=5.9.3",
113
- "@lingui/react": ">=5.9.3",
114
- "next": ">=16.1.5",
115
- "next-themes": ">=0.4.6",
122
+ "@lingui/core": ">=5.9.4",
123
+ "@lingui/react": ">=5.9.4",
124
+ "next": ">=16.2.1",
116
125
  "react": ">=19.2.4",
117
126
  "react-dom": ">=19.2.4",
118
127
  "tailwindcss": ">=4.0.0"