@radix-ng/primitives 1.0.9 → 1.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 (37) hide show
  1. package/fesm2022/radix-ng-primitives-autocomplete.mjs +11 -3
  2. package/fesm2022/radix-ng-primitives-autocomplete.mjs.map +1 -1
  3. package/fesm2022/radix-ng-primitives-combobox.mjs +11 -3
  4. package/fesm2022/radix-ng-primitives-combobox.mjs.map +1 -1
  5. package/fesm2022/radix-ng-primitives-core.mjs +9 -6
  6. package/fesm2022/radix-ng-primitives-core.mjs.map +1 -1
  7. package/fesm2022/radix-ng-primitives-date-field.mjs +18 -8
  8. package/fesm2022/radix-ng-primitives-date-field.mjs.map +1 -1
  9. package/fesm2022/radix-ng-primitives-floating-focus-manager.mjs +9 -0
  10. package/fesm2022/radix-ng-primitives-floating-focus-manager.mjs.map +1 -1
  11. package/fesm2022/radix-ng-primitives-focus-scope.mjs +241 -95
  12. package/fesm2022/radix-ng-primitives-focus-scope.mjs.map +1 -1
  13. package/fesm2022/radix-ng-primitives-menu.mjs +97 -9
  14. package/fesm2022/radix-ng-primitives-menu.mjs.map +1 -1
  15. package/fesm2022/radix-ng-primitives-navigation-menu.mjs +17 -3
  16. package/fesm2022/radix-ng-primitives-navigation-menu.mjs.map +1 -1
  17. package/fesm2022/radix-ng-primitives-popper.mjs +148 -23
  18. package/fesm2022/radix-ng-primitives-popper.mjs.map +1 -1
  19. package/fesm2022/radix-ng-primitives-portal.mjs +16 -5
  20. package/fesm2022/radix-ng-primitives-portal.mjs.map +1 -1
  21. package/fesm2022/radix-ng-primitives-select.mjs +14 -6
  22. package/fesm2022/radix-ng-primitives-select.mjs.map +1 -1
  23. package/fesm2022/radix-ng-primitives-time-field.mjs +12 -4
  24. package/fesm2022/radix-ng-primitives-time-field.mjs.map +1 -1
  25. package/package.json +1 -5
  26. package/types/radix-ng-primitives-core.d.ts +15 -12
  27. package/types/radix-ng-primitives-date-field.d.ts +14 -4
  28. package/types/radix-ng-primitives-floating-focus-manager.d.ts +7 -0
  29. package/types/radix-ng-primitives-focus-scope.d.ts +61 -44
  30. package/types/radix-ng-primitives-menu.d.ts +14 -3
  31. package/types/radix-ng-primitives-popper.d.ts +136 -43
  32. package/types/radix-ng-primitives-portal.d.ts +18 -8
  33. package/types/radix-ng-primitives-time-field.d.ts +12 -4
  34. package/fesm2022/radix-ng-primitives-focus-guards.mjs +0 -53
  35. package/fesm2022/radix-ng-primitives-focus-guards.mjs.map +0 -1
  36. package/focus-guards/README.md +0 -1
  37. package/types/radix-ng-primitives-focus-guards.d.ts +0 -15
@@ -1,5 +1,5 @@
1
1
  import * as _angular_core from '@angular/core';
2
- import { ElementRef, Provider, Type, InjectionToken } from '@angular/core';
2
+ import { ElementRef, Signal, Provider, Type, InjectionToken } from '@angular/core';
3
3
  import { ReferenceElement, Placement, Middleware, VirtualElement } from '@floating-ui/dom';
4
4
  import * as _radix_ng_primitives_core from '@radix-ng/primitives/core';
5
5
  import { NumberInput, BooleanInput } from '@radix-ng/primitives/core';
@@ -48,6 +48,45 @@ declare const SIDE_OPTIONS: readonly ["top", "right", "bottom", "left"];
48
48
  declare const ALIGN_OPTIONS: readonly ["start", "center", "end"];
49
49
  type Side = (typeof SIDE_OPTIONS)[number];
50
50
  type Align = (typeof ALIGN_OPTIONS)[number];
51
+ /**
52
+ * How the popper avoids collisions with the boundary edges (Base UI `collisionAvoidance`).
53
+ *
54
+ * - `side` — behavior on the **preferred placement axis** (`top`/`bottom` or `left`/`right`):
55
+ * `'flip'` swaps to the opposite side when it doesn't fit, `'shift'` keeps the side and nudges the
56
+ * popup within the boundary, `'none'` leaves side-axis overflow uncorrected.
57
+ * - `align` — behavior on the **alignment axis** (`start`/`center`/`end`): `'flip'` swaps `start`/`end`,
58
+ * `'shift'` nudges the popup along the alignment axis, `'none'` leaves it uncorrected.
59
+ * - `fallbackAxisSide` — when neither preferred side fits, whether to fall back to the perpendicular
60
+ * axis and which logical side to prefer (`'start'` / `'end'`), or `'none'` to stay on the axis.
61
+ *
62
+ * Any omitted field falls back to the wrapper default (`side: 'flip'`, `align: 'flip'`,
63
+ * `fallbackAxisSide: 'end'`), matching Base UI.
64
+ */
65
+ interface RdxCollisionAvoidance {
66
+ side?: 'flip' | 'shift' | 'none';
67
+ align?: 'flip' | 'shift' | 'none';
68
+ fallbackAxisSide?: 'start' | 'end' | 'none';
69
+ }
70
+ /** Fully-resolved {@link RdxCollisionAvoidance} — every field present (no wrapper-default fallback left). */
71
+ type ResolvedCollisionAvoidance = Required<RdxCollisionAvoidance>;
72
+ /**
73
+ * Function form of `sideOffset` / `alignOffset` (Base UI `OffsetFunction`). Receives the resolved
74
+ * placement and the measured anchor / positioner dimensions, and returns the offset in pixels — e.g.
75
+ * `({ anchor }) => anchor.width` to offset by the trigger's own width. `side` is the physical side the
76
+ * popup is placed against.
77
+ */
78
+ type OffsetFunction = (data: {
79
+ side: Side;
80
+ align: Align;
81
+ anchor: {
82
+ width: number;
83
+ height: number;
84
+ };
85
+ positioner: {
86
+ width: number;
87
+ height: number;
88
+ };
89
+ }) => number;
51
90
  declare function isNotNull<T>(value: T | null): value is T;
52
91
  declare function transformOrigin(options: {
53
92
  arrowWidth: number;
@@ -57,32 +96,32 @@ declare function getSideAndAlignFromPlacement(placement: Placement): readonly ["
57
96
 
58
97
  type RdxPopperAnchorElement = Element | ElementRef<Element> | VirtualElement | (() => Element | VirtualElement | null) | null | undefined;
59
98
  declare const context: () => {
60
- placedSide: _angular_core.Signal<"top" | "right" | "bottom" | "left" | undefined>;
61
- placedAlign: _angular_core.Signal<"start" | "center" | "end" | undefined>;
62
- arrowX: _angular_core.Signal<number | undefined>;
63
- arrowY: _angular_core.Signal<number | undefined>;
64
- shouldHideArrow: _angular_core.Signal<boolean>;
65
- isPositioned: _angular_core.Signal<boolean>;
66
- anchorHidden: _angular_core.Signal<boolean>;
99
+ placedSide: Signal<"top" | "right" | "bottom" | "left" | undefined>;
100
+ placedAlign: Signal<"start" | "center" | "end" | undefined>;
101
+ arrowX: Signal<number | undefined>;
102
+ arrowY: Signal<number | undefined>;
103
+ shouldHideArrow: Signal<boolean>;
104
+ isPositioned: Signal<boolean>;
105
+ anchorHidden: Signal<boolean>;
67
106
  };
68
107
  type PopperContentWrapperContext = ReturnType<typeof context>;
69
108
  declare const injectPopperContentWrapperContext: _radix_ng_primitives_core.InjectContext<{
70
- placedSide: _angular_core.Signal<"top" | "right" | "bottom" | "left" | undefined>;
71
- placedAlign: _angular_core.Signal<"start" | "center" | "end" | undefined>;
72
- arrowX: _angular_core.Signal<number | undefined>;
73
- arrowY: _angular_core.Signal<number | undefined>;
74
- shouldHideArrow: _angular_core.Signal<boolean>;
75
- isPositioned: _angular_core.Signal<boolean>;
76
- anchorHidden: _angular_core.Signal<boolean>;
109
+ placedSide: Signal<"top" | "right" | "bottom" | "left" | undefined>;
110
+ placedAlign: Signal<"start" | "center" | "end" | undefined>;
111
+ arrowX: Signal<number | undefined>;
112
+ arrowY: Signal<number | undefined>;
113
+ shouldHideArrow: Signal<boolean>;
114
+ isPositioned: Signal<boolean>;
115
+ anchorHidden: Signal<boolean>;
77
116
  }>;
78
117
  declare const providePopperContentWrapperContext: (useFactory: () => {
79
- placedSide: _angular_core.Signal<"top" | "right" | "bottom" | "left" | undefined>;
80
- placedAlign: _angular_core.Signal<"start" | "center" | "end" | undefined>;
81
- arrowX: _angular_core.Signal<number | undefined>;
82
- arrowY: _angular_core.Signal<number | undefined>;
83
- shouldHideArrow: _angular_core.Signal<boolean>;
84
- isPositioned: _angular_core.Signal<boolean>;
85
- anchorHidden: _angular_core.Signal<boolean>;
118
+ placedSide: Signal<"top" | "right" | "bottom" | "left" | undefined>;
119
+ placedAlign: Signal<"start" | "center" | "end" | undefined>;
120
+ arrowX: Signal<number | undefined>;
121
+ arrowY: Signal<number | undefined>;
122
+ shouldHideArrow: Signal<boolean>;
123
+ isPositioned: Signal<boolean>;
124
+ anchorHidden: Signal<boolean>;
86
125
  }) => Provider;
87
126
  declare class RdxPopperContentWrapper {
88
127
  private readonly elementRef;
@@ -100,22 +139,44 @@ declare class RdxPopperContentWrapper {
100
139
  */
101
140
  readonly side: _angular_core.InputSignal<"top" | "right" | "bottom" | "left">;
102
141
  /**
103
- * Distance between the anchor and the popup in pixels.
142
+ * Distance between the anchor and the popup in pixels. Also accepts an {@link OffsetFunction} that
143
+ * reads the anchor / positioner dimensions and the resolved side / align.
104
144
  */
105
- readonly sideOffset: _angular_core.InputSignalWithTransform<number, NumberInput>;
145
+ readonly sideOffset: _angular_core.InputSignalWithTransform<number | OffsetFunction, string | number | OffsetFunction | null | undefined>;
106
146
  /**
107
147
  * How to align the popup relative to the specified side. May change when collisions occur.
108
148
  */
109
149
  readonly align: _angular_core.InputSignal<"start" | "center" | "end">;
110
- /** An offset in pixels from the `start` or `end` alignment options. */
111
- readonly alignOffset: _angular_core.InputSignalWithTransform<number, NumberInput>;
150
+ /**
151
+ * An offset in pixels from the `start` or `end` alignment options. Also accepts an
152
+ * {@link OffsetFunction} (same signature as `sideOffset`).
153
+ */
154
+ readonly alignOffset: _angular_core.InputSignalWithTransform<number | OffsetFunction, string | number | OffsetFunction | null | undefined>;
112
155
  /**
113
156
  * Minimum distance to maintain between the arrow and the edges of the popup.
114
157
  * If your content has border-radius, this will prevent it from overflowing the corners.
115
158
  */
116
159
  readonly arrowPadding: _angular_core.InputSignalWithTransform<number, NumberInput>;
117
- /** When `true`, overrides the `side` and `align` preferences to prevent collisions with boundary edges. */
160
+ /**
161
+ * When `true`, overrides the `side` and `align` preferences to prevent collisions with boundary edges.
162
+ *
163
+ * @deprecated Use {@link collisionAvoidance} for fine-grained control (Base UI parity). Still honored:
164
+ * `false` disables all avoidance (unless a `collisionAvoidance` object is provided, which wins).
165
+ */
118
166
  readonly avoidCollisions: _angular_core.InputSignalWithTransform<boolean, BooleanInput>;
167
+ /**
168
+ * How the popup avoids colliding with the boundary edges, per axis (Base UI `collisionAvoidance`).
169
+ * Overrides the deprecated `avoidCollisions` and any per-primitive preset. An object here **fully
170
+ * replaces** the preset — omitted fields fall back to `side: 'flip'`, `align: 'flip'`,
171
+ * `fallbackAxisSide: 'end'`, never to the preset. See {@link RdxCollisionAvoidance}.
172
+ */
173
+ readonly collisionAvoidance: _angular_core.InputSignal<RdxCollisionAvoidance | undefined>;
174
+ /**
175
+ * Collision avoidance resolved against the deprecated `avoidCollisions` flag, the per-primitive
176
+ * config preset, and the wrapper defaults. Precedence: an explicit `collisionAvoidance` input →
177
+ * a legacy `avoidCollisions=false` (disables everything) → the config preset → the Base UI defaults.
178
+ */
179
+ private readonly effectiveCollisionAvoidance;
119
180
  /**
120
181
  * The element used as the collision boundary.
121
182
  * By default this is the viewport, though you can provide additional element(s) to be included in this check.
@@ -149,19 +210,19 @@ declare class RdxPopperContentWrapper {
149
210
  * Emits when the element is placed.
150
211
  */
151
212
  readonly placed: _angular_core.OutputEmitterRef<void>;
152
- readonly arrow: _angular_core.Signal<any>;
213
+ readonly arrow: Signal<any>;
153
214
  /**
154
215
  * When `true`, the content is rendered click/hover-through (`pointer-events: none`). Used for
155
216
  * cursor-following content (e.g. a tooltip tracking the pointer) that must never intercept the
156
217
  * pointer and steal hover from its trigger.
157
218
  */
158
219
  readonly nonInteractive: _angular_core.WritableSignal<boolean>;
159
- readonly shouldHideArrow: _angular_core.Signal<boolean>;
220
+ readonly shouldHideArrow: Signal<boolean>;
160
221
  /** Whether the arrow could not be centered on the anchor because the popup was shifted. */
161
- readonly arrowUncentered: _angular_core.Signal<boolean>;
162
- readonly arrowX: _angular_core.Signal<number | undefined>;
163
- readonly arrowY: _angular_core.Signal<number | undefined>;
164
- readonly anchorHidden: _angular_core.Signal<boolean>;
222
+ readonly arrowUncentered: Signal<boolean>;
223
+ readonly arrowX: Signal<number | undefined>;
224
+ readonly arrowY: Signal<number | undefined>;
225
+ readonly anchorHidden: Signal<boolean>;
165
226
  private readonly desiredPlacement;
166
227
  private readonly arrowSize;
167
228
  private readonly boundary;
@@ -183,23 +244,23 @@ declare class RdxPopperContentWrapper {
183
244
  /**
184
245
  * Whether the panel is positioned.
185
246
  */
186
- readonly isPositioned: _angular_core.Signal<boolean>;
247
+ readonly isPositioned: Signal<boolean>;
187
248
  /**
188
249
  * The current placement of the panel.
189
250
  */
190
- readonly placement: _angular_core.Signal<{
251
+ readonly placement: Signal<{
191
252
  side: Side;
192
253
  align: Align;
193
254
  } | undefined>;
194
255
  /**
195
256
  * The side the panel is currently placed against.
196
257
  */
197
- readonly placedSide: _angular_core.Signal<"top" | "right" | "bottom" | "left" | undefined>;
258
+ readonly placedSide: Signal<"top" | "right" | "bottom" | "left" | undefined>;
198
259
  /**
199
260
  * The current alignment of the panel.
200
261
  */
201
- readonly placedAlign: _angular_core.Signal<"start" | "center" | "end" | undefined>;
202
- protected readonly style: _angular_core.Signal<{
262
+ readonly placedAlign: Signal<"start" | "center" | "end" | undefined>;
263
+ protected readonly style: Signal<{
203
264
  visibility: string;
204
265
  pointerEvents: string;
205
266
  position: "fixed" | "absolute";
@@ -218,10 +279,20 @@ declare class RdxPopperContentWrapper {
218
279
  '--positioner-height': string;
219
280
  '--transform-origin': string;
220
281
  }>;
282
+ /**
283
+ * Whether the positioner should actively track its anchor (recompute + `autoUpdate`). Defaults to
284
+ * always-on — the historical behavior, correct for a positioner that unmounts when its layer closes.
285
+ * A positioner that can stay mounted while closed (`keepMounted`) **overrides** this with its
286
+ * open/presence signal so a closed, hidden positioner doesn't spin an endless `autoUpdate`
287
+ * `requestAnimationFrame` loop (only relevant when `updatePositionStrategy: 'always'`). It's a
288
+ * reassignable field (not `readonly`) because the render effect below reads it lazily, after the
289
+ * subclass constructor has swapped it in.
290
+ */
291
+ protected positioningActive: Signal<boolean>;
221
292
  private readonly afterRenderEffect;
222
293
  constructor();
223
294
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<RdxPopperContentWrapper, never>;
224
- static ɵdir: _angular_core.ɵɵDirectiveDeclaration<RdxPopperContentWrapper, "[rdxPopperContentWrapper]", never, { "anchor": { "alias": "anchor"; "required": false; "isSignal": true; }; "side": { "alias": "side"; "required": false; "isSignal": true; }; "sideOffset": { "alias": "sideOffset"; "required": false; "isSignal": true; }; "align": { "alias": "align"; "required": false; "isSignal": true; }; "alignOffset": { "alias": "alignOffset"; "required": false; "isSignal": true; }; "arrowPadding": { "alias": "arrowPadding"; "required": false; "isSignal": true; }; "avoidCollisions": { "alias": "avoidCollisions"; "required": false; "isSignal": true; }; "collisionBoundary": { "alias": "collisionBoundary"; "required": false; "isSignal": true; }; "collisionPadding": { "alias": "collisionPadding"; "required": false; "isSignal": true; }; "sticky": { "alias": "sticky"; "required": false; "isSignal": true; }; "hideWhenDetached": { "alias": "hideWhenDetached"; "required": false; "isSignal": true; }; "positionStrategy": { "alias": "positionStrategy"; "required": false; "isSignal": true; }; "updatePositionStrategy": { "alias": "updatePositionStrategy"; "required": false; "isSignal": true; }; }, { "placed": "placed"; }, ["arrow"], never, true, never>;
295
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<RdxPopperContentWrapper, "[rdxPopperContentWrapper]", never, { "anchor": { "alias": "anchor"; "required": false; "isSignal": true; }; "side": { "alias": "side"; "required": false; "isSignal": true; }; "sideOffset": { "alias": "sideOffset"; "required": false; "isSignal": true; }; "align": { "alias": "align"; "required": false; "isSignal": true; }; "alignOffset": { "alias": "alignOffset"; "required": false; "isSignal": true; }; "arrowPadding": { "alias": "arrowPadding"; "required": false; "isSignal": true; }; "avoidCollisions": { "alias": "avoidCollisions"; "required": false; "isSignal": true; }; "collisionAvoidance": { "alias": "collisionAvoidance"; "required": false; "isSignal": true; }; "collisionBoundary": { "alias": "collisionBoundary"; "required": false; "isSignal": true; }; "collisionPadding": { "alias": "collisionPadding"; "required": false; "isSignal": true; }; "sticky": { "alias": "sticky"; "required": false; "isSignal": true; }; "hideWhenDetached": { "alias": "hideWhenDetached"; "required": false; "isSignal": true; }; "positionStrategy": { "alias": "positionStrategy"; "required": false; "isSignal": true; }; "updatePositionStrategy": { "alias": "updatePositionStrategy"; "required": false; "isSignal": true; }; }, { "placed": "placed"; }, ["arrow"], never, true, never>;
225
296
  }
226
297
  /**
227
298
  * Providers a "thin" positioner that `extends RdxPopperContentWrapper` must include. Angular
@@ -282,20 +353,42 @@ declare class RdxPopperArrow {
282
353
  interface RdxPopperContentConfig {
283
354
  side?: Side;
284
355
  align?: Align;
285
- sideOffset?: number;
286
- alignOffset?: number;
356
+ sideOffset?: number | OffsetFunction;
357
+ alignOffset?: number | OffsetFunction;
287
358
  arrowPadding?: number;
359
+ /**
360
+ * @deprecated Use {@link collisionAvoidance} instead. Kept for back-compat: `false` disables all
361
+ * collision avoidance (equivalent to `{ side: 'none', align: 'none', fallbackAxisSide: 'none' }`).
362
+ */
288
363
  avoidCollisions?: boolean;
364
+ /** Per-primitive collision-avoidance default (Base UI parity). See {@link RdxCollisionAvoidance}. */
365
+ collisionAvoidance?: RdxCollisionAvoidance;
289
366
  collisionPadding?: number | Partial<Record<Side, number>>;
290
367
  sticky?: 'partial' | 'always';
291
368
  hideWhenDetached?: boolean;
292
369
  positionStrategy?: 'fixed' | 'absolute';
293
370
  updatePositionStrategy?: 'optimized' | 'always';
294
371
  }
372
+ /**
373
+ * Collision-avoidance preset for dropdown-style popups (Base UI `DROPDOWN_COLLISION_AVOIDANCE`).
374
+ *
375
+ * Dropdowns (select / combobox / autocomplete / menu) strictly prefer their top/bottom placement and
376
+ * cap their height with `var(--available-height)`, so they must **not** fall back to the perpendicular
377
+ * (left/right) axis. `side`/`align` fall back to the wrapper default (`'flip'`).
378
+ */
379
+ declare const DROPDOWN_COLLISION_AVOIDANCE: RdxCollisionAvoidance;
380
+ /**
381
+ * Collision-avoidance preset for regular popups (Base UI `POPUP_COLLISION_AVOIDANCE`).
382
+ *
383
+ * Popovers / tooltips / preview cards aren't height-capped and may freely flip to the perpendicular
384
+ * axis, preferring the logical end side. This equals the wrapper's built-in default; it is exported so
385
+ * popups can state the intent explicitly.
386
+ */
387
+ declare const POPUP_COLLISION_AVOIDANCE: RdxCollisionAvoidance;
295
388
  declare const RdxPopperContentConfigToken: InjectionToken<RdxPopperContentConfig>;
296
389
  declare function provideRdxPopperContentConfig(config: RdxPopperContentConfig): Provider;
297
390
 
298
391
  declare const popperImports: (typeof RdxPopperAnchor | typeof RdxPopper | typeof RdxPopperContentWrapper | typeof RdxPopperContent)[];
299
392
 
300
- export { RdxPopper, RdxPopperAnchor, RdxPopperArrow, RdxPopperContent, RdxPopperContentConfigToken, RdxPopperContentWrapper, getSideAndAlignFromPlacement, injectPopperContentWrapperContext, isNotNull, legacyPopperVars, popperImports, providePopperContentWrapperContext, provideRdxPopperContentConfig, provideRdxPopperContentWrapper, transformOrigin };
301
- export type { Align, PopperContentWrapperContext, RdxPopperAnchorElement, RdxPopperContentConfig, Side };
393
+ export { DROPDOWN_COLLISION_AVOIDANCE, POPUP_COLLISION_AVOIDANCE, RdxPopper, RdxPopperAnchor, RdxPopperArrow, RdxPopperContent, RdxPopperContentConfigToken, RdxPopperContentWrapper, getSideAndAlignFromPlacement, injectPopperContentWrapperContext, isNotNull, legacyPopperVars, popperImports, providePopperContentWrapperContext, provideRdxPopperContentConfig, provideRdxPopperContentWrapper, transformOrigin };
394
+ export type { Align, OffsetFunction, PopperContentWrapperContext, RdxCollisionAvoidance, RdxPopperAnchorElement, RdxPopperContentConfig, ResolvedCollisionAvoidance, Side };
@@ -1,4 +1,4 @@
1
- import * as i0 from '@angular/core';
1
+ import * as _angular_core from '@angular/core';
2
2
  import { ElementRef } from '@angular/core';
3
3
 
4
4
  /**
@@ -22,14 +22,14 @@ declare class RdxPortal {
22
22
  * Specify a container to portal the content into. Can be an `ElementRef`, a native element, or a
23
23
  * CSS selector. Defaults to `document.body` when not set (or when a selector matches nothing).
24
24
  */
25
- readonly container: i0.InputSignal<RdxPortalContainer | undefined>;
25
+ readonly container: _angular_core.InputSignal<RdxPortalContainer | undefined>;
26
26
  private readonly _computedContainer;
27
- readonly computedContainer: i0.Signal<RdxPortalContainer | undefined>;
27
+ readonly computedContainer: _angular_core.Signal<RdxPortalContainer | undefined>;
28
28
  private readonly elementContainer;
29
29
  constructor();
30
30
  setContainer(container: RdxPortalContainer): void;
31
- static ɵfac: i0.ɵɵFactoryDeclaration<RdxPortal, never>;
32
- static ɵdir: i0.ɵɵDirectiveDeclaration<RdxPortal, "[rdxPortal]", ["rdxPortal"], { "container": { "alias": "container"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
31
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<RdxPortal, never>;
32
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<RdxPortal, "[rdxPortal]", ["rdxPortal"], { "container": { "alias": "container"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
33
33
  }
34
34
 
35
35
  /**
@@ -56,7 +56,17 @@ declare class RdxPortalPresence {
56
56
  * Container to portal the content into. Can be an `ElementRef`, a native element, or a CSS
57
57
  * selector. Defaults to `document.body` (or when a selector matches nothing).
58
58
  */
59
- readonly container: i0.InputSignal<RdxPortalContainer | undefined>;
59
+ readonly container: _angular_core.InputSignal<RdxPortalContainer | undefined>;
60
+ /**
61
+ * Keep the portal mounted (in the container) while the layer is closed. When `true` the content
62
+ * stays in the DOM regardless of the {@link RDX_PRESENCE_CONTEXT} `present` flag — the consumer is
63
+ * responsible for hiding it while closed (typically via the `data-closed` / `data-open` state on the
64
+ * positioner). Any `*rdxXxxPortal` wrapper opts in by mapping this input in its `hostDirectives`.
65
+ */
66
+ readonly keepMounted: _angular_core.InputSignalWithTransform<boolean, unknown>;
67
+ /** The layer's own open/present flag, OR'd with {@link keepMounted} to gate mount/unmount. */
68
+ private readonly contextPresent;
69
+ private readonly present;
60
70
  private readonly _computedContainer;
61
71
  private readonly elementContainer;
62
72
  /** The live view's root nodes, exposed as a signal so the relocation effect re-runs on (re)mount. */
@@ -67,8 +77,8 @@ declare class RdxPortalPresence {
67
77
  setContainer(container: RdxPortalContainer): void;
68
78
  private mountView;
69
79
  private destroyView;
70
- static ɵfac: i0.ɵɵFactoryDeclaration<RdxPortalPresence, never>;
71
- static ɵdir: i0.ɵɵDirectiveDeclaration<RdxPortalPresence, never, never, { "container": { "alias": "container"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
80
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<RdxPortalPresence, never>;
81
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<RdxPortalPresence, never, never, { "container": { "alias": "container"; "required": false; "isSignal": true; }; "keepMounted": { "alias": "keepMounted"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
72
82
  }
73
83
 
74
84
  export { RdxPortal, RdxPortalPresence, resolvePortalContainer };
@@ -60,6 +60,13 @@ declare class RdxTimeFieldRootDirective extends RdxFormUiControlBase implements
60
60
  * The placeholder date, which is used to determine what month to display when no date is selected. This updates as the user navigates the calendar and can be used to programmatically control the calendar view
61
61
  */
62
62
  readonly placeholder: _angular_core.ModelSignal<TimeValue | undefined>;
63
+ /**
64
+ * Always-defined placeholder used for segment math. A controlled `[placeholder]` can be reset to
65
+ * `undefined`; fall back to the default time so the converted placeholder is never built from
66
+ * `undefined`.
67
+ * @ignore
68
+ */
69
+ readonly effectivePlaceholder: Signal<TimeValue>;
63
70
  /**
64
71
  * Segment input parts, collected from the projected content in DOM order. This
65
72
  * stays in sync with `segmentContents()` (granularity / locale / value changes
@@ -222,16 +229,17 @@ declare class RdxTimeFieldInputDirective {
222
229
  interface TimeFieldContextToken {
223
230
  locale: InputSignal<string>;
224
231
  value: ModelSignal<TimeValue | undefined>;
225
- placeholder: ModelSignal<TimeValue>;
232
+ /** The controlled placeholder; may be `undefined`. Use `convertedPlaceholder` for segment math. */
233
+ placeholder: Signal<TimeValue | undefined>;
226
234
  isInvalid: Signal<boolean>;
227
235
  /** Effective invalid: the built-in range check OR the form-driven invalid state. */
228
236
  invalidState: Signal<boolean>;
229
237
  /** Tri-state displayed validity (`true`/`false`/`null`): the field's gated state inside a Field, else own. */
230
238
  displayValid: Signal<boolean | null>;
231
- disabled: InputSignal<boolean>;
232
- readonly: InputSignal<boolean>;
239
+ disabled: Signal<boolean>;
240
+ readonly: Signal<boolean>;
233
241
  formatter: Signal<Formatter>;
234
- hourCycle: InputSignal<HourCycle>;
242
+ hourCycle: Signal<HourCycle | undefined>;
235
243
  segmentValues: WritableSignal<SegmentValueObj>;
236
244
  focusNext: () => void;
237
245
  setFocusedElement: (el: HTMLElement) => void;
@@ -1,53 +0,0 @@
1
- import * as i0 from '@angular/core';
2
- import { inject, Injector, afterNextRender, effect, Directive } from '@angular/core';
3
-
4
- /** Number of components which have requested interest to have focus guards */
5
- let count = 0;
6
- /**
7
- * Injects a pair of focus guards at the edges of the whole DOM tree
8
- * to ensure `focusin` & `focusout` events can be caught consistently.
9
- */
10
- class RdxFocusGuards {
11
- constructor() {
12
- this.injector = inject(Injector);
13
- afterNextRender(() => {
14
- effect((onCleanup) => {
15
- const edgeGuards = document.querySelectorAll('[data-radix-focus-guard]');
16
- document.body.insertAdjacentElement('afterbegin', edgeGuards[0] ?? this.createFocusGuard());
17
- document.body.insertAdjacentElement('beforeend', edgeGuards[1] ?? this.createFocusGuard());
18
- count++;
19
- onCleanup(() => {
20
- if (count === 1) {
21
- document.querySelectorAll('[data-radix-focus-guard]').forEach((node) => node.remove());
22
- }
23
- count--;
24
- });
25
- }, { injector: this.injector });
26
- });
27
- }
28
- createFocusGuard() {
29
- const element = document.createElement('span');
30
- element.setAttribute('data-radix-focus-guard', '');
31
- element.tabIndex = 0;
32
- element.style.outline = 'none';
33
- element.style.opacity = '0';
34
- element.style.position = 'fixed';
35
- element.style.pointerEvents = 'none';
36
- return element;
37
- }
38
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: RdxFocusGuards, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
39
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.2", type: RdxFocusGuards, isStandalone: true, selector: "[rdxFocusGuards]", ngImport: i0 }); }
40
- }
41
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: RdxFocusGuards, decorators: [{
42
- type: Directive,
43
- args: [{
44
- selector: '[rdxFocusGuards]'
45
- }]
46
- }], ctorParameters: () => [] });
47
-
48
- /**
49
- * Generated bundle index. Do not edit.
50
- */
51
-
52
- export { RdxFocusGuards };
53
- //# sourceMappingURL=radix-ng-primitives-focus-guards.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"radix-ng-primitives-focus-guards.mjs","sources":["../../../packages/primitives/focus-guards/src/focus-guards.ts","../../../packages/primitives/focus-guards/radix-ng-primitives-focus-guards.ts"],"sourcesContent":["import { afterNextRender, Directive, effect, inject, Injector } from '@angular/core';\n\n/** Number of components which have requested interest to have focus guards */\nlet count = 0;\n\n/**\n * Injects a pair of focus guards at the edges of the whole DOM tree\n * to ensure `focusin` & `focusout` events can be caught consistently.\n */\n@Directive({\n selector: '[rdxFocusGuards]'\n})\nexport class RdxFocusGuards {\n private readonly injector = inject(Injector);\n\n constructor() {\n afterNextRender(() => {\n effect(\n (onCleanup) => {\n const edgeGuards = document.querySelectorAll('[data-radix-focus-guard]');\n\n document.body.insertAdjacentElement('afterbegin', edgeGuards[0] ?? this.createFocusGuard());\n\n document.body.insertAdjacentElement('beforeend', edgeGuards[1] ?? this.createFocusGuard());\n\n count++;\n\n onCleanup(() => {\n if (count === 1) {\n document.querySelectorAll('[data-radix-focus-guard]').forEach((node) => node.remove());\n }\n\n count--;\n });\n },\n { injector: this.injector }\n );\n });\n }\n\n createFocusGuard() {\n const element = document.createElement('span');\n element.setAttribute('data-radix-focus-guard', '');\n element.tabIndex = 0;\n element.style.outline = 'none';\n element.style.opacity = '0';\n element.style.position = 'fixed';\n element.style.pointerEvents = 'none';\n return element;\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;AAEA;AACA,IAAI,KAAK,GAAG,CAAC;AAEb;;;AAGG;MAIU,cAAc,CAAA;AAGvB,IAAA,WAAA,GAAA;AAFiB,QAAA,IAAA,CAAA,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;QAGxC,eAAe,CAAC,MAAK;AACjB,YAAA,MAAM,CACF,CAAC,SAAS,KAAI;gBACV,MAAM,UAAU,GAAG,QAAQ,CAAC,gBAAgB,CAAC,0BAA0B,CAAC;AAExE,gBAAA,QAAQ,CAAC,IAAI,CAAC,qBAAqB,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;AAE3F,gBAAA,QAAQ,CAAC,IAAI,CAAC,qBAAqB,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;AAE1F,gBAAA,KAAK,EAAE;gBAEP,SAAS,CAAC,MAAK;AACX,oBAAA,IAAI,KAAK,KAAK,CAAC,EAAE;AACb,wBAAA,QAAQ,CAAC,gBAAgB,CAAC,0BAA0B,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;oBAC1F;AAEA,oBAAA,KAAK,EAAE;AACX,gBAAA,CAAC,CAAC;YACN,CAAC,EACD,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAC9B;AACL,QAAA,CAAC,CAAC;IACN;IAEA,gBAAgB,GAAA;QACZ,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC;AAC9C,QAAA,OAAO,CAAC,YAAY,CAAC,wBAAwB,EAAE,EAAE,CAAC;AAClD,QAAA,OAAO,CAAC,QAAQ,GAAG,CAAC;AACpB,QAAA,OAAO,CAAC,KAAK,CAAC,OAAO,GAAG,MAAM;AAC9B,QAAA,OAAO,CAAC,KAAK,CAAC,OAAO,GAAG,GAAG;AAC3B,QAAA,OAAO,CAAC,KAAK,CAAC,QAAQ,GAAG,OAAO;AAChC,QAAA,OAAO,CAAC,KAAK,CAAC,aAAa,GAAG,MAAM;AACpC,QAAA,OAAO,OAAO;IAClB;8GArCS,cAAc,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;kGAAd,cAAc,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,kBAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA,CAAA;;2FAAd,cAAc,EAAA,UAAA,EAAA,CAAA;kBAH1B,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACP,oBAAA,QAAQ,EAAE;AACb,iBAAA;;;ACXD;;AAEG;;;;"}
@@ -1 +0,0 @@
1
- # @radix-ng/primitives/focus-guards
@@ -1,15 +0,0 @@
1
- import * as i0 from '@angular/core';
2
-
3
- /**
4
- * Injects a pair of focus guards at the edges of the whole DOM tree
5
- * to ensure `focusin` & `focusout` events can be caught consistently.
6
- */
7
- declare class RdxFocusGuards {
8
- private readonly injector;
9
- constructor();
10
- createFocusGuard(): HTMLSpanElement;
11
- static ɵfac: i0.ɵɵFactoryDeclaration<RdxFocusGuards, never>;
12
- static ɵdir: i0.ɵɵDirectiveDeclaration<RdxFocusGuards, "[rdxFocusGuards]", never, {}, {}, never, never, true, never>;
13
- }
14
-
15
- export { RdxFocusGuards };