Remove visual prefs dimensions

active-uix
dev 5 months ago
parent fbacd1133d
commit 68dd40ef27

@ -20,8 +20,10 @@ Decisiones vigentes:
`data-motion`, `data-sound` y `data-haptic`. `data-motion`, `data-sound` y `data-haptic`.
- `theme`, `mode` y `density` visuales pertenecen a `ActiveEidos`, no al - `theme`, `mode` y `density` visuales pertenecen a `ActiveEidos`, no al
preset core de `prefs`, `ActiveApp` ni `ActiveUix`. preset core de `prefs`, `ActiveApp` ni `ActiveUix`.
- `themeDimension(...)` y `densityDimension(...)` quedan como factories - No hay `themeDimension(...)` ni `densityDimension(...)` en el catalogo
legacy/custom para apps ajenas a UIX; no usarlas en shells UIX nuevas. publico de prefs: si una app necesita dimensiones custom, usa las
primitivas genericas (`enumDimension`, `stringDimension`, etc.) o una
`PrefsDimension` propia.
## Composition Rule ## Composition Rule

@ -1,30 +0,0 @@
import { DENSITIES, type Density } from '$libs/density';
import type { PrefsDimension } from '$libs/prefs';
export interface DensityDimensionOptions {
readonly catalog?: readonly Density[];
readonly default?: Density;
}
/**
* @deprecated UIX visual density belongs to `ActiveEidos`, not to the
* standard prefs preset. Keep this only for legacy/custom app schemas
* outside UIX.
*/
export function densityDimension(
options: DensityDimensionOptions = {}
): PrefsDimension<Density> {
const catalog = options.catalog ?? DENSITIES;
const fallback = options.default ?? 'comfortable';
return {
defaultValue: fallback,
validate(value) {
if (typeof value !== 'string') return { ok: false, reason: 'unsupported_density' };
if (!catalog.includes(value as Density)) {
return { ok: false, reason: 'unsupported_density' };
}
return { ok: true, value: value as Density };
},
catalog: () => catalog
};
}

@ -2,9 +2,8 @@
* Built-in `PrefsDimension` catalog. Each dimension is its own factory * Built-in `PrefsDimension` catalog. Each dimension is its own factory
* — `localeDimension({...})`, `motionDimension({...})` — and the * — `localeDimension({...})`, `motionDimension({...})` — and the
* `standardPrefsDimensions(catalog)` preset composes the canonical set. * `standardPrefsDimensions(catalog)` preset composes the canonical set.
* Visual factories such as `themeDimension` and `densityDimension` remain * Visual theme/mode/density are not prefs dimensions in UIX; Eidos owns them
* importable for app-specific schemas, but they are not part of the standard * through its own sources.
* core preset; Eidos owns visual theme/mode/density by default.
* *
* Application-specific dimensions go alongside these, either by reusing * Application-specific dimensions go alongside these, either by reusing
* the primitive factories (`booleanDimension`, `enumDimension`, …) or * the primitive factories (`booleanDimension`, `enumDimension`, …) or
@ -14,8 +13,6 @@
export { localeDimension } from './locale.ts'; export { localeDimension } from './locale.ts';
export { languageDimension } from './language.ts'; export { languageDimension } from './language.ts';
export { themeDimension } from './theme.ts';
export { densityDimension } from './density.ts';
export { motionDimension } from './motion.ts'; export { motionDimension } from './motion.ts';
export { soundDimension } from './sound.ts'; export { soundDimension } from './sound.ts';
export { hapticDimension } from './haptic.ts'; export { hapticDimension } from './haptic.ts';

@ -1,49 +0,0 @@
import type { PrefsDimension } from '$libs/prefs';
import {
resolveTheme,
THEMES_INTENT,
type ThemeEffective,
type ThemeIntent
} from '$libs/theme';
export interface ThemeDimensionOptions {
/**
* Allowed intent values. Defaults to the full `THEMES_INTENT`
* (`'light' | 'dark' | 'system'`). Apps that don't want users to
* follow the OS pass `['light', 'dark']`.
*/
readonly intents?: readonly ThemeIntent[];
/**
* Final fallback applied when neither intent nor `env.colorScheme`
* provide a value. Must be a `ThemeEffective`.
*/
readonly default?: ThemeEffective;
}
/**
* @deprecated UIX visual mode belongs to `ActiveEidos`, not to the standard
* prefs preset. Keep this only for legacy/custom app schemas outside UIX.
*
* `TIntent` includes `'system'`, `TEffective` does not: `resolve` folds
* `'system'` into a concrete `'light' | 'dark'` using `env.colorScheme`.
*/
export function themeDimension(
options: ThemeDimensionOptions = {}
): PrefsDimension<ThemeIntent, ThemeEffective> {
const intents = options.intents ?? THEMES_INTENT;
const fallback = options.default ?? 'light';
return {
defaultValue: fallback,
validate(value) {
if (typeof value !== 'string') return { ok: false, reason: 'unsupported_theme' };
if (!intents.includes(value as ThemeIntent)) {
return { ok: false, reason: 'unsupported_theme' };
}
return { ok: true, value: value as ThemeIntent };
},
resolve(intent, env) {
return resolveTheme(intent, env.colorScheme, fallback);
},
catalog: () => intents
};
}

@ -31,7 +31,6 @@ export type { EnginePrefs, EnginePrefsOptions } from './types.ts';
export { export {
booleanDimension, booleanDimension,
currencyDimension, currencyDimension,
densityDimension,
directionDimension, directionDimension,
enumDimension, enumDimension,
hapticDimension, hapticDimension,
@ -41,7 +40,6 @@ export {
numberDimension, numberDimension,
soundDimension, soundDimension,
stringDimension, stringDimension,
themeDimension,
timezoneDimension, timezoneDimension,
unitSystemDimension unitSystemDimension
} from './dimensions/index.ts'; } from './dimensions/index.ts';

@ -2,15 +2,14 @@ import { describe, expect, it, vi } from 'vitest';
import { import {
booleanDimension, booleanDimension,
enumDimension, enumDimension,
localeDimension, localeDimension
themeDimension
} from '$prefs'; } from '$prefs';
import { createActivePrefs } from '../active-prefs.svelte.ts'; import { createActivePrefs } from '../active-prefs.svelte.ts';
import { PrefsReservedKeyError } from '../errors.ts'; import { PrefsReservedKeyError } from '../errors.ts';
const schema = { const schema = {
locale: localeDimension({ catalog: ['es-ES', 'en-US'], default: 'es-ES' }), locale: localeDimension({ catalog: ['es-ES', 'en-US'], default: 'es-ES' }),
theme: themeDimension({ default: 'light' }), accent: enumDimension(['blue', 'green'] as const, { default: 'blue' }),
sidebarCollapsed: booleanDimension({ default: false }), sidebarCollapsed: booleanDimension({ default: false }),
notifications: enumDimension(['all', 'mentions', 'none'] as const, { default: 'mentions' }) notifications: enumDimension(['all', 'mentions', 'none'] as const, { default: 'mentions' })
}; };
@ -20,7 +19,7 @@ describe('createActivePrefs — dimension-as-object surface', () => {
const prefs = createActivePrefs({ schema }); const prefs = createActivePrefs({ schema });
expect(prefs.locale.get()).toBe('es-ES'); expect(prefs.locale.get()).toBe('es-ES');
expect(prefs.theme.get()).toBe('light'); expect(prefs.accent.get()).toBe('blue');
expect(prefs.sidebarCollapsed.get()).toBe(false); expect(prefs.sidebarCollapsed.get()).toBe(false);
expect(prefs.notifications.get()).toBe('mentions'); expect(prefs.notifications.get()).toBe('mentions');
@ -39,16 +38,16 @@ describe('createActivePrefs — dimension-as-object surface', () => {
it('onChange fires only when the dimension itself changes', () => { it('onChange fires only when the dimension itself changes', () => {
const prefs = createActivePrefs({ schema }); const prefs = createActivePrefs({ schema });
const localeChange = vi.fn(); const localeChange = vi.fn();
const themeChange = vi.fn(); const accentChange = vi.fn();
prefs.locale.onChange(localeChange); prefs.locale.onChange(localeChange);
prefs.theme.onChange(themeChange); prefs.accent.onChange(accentChange);
prefs.locale.set('en-US'); prefs.locale.set('en-US');
expect(localeChange).toHaveBeenCalledWith('en-US'); expect(localeChange).toHaveBeenCalledWith('en-US');
expect(themeChange).not.toHaveBeenCalled(); expect(accentChange).not.toHaveBeenCalled();
prefs.theme.set('dark'); prefs.accent.set('green');
expect(themeChange).toHaveBeenCalledWith('dark'); expect(accentChange).toHaveBeenCalledWith('green');
prefs.dispose(); prefs.dispose();
}); });
@ -83,9 +82,9 @@ describe('createActivePrefs — dimension-as-object surface', () => {
it('state.snapshot reflects the latest commit', () => { it('state.snapshot reflects the latest commit', () => {
const prefs = createActivePrefs({ schema }); const prefs = createActivePrefs({ schema });
const v0 = prefs.state.version; const v0 = prefs.state.version;
prefs.theme.set('dark'); prefs.accent.set('green');
expect(prefs.state.version).toBe(v0 + 1); expect(prefs.state.version).toBe(v0 + 1);
expect(prefs.state.effective.theme).toBe('dark'); expect(prefs.state.effective.accent).toBe('green');
prefs.dispose(); prefs.dispose();
}); });
}); });

@ -1,5 +1,5 @@
import { describe, expect, it, vi } from 'vitest'; import { describe, expect, it, vi } from 'vitest';
import { booleanDimension, enumDimension, localeDimension, themeDimension } from '$prefs'; import { booleanDimension, enumDimension, localeDimension } from '$prefs';
import { createEnginePrefs } from '../engine-prefs.ts'; import { createEnginePrefs } from '../engine-prefs.ts';
import { import {
PrefsDisposedError, PrefsDisposedError,
@ -9,7 +9,6 @@ import {
const baseSchema = { const baseSchema = {
locale: localeDimension({ catalog: ['es-ES', 'en-US'], default: 'es-ES' }), locale: localeDimension({ catalog: ['es-ES', 'en-US'], default: 'es-ES' }),
theme: themeDimension({ default: 'light' }),
flag: booleanDimension({ default: false }), flag: booleanDimension({ default: false }),
mode: enumDimension(['compact', 'roomy'] as const, { default: 'roomy' }) mode: enumDimension(['compact', 'roomy'] as const, { default: 'roomy' })
}; };

@ -6,7 +6,7 @@
* is generic over a `PrefsSchema = Record<string, PrefsDimension>` and * is generic over a `PrefsSchema = Record<string, PrefsDimension>` and
* exposes one slot per dimension. * exposes one slot per dimension.
* *
* Built-in dimensions (`localeDimension`, `themeDimension`, …) live in * Built-in dimensions (`localeDimension`, `directionDimension`, …) live in
* `arts/prefs/dimensions/*` so the bundle can pick exactly which ones * `arts/prefs/dimensions/*` so the bundle can pick exactly which ones
* to ship. * to ship.
*/ */

@ -4,8 +4,7 @@ import {
directionDimension, directionDimension,
enumDimension, enumDimension,
languageDimension, languageDimension,
localeDimension, localeDimension
themeDimension
} from '$prefs'; } from '$prefs';
import { resolvePrefs } from '../resolve-prefs.ts'; import { resolvePrefs } from '../resolve-prefs.ts';
@ -13,7 +12,6 @@ describe('resolvePrefs — schema-generic resolver', () => {
const schema = { const schema = {
language: languageDimension({ catalog: ['es', 'en'], default: 'es' }), language: languageDimension({ catalog: ['es', 'en'], default: 'es' }),
locale: localeDimension({ catalog: ['es-ES', 'en-US'], default: 'es-ES' }), locale: localeDimension({ catalog: ['es-ES', 'en-US'], default: 'es-ES' }),
theme: themeDimension({ default: 'light' }),
direction: directionDimension(), direction: directionDimension(),
flag: booleanDimension({ default: false }), flag: booleanDimension({ default: false }),
mode: enumDimension(['compact', 'roomy'] as const, { default: 'roomy' }) mode: enumDimension(['compact', 'roomy'] as const, { default: 'roomy' })
@ -23,7 +21,6 @@ describe('resolvePrefs — schema-generic resolver', () => {
const eff = resolvePrefs({ schema, environment: {}, intent: {} }); const eff = resolvePrefs({ schema, environment: {}, intent: {} });
expect(eff.language).toBe('es'); expect(eff.language).toBe('es');
expect(eff.locale).toBe('es-ES'); expect(eff.locale).toBe('es-ES');
expect(eff.theme).toBe('light');
expect(eff.flag).toBe(false); expect(eff.flag).toBe(false);
expect(eff.mode).toBe('roomy'); expect(eff.mode).toBe('roomy');
}); });
@ -41,11 +38,10 @@ describe('resolvePrefs — schema-generic resolver', () => {
it('environment fills dimensions that have a fromEnvironment hook', () => { it('environment fills dimensions that have a fromEnvironment hook', () => {
const eff = resolvePrefs({ const eff = resolvePrefs({
schema, schema,
environment: { locales: ['en-US'], colorScheme: 'dark' }, environment: { locales: ['en-US'] },
intent: {} intent: {}
}); });
expect(eff.locale).toBe('en-US'); expect(eff.locale).toBe('en-US');
expect(eff.theme).toBe('dark');
}); });
it('drops invalid intent silently (resolver never throws)', () => { it('drops invalid intent silently (resolver never throws)', () => {

@ -65,7 +65,6 @@ export {
applyMapOverrides, applyMapOverrides,
type EffectiveSignature, type EffectiveSignature,
type HapticSignature, type HapticSignature,
type SemaActiveChannel,
type SemaCascadeRule, type SemaCascadeRule,
type SemaChannelId, type SemaChannelId,
type SemaChannelSignatures, type SemaChannelSignatures,

@ -55,9 +55,6 @@ export type {
SoundSignature SoundSignature
} from './sema-map'; } from './sema-map';
/** @deprecated kept for one cycle; use `SemaChannelId`. */
export type SemaActiveChannel = SemaChannelId;
/** /**
* Single cascade rule. Identical shape to a CSS rule — a selector that * Single cascade rule. Identical shape to a CSS rule — a selector that
* matches the target's data-attrs (state from morfo + event tokens * matches the target's data-attrs (state from morfo + event tokens

@ -110,9 +110,6 @@ export interface SemaChannelSignatures {
*/ */
export type SemaChannelId = keyof SemaChannelSignatures | (string & {}); export type SemaChannelId = keyof SemaChannelSignatures | (string & {});
/** @deprecated kept for one cycle; use `SemaChannelId`. */
export type SemaActiveChannel = SemaChannelId;
/** /**
* Phase 6 of the codex refactor (`refactorizacion_codex.md`): * Phase 6 of the codex refactor (`refactorizacion_codex.md`):
* `SemaRuntimeChannelId` is the FORWARD-LOOKING type for `channels` * `SemaRuntimeChannelId` is the FORWARD-LOOKING type for `channels`

Loading…
Cancel
Save

Powered by TurnKey Linux.