@radix-ng/primitives 0.37.0 → 0.39.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.
Files changed (78) hide show
  1. package/accordion/index.d.ts +3 -1
  2. package/accordion/src/accordion-content-presence.directive.d.ts +6 -0
  3. package/accordion/src/accordion-content.directive.d.ts +7 -8
  4. package/accordion/src/accordion-header.directive.d.ts +2 -2
  5. package/accordion/src/accordion-item.directive.d.ts +29 -77
  6. package/accordion/src/accordion-root.directive.d.ts +49 -78
  7. package/accordion/src/accordion-trigger.directive.d.ts +6 -11
  8. package/collapsible/index.d.ts +11 -0
  9. package/collapsible/src/collapsible-content-presence.directive.d.ts +6 -0
  10. package/collapsible/src/collapsible-content.directive.d.ts +13 -9
  11. package/collapsible/src/collapsible-root.directive.d.ts +19 -37
  12. package/collapsible/src/collapsible-trigger.directive.d.ts +1 -21
  13. package/core/index.d.ts +5 -0
  14. package/core/src/accessor/control-value-accessor.d.ts +67 -0
  15. package/core/src/create-context.d.ts +10 -0
  16. package/core/src/date-time/comparators.d.ts +7 -1
  17. package/core/src/date-time/useDateField.d.ts +2 -2
  18. package/core/src/types.d.ts +24 -0
  19. package/{stepper/src/utils → core/src}/useArrowNavigation.d.ts +2 -2
  20. package/core/src/useResizeObserver.d.ts +15 -0
  21. package/fesm2022/radix-ng-primitives-accordion.mjs +231 -398
  22. package/fesm2022/radix-ng-primitives-accordion.mjs.map +1 -1
  23. package/fesm2022/radix-ng-primitives-avatar.mjs +2 -10
  24. package/fesm2022/radix-ng-primitives-avatar.mjs.map +1 -1
  25. package/fesm2022/radix-ng-primitives-calendar.mjs +3 -14
  26. package/fesm2022/radix-ng-primitives-calendar.mjs.map +1 -1
  27. package/fesm2022/radix-ng-primitives-checkbox.mjs.map +1 -1
  28. package/fesm2022/radix-ng-primitives-collapsible.mjs +151 -143
  29. package/fesm2022/radix-ng-primitives-collapsible.mjs.map +1 -1
  30. package/fesm2022/radix-ng-primitives-core.mjs +248 -7
  31. package/fesm2022/radix-ng-primitives-core.mjs.map +1 -1
  32. package/fesm2022/radix-ng-primitives-hover-card.mjs +1 -3
  33. package/fesm2022/radix-ng-primitives-hover-card.mjs.map +1 -1
  34. package/fesm2022/radix-ng-primitives-menubar.mjs +1 -8
  35. package/fesm2022/radix-ng-primitives-menubar.mjs.map +1 -1
  36. package/fesm2022/radix-ng-primitives-pagination.mjs +2 -6
  37. package/fesm2022/radix-ng-primitives-pagination.mjs.map +1 -1
  38. package/fesm2022/radix-ng-primitives-popover.mjs +2 -6
  39. package/fesm2022/radix-ng-primitives-popover.mjs.map +1 -1
  40. package/fesm2022/radix-ng-primitives-presence.mjs +34 -1
  41. package/fesm2022/radix-ng-primitives-presence.mjs.map +1 -1
  42. package/fesm2022/radix-ng-primitives-progress.mjs +2 -7
  43. package/fesm2022/radix-ng-primitives-progress.mjs.map +1 -1
  44. package/fesm2022/radix-ng-primitives-radio.mjs +1 -3
  45. package/fesm2022/radix-ng-primitives-radio.mjs.map +1 -1
  46. package/fesm2022/radix-ng-primitives-select.mjs +75 -33
  47. package/fesm2022/radix-ng-primitives-select.mjs.map +1 -1
  48. package/fesm2022/radix-ng-primitives-stepper.mjs +1 -84
  49. package/fesm2022/radix-ng-primitives-stepper.mjs.map +1 -1
  50. package/fesm2022/radix-ng-primitives-switch.mjs +61 -97
  51. package/fesm2022/radix-ng-primitives-switch.mjs.map +1 -1
  52. package/fesm2022/radix-ng-primitives-tabs.mjs +4 -19
  53. package/fesm2022/radix-ng-primitives-tabs.mjs.map +1 -1
  54. package/fesm2022/radix-ng-primitives-time-field.mjs +351 -0
  55. package/fesm2022/radix-ng-primitives-time-field.mjs.map +1 -0
  56. package/fesm2022/radix-ng-primitives-toggle-group.mjs.map +1 -1
  57. package/fesm2022/radix-ng-primitives-toggle.mjs +1 -6
  58. package/fesm2022/radix-ng-primitives-toggle.mjs.map +1 -1
  59. package/fesm2022/radix-ng-primitives-tooltip.mjs +1 -3
  60. package/fesm2022/radix-ng-primitives-tooltip.mjs.map +1 -1
  61. package/hover-card/src/hover-card-root.directive.d.ts +4 -4
  62. package/package.json +5 -1
  63. package/popover/src/popover-root.directive.d.ts +4 -4
  64. package/presence/index.d.ts +1 -0
  65. package/presence/src/presence.directive.d.ts +27 -0
  66. package/select/src/select-trigger.directive.d.ts +8 -2
  67. package/select/src/select.component.d.ts +23 -6
  68. package/switch/index.d.ts +0 -1
  69. package/switch/src/switch-input.directive.d.ts +1 -1
  70. package/switch/src/switch-root.directive.d.ts +23 -43
  71. package/switch/src/switch-thumb.directive.d.ts +1 -1
  72. package/time-field/README.md +1 -0
  73. package/time-field/index.d.ts +11 -0
  74. package/time-field/src/time-field-context.token.d.ts +19 -0
  75. package/time-field/src/time-field-input.directive.d.ts +53 -0
  76. package/time-field/src/time-field-root.directive.d.ts +125 -0
  77. package/tooltip/src/tooltip-root.directive.d.ts +4 -4
  78. package/collapsible/src/collapsible-content.token.d.ts +0 -3
@@ -1,9 +1,9 @@
1
1
  import * as i0 from '@angular/core';
2
- import { forwardRef, inject, ElementRef, NgZone, booleanAttribute, Input, Directive, APP_ID, Injectable, InjectionToken, computed, effect, untracked } from '@angular/core';
2
+ import { forwardRef, input, booleanAttribute, output, linkedSignal, untracked, Directive, inject, ElementRef, NgZone, Input, APP_ID, Injectable, InjectionToken, computed, effect } from '@angular/core';
3
3
  import { NG_VALUE_ACCESSOR, NgControl, FormControlDirective, FormControlName, NgModel } from '@angular/forms';
4
4
  import { DOCUMENT } from '@angular/common';
5
5
  import { Platform } from '@angular/cdk/platform';
6
- import { getLocalTimeZone, CalendarDateTime, ZonedDateTime, getDayOfWeek, DateFormatter, createCalendar, toCalendar, CalendarDate, startOfMonth, endOfMonth, today } from '@internationalized/date';
6
+ import { getLocalTimeZone, CalendarDateTime, ZonedDateTime, getDayOfWeek, DateFormatter, createCalendar, toCalendar, CalendarDate, Time, startOfMonth, endOfMonth, today } from '@internationalized/date';
7
7
 
8
8
  /**
9
9
  * Include in the providers section of a component which utilizes ControlValueAccessor to redundant code.
@@ -23,6 +23,97 @@ function provideValueAccessor(type) {
23
23
  };
24
24
  }
25
25
 
26
+ /**
27
+ * A reusable ControlValueAccessor implementation for form controls
28
+ * @template T The type of the control's value
29
+ */
30
+ class RdxControlValueAccessor {
31
+ constructor() {
32
+ /**
33
+ * Input for the control's value with alias 'value'
34
+ * @default undefined
35
+ */
36
+ this.valueInput = input(undefined, { alias: 'value' });
37
+ /**
38
+ * Input for the disabled state with alias 'disabled'
39
+ * Uses booleanAttribute transform to convert string attributes to booleans
40
+ * @default false
41
+ */
42
+ this.disabledInput = input(false, {
43
+ alias: 'disabled',
44
+ transform: booleanAttribute
45
+ });
46
+ this.valueChange = output();
47
+ this._value = linkedSignal(() => this.valueInput());
48
+ /**
49
+ * Readonly access to the current value
50
+ */
51
+ this.value = this._value.asReadonly();
52
+ this._disabled = linkedSignal(() => this.disabledInput());
53
+ /**
54
+ * Readonly access to the disabled state
55
+ */
56
+ this.disabled = this._disabled.asReadonly();
57
+ }
58
+ /**
59
+ * Writes a new value to the control (ControlValueAccessor interface)
60
+ * @param value The new value for the control
61
+ */
62
+ writeValue(value) {
63
+ untracked(() => this._value.set(value));
64
+ }
65
+ /**
66
+ * Registers a callback for when the control value changes (ControlValueAccessor interface)
67
+ * @param fn The callback function
68
+ */
69
+ registerOnChange(fn) {
70
+ this.onChange = fn;
71
+ }
72
+ /**
73
+ * Registers a callback for when the control is touched (ControlValueAccessor interface)
74
+ * @param fn The callback function
75
+ */
76
+ registerOnTouched(fn) {
77
+ this.onTouched = fn;
78
+ }
79
+ /**
80
+ * Sets the disabled state of the control (ControlValueAccessor interface)
81
+ * @param isDisabled Whether the control should be disabled
82
+ */
83
+ setDisabledState(isDisabled) {
84
+ this._disabled.set(isDisabled);
85
+ }
86
+ /**
87
+ * Updates the control's value and triggers change detection
88
+ * @param value The new value
89
+ */
90
+ setValue(value) {
91
+ this._value.set(value);
92
+ this.valueChange.emit(value);
93
+ this.onChange?.(value);
94
+ }
95
+ markAsTouched() {
96
+ this.onTouched?.();
97
+ }
98
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: RdxControlValueAccessor, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
99
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.4", type: RdxControlValueAccessor, isStandalone: true, inputs: { valueInput: { classPropertyName: "valueInput", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange" }, providers: [provideValueAccessor(RdxControlValueAccessor)], exportAs: ["rdxControlValueAccessor"], ngImport: i0 }); }
100
+ }
101
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: RdxControlValueAccessor, decorators: [{
102
+ type: Directive,
103
+ args: [{
104
+ exportAs: 'rdxControlValueAccessor',
105
+ providers: [provideValueAccessor(RdxControlValueAccessor)]
106
+ }]
107
+ }] });
108
+ /**
109
+ * Provides a type-safe way to inject the RdxControlValueAccessor
110
+ * @template T The type of the control's value
111
+ * @returns An instance of RdxControlValueAccessor<T>
112
+ */
113
+ function injectControlValueAccessor() {
114
+ return inject(RdxControlValueAccessor);
115
+ }
116
+
26
117
  /*
27
118
  * <div [rdxAutoFocus]="true"></div>
28
119
  */
@@ -362,6 +453,43 @@ function injectWindow() {
362
453
  return inject(WINDOW);
363
454
  }
364
455
 
456
+ // Thanks for idea.
457
+ // https://github.com/unovue/reka-ui/blob/v2/packages/core/src/shared/createContext.ts
458
+ /**
459
+ * Creates a context with injector and provider functions for a given type
460
+ * @template T The type of the context value
461
+ * @param description Descriptive string for the context (used in token creation)
462
+ * @returns A tuple containing:
463
+ * - injectContext: Function to retrieve the context value
464
+ * - provideContext: Function to create a provider for the context
465
+ */
466
+ function createContext(description) {
467
+ const CONTEXT_TOKEN = new InjectionToken(`${description}Context`);
468
+ /**
469
+ * Retrieves the context value from Angular's dependency injection
470
+ * @param optional If true, returns null when context is not provided instead of throwing
471
+ * @returns The context value or null if optional and not provided
472
+ * @throws Error when context is not provided and not optional
473
+ */
474
+ const injectContext = (optional = false) => {
475
+ const value = optional ? inject(CONTEXT_TOKEN, { optional: true }) : inject(CONTEXT_TOKEN);
476
+ if (value == null && !optional) {
477
+ throw new Error(`No context provided for token ${CONTEXT_TOKEN.toString()}`);
478
+ }
479
+ return value;
480
+ };
481
+ /**
482
+ * Creates a provider that can be used to supply the context value
483
+ * @param useFactory Factory function that creates the context value
484
+ * @returns A provider that can be registered in Angular's DI system
485
+ */
486
+ const provideContext = (useFactory) => ({
487
+ provide: CONTEXT_TOKEN,
488
+ useFactory: useFactory
489
+ });
490
+ return [injectContext, provideContext];
491
+ }
492
+
365
493
  /**
366
494
  * Splits an array into chunks of a given size.
367
495
  * @param arr The array to split.
@@ -544,6 +672,16 @@ function getDefaultDate(props) {
544
672
  return toCalendar(new CalendarDateTime(year, month, day, 0, 0, 0), calendar);
545
673
  return toCalendar(new CalendarDate(year, month, day), calendar);
546
674
  }
675
+ function getDefaultTime(props) {
676
+ const { defaultValue, defaultPlaceholder } = props;
677
+ if (defaultValue) {
678
+ return defaultValue.copy();
679
+ }
680
+ if (defaultPlaceholder) {
681
+ return defaultPlaceholder.copy();
682
+ }
683
+ return new Time(0, 0, 0);
684
+ }
547
685
 
548
686
  /**
549
687
  * Retrieves an array of date values representing the days between
@@ -724,10 +862,7 @@ const TIME_SEGMENT_PARTS = ['hour', 'minute', 'second', 'dayPeriod'];
724
862
  const NON_EDITABLE_SEGMENT_PARTS = ['literal', 'timeZoneName'];
725
863
  const EDITABLE_SEGMENT_PARTS = [...DATE_SEGMENT_PARTS, ...TIME_SEGMENT_PARTS];
726
864
  const EDITABLE_TIME_SEGMENT_PARTS = [...TIME_SEGMENT_PARTS];
727
- const ALL_SEGMENT_PARTS = [
728
- ...EDITABLE_SEGMENT_PARTS,
729
- ...NON_EDITABLE_SEGMENT_PARTS
730
- ];
865
+ const ALL_SEGMENT_PARTS = [...EDITABLE_SEGMENT_PARTS, ...NON_EDITABLE_SEGMENT_PARTS];
731
866
  const ALL_EXCEPT_LITERAL_PARTS = ALL_SEGMENT_PARTS.filter((part) => part !== 'literal');
732
867
  function isDateSegmentPart(part) {
733
868
  return DATE_SEGMENT_PARTS.includes(part);
@@ -2059,6 +2194,112 @@ function getArrowPositionParams(sideAndAlign, arrowWidthAndHeight, triggerWidthA
2059
2194
  return posParams;
2060
2195
  }
2061
2196
 
2197
+ // made by https://reka-ui.com/
2198
+ const ignoredElement = ['INPUT', 'TEXTAREA'];
2199
+ /**
2200
+ * Allow arrow navigation for every html element with data-rdx-collection-item tag
2201
+ *
2202
+ * @param e Keyboard event
2203
+ * @param currentElement Event initiator element or any element that wants to handle the navigation
2204
+ * @param parentElement Parent element where contains all the collection items, this will collect every item to be used when nav
2205
+ * @param options further options
2206
+ * @returns the navigated html element or null if none
2207
+ */
2208
+ function useArrowNavigation(e, currentElement, parentElement, options = {}) {
2209
+ if (!currentElement || (options.enableIgnoredElement && ignoredElement.includes(currentElement.nodeName)))
2210
+ return null;
2211
+ const { arrowKeyOptions = 'both', attributeName = '[data-rdx-collection-item]', itemsArray = [], loop = true, dir = 'ltr', preventScroll = true, focus = false } = options;
2212
+ const [right, left, up, down, home, end] = [
2213
+ e.key === 'ArrowRight',
2214
+ e.key === 'ArrowLeft',
2215
+ e.key === 'ArrowUp',
2216
+ e.key === 'ArrowDown',
2217
+ e.key === 'Home',
2218
+ e.key === 'End'
2219
+ ];
2220
+ const goingVertical = up || down;
2221
+ const goingHorizontal = right || left;
2222
+ if (!home &&
2223
+ !end &&
2224
+ ((!goingVertical && !goingHorizontal) ||
2225
+ (arrowKeyOptions === 'vertical' && goingHorizontal) ||
2226
+ (arrowKeyOptions === 'horizontal' && goingVertical))) {
2227
+ return null;
2228
+ }
2229
+ const allCollectionItems = parentElement
2230
+ ? Array.from(parentElement.querySelectorAll(attributeName))
2231
+ : itemsArray;
2232
+ if (!allCollectionItems.length)
2233
+ return null;
2234
+ if (preventScroll)
2235
+ e.preventDefault();
2236
+ let item = null;
2237
+ if (goingHorizontal || goingVertical) {
2238
+ const goForward = goingVertical ? down : dir === 'ltr' ? right : left;
2239
+ item = findNextFocusableElement(allCollectionItems, currentElement, {
2240
+ goForward,
2241
+ loop
2242
+ });
2243
+ }
2244
+ else if (home) {
2245
+ item = allCollectionItems.length ? allCollectionItems[0] : null;
2246
+ }
2247
+ else if (end) {
2248
+ item = allCollectionItems.length ? allCollectionItems[allCollectionItems.length - 1] : null;
2249
+ }
2250
+ if (focus)
2251
+ item?.focus();
2252
+ return item;
2253
+ }
2254
+ /**
2255
+ * Recursive function to find the next focusable element to avoid disabled elements
2256
+ *
2257
+ * @param elements Elements to navigate
2258
+ * @param currentElement Current active element
2259
+ * @param options
2260
+ * @param iterations
2261
+ * @returns next focusable element
2262
+ */
2263
+ function findNextFocusableElement(elements, currentElement, options, iterations = elements.length) {
2264
+ if (--iterations === 0)
2265
+ return null;
2266
+ const index = elements.indexOf(currentElement);
2267
+ const newIndex = options.goForward ? index + 1 : index - 1;
2268
+ if (!options.loop && (newIndex < 0 || newIndex >= elements.length))
2269
+ return null;
2270
+ const adjustedNewIndex = (newIndex + elements.length) % elements.length;
2271
+ const candidate = elements[adjustedNewIndex];
2272
+ if (!candidate)
2273
+ return null;
2274
+ const isDisabled = candidate.hasAttribute('disabled') && candidate.getAttribute('disabled') !== 'false';
2275
+ if (isDisabled) {
2276
+ return findNextFocusableElement(elements, candidate, options, iterations);
2277
+ }
2278
+ return candidate;
2279
+ }
2280
+
2281
+ /**
2282
+ * Creates a resize observer effect for element
2283
+ *
2284
+ * @param options Configuration options
2285
+ * @param options.injector Angular injector
2286
+ * @param options.element Signal returning the element to observe
2287
+ * @param options.onResize Callback when element is resized
2288
+ * @returns EffectRef that can be destroyed when needed
2289
+ */
2290
+ function resizeEffect(options) {
2291
+ return effect((onCleanup) => {
2292
+ const elementOrRef = options.element();
2293
+ if (!elementOrRef)
2294
+ return;
2295
+ // Extract native element from ElementRef or use directly if it's HTMLElement
2296
+ const element = elementOrRef instanceof ElementRef ? elementOrRef.nativeElement : elementOrRef;
2297
+ const resizeObserver = new ResizeObserver(options.onResize);
2298
+ resizeObserver.observe(element);
2299
+ onCleanup(() => resizeObserver.disconnect());
2300
+ }, { injector: options.injector });
2301
+ }
2302
+
2062
2303
  // https://ngxtension.netlify.app/utilities/signals/explicit-effect/
2063
2304
  /**
2064
2305
  * This explicit effect function will take the dependencies and the function to run when the dependencies change.
@@ -2100,5 +2341,5 @@ function watch(deps, fn, options) {
2100
2341
  * Generated bundle index. Do not edit.
2101
2342
  */
2102
2343
 
2103
- export { A, ALT, ARROW_DOWN, ARROW_LEFT, ARROW_RIGHT, ARROW_UP, ASTERISK, BACKSPACE, CAPS_LOCK, CONTROL, CTRL, DELETE, END, ENTER, ESCAPE, F1, F10, F11, F12, F2, F3, F4, F5, F6, F7, F8, F9, HOME, META, P, PAGE_DOWN, PAGE_UP, RDX_POSITIONING_DEFAULTS, RDX_POSITIONS, RdxAutoFocusDirective, RdxFocusInitialDirective, RdxPositionAlign, RdxPositionSide, SHIFT, SPACE, SPACE_CODE, TAB, WINDOW, _IdGenerator, a, areAllDaysBetweenValid, clamp, createContent, createFormatter, createMonth, createMonths, getActiveElement, getAllPossibleConnectedPositions, getArrowPositionParams, getContentPosition, getDaysBetween, getDaysInMonth, getDefaultDate, getLastFirstDayOfWeek, getNextLastDayOfWeek, getOptsByGranularity, getPlaceholder, getSegmentElements, getSideAndAlignFromAllPossibleConnectedPositions, handleCalendarInitialFocus, hasTime, initializeSegmentValues, injectDocument, injectIsClient, injectNgControl, injectWindow, isAcceptableSegmentKey, isAfter, isAfterOrSame, isBefore, isBeforeOrSame, isBetween, isBetweenInclusive, isCalendarDateTime, isInsideForm, isNullish, isNumber, isNumberString, isSegmentNavigationKey, isZonedDateTime, j, k, n, p, provideToken, provideValueAccessor, roundToStepPrecision, segmentBuilders, snapValueToStep, syncSegmentValues, syncTimeSegmentValues, toDate, useDateField, watch };
2344
+ export { A, ALT, ARROW_DOWN, ARROW_LEFT, ARROW_RIGHT, ARROW_UP, ASTERISK, BACKSPACE, CAPS_LOCK, CONTROL, CTRL, DELETE, END, ENTER, ESCAPE, F1, F10, F11, F12, F2, F3, F4, F5, F6, F7, F8, F9, HOME, META, P, PAGE_DOWN, PAGE_UP, RDX_POSITIONING_DEFAULTS, RDX_POSITIONS, RdxAutoFocusDirective, RdxControlValueAccessor, RdxFocusInitialDirective, RdxPositionAlign, RdxPositionSide, SHIFT, SPACE, SPACE_CODE, TAB, WINDOW, _IdGenerator, a, areAllDaysBetweenValid, clamp, createContent, createContext, createFormatter, createMonth, createMonths, getActiveElement, getAllPossibleConnectedPositions, getArrowPositionParams, getContentPosition, getDaysBetween, getDaysInMonth, getDefaultDate, getDefaultTime, getLastFirstDayOfWeek, getNextLastDayOfWeek, getOptsByGranularity, getPlaceholder, getSegmentElements, getSideAndAlignFromAllPossibleConnectedPositions, handleCalendarInitialFocus, hasTime, initializeSegmentValues, injectControlValueAccessor, injectDocument, injectIsClient, injectNgControl, injectWindow, isAcceptableSegmentKey, isAfter, isAfterOrSame, isBefore, isBeforeOrSame, isBetween, isBetweenInclusive, isCalendarDateTime, isInsideForm, isNullish, isNumber, isNumberString, isSegmentNavigationKey, isZonedDateTime, j, k, n, p, provideToken, provideValueAccessor, resizeEffect, roundToStepPrecision, segmentBuilders, snapValueToStep, syncSegmentValues, syncTimeSegmentValues, toDate, useArrowNavigation, useDateField, watch };
2104
2345
  //# sourceMappingURL=radix-ng-primitives-core.mjs.map