@vlian/framework 1.2.51 → 1.2.55
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/analytics.umd.js +1 -1
- package/dist/index.umd.js +222 -65
- package/dist/index.umd.js.map +1 -1
- package/dist/kernel/kernel.cjs +2 -1
- package/dist/kernel/kernel.cjs.map +1 -1
- package/dist/kernel/kernel.js +2 -1
- package/dist/kernel/kernel.js.map +1 -1
- package/dist/kernel/manager/cacheManager.cjs +8 -6
- package/dist/kernel/manager/cacheManager.cjs.map +1 -1
- package/dist/kernel/manager/cacheManager.d.ts +3 -0
- package/dist/kernel/manager/cacheManager.js +8 -6
- package/dist/kernel/manager/cacheManager.js.map +1 -1
- package/dist/kernel/manager/theme/ThemeManager.cjs +86 -0
- package/dist/kernel/manager/theme/ThemeManager.cjs.map +1 -0
- package/dist/kernel/manager/theme/ThemeManager.d.ts +16 -0
- package/dist/kernel/manager/theme/ThemeManager.js +76 -0
- package/dist/kernel/manager/theme/ThemeManager.js.map +1 -0
- package/dist/kernel/manager/theme/index.cjs +13 -0
- package/dist/kernel/manager/theme/index.cjs.map +1 -0
- package/dist/kernel/manager/theme/index.d.ts +1 -0
- package/dist/kernel/manager/theme/index.js +3 -0
- package/dist/kernel/manager/theme/index.js.map +1 -0
- package/dist/kernel/manager/theme/theme.dom.cjs +63 -0
- package/dist/kernel/manager/theme/theme.dom.cjs.map +1 -0
- package/dist/kernel/manager/theme/theme.dom.d.ts +3 -0
- package/dist/kernel/manager/theme/theme.dom.js +45 -0
- package/dist/kernel/manager/theme/theme.dom.js.map +1 -0
- package/dist/kernel/manager/theme/theme.persistence.cjs +59 -0
- package/dist/kernel/manager/theme/theme.persistence.cjs.map +1 -0
- package/dist/kernel/manager/theme/theme.persistence.d.ts +5 -0
- package/dist/kernel/manager/theme/theme.persistence.js +38 -0
- package/dist/kernel/manager/theme/theme.persistence.js.map +1 -0
- package/dist/kernel/manager/theme/theme.schema.cjs +124 -0
- package/dist/kernel/manager/theme/theme.schema.cjs.map +1 -0
- package/dist/kernel/manager/theme/theme.schema.d.ts +7 -0
- package/dist/kernel/manager/theme/theme.schema.js +97 -0
- package/dist/kernel/manager/theme/theme.schema.js.map +1 -0
- package/dist/kernel/manager/themeManager.cjs +2 -95
- package/dist/kernel/manager/themeManager.cjs.map +1 -1
- package/dist/kernel/manager/themeManager.d.ts +1 -14
- package/dist/kernel/manager/themeManager.js +1 -94
- package/dist/kernel/manager/themeManager.js.map +1 -1
- package/dist/kernel/types.d.ts +2 -0
- package/dist/kernel/types.js.map +1 -1
- package/dist/state.umd.js +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
function canUseDom() {
|
|
2
|
+
return typeof document !== 'undefined';
|
|
3
|
+
}
|
|
4
|
+
export function resolveThemeMode(theme) {
|
|
5
|
+
if (theme.mode !== 'system') {
|
|
6
|
+
return theme.mode;
|
|
7
|
+
}
|
|
8
|
+
if (typeof window !== 'undefined' && window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
|
9
|
+
return 'dark';
|
|
10
|
+
}
|
|
11
|
+
return 'light';
|
|
12
|
+
}
|
|
13
|
+
export function applyThemeToDocument(nextTheme, prevTheme) {
|
|
14
|
+
if (!canUseDom()) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const root = document.documentElement;
|
|
18
|
+
const nextMode = resolveThemeMode(nextTheme);
|
|
19
|
+
const prevMode = prevTheme ? resolveThemeMode(prevTheme) : undefined;
|
|
20
|
+
if (!prevMode || prevMode !== nextMode) {
|
|
21
|
+
root.classList.remove('light', 'dark');
|
|
22
|
+
root.classList.add(nextMode);
|
|
23
|
+
}
|
|
24
|
+
if (!prevTheme || prevTheme.primaryColor !== nextTheme.primaryColor) {
|
|
25
|
+
if (nextTheme.primaryColor) {
|
|
26
|
+
root.style.setProperty('--app-primary-color', nextTheme.primaryColor);
|
|
27
|
+
} else {
|
|
28
|
+
root.style.removeProperty('--app-primary-color');
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const prevTokens = prevTheme?.tokens || {};
|
|
32
|
+
const nextTokens = nextTheme.tokens || {};
|
|
33
|
+
for (const token of Object.keys(prevTokens)){
|
|
34
|
+
if (!(token in nextTokens)) {
|
|
35
|
+
root.style.removeProperty(`--${token}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
for (const [token, value] of Object.entries(nextTokens)){
|
|
39
|
+
if (!prevTheme || prevTokens[token] !== value) {
|
|
40
|
+
root.style.setProperty(`--${token}`, String(value));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
//# sourceMappingURL=theme.dom.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/kernel/manager/theme/theme.dom.ts"],"sourcesContent":["import type { ThemeSnapshot } from '../../types';\n\nfunction canUseDom(): boolean {\n return typeof document !== 'undefined';\n}\n\nexport function resolveThemeMode(theme: ThemeSnapshot): 'light' | 'dark' {\n if (theme.mode !== 'system') {\n return theme.mode;\n }\n\n if (typeof window !== 'undefined' && window.matchMedia('(prefers-color-scheme: dark)').matches) {\n return 'dark';\n }\n\n return 'light';\n}\n\nexport function applyThemeToDocument(nextTheme: ThemeSnapshot, prevTheme?: ThemeSnapshot): void {\n if (!canUseDom()) {\n return;\n }\n\n const root = document.documentElement;\n const nextMode = resolveThemeMode(nextTheme);\n const prevMode = prevTheme ? resolveThemeMode(prevTheme) : undefined;\n\n if (!prevMode || prevMode !== nextMode) {\n root.classList.remove('light', 'dark');\n root.classList.add(nextMode);\n }\n\n if (!prevTheme || prevTheme.primaryColor !== nextTheme.primaryColor) {\n if (nextTheme.primaryColor) {\n root.style.setProperty('--app-primary-color', nextTheme.primaryColor);\n } else {\n root.style.removeProperty('--app-primary-color');\n }\n }\n\n const prevTokens = prevTheme?.tokens || {};\n const nextTokens = nextTheme.tokens || {};\n\n for (const token of Object.keys(prevTokens)) {\n if (!(token in nextTokens)) {\n root.style.removeProperty(`--${token}`);\n }\n }\n\n for (const [token, value] of Object.entries(nextTokens)) {\n if (!prevTheme || prevTokens[token] !== value) {\n root.style.setProperty(`--${token}`, String(value));\n }\n }\n}\n"],"names":["canUseDom","document","resolveThemeMode","theme","mode","window","matchMedia","matches","applyThemeToDocument","nextTheme","prevTheme","root","documentElement","nextMode","prevMode","undefined","classList","remove","add","primaryColor","style","setProperty","removeProperty","prevTokens","tokens","nextTokens","token","Object","keys","value","entries","String"],"mappings":"AAEA,SAASA;IACP,OAAO,OAAOC,aAAa;AAC7B;AAEA,OAAO,SAASC,iBAAiBC,KAAoB;IACnD,IAAIA,MAAMC,IAAI,KAAK,UAAU;QAC3B,OAAOD,MAAMC,IAAI;IACnB;IAEA,IAAI,OAAOC,WAAW,eAAeA,OAAOC,UAAU,CAAC,gCAAgCC,OAAO,EAAE;QAC9F,OAAO;IACT;IAEA,OAAO;AACT;AAEA,OAAO,SAASC,qBAAqBC,SAAwB,EAAEC,SAAyB;IACtF,IAAI,CAACV,aAAa;QAChB;IACF;IAEA,MAAMW,OAAOV,SAASW,eAAe;IACrC,MAAMC,WAAWX,iBAAiBO;IAClC,MAAMK,WAAWJ,YAAYR,iBAAiBQ,aAAaK;IAE3D,IAAI,CAACD,YAAYA,aAAaD,UAAU;QACtCF,KAAKK,SAAS,CAACC,MAAM,CAAC,SAAS;QAC/BN,KAAKK,SAAS,CAACE,GAAG,CAACL;IACrB;IAEA,IAAI,CAACH,aAAaA,UAAUS,YAAY,KAAKV,UAAUU,YAAY,EAAE;QACnE,IAAIV,UAAUU,YAAY,EAAE;YAC1BR,KAAKS,KAAK,CAACC,WAAW,CAAC,uBAAuBZ,UAAUU,YAAY;QACtE,OAAO;YACLR,KAAKS,KAAK,CAACE,cAAc,CAAC;QAC5B;IACF;IAEA,MAAMC,aAAab,WAAWc,UAAU,CAAC;IACzC,MAAMC,aAAahB,UAAUe,MAAM,IAAI,CAAC;IAExC,KAAK,MAAME,SAASC,OAAOC,IAAI,CAACL,YAAa;QAC3C,IAAI,CAAEG,CAAAA,SAASD,UAAS,GAAI;YAC1Bd,KAAKS,KAAK,CAACE,cAAc,CAAC,CAAC,EAAE,EAAEI,OAAO;QACxC;IACF;IAEA,KAAK,MAAM,CAACA,OAAOG,MAAM,IAAIF,OAAOG,OAAO,CAACL,YAAa;QACvD,IAAI,CAACf,aAAaa,UAAU,CAACG,MAAM,KAAKG,OAAO;YAC7ClB,KAAKS,KAAK,CAACC,WAAW,CAAC,CAAC,EAAE,EAAEK,OAAO,EAAEK,OAAOF;QAC9C;IACF;AACF"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
function _export(target, all) {
|
|
6
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: Object.getOwnPropertyDescriptor(all, name).get
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
_export(exports, {
|
|
12
|
+
get DEFAULT_THEME_CACHE_KEY () {
|
|
13
|
+
return DEFAULT_THEME_CACHE_KEY;
|
|
14
|
+
},
|
|
15
|
+
get loadThemeFromCache () {
|
|
16
|
+
return loadThemeFromCache;
|
|
17
|
+
},
|
|
18
|
+
get saveThemeToCache () {
|
|
19
|
+
return saveThemeToCache;
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
const _themeschema = require("./theme.schema");
|
|
23
|
+
const DEFAULT_THEME_CACHE_KEY = 'vlian:kernel:theme';
|
|
24
|
+
function resolvePersistenceContext(persistence) {
|
|
25
|
+
if (persistence?.enabled !== true) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
key: persistence.key || DEFAULT_THEME_CACHE_KEY
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
async function loadThemeFromCache(cacheManager, persistence, fallback) {
|
|
33
|
+
const persistenceContext = resolvePersistenceContext(persistence);
|
|
34
|
+
const safeFallback = (0, _themeschema.cloneTheme)(fallback);
|
|
35
|
+
if (!persistenceContext) {
|
|
36
|
+
return safeFallback;
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
const cached = await cacheManager.get(persistenceContext.key, {
|
|
40
|
+
defaultValue: safeFallback
|
|
41
|
+
});
|
|
42
|
+
return (0, _themeschema.normalizeTheme)(cached, safeFallback);
|
|
43
|
+
} catch {
|
|
44
|
+
return safeFallback;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async function saveThemeToCache(cacheManager, persistence, theme) {
|
|
48
|
+
const persistenceContext = resolvePersistenceContext(persistence);
|
|
49
|
+
if (!persistenceContext) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
await cacheManager.set(persistenceContext.key, (0, _themeschema.cloneTheme)(theme));
|
|
54
|
+
} catch {
|
|
55
|
+
// Ignore persistence failures and keep theme updates in memory.
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
//# sourceMappingURL=theme.persistence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/kernel/manager/theme/theme.persistence.ts"],"sourcesContent":["import type { StorageInstance } from '@vlian/utils';\nimport type { PersistenceOptions, ThemeSnapshot } from '../../types';\nimport { cloneTheme, normalizeTheme } from './theme.schema';\n\nexport const DEFAULT_THEME_CACHE_KEY = 'vlian:kernel:theme';\n\ntype ResolvedPersistenceContext = {\n key: string;\n};\n\nfunction resolvePersistenceContext(\n persistence: PersistenceOptions | undefined\n): ResolvedPersistenceContext | null {\n if (persistence?.enabled !== true) {\n return null;\n }\n\n return {\n key: persistence.key || DEFAULT_THEME_CACHE_KEY,\n };\n}\n\nexport async function loadThemeFromCache(\n cacheManager: StorageInstance,\n persistence: PersistenceOptions | undefined,\n fallback: ThemeSnapshot\n): Promise<ThemeSnapshot> {\n const persistenceContext = resolvePersistenceContext(persistence);\n const safeFallback = cloneTheme(fallback);\n\n if (!persistenceContext) {\n return safeFallback;\n }\n\n try {\n const cached = await cacheManager.get<ThemeSnapshot>(persistenceContext.key, {\n defaultValue: safeFallback,\n });\n return normalizeTheme(cached, safeFallback);\n } catch {\n return safeFallback;\n }\n}\n\nexport async function saveThemeToCache(\n cacheManager: StorageInstance,\n persistence: PersistenceOptions | undefined,\n theme: ThemeSnapshot\n): Promise<void> {\n const persistenceContext = resolvePersistenceContext(persistence);\n\n if (!persistenceContext) {\n return;\n }\n\n try {\n await cacheManager.set(persistenceContext.key, cloneTheme(theme));\n } catch {\n // Ignore persistence failures and keep theme updates in memory.\n }\n}\n"],"names":["DEFAULT_THEME_CACHE_KEY","loadThemeFromCache","saveThemeToCache","resolvePersistenceContext","persistence","enabled","key","cacheManager","fallback","persistenceContext","safeFallback","cloneTheme","cached","get","defaultValue","normalizeTheme","theme","set"],"mappings":";;;;;;;;;;;QAIaA;eAAAA;;QAkBSC;eAAAA;;QAsBAC;eAAAA;;;6BA1CqB;AAEpC,MAAMF,0BAA0B;AAMvC,SAASG,0BACPC,WAA2C;IAE3C,IAAIA,aAAaC,YAAY,MAAM;QACjC,OAAO;IACT;IAEA,OAAO;QACLC,KAAKF,YAAYE,GAAG,IAAIN;IAC1B;AACF;AAEO,eAAeC,mBACpBM,YAA6B,EAC7BH,WAA2C,EAC3CI,QAAuB;IAEvB,MAAMC,qBAAqBN,0BAA0BC;IACrD,MAAMM,eAAeC,IAAAA,uBAAU,EAACH;IAEhC,IAAI,CAACC,oBAAoB;QACvB,OAAOC;IACT;IAEA,IAAI;QACF,MAAME,SAAS,MAAML,aAAaM,GAAG,CAAgBJ,mBAAmBH,GAAG,EAAE;YAC3EQ,cAAcJ;QAChB;QACA,OAAOK,IAAAA,2BAAc,EAACH,QAAQF;IAChC,EAAE,OAAM;QACN,OAAOA;IACT;AACF;AAEO,eAAeR,iBACpBK,YAA6B,EAC7BH,WAA2C,EAC3CY,KAAoB;IAEpB,MAAMP,qBAAqBN,0BAA0BC;IAErD,IAAI,CAACK,oBAAoB;QACvB;IACF;IAEA,IAAI;QACF,MAAMF,aAAaU,GAAG,CAACR,mBAAmBH,GAAG,EAAEK,IAAAA,uBAAU,EAACK;IAC5D,EAAE,OAAM;IACN,gEAAgE;IAClE;AACF"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { StorageInstance } from '@vlian/utils';
|
|
2
|
+
import type { PersistenceOptions, ThemeSnapshot } from '../../types';
|
|
3
|
+
export declare const DEFAULT_THEME_CACHE_KEY = "vlian:kernel:theme";
|
|
4
|
+
export declare function loadThemeFromCache(cacheManager: StorageInstance, persistence: PersistenceOptions | undefined, fallback: ThemeSnapshot): Promise<ThemeSnapshot>;
|
|
5
|
+
export declare function saveThemeToCache(cacheManager: StorageInstance, persistence: PersistenceOptions | undefined, theme: ThemeSnapshot): Promise<void>;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { cloneTheme, normalizeTheme } from "./theme.schema";
|
|
2
|
+
export const DEFAULT_THEME_CACHE_KEY = 'vlian:kernel:theme';
|
|
3
|
+
function resolvePersistenceContext(persistence) {
|
|
4
|
+
if (persistence?.enabled !== true) {
|
|
5
|
+
return null;
|
|
6
|
+
}
|
|
7
|
+
return {
|
|
8
|
+
key: persistence.key || DEFAULT_THEME_CACHE_KEY
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export async function loadThemeFromCache(cacheManager, persistence, fallback) {
|
|
12
|
+
const persistenceContext = resolvePersistenceContext(persistence);
|
|
13
|
+
const safeFallback = cloneTheme(fallback);
|
|
14
|
+
if (!persistenceContext) {
|
|
15
|
+
return safeFallback;
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
const cached = await cacheManager.get(persistenceContext.key, {
|
|
19
|
+
defaultValue: safeFallback
|
|
20
|
+
});
|
|
21
|
+
return normalizeTheme(cached, safeFallback);
|
|
22
|
+
} catch {
|
|
23
|
+
return safeFallback;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export async function saveThemeToCache(cacheManager, persistence, theme) {
|
|
27
|
+
const persistenceContext = resolvePersistenceContext(persistence);
|
|
28
|
+
if (!persistenceContext) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
await cacheManager.set(persistenceContext.key, cloneTheme(theme));
|
|
33
|
+
} catch {
|
|
34
|
+
// Ignore persistence failures and keep theme updates in memory.
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
//# sourceMappingURL=theme.persistence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/kernel/manager/theme/theme.persistence.ts"],"sourcesContent":["import type { StorageInstance } from '@vlian/utils';\nimport type { PersistenceOptions, ThemeSnapshot } from '../../types';\nimport { cloneTheme, normalizeTheme } from './theme.schema';\n\nexport const DEFAULT_THEME_CACHE_KEY = 'vlian:kernel:theme';\n\ntype ResolvedPersistenceContext = {\n key: string;\n};\n\nfunction resolvePersistenceContext(\n persistence: PersistenceOptions | undefined\n): ResolvedPersistenceContext | null {\n if (persistence?.enabled !== true) {\n return null;\n }\n\n return {\n key: persistence.key || DEFAULT_THEME_CACHE_KEY,\n };\n}\n\nexport async function loadThemeFromCache(\n cacheManager: StorageInstance,\n persistence: PersistenceOptions | undefined,\n fallback: ThemeSnapshot\n): Promise<ThemeSnapshot> {\n const persistenceContext = resolvePersistenceContext(persistence);\n const safeFallback = cloneTheme(fallback);\n\n if (!persistenceContext) {\n return safeFallback;\n }\n\n try {\n const cached = await cacheManager.get<ThemeSnapshot>(persistenceContext.key, {\n defaultValue: safeFallback,\n });\n return normalizeTheme(cached, safeFallback);\n } catch {\n return safeFallback;\n }\n}\n\nexport async function saveThemeToCache(\n cacheManager: StorageInstance,\n persistence: PersistenceOptions | undefined,\n theme: ThemeSnapshot\n): Promise<void> {\n const persistenceContext = resolvePersistenceContext(persistence);\n\n if (!persistenceContext) {\n return;\n }\n\n try {\n await cacheManager.set(persistenceContext.key, cloneTheme(theme));\n } catch {\n // Ignore persistence failures and keep theme updates in memory.\n }\n}\n"],"names":["cloneTheme","normalizeTheme","DEFAULT_THEME_CACHE_KEY","resolvePersistenceContext","persistence","enabled","key","loadThemeFromCache","cacheManager","fallback","persistenceContext","safeFallback","cached","get","defaultValue","saveThemeToCache","theme","set"],"mappings":"AAEA,SAASA,UAAU,EAAEC,cAAc,QAAQ,iBAAiB;AAE5D,OAAO,MAAMC,0BAA0B,qBAAqB;AAM5D,SAASC,0BACPC,WAA2C;IAE3C,IAAIA,aAAaC,YAAY,MAAM;QACjC,OAAO;IACT;IAEA,OAAO;QACLC,KAAKF,YAAYE,GAAG,IAAIJ;IAC1B;AACF;AAEA,OAAO,eAAeK,mBACpBC,YAA6B,EAC7BJ,WAA2C,EAC3CK,QAAuB;IAEvB,MAAMC,qBAAqBP,0BAA0BC;IACrD,MAAMO,eAAeX,WAAWS;IAEhC,IAAI,CAACC,oBAAoB;QACvB,OAAOC;IACT;IAEA,IAAI;QACF,MAAMC,SAAS,MAAMJ,aAAaK,GAAG,CAAgBH,mBAAmBJ,GAAG,EAAE;YAC3EQ,cAAcH;QAChB;QACA,OAAOV,eAAeW,QAAQD;IAChC,EAAE,OAAM;QACN,OAAOA;IACT;AACF;AAEA,OAAO,eAAeI,iBACpBP,YAA6B,EAC7BJ,WAA2C,EAC3CY,KAAoB;IAEpB,MAAMN,qBAAqBP,0BAA0BC;IAErD,IAAI,CAACM,oBAAoB;QACvB;IACF;IAEA,IAAI;QACF,MAAMF,aAAaS,GAAG,CAACP,mBAAmBJ,GAAG,EAAEN,WAAWgB;IAC5D,EAAE,OAAM;IACN,gEAAgE;IAClE;AACF"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
function _export(target, all) {
|
|
6
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: Object.getOwnPropertyDescriptor(all, name).get
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
_export(exports, {
|
|
12
|
+
get cloneTheme () {
|
|
13
|
+
return cloneTheme;
|
|
14
|
+
},
|
|
15
|
+
get isThemeEqual () {
|
|
16
|
+
return isThemeEqual;
|
|
17
|
+
},
|
|
18
|
+
get mergeTheme () {
|
|
19
|
+
return mergeTheme;
|
|
20
|
+
},
|
|
21
|
+
get normalizeTheme () {
|
|
22
|
+
return normalizeTheme;
|
|
23
|
+
},
|
|
24
|
+
get sanitizeTokens () {
|
|
25
|
+
return sanitizeTokens;
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
const VALID_THEME_MODES = new Set([
|
|
29
|
+
'light',
|
|
30
|
+
'dark',
|
|
31
|
+
'system'
|
|
32
|
+
]);
|
|
33
|
+
const TOKEN_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_-]*$/;
|
|
34
|
+
function isPlainObject(value) {
|
|
35
|
+
return Object.prototype.toString.call(value) === '[object Object]';
|
|
36
|
+
}
|
|
37
|
+
function hasOwnProperty(value, key) {
|
|
38
|
+
return Object.prototype.hasOwnProperty.call(value, key);
|
|
39
|
+
}
|
|
40
|
+
function cloneTheme(theme) {
|
|
41
|
+
return {
|
|
42
|
+
...theme,
|
|
43
|
+
...theme.tokens ? {
|
|
44
|
+
tokens: {
|
|
45
|
+
...theme.tokens
|
|
46
|
+
}
|
|
47
|
+
} : {}
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function sanitizeTokens(tokens) {
|
|
51
|
+
if (!isPlainObject(tokens)) {
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
const sanitizedTokens = {};
|
|
55
|
+
for (const [token, tokenValue] of Object.entries(tokens)){
|
|
56
|
+
if (!TOKEN_NAME_PATTERN.test(token)) {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (typeof tokenValue === 'string' || typeof tokenValue === 'number') {
|
|
60
|
+
sanitizedTokens[token] = tokenValue;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return Object.keys(sanitizedTokens).length > 0 ? sanitizedTokens : undefined;
|
|
64
|
+
}
|
|
65
|
+
function normalizeTheme(value, fallback) {
|
|
66
|
+
const source = isPlainObject(value) ? value : {};
|
|
67
|
+
const mode = VALID_THEME_MODES.has(source.mode) ? source.mode : fallback.mode;
|
|
68
|
+
const primaryColor = typeof source.primaryColor === 'string' && source.primaryColor.trim() ? source.primaryColor : fallback.primaryColor;
|
|
69
|
+
const fallbackTokens = sanitizeTokens(fallback.tokens);
|
|
70
|
+
const incomingTokens = sanitizeTokens(source.tokens);
|
|
71
|
+
return {
|
|
72
|
+
mode,
|
|
73
|
+
...primaryColor ? {
|
|
74
|
+
primaryColor
|
|
75
|
+
} : {},
|
|
76
|
+
...incomingTokens || fallbackTokens ? {
|
|
77
|
+
tokens: {
|
|
78
|
+
...fallbackTokens || {},
|
|
79
|
+
...incomingTokens || {}
|
|
80
|
+
}
|
|
81
|
+
} : {}
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function mergeTheme(current, next) {
|
|
85
|
+
const mergedTheme = {
|
|
86
|
+
mode: hasOwnProperty(next, 'mode') && VALID_THEME_MODES.has(next.mode) ? next.mode : current.mode,
|
|
87
|
+
...hasOwnProperty(next, 'primaryColor') ? typeof next.primaryColor === 'string' && next.primaryColor.trim() ? {
|
|
88
|
+
primaryColor: next.primaryColor
|
|
89
|
+
} : {} : current.primaryColor ? {
|
|
90
|
+
primaryColor: current.primaryColor
|
|
91
|
+
} : {},
|
|
92
|
+
...hasOwnProperty(next, 'tokens') ? sanitizeTokens(next.tokens) ? {
|
|
93
|
+
tokens: sanitizeTokens(next.tokens)
|
|
94
|
+
} : {} : current.tokens ? {
|
|
95
|
+
tokens: {
|
|
96
|
+
...current.tokens
|
|
97
|
+
}
|
|
98
|
+
} : {}
|
|
99
|
+
};
|
|
100
|
+
return normalizeTheme(mergedTheme, DEFAULT_EMPTY_THEME);
|
|
101
|
+
}
|
|
102
|
+
const DEFAULT_EMPTY_THEME = {
|
|
103
|
+
mode: 'light'
|
|
104
|
+
};
|
|
105
|
+
function isThemeEqual(left, right) {
|
|
106
|
+
if (left.mode !== right.mode || left.primaryColor !== right.primaryColor) {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
const leftTokens = left.tokens || {};
|
|
110
|
+
const rightTokens = right.tokens || {};
|
|
111
|
+
const leftKeys = Object.keys(leftTokens);
|
|
112
|
+
const rightKeys = Object.keys(rightTokens);
|
|
113
|
+
if (leftKeys.length !== rightKeys.length) {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
for (const key of leftKeys){
|
|
117
|
+
if (leftTokens[key] !== rightTokens[key]) {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
//# sourceMappingURL=theme.schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/kernel/manager/theme/theme.schema.ts"],"sourcesContent":["import type { ThemeSnapshot } from '../../types';\n\nexport type ThemeListener = (next: ThemeSnapshot, prev: ThemeSnapshot) => void;\n\nconst VALID_THEME_MODES = new Set<ThemeSnapshot['mode']>(['light', 'dark', 'system']);\nconst TOKEN_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_-]*$/;\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return Object.prototype.toString.call(value) === '[object Object]';\n}\n\nfunction hasOwnProperty<T extends object>(value: T, key: PropertyKey): boolean {\n return Object.prototype.hasOwnProperty.call(value, key);\n}\n\nexport function cloneTheme(theme: ThemeSnapshot): ThemeSnapshot {\n return {\n ...theme,\n ...(theme.tokens ? { tokens: { ...theme.tokens } } : {}),\n };\n}\n\nexport function sanitizeTokens(tokens: unknown): ThemeSnapshot['tokens'] {\n if (!isPlainObject(tokens)) {\n return undefined;\n }\n\n const sanitizedTokens: NonNullable<ThemeSnapshot['tokens']> = {};\n\n for (const [token, tokenValue] of Object.entries(tokens)) {\n if (!TOKEN_NAME_PATTERN.test(token)) {\n continue;\n }\n\n if (typeof tokenValue === 'string' || typeof tokenValue === 'number') {\n sanitizedTokens[token] = tokenValue;\n }\n }\n\n return Object.keys(sanitizedTokens).length > 0 ? sanitizedTokens : undefined;\n}\n\nexport function normalizeTheme(\n value: unknown,\n fallback: ThemeSnapshot\n): ThemeSnapshot {\n const source = isPlainObject(value) ? value : {};\n const mode = VALID_THEME_MODES.has(source.mode as ThemeSnapshot['mode'])\n ? (source.mode as ThemeSnapshot['mode'])\n : fallback.mode;\n const primaryColor = typeof source.primaryColor === 'string' && source.primaryColor.trim()\n ? source.primaryColor\n : fallback.primaryColor;\n const fallbackTokens = sanitizeTokens(fallback.tokens);\n const incomingTokens = sanitizeTokens(source.tokens);\n\n return {\n mode,\n ...(primaryColor ? { primaryColor } : {}),\n ...(incomingTokens || fallbackTokens\n ? { tokens: { ...(fallbackTokens || {}), ...(incomingTokens || {}) } }\n : {}),\n };\n}\n\nexport function mergeTheme(current: ThemeSnapshot, next: Partial<ThemeSnapshot>): ThemeSnapshot {\n const mergedTheme: ThemeSnapshot = {\n mode: hasOwnProperty(next, 'mode') && VALID_THEME_MODES.has(next.mode as ThemeSnapshot['mode'])\n ? (next.mode as ThemeSnapshot['mode'])\n : current.mode,\n ...(hasOwnProperty(next, 'primaryColor')\n ? (typeof next.primaryColor === 'string' && next.primaryColor.trim()\n ? { primaryColor: next.primaryColor }\n : {})\n : (current.primaryColor ? { primaryColor: current.primaryColor } : {})),\n ...(hasOwnProperty(next, 'tokens')\n ? (sanitizeTokens(next.tokens) ? { tokens: sanitizeTokens(next.tokens) } : {})\n : (current.tokens ? { tokens: { ...current.tokens } } : {})),\n };\n\n return normalizeTheme(mergedTheme, DEFAULT_EMPTY_THEME);\n}\n\nconst DEFAULT_EMPTY_THEME: ThemeSnapshot = { mode: 'light' };\n\nexport function isThemeEqual(left: ThemeSnapshot, right: ThemeSnapshot): boolean {\n if (left.mode !== right.mode || left.primaryColor !== right.primaryColor) {\n return false;\n }\n\n const leftTokens = left.tokens || {};\n const rightTokens = right.tokens || {};\n const leftKeys = Object.keys(leftTokens);\n const rightKeys = Object.keys(rightTokens);\n\n if (leftKeys.length !== rightKeys.length) {\n return false;\n }\n\n for (const key of leftKeys) {\n if (leftTokens[key] !== rightTokens[key]) {\n return false;\n }\n }\n\n return true;\n}\n"],"names":["cloneTheme","isThemeEqual","mergeTheme","normalizeTheme","sanitizeTokens","VALID_THEME_MODES","Set","TOKEN_NAME_PATTERN","isPlainObject","value","Object","prototype","toString","call","hasOwnProperty","key","theme","tokens","undefined","sanitizedTokens","token","tokenValue","entries","test","keys","length","fallback","source","mode","has","primaryColor","trim","fallbackTokens","incomingTokens","current","next","mergedTheme","DEFAULT_EMPTY_THEME","left","right","leftTokens","rightTokens","leftKeys","rightKeys"],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ThemeSnapshot } from '../../types';
|
|
2
|
+
export type ThemeListener = (next: ThemeSnapshot, prev: ThemeSnapshot) => void;
|
|
3
|
+
export declare function cloneTheme(theme: ThemeSnapshot): ThemeSnapshot;
|
|
4
|
+
export declare function sanitizeTokens(tokens: unknown): ThemeSnapshot['tokens'];
|
|
5
|
+
export declare function normalizeTheme(value: unknown, fallback: ThemeSnapshot): ThemeSnapshot;
|
|
6
|
+
export declare function mergeTheme(current: ThemeSnapshot, next: Partial<ThemeSnapshot>): ThemeSnapshot;
|
|
7
|
+
export declare function isThemeEqual(left: ThemeSnapshot, right: ThemeSnapshot): boolean;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
const VALID_THEME_MODES = new Set([
|
|
2
|
+
'light',
|
|
3
|
+
'dark',
|
|
4
|
+
'system'
|
|
5
|
+
]);
|
|
6
|
+
const TOKEN_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_-]*$/;
|
|
7
|
+
function isPlainObject(value) {
|
|
8
|
+
return Object.prototype.toString.call(value) === '[object Object]';
|
|
9
|
+
}
|
|
10
|
+
function hasOwnProperty(value, key) {
|
|
11
|
+
return Object.prototype.hasOwnProperty.call(value, key);
|
|
12
|
+
}
|
|
13
|
+
export function cloneTheme(theme) {
|
|
14
|
+
return {
|
|
15
|
+
...theme,
|
|
16
|
+
...theme.tokens ? {
|
|
17
|
+
tokens: {
|
|
18
|
+
...theme.tokens
|
|
19
|
+
}
|
|
20
|
+
} : {}
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export function sanitizeTokens(tokens) {
|
|
24
|
+
if (!isPlainObject(tokens)) {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
const sanitizedTokens = {};
|
|
28
|
+
for (const [token, tokenValue] of Object.entries(tokens)){
|
|
29
|
+
if (!TOKEN_NAME_PATTERN.test(token)) {
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
if (typeof tokenValue === 'string' || typeof tokenValue === 'number') {
|
|
33
|
+
sanitizedTokens[token] = tokenValue;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return Object.keys(sanitizedTokens).length > 0 ? sanitizedTokens : undefined;
|
|
37
|
+
}
|
|
38
|
+
export function normalizeTheme(value, fallback) {
|
|
39
|
+
const source = isPlainObject(value) ? value : {};
|
|
40
|
+
const mode = VALID_THEME_MODES.has(source.mode) ? source.mode : fallback.mode;
|
|
41
|
+
const primaryColor = typeof source.primaryColor === 'string' && source.primaryColor.trim() ? source.primaryColor : fallback.primaryColor;
|
|
42
|
+
const fallbackTokens = sanitizeTokens(fallback.tokens);
|
|
43
|
+
const incomingTokens = sanitizeTokens(source.tokens);
|
|
44
|
+
return {
|
|
45
|
+
mode,
|
|
46
|
+
...primaryColor ? {
|
|
47
|
+
primaryColor
|
|
48
|
+
} : {},
|
|
49
|
+
...incomingTokens || fallbackTokens ? {
|
|
50
|
+
tokens: {
|
|
51
|
+
...fallbackTokens || {},
|
|
52
|
+
...incomingTokens || {}
|
|
53
|
+
}
|
|
54
|
+
} : {}
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
export function mergeTheme(current, next) {
|
|
58
|
+
const mergedTheme = {
|
|
59
|
+
mode: hasOwnProperty(next, 'mode') && VALID_THEME_MODES.has(next.mode) ? next.mode : current.mode,
|
|
60
|
+
...hasOwnProperty(next, 'primaryColor') ? typeof next.primaryColor === 'string' && next.primaryColor.trim() ? {
|
|
61
|
+
primaryColor: next.primaryColor
|
|
62
|
+
} : {} : current.primaryColor ? {
|
|
63
|
+
primaryColor: current.primaryColor
|
|
64
|
+
} : {},
|
|
65
|
+
...hasOwnProperty(next, 'tokens') ? sanitizeTokens(next.tokens) ? {
|
|
66
|
+
tokens: sanitizeTokens(next.tokens)
|
|
67
|
+
} : {} : current.tokens ? {
|
|
68
|
+
tokens: {
|
|
69
|
+
...current.tokens
|
|
70
|
+
}
|
|
71
|
+
} : {}
|
|
72
|
+
};
|
|
73
|
+
return normalizeTheme(mergedTheme, DEFAULT_EMPTY_THEME);
|
|
74
|
+
}
|
|
75
|
+
const DEFAULT_EMPTY_THEME = {
|
|
76
|
+
mode: 'light'
|
|
77
|
+
};
|
|
78
|
+
export function isThemeEqual(left, right) {
|
|
79
|
+
if (left.mode !== right.mode || left.primaryColor !== right.primaryColor) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
const leftTokens = left.tokens || {};
|
|
83
|
+
const rightTokens = right.tokens || {};
|
|
84
|
+
const leftKeys = Object.keys(leftTokens);
|
|
85
|
+
const rightKeys = Object.keys(rightTokens);
|
|
86
|
+
if (leftKeys.length !== rightKeys.length) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
for (const key of leftKeys){
|
|
90
|
+
if (leftTokens[key] !== rightTokens[key]) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
//# sourceMappingURL=theme.schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/kernel/manager/theme/theme.schema.ts"],"sourcesContent":["import type { ThemeSnapshot } from '../../types';\n\nexport type ThemeListener = (next: ThemeSnapshot, prev: ThemeSnapshot) => void;\n\nconst VALID_THEME_MODES = new Set<ThemeSnapshot['mode']>(['light', 'dark', 'system']);\nconst TOKEN_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_-]*$/;\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return Object.prototype.toString.call(value) === '[object Object]';\n}\n\nfunction hasOwnProperty<T extends object>(value: T, key: PropertyKey): boolean {\n return Object.prototype.hasOwnProperty.call(value, key);\n}\n\nexport function cloneTheme(theme: ThemeSnapshot): ThemeSnapshot {\n return {\n ...theme,\n ...(theme.tokens ? { tokens: { ...theme.tokens } } : {}),\n };\n}\n\nexport function sanitizeTokens(tokens: unknown): ThemeSnapshot['tokens'] {\n if (!isPlainObject(tokens)) {\n return undefined;\n }\n\n const sanitizedTokens: NonNullable<ThemeSnapshot['tokens']> = {};\n\n for (const [token, tokenValue] of Object.entries(tokens)) {\n if (!TOKEN_NAME_PATTERN.test(token)) {\n continue;\n }\n\n if (typeof tokenValue === 'string' || typeof tokenValue === 'number') {\n sanitizedTokens[token] = tokenValue;\n }\n }\n\n return Object.keys(sanitizedTokens).length > 0 ? sanitizedTokens : undefined;\n}\n\nexport function normalizeTheme(\n value: unknown,\n fallback: ThemeSnapshot\n): ThemeSnapshot {\n const source = isPlainObject(value) ? value : {};\n const mode = VALID_THEME_MODES.has(source.mode as ThemeSnapshot['mode'])\n ? (source.mode as ThemeSnapshot['mode'])\n : fallback.mode;\n const primaryColor = typeof source.primaryColor === 'string' && source.primaryColor.trim()\n ? source.primaryColor\n : fallback.primaryColor;\n const fallbackTokens = sanitizeTokens(fallback.tokens);\n const incomingTokens = sanitizeTokens(source.tokens);\n\n return {\n mode,\n ...(primaryColor ? { primaryColor } : {}),\n ...(incomingTokens || fallbackTokens\n ? { tokens: { ...(fallbackTokens || {}), ...(incomingTokens || {}) } }\n : {}),\n };\n}\n\nexport function mergeTheme(current: ThemeSnapshot, next: Partial<ThemeSnapshot>): ThemeSnapshot {\n const mergedTheme: ThemeSnapshot = {\n mode: hasOwnProperty(next, 'mode') && VALID_THEME_MODES.has(next.mode as ThemeSnapshot['mode'])\n ? (next.mode as ThemeSnapshot['mode'])\n : current.mode,\n ...(hasOwnProperty(next, 'primaryColor')\n ? (typeof next.primaryColor === 'string' && next.primaryColor.trim()\n ? { primaryColor: next.primaryColor }\n : {})\n : (current.primaryColor ? { primaryColor: current.primaryColor } : {})),\n ...(hasOwnProperty(next, 'tokens')\n ? (sanitizeTokens(next.tokens) ? { tokens: sanitizeTokens(next.tokens) } : {})\n : (current.tokens ? { tokens: { ...current.tokens } } : {})),\n };\n\n return normalizeTheme(mergedTheme, DEFAULT_EMPTY_THEME);\n}\n\nconst DEFAULT_EMPTY_THEME: ThemeSnapshot = { mode: 'light' };\n\nexport function isThemeEqual(left: ThemeSnapshot, right: ThemeSnapshot): boolean {\n if (left.mode !== right.mode || left.primaryColor !== right.primaryColor) {\n return false;\n }\n\n const leftTokens = left.tokens || {};\n const rightTokens = right.tokens || {};\n const leftKeys = Object.keys(leftTokens);\n const rightKeys = Object.keys(rightTokens);\n\n if (leftKeys.length !== rightKeys.length) {\n return false;\n }\n\n for (const key of leftKeys) {\n if (leftTokens[key] !== rightTokens[key]) {\n return false;\n }\n }\n\n return true;\n}\n"],"names":["VALID_THEME_MODES","Set","TOKEN_NAME_PATTERN","isPlainObject","value","Object","prototype","toString","call","hasOwnProperty","key","cloneTheme","theme","tokens","sanitizeTokens","undefined","sanitizedTokens","token","tokenValue","entries","test","keys","length","normalizeTheme","fallback","source","mode","has","primaryColor","trim","fallbackTokens","incomingTokens","mergeTheme","current","next","mergedTheme","DEFAULT_EMPTY_THEME","isThemeEqual","left","right","leftTokens","rightTokens","leftKeys","rightKeys"],"mappings":"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"}
|
|
@@ -5,102 +5,9 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
Object.defineProperty(exports, "ThemeManager", {
|
|
6
6
|
enumerable: true,
|
|
7
7
|
get: function() {
|
|
8
|
-
return ThemeManager;
|
|
8
|
+
return _theme.ThemeManager;
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
|
-
const
|
|
12
|
-
const _persistence = require("./persistence");
|
|
13
|
-
function _define_property(obj, key, value) {
|
|
14
|
-
if (key in obj) {
|
|
15
|
-
Object.defineProperty(obj, key, {
|
|
16
|
-
value: value,
|
|
17
|
-
enumerable: true,
|
|
18
|
-
configurable: true,
|
|
19
|
-
writable: true
|
|
20
|
-
});
|
|
21
|
-
} else {
|
|
22
|
-
obj[key] = value;
|
|
23
|
-
}
|
|
24
|
-
return obj;
|
|
25
|
-
}
|
|
26
|
-
function applyThemeToDocument(theme) {
|
|
27
|
-
if (typeof document === 'undefined') {
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
const root = document.documentElement;
|
|
31
|
-
root.classList.remove('light', 'dark');
|
|
32
|
-
const resolvedMode = theme.mode === 'system' ? typeof window !== 'undefined' && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light' : theme.mode;
|
|
33
|
-
root.classList.add(resolvedMode);
|
|
34
|
-
if (theme.primaryColor) {
|
|
35
|
-
root.style.setProperty('--app-primary-color', theme.primaryColor);
|
|
36
|
-
}
|
|
37
|
-
if (theme.tokens) {
|
|
38
|
-
Object.entries(theme.tokens).forEach(([token, tokenValue])=>{
|
|
39
|
-
root.style.setProperty(`--${token}`, String(tokenValue));
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
let ThemeManager = class ThemeManager {
|
|
44
|
-
async initialize(context) {
|
|
45
|
-
this.config = context.config.theme;
|
|
46
|
-
this.theme = {
|
|
47
|
-
..._constants.DEFAULT_THEME,
|
|
48
|
-
...this.config.initial || {}
|
|
49
|
-
};
|
|
50
|
-
const persisted = await (0, _persistence.readPersistedValue)(this.config.persistence);
|
|
51
|
-
if (persisted !== null) {
|
|
52
|
-
try {
|
|
53
|
-
const parsed = JSON.parse(persisted);
|
|
54
|
-
this.theme = {
|
|
55
|
-
...this.theme,
|
|
56
|
-
...parsed
|
|
57
|
-
};
|
|
58
|
-
} catch {
|
|
59
|
-
// ignore parse errors
|
|
60
|
-
}
|
|
61
|
-
} else {
|
|
62
|
-
await (0, _persistence.writePersistedValue)(this.config.persistence, JSON.stringify(this.theme));
|
|
63
|
-
}
|
|
64
|
-
applyThemeToDocument(this.theme);
|
|
65
|
-
}
|
|
66
|
-
getTheme() {
|
|
67
|
-
return {
|
|
68
|
-
...this.theme
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
subscribe(listener) {
|
|
72
|
-
this.listeners.add(listener);
|
|
73
|
-
return ()=>{
|
|
74
|
-
this.listeners.delete(listener);
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
emit(next, prev) {
|
|
78
|
-
this.listeners.forEach((listener)=>{
|
|
79
|
-
listener({
|
|
80
|
-
...next
|
|
81
|
-
}, {
|
|
82
|
-
...prev
|
|
83
|
-
});
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
async setTheme(nextTheme) {
|
|
87
|
-
const prev = this.theme;
|
|
88
|
-
this.theme = {
|
|
89
|
-
...this.theme,
|
|
90
|
-
...nextTheme
|
|
91
|
-
};
|
|
92
|
-
applyThemeToDocument(this.theme);
|
|
93
|
-
await (0, _persistence.writePersistedValue)(this.config.persistence, JSON.stringify(this.theme));
|
|
94
|
-
this.emit(this.theme, prev);
|
|
95
|
-
}
|
|
96
|
-
getSnapshot() {
|
|
97
|
-
return this.getTheme();
|
|
98
|
-
}
|
|
99
|
-
constructor(){
|
|
100
|
-
_define_property(this, "theme", _constants.DEFAULT_THEME);
|
|
101
|
-
_define_property(this, "config", _constants.DEFAULT_CONFIG.theme);
|
|
102
|
-
_define_property(this, "listeners", new Set());
|
|
103
|
-
}
|
|
104
|
-
};
|
|
11
|
+
const _theme = require("./theme");
|
|
105
12
|
|
|
106
13
|
//# sourceMappingURL=themeManager.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/kernel/manager/themeManager.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"sources":["../../../src/kernel/manager/themeManager.ts"],"sourcesContent":["export { ThemeManager } from './theme';\n"],"names":["ThemeManager"],"mappings":";;;;+BAASA;;;eAAAA,mBAAY;;;uBAAQ"}
|
|
@@ -1,14 +1 @@
|
|
|
1
|
-
|
|
2
|
-
type ThemeListener = (next: ThemeSnapshot, prev: ThemeSnapshot) => void;
|
|
3
|
-
export declare class ThemeManager implements KernelManager<ThemeSnapshot> {
|
|
4
|
-
private theme;
|
|
5
|
-
private config;
|
|
6
|
-
private listeners;
|
|
7
|
-
initialize(context: KernelManagerContext): Promise<void>;
|
|
8
|
-
getTheme(): ThemeSnapshot;
|
|
9
|
-
subscribe(listener: ThemeListener): () => void;
|
|
10
|
-
private emit;
|
|
11
|
-
setTheme(nextTheme: ThemeSnapshot): Promise<void>;
|
|
12
|
-
getSnapshot(): ThemeSnapshot;
|
|
13
|
-
}
|
|
14
|
-
export {};
|
|
1
|
+
export { ThemeManager } from './theme';
|