@larose-ui/core 0.1.1 → 0.1.2

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/dist/index.d.ts CHANGED
@@ -157,6 +157,56 @@ declare function createCompositeFeatureFlagEvaluator(evaluators: FeatureFlagEval
157
157
  declare function detectA11yPreferences(): A11yPreferences;
158
158
  declare function subscribeA11yPreferences(onChange: (preferences: A11yPreferences) => void): () => void;
159
159
 
160
+ /** Physics parameters for spring simulation (mass-normalized). */
161
+ interface SpringConfig {
162
+ stiffness: number;
163
+ damping: number;
164
+ mass?: number;
165
+ }
166
+ type SpringPresetName = 'snappy' | 'smooth' | 'gentle' | 'responsive' | 'bouncy';
167
+ interface SpringState {
168
+ value: number;
169
+ velocity: number;
170
+ }
171
+ type ReducedMotionPolicy = 'system' | 'always' | 'never';
172
+ type MotionSemanticPreset = SpringPresetName | 'none';
173
+
174
+ /** Apple-inspired spring presets — tuned for UI hierarchy. */
175
+ declare const SPRING_PRESETS: Record<SpringPresetName, SpringConfig>;
176
+ declare function getSpringPreset(name: SpringPresetName): SpringConfig;
177
+ /**
178
+ * Advance a spring simulation by one timestep (seconds).
179
+ * Uses implicit Euler integration — stable for UI frame rates.
180
+ */
181
+ declare function stepSpring(state: SpringState, target: number, config: SpringConfig, deltaTime: number): SpringState;
182
+ /** Returns true when the spring has settled near the target. */
183
+ declare function isSpringSettled(state: SpringState, target: number, precision?: number, velocityPrecision?: number): boolean;
184
+ /**
185
+ * Animate a spring to completion over discrete steps.
186
+ * Useful for tests and non-RAF environments.
187
+ */
188
+ declare function animateSpringToTarget(from: number, target: number, config: SpringConfig, options?: {
189
+ velocity?: number;
190
+ maxSteps?: number;
191
+ deltaTime?: number;
192
+ }): SpringState;
193
+ /** Approximate spring response time in seconds (for duration hints). */
194
+ declare function springResponseTime(config: SpringConfig): number;
195
+
196
+ declare function resolveReducedMotion(policy: ReducedMotionPolicy, systemPrefersReduced: boolean): boolean;
197
+ /** Scale motion duration to zero when reduced motion is active. */
198
+ declare function motionDuration(durationMs: number, reducedMotion: boolean): number;
199
+
200
+ /**
201
+ * Returns a safe href for in-app navigation, or undefined when the URL is unsafe.
202
+ * Blocks javascript:, data:, vbscript:, blob:, and protocol-relative URLs.
203
+ */
204
+ declare function sanitizeNavigationUrl(url: string | undefined): string | undefined;
205
+ /**
206
+ * Validates same-origin relative redirect targets (e.g. login paths).
207
+ */
208
+ declare function isSafeRedirectPath(url: string): boolean;
209
+
160
210
  /**
161
211
  * UI component lifecycle states supported across laRose.
162
212
  */
@@ -214,6 +264,9 @@ interface VersionInfo {
214
264
  }
215
265
  type Variant = 'primary' | 'secondary' | 'outline' | 'ghost' | 'destructive';
216
266
  type Size = 'sm' | 'md' | 'lg';
267
+ /** Apple HIG button semantic roles — style, content, and role. */
268
+ type ButtonRole = 'normal' | 'primary' | 'cancel' | 'destructive';
269
+ type TypographyRole = 'display' | 'largeTitle' | 'title' | 'headline' | 'body' | 'callout' | 'subheadline' | 'footnote' | 'caption';
217
270
  interface ComponentStateProps {
218
271
  state?: UIState;
219
272
  loading?: boolean;
@@ -230,4 +283,4 @@ declare function createEventEmitter<T extends Record<string, unknown>>(): {
230
283
  };
231
284
  declare const LAROSE_VERSION = "0.1.0";
232
285
 
233
- export { type A11yPreferences, type ApiError, type AsyncEvent, type AsyncState, type AsyncStateMachine, type ComponentStateProps, type Density, type Environment, type FeatureFlagEvaluationContext, type FeatureFlagEvaluator, type FeatureFlagResult, type FeatureFlagSnapshot, type HttpErrorCode, LAROSE_VERSION, type LaRoseRuntimeContext, type LocaleSnapshot, type NetworkCondition, type NetworkSnapshot, type OfflineSnapshot, type PercentageRolloutConfig, type Permission, type PermissionFallback, type PermissionSnapshot, type RuntimeEvent, type RuntimeEventBus, type RuntimeEventType, type SessionEvent, type SessionState, type SessionStateMachine, type Size, type StaticFeatureFlagValue, type TenantContext, type ThemeMode, type ThemeSnapshot, type UIState, type UserContext, type Variant, type VersionInfo, type VersionMatrix, classifyHttpError, createAsyncStateMachine, createCompositeFeatureFlagEvaluator, createDefaultRuntimeContext, createEventEmitter, createPercentageRolloutEvaluator, createRuntimeEventBus, createSessionStateMachine, createStaticFeatureFlagEvaluator, detectA11yPreferences, resetDeprecationWarnings, resolveUIState, subscribeA11yPreferences, warnDeprecation };
286
+ export { type A11yPreferences, type ApiError, type AsyncEvent, type AsyncState, type AsyncStateMachine, type ButtonRole, type ComponentStateProps, type Density, type Environment, type FeatureFlagEvaluationContext, type FeatureFlagEvaluator, type FeatureFlagResult, type FeatureFlagSnapshot, type HttpErrorCode, LAROSE_VERSION, type LaRoseRuntimeContext, type LocaleSnapshot, type MotionSemanticPreset, type NetworkCondition, type NetworkSnapshot, type OfflineSnapshot, type PercentageRolloutConfig, type Permission, type PermissionFallback, type PermissionSnapshot, type ReducedMotionPolicy, type RuntimeEvent, type RuntimeEventBus, type RuntimeEventType, SPRING_PRESETS, type SessionEvent, type SessionState, type SessionStateMachine, type Size, type SpringConfig, type SpringPresetName, type SpringState, type StaticFeatureFlagValue, type TenantContext, type ThemeMode, type ThemeSnapshot, type TypographyRole, type UIState, type UserContext, type Variant, type VersionInfo, type VersionMatrix, animateSpringToTarget, classifyHttpError, createAsyncStateMachine, createCompositeFeatureFlagEvaluator, createDefaultRuntimeContext, createEventEmitter, createPercentageRolloutEvaluator, createRuntimeEventBus, createSessionStateMachine, createStaticFeatureFlagEvaluator, detectA11yPreferences, getSpringPreset, isSafeRedirectPath, isSpringSettled, motionDuration, resetDeprecationWarnings, resolveReducedMotion, resolveUIState, sanitizeNavigationUrl, springResponseTime, stepSpring, subscribeA11yPreferences, warnDeprecation };
package/dist/index.js CHANGED
@@ -210,6 +210,96 @@ function subscribeA11yPreferences(onChange) {
210
210
  };
211
211
  }
212
212
 
213
+ // src/motion/springs.ts
214
+ var SPRING_PRESETS = {
215
+ /** Small UI feedback — buttons, toggles. */
216
+ responsive: { stiffness: 380, damping: 32, mass: 1 },
217
+ /** Snappy menus, dropdowns. */
218
+ snappy: { stiffness: 320, damping: 28, mass: 1 },
219
+ /** Modal / dialog entrance. */
220
+ smooth: { stiffness: 220, damping: 26, mass: 1 },
221
+ /** Drawer, sheet movement. */
222
+ gentle: { stiffness: 180, damping: 24, mass: 1 },
223
+ /** Playful emphasis — use sparingly. */
224
+ bouncy: { stiffness: 260, damping: 18, mass: 1 }
225
+ };
226
+ function getSpringPreset(name) {
227
+ return { ...SPRING_PRESETS[name] };
228
+ }
229
+ function stepSpring(state, target, config, deltaTime) {
230
+ const mass = config.mass ?? 1;
231
+ const stiffness = config.stiffness;
232
+ const damping = config.damping;
233
+ const displacement = state.value - target;
234
+ const springForce = -stiffness * displacement;
235
+ const dampingForce = -damping * state.velocity;
236
+ const acceleration = (springForce + dampingForce) / mass;
237
+ const velocity = state.velocity + acceleration * deltaTime;
238
+ const value = state.value + velocity * deltaTime;
239
+ return { value, velocity };
240
+ }
241
+ function isSpringSettled(state, target, precision = 1e-3, velocityPrecision = 0.01) {
242
+ return Math.abs(state.value - target) < precision && Math.abs(state.velocity) < velocityPrecision;
243
+ }
244
+ function animateSpringToTarget(from, target, config, options = {}) {
245
+ const maxSteps = options.maxSteps ?? 600;
246
+ const deltaTime = options.deltaTime ?? 1 / 60;
247
+ let state = { value: from, velocity: options.velocity ?? 0 };
248
+ for (let i = 0; i < maxSteps; i++) {
249
+ state = stepSpring(state, target, config, deltaTime);
250
+ if (isSpringSettled(state, target)) break;
251
+ }
252
+ return state;
253
+ }
254
+ function springResponseTime(config) {
255
+ const mass = config.mass ?? 1;
256
+ const omega = Math.sqrt(config.stiffness / mass);
257
+ const zeta = config.damping / (2 * Math.sqrt(config.stiffness * mass));
258
+ if (zeta < 1) {
259
+ return 2 * Math.PI / (omega * Math.sqrt(1 - zeta * zeta));
260
+ }
261
+ return 4 / (zeta * omega);
262
+ }
263
+
264
+ // src/motion/reduced.ts
265
+ function resolveReducedMotion(policy, systemPrefersReduced) {
266
+ switch (policy) {
267
+ case "always":
268
+ return true;
269
+ case "never":
270
+ return false;
271
+ case "system":
272
+ default:
273
+ return systemPrefersReduced;
274
+ }
275
+ }
276
+ function motionDuration(durationMs, reducedMotion) {
277
+ return reducedMotion ? 0 : durationMs;
278
+ }
279
+
280
+ // src/security/url.ts
281
+ var UNSAFE_PROTOCOL = /^\s*(javascript|data|vbscript|blob):/i;
282
+ var PROTOCOL_RELATIVE = /^\s*\/\//;
283
+ function normalizeForCheck(url) {
284
+ return url.trim().replace(/\\/g, "/");
285
+ }
286
+ function sanitizeNavigationUrl(url) {
287
+ if (!url) return void 0;
288
+ const trimmed = url.trim();
289
+ if (!trimmed) return void 0;
290
+ const normalized = normalizeForCheck(trimmed);
291
+ if (UNSAFE_PROTOCOL.test(normalized)) return void 0;
292
+ if (PROTOCOL_RELATIVE.test(normalized)) return void 0;
293
+ return trimmed;
294
+ }
295
+ function isSafeRedirectPath(url) {
296
+ const normalized = normalizeForCheck(url);
297
+ if (!normalized.startsWith("/")) return false;
298
+ if (PROTOCOL_RELATIVE.test(normalized)) return false;
299
+ if (UNSAFE_PROTOCOL.test(normalized)) return false;
300
+ return true;
301
+ }
302
+
213
303
  // src/index.ts
214
304
  function classifyHttpError(status, message) {
215
305
  const defaultMessage = message ?? "An unexpected error occurred";
@@ -313,6 +403,8 @@ function createEventEmitter() {
313
403
  var LAROSE_VERSION = "0.1.0";
314
404
  export {
315
405
  LAROSE_VERSION,
406
+ SPRING_PRESETS,
407
+ animateSpringToTarget,
316
408
  classifyHttpError,
317
409
  createAsyncStateMachine,
318
410
  createCompositeFeatureFlagEvaluator,
@@ -323,8 +415,16 @@ export {
323
415
  createSessionStateMachine,
324
416
  createStaticFeatureFlagEvaluator,
325
417
  detectA11yPreferences,
418
+ getSpringPreset,
419
+ isSafeRedirectPath,
420
+ isSpringSettled,
421
+ motionDuration,
326
422
  resetDeprecationWarnings,
423
+ resolveReducedMotion,
327
424
  resolveUIState,
425
+ sanitizeNavigationUrl,
426
+ springResponseTime,
427
+ stepSpring,
328
428
  subscribeA11yPreferences,
329
429
  warnDeprecation
330
430
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@larose-ui/core",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Core types, state machines, and utilities for laRose UI platform",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",