@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.
Files changed (48) hide show
  1. package/dist/analytics.umd.js +1 -1
  2. package/dist/index.umd.js +222 -65
  3. package/dist/index.umd.js.map +1 -1
  4. package/dist/kernel/kernel.cjs +2 -1
  5. package/dist/kernel/kernel.cjs.map +1 -1
  6. package/dist/kernel/kernel.js +2 -1
  7. package/dist/kernel/kernel.js.map +1 -1
  8. package/dist/kernel/manager/cacheManager.cjs +8 -6
  9. package/dist/kernel/manager/cacheManager.cjs.map +1 -1
  10. package/dist/kernel/manager/cacheManager.d.ts +3 -0
  11. package/dist/kernel/manager/cacheManager.js +8 -6
  12. package/dist/kernel/manager/cacheManager.js.map +1 -1
  13. package/dist/kernel/manager/theme/ThemeManager.cjs +86 -0
  14. package/dist/kernel/manager/theme/ThemeManager.cjs.map +1 -0
  15. package/dist/kernel/manager/theme/ThemeManager.d.ts +16 -0
  16. package/dist/kernel/manager/theme/ThemeManager.js +76 -0
  17. package/dist/kernel/manager/theme/ThemeManager.js.map +1 -0
  18. package/dist/kernel/manager/theme/index.cjs +13 -0
  19. package/dist/kernel/manager/theme/index.cjs.map +1 -0
  20. package/dist/kernel/manager/theme/index.d.ts +1 -0
  21. package/dist/kernel/manager/theme/index.js +3 -0
  22. package/dist/kernel/manager/theme/index.js.map +1 -0
  23. package/dist/kernel/manager/theme/theme.dom.cjs +63 -0
  24. package/dist/kernel/manager/theme/theme.dom.cjs.map +1 -0
  25. package/dist/kernel/manager/theme/theme.dom.d.ts +3 -0
  26. package/dist/kernel/manager/theme/theme.dom.js +45 -0
  27. package/dist/kernel/manager/theme/theme.dom.js.map +1 -0
  28. package/dist/kernel/manager/theme/theme.persistence.cjs +59 -0
  29. package/dist/kernel/manager/theme/theme.persistence.cjs.map +1 -0
  30. package/dist/kernel/manager/theme/theme.persistence.d.ts +5 -0
  31. package/dist/kernel/manager/theme/theme.persistence.js +38 -0
  32. package/dist/kernel/manager/theme/theme.persistence.js.map +1 -0
  33. package/dist/kernel/manager/theme/theme.schema.cjs +124 -0
  34. package/dist/kernel/manager/theme/theme.schema.cjs.map +1 -0
  35. package/dist/kernel/manager/theme/theme.schema.d.ts +7 -0
  36. package/dist/kernel/manager/theme/theme.schema.js +97 -0
  37. package/dist/kernel/manager/theme/theme.schema.js.map +1 -0
  38. package/dist/kernel/manager/themeManager.cjs +2 -95
  39. package/dist/kernel/manager/themeManager.cjs.map +1 -1
  40. package/dist/kernel/manager/themeManager.d.ts +1 -14
  41. package/dist/kernel/manager/themeManager.js +1 -94
  42. package/dist/kernel/manager/themeManager.js.map +1 -1
  43. package/dist/kernel/types.d.ts +2 -0
  44. package/dist/kernel/types.js.map +1 -1
  45. package/dist/state.umd.js +1 -1
  46. package/dist/types.d.ts +2 -0
  47. package/dist/types.js.map +1 -1
  48. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * @vlian/framework v1.2.50
2
+ * @vlian/framework v1.2.54
3
3
  * Secra Framework - 一个现代化的低代码框架
4
4
  * (c) 2026 Secra Framework Contributors
5
5
  * Licensed under Apache-2.0
package/dist/index.umd.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * @vlian/framework v1.2.50
2
+ * @vlian/framework v1.2.54
3
3
  * Secra Framework - 一个现代化的低代码框架
4
4
  * (c) 2026 Secra Framework Contributors
5
5
  * Licensed under Apache-2.0
@@ -12418,20 +12418,198 @@
12418
12418
  class CacheManager {
12419
12419
  initialize(context) {
12420
12420
  this.snapshot = context.config.cache;
12421
- storage.initialize({
12421
+ this.cacheIn = vlianUtils.createStorage({
12422
+ type: this.snapshot.storageOptions?.type || 'local',
12422
12423
  prefix: this.snapshot.storageOptions?.prefix || 'vlian',
12423
12424
  defaultExpire: this.snapshot.storageOptions?.defaultExpire || 24 * 60 * 60 * 1000,
12424
- tableName: this.snapshot.storageOptions?.tableName,
12425
- cache: {
12426
- enabled: this.snapshot.enabled
12427
- }
12425
+ dbName: this.snapshot.storageOptions?.tableName
12428
12426
  });
12429
12427
  }
12428
+ get cache() {
12429
+ return this.cacheIn;
12430
+ }
12430
12431
  getSnapshot() {
12431
12432
  return this.snapshot;
12432
12433
  }
12433
12434
  constructor(){
12434
12435
  _define_property$3(this, "snapshot", DEFAULT_CONFIG.cache);
12436
+ _define_property$3(this, "cacheIn", void 0);
12437
+ }
12438
+ }
12439
+
12440
+ function canUseDom() {
12441
+ return typeof document !== 'undefined';
12442
+ }
12443
+ function resolveThemeMode(theme) {
12444
+ if (theme.mode !== 'system') {
12445
+ return theme.mode;
12446
+ }
12447
+ if (typeof window !== 'undefined' && window.matchMedia('(prefers-color-scheme: dark)').matches) {
12448
+ return 'dark';
12449
+ }
12450
+ return 'light';
12451
+ }
12452
+ function applyThemeToDocument(nextTheme, prevTheme) {
12453
+ if (!canUseDom()) {
12454
+ return;
12455
+ }
12456
+ const root = document.documentElement;
12457
+ const nextMode = resolveThemeMode(nextTheme);
12458
+ const prevMode = prevTheme ? resolveThemeMode(prevTheme) : undefined;
12459
+ if (!prevMode || prevMode !== nextMode) {
12460
+ root.classList.remove('light', 'dark');
12461
+ root.classList.add(nextMode);
12462
+ }
12463
+ if (!prevTheme || prevTheme.primaryColor !== nextTheme.primaryColor) {
12464
+ if (nextTheme.primaryColor) {
12465
+ root.style.setProperty('--app-primary-color', nextTheme.primaryColor);
12466
+ } else {
12467
+ root.style.removeProperty('--app-primary-color');
12468
+ }
12469
+ }
12470
+ const prevTokens = prevTheme?.tokens || {};
12471
+ const nextTokens = nextTheme.tokens || {};
12472
+ for (const token of Object.keys(prevTokens)){
12473
+ if (!(token in nextTokens)) {
12474
+ root.style.removeProperty(`--${token}`);
12475
+ }
12476
+ }
12477
+ for (const [token, value] of Object.entries(nextTokens)){
12478
+ if (!prevTheme || prevTokens[token] !== value) {
12479
+ root.style.setProperty(`--${token}`, String(value));
12480
+ }
12481
+ }
12482
+ }
12483
+
12484
+ const VALID_THEME_MODES = new Set([
12485
+ 'light',
12486
+ 'dark',
12487
+ 'system'
12488
+ ]);
12489
+ const TOKEN_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_-]*$/;
12490
+ function isPlainObject(value) {
12491
+ return Object.prototype.toString.call(value) === '[object Object]';
12492
+ }
12493
+ function hasOwnProperty(value, key) {
12494
+ return Object.prototype.hasOwnProperty.call(value, key);
12495
+ }
12496
+ function cloneTheme(theme) {
12497
+ return {
12498
+ ...theme,
12499
+ ...theme.tokens ? {
12500
+ tokens: {
12501
+ ...theme.tokens
12502
+ }
12503
+ } : {}
12504
+ };
12505
+ }
12506
+ function sanitizeTokens(tokens) {
12507
+ if (!isPlainObject(tokens)) {
12508
+ return undefined;
12509
+ }
12510
+ const sanitizedTokens = {};
12511
+ for (const [token, tokenValue] of Object.entries(tokens)){
12512
+ if (!TOKEN_NAME_PATTERN.test(token)) {
12513
+ continue;
12514
+ }
12515
+ if (typeof tokenValue === 'string' || typeof tokenValue === 'number') {
12516
+ sanitizedTokens[token] = tokenValue;
12517
+ }
12518
+ }
12519
+ return Object.keys(sanitizedTokens).length > 0 ? sanitizedTokens : undefined;
12520
+ }
12521
+ function normalizeTheme(value, fallback) {
12522
+ const source = isPlainObject(value) ? value : {};
12523
+ const mode = VALID_THEME_MODES.has(source.mode) ? source.mode : fallback.mode;
12524
+ const primaryColor = typeof source.primaryColor === 'string' && source.primaryColor.trim() ? source.primaryColor : fallback.primaryColor;
12525
+ const fallbackTokens = sanitizeTokens(fallback.tokens);
12526
+ const incomingTokens = sanitizeTokens(source.tokens);
12527
+ return {
12528
+ mode,
12529
+ ...primaryColor ? {
12530
+ primaryColor
12531
+ } : {},
12532
+ ...incomingTokens || fallbackTokens ? {
12533
+ tokens: {
12534
+ ...fallbackTokens || {},
12535
+ ...incomingTokens || {}
12536
+ }
12537
+ } : {}
12538
+ };
12539
+ }
12540
+ function mergeTheme(current, next) {
12541
+ const mergedTheme = {
12542
+ mode: hasOwnProperty(next, 'mode') && VALID_THEME_MODES.has(next.mode) ? next.mode : current.mode,
12543
+ ...hasOwnProperty(next, 'primaryColor') ? typeof next.primaryColor === 'string' && next.primaryColor.trim() ? {
12544
+ primaryColor: next.primaryColor
12545
+ } : {} : current.primaryColor ? {
12546
+ primaryColor: current.primaryColor
12547
+ } : {},
12548
+ ...hasOwnProperty(next, 'tokens') ? sanitizeTokens(next.tokens) ? {
12549
+ tokens: sanitizeTokens(next.tokens)
12550
+ } : {} : current.tokens ? {
12551
+ tokens: {
12552
+ ...current.tokens
12553
+ }
12554
+ } : {}
12555
+ };
12556
+ return normalizeTheme(mergedTheme, DEFAULT_EMPTY_THEME);
12557
+ }
12558
+ const DEFAULT_EMPTY_THEME = {
12559
+ mode: 'light'
12560
+ };
12561
+ function isThemeEqual(left, right) {
12562
+ if (left.mode !== right.mode || left.primaryColor !== right.primaryColor) {
12563
+ return false;
12564
+ }
12565
+ const leftTokens = left.tokens || {};
12566
+ const rightTokens = right.tokens || {};
12567
+ const leftKeys = Object.keys(leftTokens);
12568
+ const rightKeys = Object.keys(rightTokens);
12569
+ if (leftKeys.length !== rightKeys.length) {
12570
+ return false;
12571
+ }
12572
+ for (const key of leftKeys){
12573
+ if (leftTokens[key] !== rightTokens[key]) {
12574
+ return false;
12575
+ }
12576
+ }
12577
+ return true;
12578
+ }
12579
+
12580
+ const DEFAULT_THEME_CACHE_KEY = 'vlian:kernel:theme';
12581
+ function resolvePersistenceContext(persistence) {
12582
+ if (persistence?.enabled !== true) {
12583
+ return null;
12584
+ }
12585
+ return {
12586
+ key: persistence.key || DEFAULT_THEME_CACHE_KEY
12587
+ };
12588
+ }
12589
+ async function loadThemeFromCache(cacheManager, persistence, fallback) {
12590
+ const persistenceContext = resolvePersistenceContext(persistence);
12591
+ const safeFallback = cloneTheme(fallback);
12592
+ if (!persistenceContext) {
12593
+ return safeFallback;
12594
+ }
12595
+ try {
12596
+ const cached = await cacheManager.get(persistenceContext.key, {
12597
+ defaultValue: safeFallback
12598
+ });
12599
+ return normalizeTheme(cached, safeFallback);
12600
+ } catch {
12601
+ return safeFallback;
12602
+ }
12603
+ }
12604
+ async function saveThemeToCache(cacheManager, persistence, theme) {
12605
+ const persistenceContext = resolvePersistenceContext(persistence);
12606
+ if (!persistenceContext) {
12607
+ return;
12608
+ }
12609
+ try {
12610
+ await cacheManager.set(persistenceContext.key, cloneTheme(theme));
12611
+ } catch {
12612
+ // Ignore persistence failures and keep theme updates in memory.
12435
12613
  }
12436
12614
  }
12437
12615
 
@@ -12448,50 +12626,20 @@
12448
12626
  }
12449
12627
  return obj;
12450
12628
  }
12451
- function applyThemeToDocument(theme) {
12452
- if (typeof document === 'undefined') {
12453
- return;
12454
- }
12455
- const root = document.documentElement;
12456
- root.classList.remove('light', 'dark');
12457
- const resolvedMode = theme.mode === 'system' ? typeof window !== 'undefined' && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light' : theme.mode;
12458
- root.classList.add(resolvedMode);
12459
- if (theme.primaryColor) {
12460
- root.style.setProperty('--app-primary-color', theme.primaryColor);
12461
- }
12462
- if (theme.tokens) {
12463
- Object.entries(theme.tokens).forEach(([token, tokenValue])=>{
12464
- root.style.setProperty(`--${token}`, String(tokenValue));
12465
- });
12466
- }
12467
- }
12468
12629
  class ThemeManager {
12469
12630
  async initialize(context) {
12470
12631
  this.config = context.config.theme;
12471
- this.theme = {
12472
- ...DEFAULT_THEME,
12473
- ...this.config.initial || {}
12474
- };
12475
- const persisted = await readPersistedValue(this.config.persistence);
12476
- if (persisted !== null) {
12477
- try {
12478
- const parsed = JSON.parse(persisted);
12479
- this.theme = {
12480
- ...this.theme,
12481
- ...parsed
12482
- };
12483
- } catch {
12484
- // ignore parse errors
12485
- }
12486
- } else {
12487
- await writePersistedValue(this.config.persistence, JSON.stringify(this.theme));
12488
- }
12632
+ this.cacheManager = context.cacheManager;
12633
+ const initialTheme = normalizeTheme(this.config.initial || {}, DEFAULT_THEME);
12634
+ this.theme = await loadThemeFromCache(this.cacheManager, this.config.persistence, initialTheme);
12489
12635
  applyThemeToDocument(this.theme);
12636
+ this.initialized = true;
12490
12637
  }
12491
12638
  getTheme() {
12492
- return {
12493
- ...this.theme
12494
- };
12639
+ return cloneTheme(this.theme);
12640
+ }
12641
+ getSnapshot() {
12642
+ return this.getTheme();
12495
12643
  }
12496
12644
  subscribe(listener) {
12497
12645
  this.listeners.add(listener);
@@ -12499,32 +12647,40 @@
12499
12647
  this.listeners.delete(listener);
12500
12648
  };
12501
12649
  }
12502
- emit(next, prev) {
12503
- this.listeners.forEach((listener)=>{
12504
- listener({
12505
- ...next
12506
- }, {
12507
- ...prev
12508
- });
12509
- });
12510
- }
12511
12650
  async setTheme(nextTheme) {
12512
- const prev = this.theme;
12513
- this.theme = {
12514
- ...this.theme,
12515
- ...nextTheme
12516
- };
12517
- applyThemeToDocument(this.theme);
12518
- await writePersistedValue(this.config.persistence, JSON.stringify(this.theme));
12519
- this.emit(this.theme, prev);
12651
+ this.ensureInitialized();
12652
+ const prevTheme = this.theme;
12653
+ const mergedTheme = mergeTheme(prevTheme, nextTheme);
12654
+ if (isThemeEqual(prevTheme, mergedTheme)) {
12655
+ return;
12656
+ }
12657
+ this.theme = mergedTheme;
12658
+ applyThemeToDocument(this.theme, prevTheme);
12659
+ if (this.cacheManager) {
12660
+ await saveThemeToCache(this.cacheManager, this.config.persistence, this.theme);
12661
+ }
12662
+ this.emit(this.theme, prevTheme);
12520
12663
  }
12521
- getSnapshot() {
12522
- return this.getTheme();
12664
+ ensureInitialized() {
12665
+ if (!this.initialized) {
12666
+ throw new Error('ThemeManager must be initialized before use.');
12667
+ }
12668
+ }
12669
+ emit(next, prev) {
12670
+ for (const listener of this.listeners){
12671
+ try {
12672
+ listener(cloneTheme(next), cloneTheme(prev));
12673
+ } catch {
12674
+ // Keep notifying remaining listeners even if one fails.
12675
+ }
12676
+ }
12523
12677
  }
12524
12678
  constructor(){
12525
- _define_property$2(this, "theme", DEFAULT_THEME);
12679
+ _define_property$2(this, "theme", cloneTheme(DEFAULT_THEME));
12526
12680
  _define_property$2(this, "config", DEFAULT_CONFIG.theme);
12527
12681
  _define_property$2(this, "listeners", new Set());
12682
+ _define_property$2(this, "cacheManager", null);
12683
+ _define_property$2(this, "initialized", false);
12528
12684
  }
12529
12685
  }
12530
12686
 
@@ -12798,7 +12954,8 @@
12798
12954
  }
12799
12955
  const context = {
12800
12956
  instanceId: this.instanceId,
12801
- config: this.config
12957
+ config: this.config,
12958
+ cacheManager: this.cacheManager.cache
12802
12959
  };
12803
12960
  const initPromise = (async ()=>{
12804
12961
  await manager.initialize(context);