Skip to content

Commit 92fcc08

Browse files
authored
Release v0.4.0-alpha.0
2 parents eddc244 + fbca929 commit 92fcc08

37 files changed

+1829
-174
lines changed

README.md

Lines changed: 62 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# KompKit
22

3-
[![Version](https://img.shields.io/badge/version-0.3.0--alpha.0-orange.svg)](https://github.com/Kompkit/KompKit/releases)
3+
[![Version](https://img.shields.io/badge/version-0.4.0--alpha.0-orange.svg)](https://github.com/Kompkit/KompKit/releases)
44
[![Web CI](https://github.com/Kompkit/KompKit/actions/workflows/web.yml/badge.svg?branch=develop)](https://github.com/Kompkit/KompKit/actions/workflows/web.yml)
55
[![Kotlin CI](https://github.com/Kompkit/KompKit/actions/workflows/android.yml/badge.svg?branch=develop)](https://github.com/Kompkit/KompKit/actions/workflows/android.yml)
66
[![Flutter CI](https://github.com/Kompkit/KompKit/actions/workflows/flutter.yml/badge.svg?branch=develop)](https://github.com/Kompkit/KompKit/actions/workflows/flutter.yml)
@@ -60,6 +60,8 @@ KompKit provides essential utility functions that work seamlessly across Web (Ty
6060
- **🕐 debounce** - Delay function execution until after a wait period (prevents excessive API calls)
6161
- **📧 isEmail** - Validate email addresses with robust regex patterns
6262
- **💰 formatCurrency** - Format numbers as currency with full locale support
63+
- **📐 clamp** - Constrain a number within an inclusive [min, max] range
64+
- **⏱️ throttle** - Limit a function to execute at most once per wait period
6365

6466
### Key Features
6567

@@ -95,7 +97,7 @@ Add to your `pubspec.yaml`:
9597

9698
```yaml
9799
dependencies:
98-
kompkit_core: ^0.3.0-alpha.1
100+
kompkit_core: ^0.4.0-alpha.0
99101
```
100102
101103
Then run:
@@ -129,40 +131,80 @@ Once installed, you can import and use KompKit utilities:
129131
**TypeScript/JavaScript:**
130132

131133
```typescript
132-
import { debounce, isEmail, formatCurrency } from "kompkit-core";
134+
import {
135+
debounce,
136+
isEmail,
137+
formatCurrency,
138+
clamp,
139+
throttle,
140+
} from "kompkit-core";
141+
142+
// Delay execution until typing stops
143+
const onSearch = debounce(
144+
(query: string) => console.log("Search:", query),
145+
300,
146+
);
147+
148+
// Validate email
149+
console.log(isEmail("user@example.com")); // true
133150

134-
const search = debounce((query: string) => {
135-
console.log("Searching:", query);
136-
}, 300);
151+
// Format as currency
152+
console.log(formatCurrency(1234.56)); // "$1,234.56"
137153

138-
console.log(isEmail("user@example.com")); // true
139-
console.log(formatCurrency(1234.56)); // "1.234,56 €"
154+
// Constrain a value to a range
155+
console.log(clamp(15, 0, 10)); // 10
156+
157+
// Rate-limit a scroll handler
158+
const onScroll = throttle(() => console.log("scrollY:", window.scrollY), 200);
159+
window.addEventListener("scroll", onScroll);
140160
```
141161

142162
**Kotlin:**
143163

144164
```kotlin
145165
import com.kompkit.core.*
146166

147-
val search = debounce<String>(300L, scope) { query ->
148-
println("Searching: $query")
149-
}
167+
// Delay execution until typing stops
168+
val onSearch = debounce<String>(300L, scope) { query -> println("Search: $query") }
150169

170+
// Validate email
151171
println(isEmail("user@example.com")) // true
152-
println(formatCurrency(1234.56)) // "1.234,56 €"
172+
173+
// Format as currency
174+
println(formatCurrency(1234.56)) // "$1,234.56"
175+
176+
// Constrain a value to a range
177+
println(clamp(15.0, 0.0, 10.0)) // 10.0
178+
179+
// Rate-limit a scroll handler
180+
val onScroll = throttle<Int>(200L, scope) { pos -> println("scroll: $pos") }
153181
```
154182

155183
**Dart/Flutter:**
156184

157185
```dart
158186
import 'package:kompkit_core/kompkit_core.dart';
159187
160-
final search = debounce<String>((String query) {
161-
print('Searching: $query');
162-
}, const Duration(milliseconds: 300));
188+
// Delay execution until typing stops
189+
final onSearch = debounce<String>(
190+
(query) => print('Search: $query'),
191+
const Duration(milliseconds: 300),
192+
);
163193
194+
// Validate email
164195
print(isEmail('user@example.com')); // true
165-
print(formatCurrency(1234.56)); // "1.234,56 €"
196+
197+
// Format as currency
198+
print(formatCurrency(1234.56)); // "$1,234.56"
199+
200+
// Constrain a value to a range
201+
print(clamp(15.0, 0.0, 10.0)); // 10.0
202+
203+
// Rate-limit a scroll handler
204+
final onScroll = throttle<double>(
205+
(offset) => print('scroll: $offset'),
206+
const Duration(milliseconds: 200),
207+
);
166208
```
167209

168210
## Documentation
@@ -211,7 +253,7 @@ KompKit/
211253

212254
## Version Information
213255

214-
- **Current Version**: `0.3.0-alpha`
256+
- **Current Version**: `0.4.0-alpha.0`
215257
- **Minimum Requirements**:
216258
- Node.js 20+ (Web)
217259
- JDK 17+ (Android)
@@ -225,7 +267,7 @@ KompKit/
225267
KompKit is currently in **alpha**. This means:
226268

227269
- **APIs may change** between alpha versions without a deprecation period.
228-
- **Pin to exact versions** in production: `"kompkit-core": "0.3.0-alpha.1"` / `kompkit_core: 0.3.0-alpha.1`.
270+
- **Pin to exact versions** in production: `"kompkit-core": "0.4.0-alpha.0"` / `kompkit_core: 0.4.0-alpha.0`.
229271
- **Breaking changes** will be documented in [CHANGELOG.md](./docs/CHANGELOG.md) with migration notes.
230272
- Once `1.0.0` is released, the project will follow strict [Semantic Versioning](https://semver.org/): breaking changes only in major versions.
231273

@@ -237,6 +279,8 @@ KompKit aims for **conceptual parity**, not syntactic identity. The following di
237279
| ---------------- | -------- | -------------------------------------------------------------- | ----------------------------------------------------------- |
238280
| `debounce` | Kotlin | Requires `CoroutineScope` parameter | Structured concurrency — no global timer API on JVM |
239281
| `debounce` | Kotlin | Action is first parameter, scope is last | Enables idiomatic trailing lambda syntax |
282+
| `throttle` | Kotlin | Requires `CoroutineScope` parameter | Same structured concurrency constraint as `debounce` |
283+
| `throttle` | Dart | `wait` is a `Duration`, not a number | Idiomatic Dart — no bare millisecond integers |
240284
| `formatCurrency` | Kotlin | Accepts `String` locale, converts to `Locale` internally | JVM `NumberFormat` requires `java.util.Locale` |
241285
| `formatCurrency` | Dart | Accepts BCP 47 locale, normalizes hyphen→underscore internally | `intl` package uses underscore-separated locale identifiers |
242286

SECURITY.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44

55
| Version | Supported |
66
| --------------- | ---------------------- |
7-
| `0.3.0-alpha.1` | ✅ Current |
7+
| `0.4.0-alpha.0` | ✅ Current |
8+
| `0.3.0-alpha.1` | ❌ No longer supported |
89
| `0.2.0-alpha.0` | ❌ No longer supported |
910
| `0.1.0-alpha` | ❌ No longer supported |
1011

docs/ARCHITECTURE.md

Lines changed: 62 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,16 +45,18 @@ All modules implement identical functionality:
4545
- **debounce**: Function execution delay with cancellation
4646
- **isEmail**: Email validation using regex patterns
4747
- **formatCurrency**: Localized currency formatting
48+
- **clamp**: Constrain a number within an inclusive [min, max] range
49+
- **throttle**: Limit function execution to at most once per wait period
4850

4951
## API Parity Contract
5052

5153
This section defines the formal contract for cross-platform API consistency in KompKit.
5254

5355
### What is Guaranteed
5456

55-
- **Function names** are identical across all platforms (`debounce`, `isEmail`, `formatCurrency`).
57+
- **Function names** are identical across all platforms (`debounce`, `isEmail`, `formatCurrency`, `clamp`, `throttle`).
5658
- **Behavioral semantics** are identical: given the same inputs, all platforms produce the same observable output.
57-
- **Default values** are identical: `wait = 250ms`, `currency = "EUR"`, `locale = "en-US"`.
59+
- **Default values** are identical: `wait = 250ms`, `currency = "USD"`, `locale = "en-US"`.
5860
- **Error handling philosophy** is consistent: invalid inputs that cannot produce a meaningful result throw/throw-equivalent errors. Silent fallbacks are not permitted.
5961
- **Cancel capability**: `debounce` returns an object with a `cancel()` method on all platforms, allowing callers to discard pending executions (required for safe use in component lifecycles).
6062

@@ -70,9 +72,11 @@ This section defines the formal contract for cross-platform API consistency in K
7072
Every utility follows the same mental model regardless of platform:
7173

7274
```
73-
debounce(action, options) → Debounced<T> (with .cancel())
74-
isEmail(value) → Boolean
75-
formatCurrency(amount, options) → String
75+
debounce(action, options) → Debounced<T> (with .cancel())
76+
isEmail(value) → Boolean
77+
formatCurrency(amount, options) → String
78+
clamp(value, min, max) → Number
79+
throttle(fn, wait) → Throttled<T> (with .cancel())
7680
```
7781

7882
A developer familiar with the TypeScript API should be able to use the Kotlin or Dart API with only idiomatic adjustments — not conceptual re-learning.
@@ -120,9 +124,21 @@ export function isEmail(value: string): boolean;
120124

121125
export function formatCurrency(
122126
amount: number,
123-
currency?: string, // default: "EUR"
127+
currency?: string, // default: "USD"
124128
locale?: string, // default: "en-US"
125129
): string;
130+
131+
export function clamp(value: number, min: number, max: number): number;
132+
133+
export interface Throttled<T extends (...args: any[]) => void> {
134+
(...args: Parameters<T>): void;
135+
cancel(): void;
136+
}
137+
138+
export function throttle<T extends (...args: any[]) => void>(
139+
fn: T,
140+
wait: number, // must be > 0
141+
): Throttled<T>;
126142
```
127143

128144
**Kotlin:**
@@ -143,9 +159,22 @@ fun isEmail(value: String): Boolean
143159

144160
fun formatCurrency(
145161
amount: Double,
146-
currency: String = "EUR",
162+
currency: String = "USD",
147163
locale: String = "en-US", // converted internally to java.util.Locale
148164
): String
165+
166+
fun clamp(value: Double, min: Double, max: Double): Double
167+
168+
class Throttled<T>(private val invoke: (T) -> Unit) {
169+
operator fun invoke(value: T): Unit
170+
fun cancel(): Unit
171+
}
172+
173+
fun <T> throttle(
174+
waitMs: Long, // must be > 0
175+
scope: CoroutineScope, // platform constraint: structured concurrency
176+
action: (T) -> Unit,
177+
): Throttled<T>
149178
```
150179

151180
**Dart:**
@@ -165,9 +194,21 @@ bool isEmail(String value);
165194
166195
String formatCurrency(
167196
num amount, {
168-
String currency = "EUR",
197+
String currency = "USD",
169198
String locale = "en-US",
170199
});
200+
201+
double clamp(double value, double min, double max);
202+
203+
class Throttled<T> {
204+
void call(T arg);
205+
void cancel();
206+
}
207+
208+
Throttled<T> throttle<T>(
209+
void Function(T) fn,
210+
Duration wait, // must be > Duration.zero
211+
);
171212
```
172213

173214
### Platform-Specific Adaptations
@@ -180,20 +221,26 @@ While maintaining API consistency, we leverage platform strengths:
180221
- **setTimeout/clearTimeout** for timing control
181222
- **Intl.NumberFormat** for currency formatting
182223
- **RegExp** for email validation
224+
- **Math.min/Math.max** for clamp
225+
- **setTimeout/clearTimeout** for throttle timer
183226

184227
#### Kotlin Implementation
185228

186229
- **Coroutines** for asynchronous debounce operations
187230
- **Job cancellation** for timing control
188231
- **NumberFormat/Currency** for localized formatting
189232
- **Regex** for email validation
233+
- **Double.coerceIn** for clamp
234+
- **Coroutine delay + Job** for throttle wait period
190235

191236
#### Dart/Flutter Implementation
192237

193238
- **Timer** for debounce scheduling and cancellation
194239
- **intl package** (`NumberFormat.currency`) for localized formatting
195240
- **RegExp** for email validation
196241
- **Null safety** with full type-safe APIs
242+
- **num.clamp** for clamp
243+
- **Timer** for throttle scheduling (same as debounce)
197244

198245
## Build System Architecture
199246

@@ -272,16 +319,20 @@ android.yml:
272319
273320
```
274321
packages/core/web/tests/
275-
└── core.test.ts # All utility tests
322+
├── core.test.ts # debounce, isEmail, formatCurrency tests
323+
├── clamp.test.ts # clamp unit tests
324+
└── throttle.test.ts # throttle unit tests
276325

277326
packages/core/android/src/test/kotlin/com/kompkit/core/
278-
└── CoreTests.kt # All utility tests
327+
└── CoreTests.kt # All utility tests (incl. ThrottleTests, ClampTests)
279328

280329
packages/core/flutter/test/
281330
├── kompkit_core_test.dart # Integration tests
282331
├── debounce_test.dart # Debounce unit tests
283332
├── validate_test.dart # Validation unit tests
284-
└── format_test.dart # Formatting unit tests
333+
├── format_test.dart # Formatting unit tests
334+
├── clamp_test.dart # Clamp unit tests
335+
└── throttle_test.dart # Throttle unit tests
285336
```
286337

287338
### Test Coverage

docs/CHANGELOG.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,42 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [0.4.0-alpha.0] - 2026-02-28
11+
12+
### Added
13+
14+
- **`clamp` utility** across all platforms — constrain a number within an inclusive `[min, max]` range
15+
- TypeScript: `clamp(value: number, min: number, max: number): number`
16+
- Kotlin: `clamp(value: Double, min: Double, max: Double): Double`
17+
- Dart: `clamp(double value, double min, double max): double`
18+
- Throws `RangeError` / `IllegalArgumentException` / `ArgumentError` if `min > max` or any argument is non-finite
19+
- Exported from all public entry points; full unit test coverage on all platforms
20+
21+
- **`throttle` utility** across all platforms — limit a function to execute at most once per wait period
22+
- TypeScript: `throttle<T>(fn: T, wait: number): T & { cancel(): void }`
23+
- Kotlin: `throttle<T>(waitMs: Long, scope: CoroutineScope, action: (T) -> Unit): Throttled<T>`
24+
- Dart: `throttle<T>(void Function(T) fn, Duration wait): Throttled<T>`
25+
- First call executes immediately; subsequent calls within the wait period are ignored
26+
- `cancel()` resets internal state with no pending execution firing
27+
- Throws `Error` / `IllegalArgumentException` / `ArgumentError` if `wait <= 0`
28+
- Exported from all public entry points; full unit test coverage on all platforms
29+
30+
### Changed
31+
32+
- **`formatCurrency` default currency**: Changed from `EUR` to `USD` across all platforms (TypeScript, Kotlin, Dart)
33+
- **`formatCurrency` finite validation**: Added validation that throws on `NaN` and `Infinity` amounts across all platforms
34+
- TypeScript: throws `RangeError`
35+
- Kotlin: throws `IllegalArgumentException`
36+
- Dart: throws `ArgumentError`
37+
- **Documentation**: Updated all guides (getting-started, web, android, flutter, ARCHITECTURE, recipes, FAQ) to cover `clamp` and `throttle`
38+
- **Documentation**: Corrected `formatCurrency` examples to reflect `USD` default
39+
- **Documentation**: Added Platform Differences section to npm README documenting Dart single-argument debounce limitation and other divergences
40+
- **Packaging**: Clarified that `kompkit-core` ships both ESM and CommonJS builds (not ESM-only)
41+
42+
### Fixed
43+
44+
- Documentation inconsistency where examples showed `USD` but default was `EUR`
45+
1046
## [0.3.0-alpha] - 2026-02-09
1147

1248
### Changed

0 commit comments

Comments
 (0)