@askrjs/askr 0.0.9 → 0.0.10

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.
Files changed (49) hide show
  1. package/dist/chunk-37RC6ZT3.js +1 -0
  2. package/dist/chunk-4RTKQ7SC.js +1 -0
  3. package/dist/chunk-534P7OMI.js +2 -0
  4. package/dist/chunk-62D2TNHX.js +1 -0
  5. package/dist/chunk-CI6AOGB5.js +1 -0
  6. package/dist/chunk-D2JSJKCW.js +1 -0
  7. package/dist/chunk-DPHQ4JD6.js +1 -0
  8. package/dist/chunk-FFSNBDHN.js +1 -0
  9. package/dist/chunk-JJDSOK6C.js +1 -0
  10. package/dist/chunk-LOSY3JCR.js +1 -0
  11. package/dist/chunk-OQMK7H2R.js +1 -0
  12. package/dist/chunk-Q7GRUZHR.js +1 -0
  13. package/dist/chunk-XKFPM4SY.js +2 -0
  14. package/dist/chunk-Y3Q3LOFT.js +1 -0
  15. package/dist/chunk-YRY4OLQF.js +1 -0
  16. package/dist/{component-DHAn9JxU.d.ts → component-mtwBWhUr.d.ts} +1 -1
  17. package/dist/for/index.d.ts +61 -0
  18. package/dist/for/index.js +1 -0
  19. package/dist/foundations/core.d.ts +449 -0
  20. package/dist/foundations/core.js +1 -0
  21. package/dist/foundations/index.d.ts +4 -722
  22. package/dist/foundations/index.js +1 -1274
  23. package/dist/foundations/structures.d.ts +223 -0
  24. package/dist/foundations/structures.js +1 -0
  25. package/dist/fx/index.js +1 -636
  26. package/dist/index.d.ts +2 -2
  27. package/dist/index.js +1 -3955
  28. package/dist/jsx-dev-runtime.js +1 -17
  29. package/dist/jsx-runtime.js +1 -23
  30. package/dist/logger-MPMIVXAP.js +1 -0
  31. package/dist/main-EPE35NMW.js +65 -0
  32. package/dist/navigate-6CC6IXXF.js +1 -0
  33. package/dist/resources/index.d.ts +1 -1
  34. package/dist/resources/index.js +1 -792
  35. package/dist/route-4QZ3RYN5.js +1 -0
  36. package/dist/router/index.d.ts +5 -0
  37. package/dist/router/index.js +1 -3194
  38. package/dist/ssr/index.js +1 -3935
  39. package/dist/vite/index.js +1 -2306
  40. package/package.json +19 -5
  41. package/dist/foundations/index.js.map +0 -1
  42. package/dist/fx/index.js.map +0 -1
  43. package/dist/index.js.map +0 -1
  44. package/dist/jsx-dev-runtime.js.map +0 -1
  45. package/dist/jsx-runtime.js.map +0 -1
  46. package/dist/resources/index.js.map +0 -1
  47. package/dist/router/index.js.map +0 -1
  48. package/dist/ssr/index.js.map +0 -1
  49. package/dist/vite/index.js.map +0 -1
@@ -1,724 +1,6 @@
1
+ export { ComposeHandlersOptions, ControllableState, DismissableOptions, FocusableOptions, FocusableResult, FormatIdOptions, HoverableOptions, HoverableResult, InteractionPolicyInput, Orientation, PressableOptions, PressableResult, Ref, RovingFocusOptions, RovingFocusResult, applyInteractionPolicy, ariaDisabled, ariaExpanded, ariaSelected, composeHandlers, composeRefs, controllableState, dismissable, focusable, formatId, hoverable, isControlled, makeControllable, mergeInteractionProps, mergeProps, pressable, resolveControllable, rovingFocus, setRef } from './core.js';
1
2
  export { L as LayoutComponent, l as layout } from '../layout-BINPv-nz.js';
3
+ export { Collection, CollectionItem, DefaultPortal, Layer, LayerManager, LayerOptions, Portal, Presence, PresenceProps, Slot, SlotProps, createCollection, createLayer, definePortal } from './structures.js';
2
4
  import '../types-DxdosFWx.js';
3
- import { J as JSXElement } from '../jsx-CSWf4VFg.js';
4
- import { S as State } from '../component-DHAn9JxU.js';
5
-
6
- type SlotProps = {
7
- asChild: true;
8
- children: JSXElement;
9
- [key: string]: unknown;
10
- } | {
11
- asChild?: false;
12
- children?: unknown;
13
- };
14
- /**
15
- * Slot
16
- *
17
- * Structural primitive for prop forwarding patterns.
18
- *
19
- * POLICY DECISIONS (LOCKED):
20
- *
21
- * 1. asChild Pattern
22
- * When asChild=true, merges props into the single child element.
23
- * Child must be a valid JSXElement; non-element children return null.
24
- * **Slot props override child props** (injection pattern).
25
- *
26
- * 2. Fallback Behavior
27
- * When asChild=false, returns a Fragment (structural no-op).
28
- * No DOM element is introduced.
29
- *
30
- * 3. Type Safety
31
- * asChild=true requires exactly one JSXElement child (enforced by type).
32
- * Runtime validates with isElement() check.
33
- */
34
- declare function Slot(props: SlotProps): JSXElement | null;
35
-
36
- interface PresenceProps {
37
- present: boolean | (() => boolean);
38
- children?: unknown;
39
- }
40
- /**
41
- * Presence
42
- *
43
- * Structural policy primitive for conditional mount/unmount.
44
- * - No timers
45
- * - No animation coupling
46
- * - No DOM side-effects
47
- *
48
- * POLICY DECISIONS (LOCKED):
49
- *
50
- * 1. Present as Function
51
- * Accepts boolean OR function to support lazy evaluation patterns.
52
- * Function is called once per render. Use boolean form for static values.
53
- *
54
- * 2. Children Type
55
- * `children` is intentionally `unknown` to remain runtime-agnostic.
56
- * The runtime owns child normalization and validation.
57
- *
58
- * 3. Immediate Mount/Unmount
59
- * No exit animations or transitions. When `present` becomes false,
60
- * children are removed immediately. Animation must be layered above
61
- * this primitive.
62
- */
63
- declare function Presence({ present, children, }: PresenceProps): JSXElement | null;
64
-
65
- /**
66
- * Portal / Host primitive.
67
- *
68
- * Foundations remain runtime-agnostic: a portal is an explicit read/write slot.
69
- * Scheduling and attachment are owned by the runtime when `createPortalSlot`
70
- * exists; otherwise this falls back to a local slot (deterministic, but does
71
- * not schedule updates).
72
- *
73
- * POLICY DECISIONS (LOCKED):
74
- *
75
- * 1. Local Mutable State
76
- * Foundations may use local mutable state ONLY to model deterministic slots,
77
- * never to coordinate timing, effects, or ordering. The fallback mode uses
78
- * closure-local `mounted` and `value` variables which are non-escaping and
79
- * deterministic.
80
- *
81
- * 2. Return Type Philosophy
82
- * Portal call signatures return `unknown` (intentionally opaque). The runtime
83
- * owns the concrete type. This prevents foundations from assuming JSX.Element
84
- * or DOM node types, maintaining runtime-agnostic portability.
85
- */
86
- interface Portal<T = unknown> {
87
- /** Mount point — rendered exactly once */
88
- (): unknown;
89
- /** Render content into the portal */
90
- render(props: {
91
- children?: T;
92
- }): unknown;
93
- }
94
- declare function definePortal<T = unknown>(): Portal<T>;
95
- declare const DefaultPortal: Portal<unknown>;
96
-
97
- /**
98
- * createCollection
99
- *
100
- * Ordered descendant registry for coordinating items without DOM queries.
101
- *
102
- * INVARIANTS:
103
- * 1. Registration order determines item order (no DOM queries)
104
- * 2. Stable ordering across renders (insertion order preserved)
105
- * 3. Each item may have metadata (type-safe, user-defined)
106
- * 4. No implicit global state (explicit collection instances)
107
- * 5. No automatic cleanup (caller controls lifecycle)
108
- *
109
- * DESIGN:
110
- * - Returns a registry API ({ register, items, clear })
111
- * - Items are stored in insertion order
112
- * - Registration returns an unregister function
113
- * - No side effects on registration (pure data structure)
114
- *
115
- * USAGE:
116
- * const collection = createCollection<HTMLElement, { disabled: boolean }>();
117
- * const unregister = collection.register(element, { disabled: false });
118
- * const allItems = collection.items();
119
- * unregister();
120
- */
121
- type CollectionItem<TNode, TMetadata = unknown> = {
122
- node: TNode;
123
- metadata: TMetadata;
124
- };
125
- interface Collection<TNode, TMetadata = unknown> {
126
- /**
127
- * Register a node with optional metadata.
128
- * Returns an unregister function.
129
- */
130
- register(node: TNode, metadata: TMetadata): () => void;
131
- /**
132
- * Get all registered items in insertion order.
133
- */
134
- items(): ReadonlyArray<CollectionItem<TNode, TMetadata>>;
135
- /**
136
- * Clear all registered items.
137
- */
138
- clear(): void;
139
- /**
140
- * Get the count of registered items.
141
- */
142
- size(): number;
143
- }
144
- declare function createCollection<TNode, TMetadata = unknown>(): Collection<TNode, TMetadata>;
145
-
146
- /**
147
- * createLayer
148
- *
149
- * Manages stacking order and coordination for overlays (modals, popovers, etc).
150
- *
151
- * INVARIANTS:
152
- * 1. Layers are ordered by registration time (FIFO)
153
- * 2. Only the top layer handles Escape key
154
- * 3. Only the top layer handles outside pointer events
155
- * 4. Nested layers are supported
156
- * 5. Does not implement portals (orthogonal concern)
157
- * 6. No automatic DOM insertion (caller controls mounting)
158
- *
159
- * DESIGN:
160
- * - Returns a layer manager with register/unregister API
161
- * - Each layer has a unique ID and can query if it's the top layer
162
- * - Escape and outside pointer coordination via callbacks
163
- * - No z-index management (CSS concern)
164
- *
165
- * USAGE:
166
- * const manager = createLayer();
167
- *
168
- * const layer = manager.register({
169
- * onEscape: () => { ... },
170
- * onOutsidePointer: () => { ... }
171
- * });
172
- *
173
- * layer.isTop(); // true if this is the topmost layer
174
- * layer.unregister();
175
- */
176
- interface LayerOptions {
177
- /**
178
- * Called when Escape is pressed and this is the top layer
179
- */
180
- onEscape?: () => void;
181
- /**
182
- * Called when pointer event occurs outside and this is the top layer
183
- */
184
- onOutsidePointer?: (e: PointerEvent) => void;
185
- /**
186
- * Optional node reference for outside pointer detection
187
- */
188
- node?: Node | null;
189
- }
190
- interface Layer {
191
- /**
192
- * Unique layer ID
193
- */
194
- id: number;
195
- /**
196
- * Check if this layer is the topmost
197
- */
198
- isTop(): boolean;
199
- /**
200
- * Remove this layer from the stack
201
- */
202
- unregister(): void;
203
- }
204
- interface LayerManager {
205
- /**
206
- * Register a new layer
207
- */
208
- register(options: LayerOptions): Layer;
209
- /**
210
- * Get all active layers in order
211
- */
212
- layers(): ReadonlyArray<Layer>;
213
- /**
214
- * Manually trigger escape handling on the top layer
215
- */
216
- handleEscape(): void;
217
- /**
218
- * Manually trigger outside pointer handling on the top layer
219
- */
220
- handleOutsidePointer(e: PointerEvent): void;
221
- }
222
- declare function createLayer(): LayerManager;
223
-
224
- /**
225
- * composeHandlers
226
- *
227
- * Compose two event handlers into one. The first handler runs, and unless it
228
- * calls `event.preventDefault()` (or sets `defaultPrevented`), the second
229
- * handler runs. This prevents accidental clobbering of child handlers when
230
- * injecting props.
231
- *
232
- * POLICY DECISIONS (LOCKED):
233
- *
234
- * 1. Execution Order
235
- * First handler runs before second (injected before base).
236
- * This allows injected handlers to prevent default behavior.
237
- *
238
- * 2. Default Prevention Check
239
- * By default, checks `defaultPrevented` on first argument.
240
- * Can be disabled via options.checkDefaultPrevented = false.
241
- *
242
- * 3. Undefined Handler Support
243
- * Undefined handlers are skipped (no-op). This simplifies usage
244
- * where handlers are optional.
245
- *
246
- * 4. Type Safety
247
- * Args are readonly to prevent mutation. Return type matches input.
248
- */
249
- interface ComposeHandlersOptions {
250
- /**
251
- * When true (default), do not run the second handler if the first prevented default.
252
- * When false, always run both handlers.
253
- */
254
- checkDefaultPrevented?: boolean;
255
- }
256
- declare function composeHandlers<A extends readonly unknown[]>(first?: (...args: A) => void, second?: (...args: A) => void, options?: ComposeHandlersOptions): (...args: A) => void;
257
-
258
- declare function mergeProps<TBase extends object, TInjected extends object>(base: TBase, injected: TInjected): TInjected & TBase;
259
-
260
- /**
261
- * Tiny aria helpers
262
- */
263
- declare function ariaDisabled(disabled?: boolean): {
264
- 'aria-disabled'?: 'true';
265
- };
266
- declare function ariaExpanded(expanded?: boolean): {
267
- 'aria-expanded'?: 'true' | 'false';
268
- };
269
- declare function ariaSelected(selected?: boolean): {
270
- 'aria-selected'?: 'true' | 'false';
271
- };
272
-
273
- /**
274
- * Ref composition utilities
275
- *
276
- * POLICY DECISIONS (LOCKED):
277
- *
278
- * 1. Ref Types Supported
279
- * - Callback refs: (value: T | null) => void
280
- * - Object refs: { current: T | null }
281
- * - null/undefined (no-op)
282
- *
283
- * 2. Write Failure Handling
284
- * setRef catches write failures (readonly refs) and ignores them.
285
- * This is intentional — refs may be readonly in some contexts.
286
- *
287
- * 3. Composition Order
288
- * composeRefs applies refs in array order (left to right).
289
- * All refs are called even if one fails.
290
- */
291
- type Ref<T> = ((value: T | null) => void) | {
292
- current: T | null;
293
- } | null | undefined;
294
- declare function setRef<T>(ref: Ref<T>, value: T | null): void;
295
- declare function composeRefs<T>(...refs: Array<Ref<T>>): (value: T | null) => void;
296
-
297
- interface UseIdOptions {
298
- /** Defaults to 'askr' */
299
- prefix?: string;
300
- /** Stable, caller-provided identity */
301
- id: string | number;
302
- }
303
- /**
304
- * useId
305
- *
306
- * Formats a stable ID from a caller-provided identity.
307
- * - Pure and deterministic (no time/randomness/global counters)
308
- * - SSR-safe
309
- *
310
- * POLICY DECISIONS (LOCKED):
311
- *
312
- * 1. No Auto-Generation
313
- * Caller must provide the `id`. No random/sequential generation.
314
- * This ensures determinism and SSR safety.
315
- *
316
- * 2. Format Convention
317
- * IDs are formatted as `{prefix}-{id}`.
318
- * Default prefix is "askr".
319
- *
320
- * 3. Type Coercion
321
- * Numbers are coerced to strings via String().
322
- * This is deterministic and consistent.
323
- */
324
- declare function useId(options: UseIdOptions): string;
325
-
326
- /**
327
- * controllable
328
- *
329
- * Small utilities for controlled vs uncontrolled components. These helpers are
330
- * intentionally minimal and do not manage state themselves; they help component
331
- * implementations make correct decisions about when to call `onChange` vs
332
- * update internal state.
333
- *
334
- * POLICY DECISIONS (LOCKED):
335
- *
336
- * 1. Controlled Detection
337
- * A value is "controlled" if it is not `undefined`.
338
- * This matches React conventions and is SSR-safe.
339
- *
340
- * 2. onChange Timing
341
- * - Controlled mode: onChange called immediately, no internal update
342
- * - Uncontrolled mode: internal state updated first, then onChange called
343
- * This ensures onChange sees the new value in both modes.
344
- *
345
- * 3. Value Equality
346
- * controllableState uses Object.is() to prevent unnecessary onChange calls.
347
- * This is intentional — strict equality, no deep comparison.
348
- */
349
-
350
- declare function isControlled<T>(value: T | undefined): value is T;
351
- declare function resolveControllable<T>(value: T | undefined, defaultValue: T): {
352
- value: T;
353
- isControlled: boolean;
354
- };
355
- declare function makeControllable<T>(options: {
356
- value: T | undefined;
357
- defaultValue: T;
358
- onChange?: (next: T) => void;
359
- setInternal?: (next: T) => void;
360
- }): {
361
- set: (next: T) => void;
362
- isControlled: boolean;
363
- };
364
- type ControllableState<T> = State<T> & {
365
- isControlled: boolean;
366
- };
367
- /**
368
- * controllableState
369
- *
370
- * Hook-like primitive that mirrors `state()` semantics while supporting
371
- * controlled/uncontrolled behavior.
372
- */
373
- declare function controllableState<T>(options: {
374
- value: T | undefined;
375
- defaultValue: T;
376
- onChange?: (next: T) => void;
377
- }): ControllableState<T>;
378
-
379
- interface DefaultPreventable {
380
- defaultPrevented?: boolean;
381
- preventDefault?: () => void;
382
- }
383
- interface PropagationStoppable {
384
- stopPropagation?: () => void;
385
- }
386
- interface KeyboardLikeEvent extends DefaultPreventable, PropagationStoppable {
387
- key: string;
388
- }
389
- interface PointerLikeEvent extends DefaultPreventable, PropagationStoppable {
390
- target?: unknown;
391
- }
392
-
393
- /**
394
- * pressable
395
- *
396
- * Interaction helper that produces VNode props for 'press' semantics.
397
- * - Pure and deterministic: no DOM construction or mutation here
398
- * - The runtime owns event attachment and scheduling
399
- * - This helper returns plain props (handlers) intended to be attached by the runtime
400
- *
401
- * Behaviour:
402
- * - For native buttons: only an `onClick` prop is provided (no ARIA or keyboard shims)
403
- * - For non-button elements: add `role="button"` and `tabIndex` and keyboard handlers
404
- * - Activation: `Enter` activates on keydown, `Space` activates on keyup (matches native button)
405
- * - Disabled: handlers short-circuit and `aria-disabled` is set for all hosts
406
- *
407
- * POLICY DECISIONS (LOCKED):
408
- *
409
- * 1. Activation Timing (Platform Parity)
410
- * - Enter fires on keydown (immediate response)
411
- * - Space fires on keyup (allows cancel by moving focus, matches native)
412
- * - Space keydown prevents scroll (matches native button behavior)
413
- *
414
- * 2. Disabled Enforcement Strategy
415
- * - Native buttons: Use HTML `disabled` attribute (platform-enforced non-interactivity)
416
- * AND `aria-disabled` (consistent a11y signaling)
417
- * - Non-native: Use `tabIndex=-1` (removes from tab order)
418
- * AND `aria-disabled` (signals disabled state to AT)
419
- * - Click handler short-circuits as defense-in-depth (prevents leaked focus issues)
420
- *
421
- * 3. Key Repeat Behavior
422
- * - Held Enter/Space will fire onPress repeatedly (matches native button)
423
- * - No debouncing or repeat prevention (platform parity)
424
- */
425
- interface PressableOptions {
426
- disabled?: boolean;
427
- onPress?: (e: PressEvent) => void;
428
- /**
429
- * Whether the host is a native button. Defaults to false.
430
- */
431
- isNativeButton?: boolean;
432
- }
433
-
434
- type PressEvent = DefaultPreventable & PropagationStoppable;
435
- interface PressableResult {
436
- onClick: (e: PressEvent) => void;
437
- disabled?: true;
438
- role?: 'button';
439
- tabIndex?: number;
440
- onKeyDown?: (e: KeyboardLikeEvent) => void;
441
- onKeyUp?: (e: KeyboardLikeEvent) => void;
442
- 'aria-disabled'?: 'true';
443
- }
444
- declare function pressable({ disabled, onPress, isNativeButton, }: PressableOptions): PressableResult;
445
-
446
- /**
447
- * dismissable
448
- *
449
- * THE dismissal primitive. Handles Escape key and outside interactions.
450
- *
451
- * INVARIANTS:
452
- * 1. Returns props that compose via mergeProps (no factories)
453
- * 2. Disabled state respected exactly once, here
454
- * 3. No side effects - pure props generation
455
- * 4. Outside detection requires explicit node reference
456
- * 5. This is the ONLY dismissal primitive - do not create alternatives
457
- *
458
- * DESIGN:
459
- * - Returns standard event handler props (onKeyDown, onPointerDownCapture)
460
- * - Composable via mergeProps with other foundations
461
- * - Caller provides node reference for outside detection
462
- * - Single onDismiss callback for all dismiss triggers
463
- *
464
- * PIT OF SUCCESS:
465
- * ✓ Can't accidentally bypass (only way to get dismiss behavior)
466
- * ✓ Can't duplicate (disabled checked once)
467
- * ✓ Composes via mergeProps (standard props)
468
- * ✓ Wrong usage is hard (no factories to misuse)
469
- *
470
- * USAGE:
471
- * const props = dismissable({
472
- * node: elementRef,
473
- * disabled: false,
474
- * onDismiss: () => close()
475
- * });
476
- *
477
- * <div ref={elementRef} {...props}>Content</div>
478
- *
479
- * MISUSE EXAMPLE (PREVENTED):
480
- * ❌ Can't forget to check disabled - checked inside dismissable
481
- * ❌ Can't create custom escape handler - this is the only one
482
- * ❌ Can't bypass via direct event listeners - mergeProps composes correctly
483
- */
484
- interface DismissableOptions {
485
- /**
486
- * Reference to the element for outside click detection
487
- */
488
- node?: Node | null;
489
- /**
490
- * Whether dismiss is disabled
491
- */
492
- disabled?: boolean;
493
- /**
494
- * Called when dismiss is triggered (Escape or outside click)
495
- */
496
- onDismiss?: (trigger: 'escape' | 'outside') => void;
497
- }
498
-
499
- declare function dismissable({ node, disabled, onDismiss, }: DismissableOptions): {
500
- onKeyDown: (e: KeyboardLikeEvent) => void;
501
- onPointerDownCapture: (e: PointerLikeEvent) => void;
502
- };
503
-
504
- /**
505
- * focusable
506
- *
507
- * Normalize focus-related props for hosts.
508
- * - No DOM manipulation here; returns props that the runtime may attach.
509
- */
510
- interface FocusableOptions {
511
- disabled?: boolean;
512
- tabIndex?: number | undefined;
513
- }
514
- interface FocusableResult {
515
- tabIndex?: number;
516
- 'aria-disabled'?: 'true';
517
- }
518
- declare function focusable({ disabled, tabIndex, }: FocusableOptions): FocusableResult;
519
-
520
- /**
521
- * hoverable
522
- *
523
- * Produces props for pointer enter/leave handling. Pure and deterministic.
524
- */
525
- interface HoverableOptions {
526
- disabled?: boolean;
527
- onEnter?: (e: HoverEvent) => void;
528
- onLeave?: (e: HoverEvent) => void;
529
- }
530
-
531
- type HoverEvent = DefaultPreventable & PropagationStoppable;
532
- interface HoverableResult {
533
- onPointerEnter?: (e: HoverEvent) => void;
534
- onPointerLeave?: (e: HoverEvent) => void;
535
- }
536
- declare function hoverable({ disabled, onEnter, onLeave, }: HoverableOptions): HoverableResult;
537
-
538
- /**
539
- * rovingFocus
540
- *
541
- * Single tab stop navigation with arrow-key control.
542
- *
543
- * INVARIANTS:
544
- * 1. Only one item in the group is reachable via Tab (single tab stop)
545
- * 2. Arrow keys move focus within the group
546
- * 3. Orientation determines which arrow keys are active
547
- * 4. Looping is opt-in
548
- * 5. Disabled items are skipped
549
- * 6. Returns props objects, never factories (composes via mergeProps)
550
- *
551
- * DESIGN:
552
- * - Container gets onKeyDown for arrow navigation
553
- * - Each item gets tabIndex based on current selection
554
- * - Navigation logic is pure - caller controls focus application
555
- * - Disabled check happens per-item via predicate
556
- *
557
- * PIT OF SUCCESS:
558
- * ✓ Can't accidentally break tab order (tabIndex assigned correctly)
559
- * ✓ Can't duplicate navigation logic (single source)
560
- * ✓ Composes via mergeProps (all standard props)
561
- * ✓ Type-safe - invalid indices caught at call site
562
- *
563
- * USAGE:
564
- * const nav = rovingFocus({
565
- * currentIndex: 0,
566
- * itemCount: 3,
567
- * orientation: 'horizontal',
568
- * onNavigate: setIndex
569
- * });
570
- *
571
- * <div {...nav.container}>
572
- * <button {...nav.item(0)}>First</button>
573
- * <button {...nav.item(1)}>Second</button>
574
- * </div>
575
- *
576
- * MISUSE EXAMPLE (PREVENTED):
577
- * ❌ Can't forget to set tabIndex - returned in item props
578
- * ❌ Can't create conflicting arrow handlers - mergeProps composes
579
- * ❌ Can't skip disabled items incorrectly - logic is internal
580
- */
581
-
582
- type Orientation = 'horizontal' | 'vertical' | 'both';
583
- interface RovingFocusOptions {
584
- /**
585
- * Current focused index
586
- */
587
- currentIndex: number;
588
- /**
589
- * Total number of items
590
- */
591
- itemCount: number;
592
- /**
593
- * Navigation orientation
594
- * - horizontal: ArrowLeft/ArrowRight
595
- * - vertical: ArrowUp/ArrowDown
596
- * - both: all arrow keys
597
- */
598
- orientation?: Orientation;
599
- /**
600
- * Whether to loop when reaching the end
601
- */
602
- loop?: boolean;
603
- /**
604
- * Callback when navigation occurs
605
- */
606
- onNavigate?: (index: number) => void;
607
- /**
608
- * Optional disabled state check per index
609
- */
610
- isDisabled?: (index: number) => boolean;
611
- }
612
- interface RovingFocusResult {
613
- /**
614
- * Props for the container element (composes via mergeProps)
615
- */
616
- container: {
617
- onKeyDown: (e: KeyboardLikeEvent) => void;
618
- };
619
- /**
620
- * Generate props for an item at the given index (composes via mergeProps)
621
- */
622
- item: (index: number) => {
623
- tabIndex: number;
624
- 'data-roving-index': number;
625
- };
626
- }
627
- declare function rovingFocus(options: RovingFocusOptions): RovingFocusResult;
628
-
629
- /**
630
- * INTERACTION POLICY (FRAMEWORK LAW)
631
- *
632
- * This is THE ONLY way to create interactive elements. Components MUST NOT
633
- * implement interaction logic directly.
634
- *
635
- * INVARIANTS (ENFORCED):
636
- * 1. "Press" is the semantic. Click/touch/Enter/Space are implementation details.
637
- * 2. Disabled is enforced exactly once, here. Components may not check disabled.
638
- * 3. Keyboard handling is automatic. Components may not add onKeyDown for activation.
639
- * 4. Native elements opt out of polyfills, not semantics.
640
- * 5. asChild may replace the host element, not interaction behavior.
641
- * 6. This policy is the SINGLE SOURCE OF TRUTH for interactive behavior.
642
- *
643
- * DESIGN:
644
- * - Single public function: applyInteractionPolicy
645
- * - Returns props that compose via mergeProps
646
- * - Delegates to pressable for mechanics
647
- * - Enforces disabled once and only once
648
- * - No configuration beyond disabled and native element type
649
- *
650
- * PIT OF SUCCESS:
651
- * ✓ Can't bypass policy (only way to get interaction behavior)
652
- * ✓ Can't duplicate disabled checks (enforced once, here)
653
- * ✓ Can't write custom keyboard handlers for buttons (policy owns it)
654
- * ✓ Composes via mergeProps (standard props)
655
- * ✓ Wrong usage is impossible (no escape hatch)
656
- *
657
- * USAGE:
658
- * function Button({ onPress, disabled }) {
659
- * const interaction = applyInteractionPolicy({
660
- * isNative: true,
661
- * disabled,
662
- * onPress
663
- * });
664
- *
665
- * return <button {...interaction}>Click me</button>;
666
- * }
667
- *
668
- * MISUSE EXAMPLE (PREVENTED):
669
- * ❌ Button checking disabled again:
670
- * function Button({ disabled, onPress }) {
671
- * if (disabled) return; // NO! Policy handles this
672
- * const interaction = applyInteractionPolicy(...);
673
- * }
674
- *
675
- * ❌ Custom keyboard handler:
676
- * function Button({ onPress }) {
677
- * const interaction = applyInteractionPolicy(...);
678
- * return <button {...interaction} onKeyDown={...}>; // NO! Policy owns this
679
- * }
680
- *
681
- * ❌ Direct event handler:
682
- * <button onClick={onPress}>; // NO! Use applyInteractionPolicy
683
- */
684
- interface InteractionPolicyInput {
685
- /** Whether the host element is a native interactive element (button, a, etc) */
686
- isNative: boolean;
687
- /** Disabled state - checked ONLY here, never in components */
688
- disabled: boolean;
689
- /** User-provided press handler - semantic action, not DOM event */
690
- onPress?: (e: Event) => void;
691
- /** Optional ref to compose */
692
- ref?: any;
693
- }
694
- /**
695
- * THE interaction policy. Components MUST use this, NEVER implement
696
- * interaction logic directly.
697
- */
698
- declare function applyInteractionPolicy({ isNative, disabled, onPress, ref, }: InteractionPolicyInput): {
699
- disabled: true | undefined;
700
- onClick: (e: Event) => void;
701
- ref: any;
702
- } | {
703
- 'aria-disabled': true | undefined;
704
- tabIndex: number;
705
- ref: any;
706
- onClick: (e: DefaultPreventable & PropagationStoppable) => void;
707
- disabled?: true;
708
- role?: "button";
709
- onKeyDown?: (e: KeyboardLikeEvent) => void;
710
- onKeyUp?: (e: KeyboardLikeEvent) => void;
711
- };
712
- /**
713
- * Merge rule for Slot / asChild
714
- *
715
- * Precedence:
716
- * policy → user → child
717
- *
718
- * Event handlers are composed (policy first).
719
- * Refs are always composed.
720
- * Policy props MUST take precedence to enforce invariants.
721
- */
722
- declare function mergeInteractionProps(childProps: Record<string, any>, policyProps: Record<string, any>, userProps?: Record<string, any>): Record<string, any>;
723
-
724
- export { type Collection, type CollectionItem, type ComposeHandlersOptions, type ControllableState, DefaultPortal, type DismissableOptions, type FocusableOptions, type FocusableResult, type HoverableOptions, type HoverableResult, type InteractionPolicyInput, JSXElement, type Layer, type LayerManager, type LayerOptions, type Orientation, type Portal, Presence, type PresenceProps, type PressableOptions, type PressableResult, type Ref, type RovingFocusOptions, type RovingFocusResult, Slot, type SlotProps, applyInteractionPolicy, ariaDisabled, ariaExpanded, ariaSelected, composeHandlers, composeRefs, controllableState, createCollection, createLayer, definePortal, dismissable, focusable, hoverable, isControlled, makeControllable, mergeInteractionProps, mergeProps, pressable, resolveControllable, rovingFocus, setRef, useId };
5
+ export { J as JSXElement } from '../jsx-CSWf4VFg.js';
6
+ import '../component-mtwBWhUr.js';