@kalink-ui/seedly 0.29.1 → 0.30.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,49 @@
1
1
  # @kalink-ui/seedly
2
2
 
3
+ ## 0.30.0
4
+
5
+ ### Minor Changes
6
+
7
+ - e257be4: feat(styles): add dynamic fluid scale helpers
8
+
9
+ New
10
+ - `getInterpolationFor(value, options)`: per-value exponential mapping from a mobile range to a desktop range.
11
+ - `toFluidClamp([min, max], options)`: build a viewport-based CSS `clamp()` with `interpolateFrom`/`interpolateTo` (defaults `23.5` and `80`).
12
+ - `toFluidClampFor(value, options)`: convenience to compute the mapped max and format a `clamp()` in one step.
13
+
14
+ Updates
15
+ - Storybook theme now uses the new helpers and no longer depends on an interpolation variable.
16
+
17
+ Usage
18
+
19
+ ```ts
20
+ import {
21
+ getInterpolationFor,
22
+ toFluidClampFor,
23
+ } from '@kalink-ui/seedly/styles';
24
+
25
+ const mapped = getInterpolationFor(12, {
26
+ lowMin: 12,
27
+ lowMax: 64,
28
+ highMin: 12,
29
+ highMax: 200,
30
+ exponent: 2,
31
+ rounding: 'none',
32
+ });
33
+
34
+ const clamp = toFluidClampFor(12, {
35
+ lowMin: 12,
36
+ lowMax: 64,
37
+ highMin: 12,
38
+ highMax: 200,
39
+ exponent: 2,
40
+ rounding: 'none',
41
+ // optional overrides
42
+ interpolateFrom: 23.5,
43
+ interpolateTo: 80,
44
+ });
45
+ ```
46
+
3
47
  ## 0.29.1
4
48
 
5
49
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kalink-ui/seedly",
3
- "version": "0.29.1",
3
+ "version": "0.30.0",
4
4
  "description": "A set of components for building UIs with React and TypeScript",
5
5
  "sideEffects": false,
6
6
  "license": "MIT",
@@ -43,8 +43,8 @@
43
43
  "vite": "^6.3.5",
44
44
  "vite-tsconfig-paths": "^5.1.4",
45
45
  "vitest": "^3.2.3",
46
- "@kalink-ui/eslint-config": "0.10.0",
47
- "@kalink-ui/typescript-config": "0.4.0"
46
+ "@kalink-ui/typescript-config": "0.4.0",
47
+ "@kalink-ui/eslint-config": "0.10.0"
48
48
  },
49
49
  "peerDependencies": {
50
50
  "@vanilla-extract/css": "^1.17.1",
@@ -34,3 +34,13 @@ export {
34
34
  } from './responsive';
35
35
 
36
36
  export { breakpoints, screen, type BreakpointKey } from './breakpoints';
37
+
38
+ export {
39
+ getInterpolationFor,
40
+ toFluidClamp,
41
+ toFluidClampFor,
42
+ type Interval,
43
+ type ExponentialScaleOptions,
44
+ type DynamicInterpolationOptions,
45
+ type FluidClampOptions,
46
+ } from './scale';
@@ -0,0 +1,149 @@
1
+ export type Interval = [number, number];
2
+
3
+ /**
4
+ * Common easing/rounding options used by the interpolation helpers.
5
+ * Note: `minStep` is ignored in single-value mapping but kept for backward
6
+ * compatibility of the public types.
7
+ */
8
+ export interface ExponentialScaleOptions {
9
+ exponent?: number; // 1 = linear, >1 = ease-in, <1 = ease-out
10
+ minStep?: number; // kept for compatibility; not used by per-value mapping
11
+ rounding?: 'none' | 'round' | 'floor' | 'ceil';
12
+ }
13
+
14
+ export interface DynamicInterpolationOptions extends ExponentialScaleOptions {
15
+ lowMin: number;
16
+ lowMax: number;
17
+ highMin: number;
18
+ highMax: number;
19
+ clampInput?: boolean; // clamp input inside [lowMin, lowMax]
20
+ ensureGteInput?: boolean; // ensure output >= input
21
+ }
22
+
23
+ export interface FluidClampOptions {
24
+ unit?: 'rem' | 'px';
25
+ baseFontSize?: number; // px per rem when unit is 'rem'
26
+ interpolateFrom?: number; // defaults to 23.5 (in `unit`)
27
+ interpolateTo?: number; // defaults to 80 (in `unit`)
28
+ }
29
+
30
+ /**
31
+ * Format a `[min, max]` pair into a CSS clamp() with viewport-based interpolation:
32
+ * clamp(min, calc(min + (max - min) * ((100vw - from) / (to - from))), max)
33
+ *
34
+ * - `from`/`to` default to 23.5 and 80 (in the selected `unit`).
35
+ * - `unit` may be 'rem' (default) or 'px'. When 'rem', values are converted from px
36
+ * using `baseFontSize` (default 16).
37
+ */
38
+ export function toFluidClamp(
39
+ [min, max]: Interval,
40
+ options: FluidClampOptions = {},
41
+ ): string {
42
+ const unit = options.unit ?? 'rem';
43
+ const base = options.baseFontSize ?? 16;
44
+ const from = options.interpolateFrom ?? 23.5;
45
+ const to = options.interpolateTo ?? 80;
46
+
47
+ const toUnit = (px: number): number => {
48
+ if (unit === 'px') {
49
+ return px;
50
+ }
51
+
52
+ return px / base;
53
+ };
54
+
55
+ const minU = toUnit(min);
56
+ const maxU = toUnit(max);
57
+ const diffU = maxU - minU;
58
+
59
+ const interp = `((100vw - ${from}${unit}) / (${to} - ${from}))`;
60
+
61
+ return `clamp(${minU}${unit}, calc(${minU}${unit} + (${diffU} * ${interp})), ${maxU}${unit})`;
62
+ }
63
+
64
+ // Batch scale helpers were removed in favor of per-value mapping.
65
+
66
+ /**
67
+ * Map a single `value` from [lowMin, lowMax] to [highMin, highMax] using
68
+ * exponential easing. Optionally rounds, clamps input, and ensures the output
69
+ * is not below the input (enabled by default).
70
+ */
71
+ export function getInterpolationFor(
72
+ value: number,
73
+ {
74
+ lowMin,
75
+ lowMax,
76
+ highMin,
77
+ highMax,
78
+ exponent = 2,
79
+ rounding = 'round',
80
+ clampInput = true,
81
+ ensureGteInput = true,
82
+ }: DynamicInterpolationOptions,
83
+ ): number {
84
+ if (lowMax === lowMin) {
85
+ throw new Error('getInterpolationFor: lowMin and lowMax must differ.');
86
+ }
87
+
88
+ const clamp = (v: number, min: number, max: number): number => {
89
+ if (v < min) {
90
+ return min;
91
+ }
92
+
93
+ if (v > max) {
94
+ return max;
95
+ }
96
+
97
+ return v;
98
+ };
99
+
100
+ const round = (v: number): number => {
101
+ if (rounding === 'none') {
102
+ return v;
103
+ }
104
+
105
+ if (rounding === 'floor') {
106
+ return Math.floor(v);
107
+ }
108
+
109
+ if (rounding === 'ceil') {
110
+ return Math.ceil(v);
111
+ }
112
+
113
+ return Math.round(v);
114
+ };
115
+
116
+ const input = clampInput ? clamp(value, lowMin, lowMax) : value;
117
+
118
+ const t = (input - lowMin) / (lowMax - lowMin);
119
+ const eased = Math.pow(t, exponent);
120
+ const mapped = highMin + eased * (highMax - highMin);
121
+
122
+ let result = round(mapped);
123
+
124
+ if (ensureGteInput && result < input) {
125
+ result = input;
126
+ }
127
+
128
+ return result;
129
+ }
130
+
131
+ export interface FluidClampForOptions
132
+ extends DynamicInterpolationOptions,
133
+ FluidClampOptions {}
134
+
135
+ /**
136
+ * Convenience to produce a CSS clamp() for a single `value` by first computing
137
+ * its mapped high value via `getInterpolationFor`, then formatting with
138
+ * `toFluidClamp` using viewport interpolation.
139
+ */
140
+ export function toFluidClampFor(
141
+ value: number,
142
+ { unit = 'rem', baseFontSize = 16, ...opts }: FluidClampForOptions,
143
+ ): string {
144
+ return toFluidClamp([value, getInterpolationFor(value, opts)], {
145
+ unit,
146
+ baseFontSize,
147
+ ...opts,
148
+ });
149
+ }