@ariaui/typography 0.2.0

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.
@@ -0,0 +1,365 @@
1
+ /**
2
+ * A complete text style definition.
3
+ */
4
+ interface TextStyle {
5
+ /** Font size, e.g. `"1rem"`, `"clamp(1rem, 0.5rem + 1.5vw, 1.5rem)"` */
6
+ readonly fontSize: string;
7
+ /** Line height, e.g. `"1.5rem"` */
8
+ readonly lineHeight: string;
9
+ /** Letter spacing, e.g. `"-0.02em"`, `"0em"` */
10
+ readonly letterSpacing: string;
11
+ /** Font weight, e.g. `"400"`, `"600"` */
12
+ readonly fontWeight?: string;
13
+ /** Font family, e.g. `"'Inter', sans-serif"` */
14
+ readonly fontFamily?: string;
15
+ }
16
+ /**
17
+ * A single step in a type scale. Mirrors `TypeStep` from `@ariaui/tokens`
18
+ * but kept independent so the core package has no dependency.
19
+ */
20
+ interface ScaleStep {
21
+ /** Font size in rem, e.g. `"1rem"` */
22
+ readonly size: string;
23
+ /** Line height in rem, e.g. `"1.5rem"` */
24
+ readonly lineHeight: string;
25
+ /** Letter spacing in em, e.g. `"-0.02em"` */
26
+ readonly letterSpacing: string;
27
+ /** Recommended font weight */
28
+ readonly fontWeight?: string;
29
+ }
30
+ /**
31
+ * Configuration for CSS `clamp()`-based fluid typography.
32
+ */
33
+ interface FluidConfig {
34
+ /** Minimum font size in rem */
35
+ readonly minSize: number;
36
+ /** Maximum font size in rem */
37
+ readonly maxSize: number;
38
+ /** Minimum viewport width in px (default 320) */
39
+ readonly minViewport?: number;
40
+ /** Maximum viewport width in px (default 1280) */
41
+ readonly maxViewport?: number;
42
+ }
43
+ /**
44
+ * A font stack definition.
45
+ */
46
+ interface FontStack {
47
+ /** Human-readable name, e.g. `"sans"` */
48
+ readonly name: string;
49
+ /** Ordered list of font families */
50
+ readonly families: readonly string[];
51
+ }
52
+ /**
53
+ * Breakpoint name → pixel value mapping.
54
+ */
55
+ type Breakpoints = Record<string, number>;
56
+ /**
57
+ * A responsive text style: default + optional breakpoint overrides.
58
+ */
59
+ interface ResponsiveTextStyle {
60
+ /** Base style (no media query) */
61
+ readonly default: TextStyle;
62
+ /** Keyed by breakpoint name */
63
+ readonly breakpoints: Record<string, TextStyle>;
64
+ }
65
+ /**
66
+ * Configuration for vertical rhythm / baseline grid.
67
+ */
68
+ interface BaselineConfig {
69
+ /** Baseline grid unit in rem (default 0.25 — 4px at 16px root) */
70
+ readonly gridUnit?: number;
71
+ /** Rounding strategy: `"ceil"` rounds up, `"round"` rounds to nearest, `"floor"` rounds down */
72
+ readonly rounding?: "ceil" | "round" | "floor";
73
+ }
74
+
75
+ /** Pre-defined modular scale ratios. */
76
+ declare const RATIOS: {
77
+ readonly minorSecond: 1.067;
78
+ readonly majorSecond: 1.125;
79
+ readonly minorThird: 1.2;
80
+ readonly majorThird: 1.25;
81
+ readonly perfectFourth: 1.333;
82
+ readonly augmentedFourth: 1.414;
83
+ readonly perfectFifth: 1.5;
84
+ readonly goldenRatio: 1.618;
85
+ };
86
+ /**
87
+ * Create a modular type scale.
88
+ *
89
+ * Generates `steps` sizes by multiplying a base size by the ratio.
90
+ * Steps are named with a numeric index (0 = base, positive = larger,
91
+ * negative = smaller).
92
+ *
93
+ * @param base - Base font size in rem (default 1)
94
+ * @param ratio - Scale ratio (use `RATIOS` or a custom number)
95
+ * @param stepsUp - Number of steps above the base (default 5)
96
+ * @param stepsDown - Number of steps below the base (default 2)
97
+ *
98
+ * @example
99
+ * createModularScale(1, RATIOS.perfectFourth, 5, 2)
100
+ * // → { "-2": ..., "-1": ..., "0": ..., "1": ..., ... "5": ... }
101
+ */
102
+ declare function createModularScale(base?: number, ratio?: number, stepsUp?: number, stepsDown?: number): Record<string, ScaleStep>;
103
+ /**
104
+ * Extend an existing scale with overrides.
105
+ *
106
+ * Each override is shallowly merged with the existing step (if present)
107
+ * or added as a new step.
108
+ */
109
+ declare function extendScale(base: Record<string, ScaleStep>, overrides: Record<string, Partial<ScaleStep>>): Record<string, ScaleStep>;
110
+ /**
111
+ * Get a single step from a scale by name.
112
+ */
113
+ declare function getStep(scale: Record<string, ScaleStep>, name: string): ScaleStep | undefined;
114
+ /**
115
+ * List all step names in a scale, sorted by font size (smallest first).
116
+ */
117
+ declare function listSteps(scale: Record<string, ScaleStep>): string[];
118
+
119
+ /**
120
+ * Generate a CSS `clamp()` value for fluid typography.
121
+ *
122
+ * Uses the formula:
123
+ * ```
124
+ * clamp(minSize, preferredValue, maxSize)
125
+ * ```
126
+ * where `preferredValue = baseRem + slopeVw`
127
+ *
128
+ * @example
129
+ * fluidSize({ minSize: 1, maxSize: 1.5 })
130
+ * // → "clamp(1rem, 0.7667rem + 0.7292vw, 1.5rem)"
131
+ */
132
+ declare function fluidSize(config: FluidConfig): string;
133
+ /**
134
+ * Generate a fluid `TextStyle` by interpolating between a min and max `ScaleStep`.
135
+ *
136
+ * Font size uses `clamp()`, line-height and letter-spacing use the max step values.
137
+ *
138
+ * @param min - Scale step at the minimum viewport
139
+ * @param max - Scale step at the maximum viewport
140
+ * @param viewports - Optional min/max viewport widths in px
141
+ */
142
+ declare function fluidStyle(min: ScaleStep, max: ScaleStep, viewports?: {
143
+ min?: number;
144
+ max?: number;
145
+ }): TextStyle;
146
+ /**
147
+ * Make an entire scale fluid between mobile and desktop sizes.
148
+ *
149
+ * Both scales must have matching keys. For each key, a fluid style
150
+ * is generated by interpolating the mobile step to the desktop step.
151
+ *
152
+ * @param mobileScale - Scale at the minimum viewport
153
+ * @param desktopScale - Scale at the maximum viewport
154
+ * @param viewports - Optional min/max viewport widths in px
155
+ */
156
+ declare function fluidScale(mobileScale: Record<string, ScaleStep>, desktopScale: Record<string, ScaleStep>, viewports?: {
157
+ min?: number;
158
+ max?: number;
159
+ }): Record<string, TextStyle>;
160
+
161
+ /** System UI font stack — uses the OS default sans-serif. */
162
+ declare const systemStack: FontStack;
163
+ /** Sans-serif stack with Inter as the primary font. */
164
+ declare const sansStack: FontStack;
165
+ /** Serif font stack. */
166
+ declare const serifStack: FontStack;
167
+ /** Monospace font stack. */
168
+ declare const monoStack: FontStack;
169
+ /** All pre-defined stacks keyed by name. */
170
+ declare const FONT_STACKS: Record<string, FontStack>;
171
+ /**
172
+ * Build a CSS `font-family` value from a `FontStack`.
173
+ *
174
+ * @example
175
+ * buildFontFamily(sansStack)
176
+ * // → "'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"
177
+ */
178
+ declare function buildFontFamily(stack: FontStack): string;
179
+ /**
180
+ * Create a custom font stack.
181
+ *
182
+ * @param name - Stack identifier
183
+ * @param primary - Primary font family (will be quoted if needed)
184
+ * @param fallback - Base fallback stack to append (default: `systemStack`)
185
+ */
186
+ declare function createFontStack(name: string, primary: string, fallback?: FontStack): FontStack;
187
+
188
+ /**
189
+ * Create a `TextStyle` from a `ScaleStep` with optional overrides.
190
+ *
191
+ * @example
192
+ * createTextStyle({ size: "1rem", lineHeight: "1.5rem", letterSpacing: "0em" })
193
+ * // → { fontSize: "1rem", lineHeight: "1.5rem", letterSpacing: "0em" }
194
+ *
195
+ * createTextStyle(step, { fontWeight: "700", fontFamily: "'Inter', sans-serif" })
196
+ */
197
+ declare function createTextStyle(step: ScaleStep, overrides?: Partial<TextStyle>): TextStyle;
198
+ /**
199
+ * Merge multiple partial text styles. Later values win.
200
+ *
201
+ * Undefined properties are omitted from the result unless a later
202
+ * style provides them.
203
+ *
204
+ * @example
205
+ * mergeTextStyles(
206
+ * { fontSize: "1rem", lineHeight: "1.5rem", letterSpacing: "0em" },
207
+ * { fontWeight: "700" },
208
+ * )
209
+ */
210
+ declare function mergeTextStyles(...styles: Partial<TextStyle>[]): TextStyle;
211
+
212
+ /**
213
+ * Convert a `TextStyle` to a React `CSSProperties` object.
214
+ *
215
+ * @example
216
+ * toCSSProperties(style)
217
+ * // → { fontSize: "1rem", lineHeight: "1.5rem", letterSpacing: "0em" }
218
+ */
219
+ declare function toCSSProperties(style: TextStyle): Record<string, string>;
220
+ /**
221
+ * Convert a `TextStyle` to a CSS declaration block string.
222
+ *
223
+ * @example
224
+ * toCSSDeclarations(style)
225
+ * // → "font-size: 1rem;\nline-height: 1.5rem;\nletter-spacing: 0em;"
226
+ */
227
+ declare function toCSSDeclarations(style: TextStyle): string;
228
+ /**
229
+ * Generate CSS using `var()` references to `@ariaui/tokens` CSS custom properties.
230
+ *
231
+ * @param stepName - Token step name, e.g. `"display-2xl"`, `"text-md"`
232
+ *
233
+ * @example
234
+ * toCSSVars("display-2xl")
235
+ * // → "font-size: var(--font-size-display-2xl);\nline-height: var(--font-size-display-2xl--line-height);\nletter-spacing: var(--font-size-display-2xl--letter-spacing);"
236
+ */
237
+ declare function toCSSVars(stepName: string): string;
238
+ /**
239
+ * Convert a `TextStyle` to Tailwind CSS arbitrary-value classes.
240
+ *
241
+ * @example
242
+ * toTailwindClasses(style)
243
+ * // → "text-[1rem] leading-[1.5rem] tracking-[0em]"
244
+ */
245
+ declare function toTailwindClasses(style: TextStyle): string;
246
+
247
+ /**
248
+ * Default breakpoints matching Tailwind CSS v4 defaults.
249
+ */
250
+ declare const BREAKPOINTS: Breakpoints;
251
+ /**
252
+ * Build a `ResponsiveTextStyle` from a map of breakpoint → scale step or text style.
253
+ *
254
+ * The `"default"` key is required; all other keys must match a breakpoint name.
255
+ *
256
+ * @param config - Map of `"default"` + breakpoint names to `ScaleStep` or `TextStyle`
257
+ * @param breakpoints - Breakpoint definitions (default: Tailwind breakpoints)
258
+ *
259
+ * @example
260
+ * responsiveStyle({
261
+ * default: { size: "0.875rem", lineHeight: "1.25rem", letterSpacing: "0em" },
262
+ * md: { size: "1rem", lineHeight: "1.5rem", letterSpacing: "0em" },
263
+ * lg: { size: "1.125rem", lineHeight: "1.75rem", letterSpacing: "0em" },
264
+ * })
265
+ */
266
+ declare function responsiveStyle(config: Record<string, ScaleStep | TextStyle>, breakpoints?: Breakpoints): ResponsiveTextStyle;
267
+ /**
268
+ * Get the sorted breakpoint entries from a `ResponsiveTextStyle`,
269
+ * ordered by viewport width (ascending).
270
+ *
271
+ * Useful for consumers that need to iterate breakpoints in order.
272
+ *
273
+ * @returns Array of `[breakpointName, pixelWidth, textStyle]` tuples.
274
+ */
275
+ declare function sortedBreakpoints(responsive: ResponsiveTextStyle, breakpoints?: Breakpoints): Array<[string, number, TextStyle]>;
276
+
277
+ /**
278
+ * Calculate the optimal line length in `ch` units.
279
+ *
280
+ * Based on the typographic guideline of **45–75 characters per line**
281
+ * (Bringhurst). The ideal is ~66 characters.
282
+ *
283
+ * The font-size parameter is accepted for API consistency but the
284
+ * recommended range is font-size-independent when using `ch` units
285
+ * (which scale with the font).
286
+ *
287
+ * @param options.min - Minimum characters per line (default 45)
288
+ * @param options.max - Maximum characters per line (default 75)
289
+ * @param options.ideal - Ideal characters per line (default 66)
290
+ *
291
+ * @returns The ideal measure as a `ch` string.
292
+ *
293
+ * @example
294
+ * optimalMeasure() // → "66ch"
295
+ * optimalMeasure({ ideal: 60 }) // → "60ch"
296
+ */
297
+ declare function optimalMeasure(options?: {
298
+ min?: number;
299
+ max?: number;
300
+ ideal?: number;
301
+ }): string;
302
+ /**
303
+ * Get the full measure range as min/max `ch` values.
304
+ *
305
+ * Useful for setting `min-width` / `max-width` on a reading container.
306
+ *
307
+ * @example
308
+ * measureRange() // → { min: "45ch", max: "75ch", ideal: "66ch" }
309
+ */
310
+ declare function measureRange(options?: {
311
+ min?: number;
312
+ max?: number;
313
+ ideal?: number;
314
+ }): {
315
+ min: string;
316
+ max: string;
317
+ ideal: string;
318
+ };
319
+ /**
320
+ * Snap a line-height to a baseline grid.
321
+ *
322
+ * Given a font size and a grid unit (default 0.25rem = 4px), returns
323
+ * the smallest line-height that:
324
+ * 1. Is a multiple of `gridUnit`
325
+ * 2. Is ≥ the font size × minimum line-height ratio (default 1.2)
326
+ *
327
+ * @param fontSize - Font size as a rem string (e.g. `"1rem"`)
328
+ * @param config - Baseline grid configuration
329
+ *
330
+ * @example
331
+ * snapToBaseline("1rem") // → "1.5rem" (1.5 = 6 × 0.25)
332
+ * snapToBaseline("2.25rem") // → "2.75rem" (2.75 = 11 × 0.25)
333
+ * snapToBaseline("1rem", { gridUnit: 0.5 }) // → "1.5rem"
334
+ */
335
+ declare function snapToBaseline(fontSize: string, config?: BaselineConfig): string;
336
+ /**
337
+ * Calculate the vertical spacing (margin/padding) needed to maintain
338
+ * rhythm between elements on a baseline grid.
339
+ *
340
+ * @param lineHeight - Current line-height as a rem string
341
+ * @param lines - Number of grid lines of spacing (default 1)
342
+ * @param gridUnit - Grid unit in rem (default 0.25)
343
+ *
344
+ * @example
345
+ * rhythmSpacing("1.5rem") // → "0.25rem" (one 4px grid line)
346
+ * rhythmSpacing("1.5rem", 2) // → "0.5rem" (two grid lines)
347
+ * rhythmSpacing("1.5rem", 4) // → "1rem" (four grid lines = 16px)
348
+ */
349
+ declare function rhythmSpacing(lineHeight: string, lines?: number, gridUnit?: number): string;
350
+ /**
351
+ * Generate a complete vertical rhythm configuration for a text style.
352
+ *
353
+ * Returns the snapped line-height plus recommended spacing above and below.
354
+ *
355
+ * @param fontSize - Font size as a rem string
356
+ * @param spacingLines - Lines of spacing between paragraphs (default 4 = 1rem)
357
+ * @param config - Baseline grid configuration
358
+ */
359
+ declare function verticalRhythm(fontSize: string, spacingLines?: number, config?: BaselineConfig): {
360
+ lineHeight: string;
361
+ marginTop: string;
362
+ marginBottom: string;
363
+ };
364
+
365
+ export { BREAKPOINTS, type BaselineConfig, type Breakpoints, FONT_STACKS, type FluidConfig, type FontStack, RATIOS, type ResponsiveTextStyle, type ScaleStep, type TextStyle, buildFontFamily, createFontStack, createModularScale, createTextStyle, extendScale, fluidScale, fluidSize, fluidStyle, getStep, listSteps, measureRange, mergeTextStyles, monoStack, optimalMeasure, responsiveStyle, rhythmSpacing, sansStack, serifStack, snapToBaseline, sortedBreakpoints, systemStack, toCSSDeclarations, toCSSProperties, toCSSVars, toTailwindClasses, verticalRhythm };
package/dist/index.js ADDED
@@ -0,0 +1,62 @@
1
+ import {
2
+ BREAKPOINTS,
3
+ FONT_STACKS,
4
+ RATIOS,
5
+ buildFontFamily,
6
+ createFontStack,
7
+ createModularScale,
8
+ createTextStyle,
9
+ extendScale,
10
+ fluidScale,
11
+ fluidSize,
12
+ fluidStyle,
13
+ getStep,
14
+ listSteps,
15
+ measureRange,
16
+ mergeTextStyles,
17
+ monoStack,
18
+ optimalMeasure,
19
+ responsiveStyle,
20
+ rhythmSpacing,
21
+ sansStack,
22
+ serifStack,
23
+ snapToBaseline,
24
+ sortedBreakpoints,
25
+ systemStack,
26
+ toCSSDeclarations,
27
+ toCSSProperties,
28
+ toCSSVars,
29
+ toTailwindClasses,
30
+ verticalRhythm
31
+ } from "./chunk-F7KWOKBZ.js";
32
+ export {
33
+ BREAKPOINTS,
34
+ FONT_STACKS,
35
+ RATIOS,
36
+ buildFontFamily,
37
+ createFontStack,
38
+ createModularScale,
39
+ createTextStyle,
40
+ extendScale,
41
+ fluidScale,
42
+ fluidSize,
43
+ fluidStyle,
44
+ getStep,
45
+ listSteps,
46
+ measureRange,
47
+ mergeTextStyles,
48
+ monoStack,
49
+ optimalMeasure,
50
+ responsiveStyle,
51
+ rhythmSpacing,
52
+ sansStack,
53
+ serifStack,
54
+ snapToBaseline,
55
+ sortedBreakpoints,
56
+ systemStack,
57
+ toCSSDeclarations,
58
+ toCSSProperties,
59
+ toCSSVars,
60
+ toTailwindClasses,
61
+ verticalRhythm
62
+ };