refactor(AdjustTypography): add typography-control module (factory, types, constants)

This commit is contained in:
Ilia Mashkov
2026-05-31 16:52:37 +03:00
parent 4640d6e521
commit 7834c7cbf2
6 changed files with 181 additions and 5 deletions
+3
View File
@@ -1,5 +1,8 @@
export {
createTypographySettingsStore,
MULTIPLIER_L,
MULTIPLIER_M,
MULTIPLIER_S,
type TypographySettingsStore,
typographySettingsStore,
} from './model';
@@ -0,0 +1,76 @@
import {
DEFAULT_FONT_SIZE,
DEFAULT_FONT_WEIGHT,
DEFAULT_LETTER_SPACING,
DEFAULT_LINE_HEIGHT,
FONT_SIZE_STEP,
FONT_WEIGHT_STEP,
LETTER_SPACING_STEP,
LINE_HEIGHT_STEP,
MAX_FONT_SIZE,
MAX_FONT_WEIGHT,
MAX_LETTER_SPACING,
MAX_LINE_HEIGHT,
MIN_FONT_SIZE,
MIN_FONT_WEIGHT,
MIN_LETTER_SPACING,
MIN_LINE_HEIGHT,
} from '$entities/Font';
import type {
ControlId,
ControlModel,
} from '../types/typography';
/**
* Responsive font-size scaling factors applied by typographySettingsStore.
*/
export const MULTIPLIER_S = 0.5;
export const MULTIPLIER_M = 0.75;
export const MULTIPLIER_L = 1;
/**
* Default control definitions seeding the typography settings store.
* Composed from the font-render ranges/defaults owned by the Font entity.
*/
export const DEFAULT_TYPOGRAPHY_CONTROLS_DATA: ControlModel<ControlId>[] = [
{
id: 'font_size',
value: DEFAULT_FONT_SIZE,
max: MAX_FONT_SIZE,
min: MIN_FONT_SIZE,
step: FONT_SIZE_STEP,
increaseLabel: 'Increase Font Size',
decreaseLabel: 'Decrease Font Size',
controlLabel: 'Size',
},
{
id: 'font_weight',
value: DEFAULT_FONT_WEIGHT,
max: MAX_FONT_WEIGHT,
min: MIN_FONT_WEIGHT,
step: FONT_WEIGHT_STEP,
increaseLabel: 'Increase Font Weight',
decreaseLabel: 'Decrease Font Weight',
controlLabel: 'Weight',
},
{
id: 'line_height',
value: DEFAULT_LINE_HEIGHT,
max: MAX_LINE_HEIGHT,
min: MIN_LINE_HEIGHT,
step: LINE_HEIGHT_STEP,
increaseLabel: 'Increase Line Height',
decreaseLabel: 'Decrease Line Height',
controlLabel: 'Leading',
},
{
id: 'letter_spacing',
value: DEFAULT_LETTER_SPACING,
max: MAX_LETTER_SPACING,
min: MIN_LETTER_SPACING,
step: LETTER_SPACING_STEP,
increaseLabel: 'Increase Letter Spacing',
decreaseLabel: 'Decrease Letter Spacing',
controlLabel: 'Tracking',
},
];
@@ -1,3 +1,8 @@
export {
MULTIPLIER_L,
MULTIPLIER_M,
MULTIPLIER_S,
} from './const/const';
export {
createTypographySettingsStore,
type TypographySettingsStore,
@@ -0,0 +1,27 @@
import type {
ControlLabels,
NumericControl,
} from '$shared/ui';
/**
* Identifiers for the adjustable typography axes
*/
export type ControlId = 'font_size' | 'font_weight' | 'line_height' | 'letter_spacing';
/**
* Static configuration for one typography control.
*
* Derived from the SSOT contract types — declares no fields of its own beyond
* the domain `id`. Bounds come from NumericControl, labels from ControlLabels.
*
* @template T - Control identifier type
*/
export type ControlModel<T extends string = string> =
& Pick<NumericControl, 'value' | 'min' | 'max' | 'step'>
& ControlLabels
& {
/**
* Unique identifier for the control
*/
id: T;
};
@@ -0,0 +1,67 @@
/**
* Bounded numeric control for typography settings.
*
* Produces a reactive control that clamps to [min, max] and rounds to step.
* Implements the NumericControl contract that ComboControl renders.
*/
import {
clampNumber,
roundToStepPrecision,
} from '$shared/lib/utils';
import type { NumericControl } from '$shared/ui';
/**
* Bounds + initial value seed for a control
*/
type ControlSeed = Pick<NumericControl, 'value' | 'min' | 'max' | 'step'>;
/**
* Create a reactive bounded numeric control.
*
* @param initialState - Initial value and bounds
* @returns A NumericControl whose value is always clamped and step-rounded
*/
export function createTypographyControl(initialState: ControlSeed): NumericControl {
let value = $state(initialState.value);
let max = $state(initialState.max);
let min = $state(initialState.min);
let step = $state(initialState.step);
const { isAtMax, isAtMin } = $derived({
isAtMax: value >= max,
isAtMin: value <= min,
});
return {
get value() {
return value;
},
set value(newValue) {
const rounded = roundToStepPrecision(clampNumber(newValue, min, max), step);
if (value !== rounded) {
value = rounded;
}
},
get max() {
return max;
},
get min() {
return min;
},
get step() {
return step;
},
get isAtMax() {
return isAtMax;
},
get isAtMin() {
return isAtMin;
},
increase() {
value = roundToStepPrecision(clampNumber(value + step, min, max), step);
},
decrease() {
value = roundToStepPrecision(clampNumber(value - step, min, max), step);
},
};
}
@@ -1,12 +1,10 @@
import {
type TypographyControl,
createTypographyControl,
} from '$shared/lib';
import type { NumericControl } from '$shared/ui';
import {
describe,
expect,
it,
} from 'vitest';
import { createTypographyControl } from './createTypographyControl.svelte';
/**
* Test Strategy for createTypographyControl Helper
@@ -34,7 +32,7 @@ describe('createTypographyControl - Unit Tests', () => {
min?: number;
max?: number;
step?: number;
}): TypographyControl {
}): NumericControl {
return createTypographyControl({
value: initialValue,
min: options?.min ?? 0,