@radix-ng/primitives 0.34.0 → 0.36.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 (61) hide show
  1. package/calendar/src/calendar-root.directive.d.ts +3 -3
  2. package/core/index.d.ts +3 -0
  3. package/core/src/accessor/provide-value-accessor.d.ts +1 -1
  4. package/core/src/clamp.d.ts +38 -0
  5. package/core/src/date-time/index.d.ts +3 -0
  6. package/core/src/date-time/parser.d.ts +37 -0
  7. package/core/src/date-time/parts.d.ts +12 -0
  8. package/core/src/date-time/segment.d.ts +4 -0
  9. package/core/src/date-time/types.d.ts +18 -1
  10. package/core/src/date-time/useDateField.d.ts +141 -0
  11. package/core/src/date-time/utils.d.ts +3 -0
  12. package/core/src/getActiveElement.d.ts +1 -0
  13. package/core/src/provide-token.d.ts +22 -0
  14. package/date-field/README.md +1 -0
  15. package/date-field/index.d.ts +11 -0
  16. package/date-field/src/date-field-context.token.d.ts +18 -0
  17. package/date-field/src/date-field-input.directive.d.ts +53 -0
  18. package/date-field/src/date-field-root.directive.d.ts +126 -0
  19. package/dialog/src/dialog-ref.d.ts +3 -0
  20. package/dialog/src/dialog.config.d.ts +1 -0
  21. package/fesm2022/radix-ng-primitives-calendar.mjs +6 -15
  22. package/fesm2022/radix-ng-primitives-calendar.mjs.map +1 -1
  23. package/fesm2022/radix-ng-primitives-checkbox.mjs +3 -4
  24. package/fesm2022/radix-ng-primitives-checkbox.mjs.map +1 -1
  25. package/fesm2022/radix-ng-primitives-core.mjs +1097 -8
  26. package/fesm2022/radix-ng-primitives-core.mjs.map +1 -1
  27. package/fesm2022/radix-ng-primitives-date-field.mjs +334 -0
  28. package/fesm2022/radix-ng-primitives-date-field.mjs.map +1 -0
  29. package/fesm2022/radix-ng-primitives-dialog.mjs +54 -4
  30. package/fesm2022/radix-ng-primitives-dialog.mjs.map +1 -1
  31. package/fesm2022/radix-ng-primitives-navigation-menu.mjs +0 -2
  32. package/fesm2022/radix-ng-primitives-navigation-menu.mjs.map +1 -1
  33. package/fesm2022/radix-ng-primitives-number-field.mjs +502 -0
  34. package/fesm2022/radix-ng-primitives-number-field.mjs.map +1 -0
  35. package/fesm2022/radix-ng-primitives-progress.mjs +3 -3
  36. package/fesm2022/radix-ng-primitives-progress.mjs.map +1 -1
  37. package/fesm2022/radix-ng-primitives-radio.mjs +7 -7
  38. package/fesm2022/radix-ng-primitives-radio.mjs.map +1 -1
  39. package/fesm2022/radix-ng-primitives-switch.mjs +7 -15
  40. package/fesm2022/radix-ng-primitives-switch.mjs.map +1 -1
  41. package/fesm2022/radix-ng-primitives-tabs.mjs +3 -6
  42. package/fesm2022/radix-ng-primitives-tabs.mjs.map +1 -1
  43. package/fesm2022/radix-ng-primitives-toggle-group.mjs +8 -10
  44. package/fesm2022/radix-ng-primitives-toggle-group.mjs.map +1 -1
  45. package/fesm2022/radix-ng-primitives-toggle.mjs +5 -12
  46. package/fesm2022/radix-ng-primitives-toggle.mjs.map +1 -1
  47. package/hover-card/src/hover-card-root.directive.d.ts +4 -4
  48. package/number-field/README.md +1 -0
  49. package/number-field/index.d.ts +17 -0
  50. package/number-field/src/number-field-context.token.d.ts +24 -0
  51. package/number-field/src/number-field-decrement.directive.d.ts +23 -0
  52. package/number-field/src/number-field-increment.directive.d.ts +23 -0
  53. package/number-field/src/number-field-input.directive.d.ts +22 -0
  54. package/number-field/src/number-field-root.directive.d.ts +86 -0
  55. package/number-field/src/types.d.ts +1 -0
  56. package/number-field/src/utils.d.ts +18 -0
  57. package/package.json +9 -1
  58. package/popover/src/popover-root.directive.d.ts +4 -4
  59. package/switch/src/switch-root.directive.d.ts +0 -1
  60. package/toggle/src/toggle.directive.d.ts +0 -1
  61. package/tooltip/src/tooltip-root.directive.d.ts +4 -4
@@ -0,0 +1,334 @@
1
+ import * as i0 from '@angular/core';
2
+ import { InjectionToken, inject, input, computed, signal, effect, Directive, ElementRef, model, booleanAttribute, NgModule } from '@angular/core';
3
+ import { useDateField, getDefaultDate, hasTime, isBefore, createContent, watch, isNullish, createFormatter, initializeSegmentValues, syncSegmentValues, getSegmentElements, ARROW_LEFT, ARROW_RIGHT, isSegmentNavigationKey, provideToken } from '@radix-ng/primitives/core';
4
+
5
+ const DATE_FIELDS_ROOT_CONTEXT = new InjectionToken('DATE_FIELDS_ROOT_CONTEXT');
6
+ function injectDateFieldsRootContext() {
7
+ return inject(DATE_FIELDS_ROOT_CONTEXT);
8
+ }
9
+
10
+ class RdxDateFieldInputDirective {
11
+ constructor(el) {
12
+ this.el = el;
13
+ this.rootContext = injectDateFieldsRootContext();
14
+ /**
15
+ * The part of the date to render
16
+ * `'day' | 'month' | 'year' | 'hour' | 'minute' | 'second' | 'dayPeriod' | 'literal' | 'timeZoneName'`
17
+ */
18
+ this.part = input();
19
+ /**
20
+ * @ignore
21
+ */
22
+ this.disabled = computed(() => this.rootContext.disabled());
23
+ /**
24
+ * @ignore
25
+ */
26
+ this.readonly = computed(() => this.rootContext.readonly());
27
+ /**
28
+ * @ignore
29
+ */
30
+ this.isInvalid = computed(() => this.rootContext.isInvalid());
31
+ /**
32
+ * @ignore
33
+ */
34
+ this.hasLeftFocus = signal(true);
35
+ /**
36
+ * @ignore
37
+ */
38
+ this.lastKeyZero = signal(false);
39
+ this.fieldData = computed(() => {
40
+ return useDateField({
41
+ hasLeftFocus: this.hasLeftFocus,
42
+ lastKeyZero: this.lastKeyZero,
43
+ placeholder: this.rootContext.placeholder,
44
+ hourCycle: this.rootContext.hourCycle(),
45
+ segmentValues: this.rootContext.segmentValues,
46
+ formatter: this.rootContext.formatter,
47
+ part: this.part(),
48
+ disabled: this.rootContext.disabled,
49
+ readonly: this.rootContext.readonly,
50
+ modelValue: this.rootContext.value,
51
+ focusNext: this.rootContext.focusNext
52
+ });
53
+ });
54
+ this.attributes = computed(() => this.fieldData().attributes());
55
+ effect(() => {
56
+ const { handleSegmentClick, handleSegmentKeydown } = this.fieldData();
57
+ this.handleSegmentKeydown = handleSegmentKeydown;
58
+ this.handleSegmentClick = handleSegmentClick;
59
+ });
60
+ effect(() => {
61
+ const attrs = this.attributes();
62
+ Object.entries(attrs).forEach(([attr, value]) => {
63
+ this.el.nativeElement.setAttribute(attr, String(value));
64
+ });
65
+ });
66
+ }
67
+ /**
68
+ * @ignore
69
+ */
70
+ onFocus(e) {
71
+ this.rootContext.setFocusedElement(e.target);
72
+ }
73
+ /**
74
+ * @ignore
75
+ */
76
+ onFocusOut() {
77
+ this.hasLeftFocus.set(true);
78
+ }
79
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: RdxDateFieldInputDirective, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); }
80
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.4", type: RdxDateFieldInputDirective, isStandalone: true, selector: "[rdxDateFieldInput]", inputs: { part: { classPropertyName: "part", publicName: "part", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "mousedown": "part() !== \"literal\" && handleSegmentClick($event)", "keydown": "part() !== \"literal\" && handleSegmentKeydown($event)", "focus": "part() !== \"literal\" && onFocus($event)", "focusout": "part() !== \"literal\" && onFocusOut()" }, properties: { "attr.contenteditable": "disabled() || readonly() ? false : part() !== \"literal\"", "attr.data-rdx-date-field-segment": "part()", "attr.aria-disabled": "disabled() ? \"\" : undefined", "attr.data-disabled": "disabled() ? \"\" : undefined", "attr.data-invalid": "isInvalid() ? \"\" : undefined", "attr.aria-invalid": "isInvalid() ? true : undefined" } }, ngImport: i0 }); }
81
+ }
82
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: RdxDateFieldInputDirective, decorators: [{
83
+ type: Directive,
84
+ args: [{
85
+ selector: '[rdxDateFieldInput]',
86
+ host: {
87
+ '[attr.contenteditable]': 'disabled() || readonly() ? false : part() !== "literal"',
88
+ '[attr.data-rdx-date-field-segment]': 'part()',
89
+ '[attr.aria-disabled]': 'disabled() ? "" : undefined',
90
+ '[attr.data-disabled]': 'disabled() ? "" : undefined',
91
+ '[attr.data-invalid]': 'isInvalid() ? "" : undefined',
92
+ '[attr.aria-invalid]': 'isInvalid() ? true : undefined',
93
+ '(mousedown)': 'part() !== "literal" && handleSegmentClick($event)',
94
+ '(keydown)': 'part() !== "literal" && handleSegmentKeydown($event)',
95
+ '(focus)': 'part() !== "literal" && onFocus($event)',
96
+ '(focusout)': 'part() !== "literal" && onFocusOut()'
97
+ }
98
+ }]
99
+ }], ctorParameters: () => [{ type: i0.ElementRef }] });
100
+
101
+ class RdxDateFieldRootDirective {
102
+ constructor() {
103
+ this.elementRef = inject((ElementRef));
104
+ /**
105
+ * The controlled checked state of the calendar.
106
+ */
107
+ this.value = model();
108
+ /**
109
+ * A callback fired when the date field's value is invalid.
110
+ */
111
+ this.isDateUnavailable = input(undefined);
112
+ /**
113
+ * The hour cycle to use for formatting times. Defaults to the locale preference
114
+ */
115
+ this.hourCycle = input();
116
+ /**
117
+ * The granularity to use for formatting the field. Defaults to 'day' if a CalendarDate is provided, otherwise defaults to 'minute'.
118
+ * The field will render segments for each part of the date up to and including the specified granularity.
119
+ */
120
+ this.granularity = input();
121
+ /**
122
+ * The locale to use for formatting dates.
123
+ */
124
+ this.locale = input('en');
125
+ this.dir = input('ltr');
126
+ /**
127
+ * The minimum valid date that can be entered.
128
+ */
129
+ this.minValue = input();
130
+ /**
131
+ * The maximum valid date that can be entered.
132
+ */
133
+ this.maxValue = input();
134
+ /**
135
+ * Whether or not to hide the time zone segment of the field.
136
+ */
137
+ this.hideTimeZone = input(false, { transform: booleanAttribute });
138
+ this.disabled = input(false, { transform: booleanAttribute });
139
+ /**
140
+ * Whether or not the field is readonly.
141
+ */
142
+ this.readonly = input(false, { transform: booleanAttribute });
143
+ /**
144
+ * @ignore
145
+ */
146
+ this.defaultDate = computed(() => getDefaultDate({
147
+ defaultPlaceholder: undefined,
148
+ granularity: this.granularity(),
149
+ defaultValue: this.value(),
150
+ locale: this.locale()
151
+ }));
152
+ /**
153
+ * 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
154
+ */
155
+ this.placeholder = model(this.defaultDate().copy());
156
+ // Internal state
157
+ /**
158
+ * @ignore
159
+ */
160
+ this.segmentElements = signal(new Set());
161
+ /**
162
+ * @ignore
163
+ */
164
+ this.currentFocusedElement = signal(null);
165
+ /**
166
+ * @ignore
167
+ */
168
+ this.segmentValues = signal({
169
+ year: null,
170
+ month: null,
171
+ day: null,
172
+ hour: null,
173
+ minute: null,
174
+ second: null,
175
+ dayPeriod: null
176
+ });
177
+ /**
178
+ * @ignore
179
+ */
180
+ this.inferredGranularity = computed(() => {
181
+ const placeholder = this.placeholder();
182
+ if (this.granularity())
183
+ return placeholder && !hasTime(placeholder) ? 'day' : this.granularity();
184
+ return placeholder && hasTime(placeholder) ? 'minute' : 'day';
185
+ });
186
+ /**
187
+ * @ignore
188
+ */
189
+ this.isInvalid = computed(() => {
190
+ if (!this.value())
191
+ return false;
192
+ if (this.isDateUnavailable()?.(this.value()))
193
+ return true;
194
+ if (this.minValue() && isBefore(this.value(), this.minValue()))
195
+ return true;
196
+ if (this.maxValue() && isBefore(this.maxValue(), this.value()))
197
+ return true;
198
+ return false;
199
+ });
200
+ /**
201
+ * @ignore
202
+ */
203
+ this.allSegmentContent = computed(() => createContent({
204
+ granularity: this.inferredGranularity(),
205
+ dateRef: this.placeholder(),
206
+ formatter: this.formatter,
207
+ hideTimeZone: this.hideTimeZone(),
208
+ hourCycle: this.hourCycle(),
209
+ segmentValues: this.segmentValues(),
210
+ locale: this.locale
211
+ }));
212
+ /**
213
+ * An array of segments that should be readonly, which prevent user input on them.
214
+ */
215
+ this.segmentContents = computed(() => this.allSegmentContent().arr);
216
+ /**
217
+ * @ignore
218
+ */
219
+ this.currentSegmentIndex = computed(() => Array.from(this.segmentElements()).findIndex((el) => el.getAttribute('data-rdx-date-field-segment') ===
220
+ this.currentFocusedElement()?.getAttribute('data-rdx-date-field-segment')));
221
+ /**
222
+ * @ignore
223
+ */
224
+ this.prevFocusableSegment = computed(() => {
225
+ const sign = this.dir() === 'rtl' ? -1 : 1;
226
+ const prevCondition = sign > 0 ? this.currentSegmentIndex() < 0 : this.currentSegmentIndex() > this.segmentElements().size - 1;
227
+ if (prevCondition)
228
+ return null;
229
+ const segmentToFocus = Array.from(this.segmentElements())[this.currentSegmentIndex() - sign];
230
+ return segmentToFocus;
231
+ });
232
+ /**
233
+ * @ignore
234
+ */
235
+ this.nextFocusableSegment = computed(() => {
236
+ const sign = this.dir() === 'rtl' ? -1 : 1;
237
+ const nextCondition = sign < 0 ? this.currentSegmentIndex() < 0 : this.currentSegmentIndex() > this.segmentElements().size - 1;
238
+ if (nextCondition)
239
+ return null;
240
+ const segmentToFocus = Array.from(this.segmentElements())[this.currentSegmentIndex() + sign];
241
+ return segmentToFocus;
242
+ });
243
+ /**
244
+ * @ignore
245
+ */
246
+ this.focusNext = () => {
247
+ this.nextFocusableSegment()?.focus();
248
+ };
249
+ watch([this.value], ([modelValue]) => {
250
+ if (!isNullish(modelValue) && this.placeholder()?.compare(modelValue) !== 0) {
251
+ this.placeholder.set(modelValue.copy());
252
+ }
253
+ });
254
+ }
255
+ ngOnInit() {
256
+ const defDate = getDefaultDate({
257
+ defaultPlaceholder: undefined,
258
+ granularity: this.granularity(),
259
+ defaultValue: this.value(),
260
+ locale: this.locale()
261
+ });
262
+ this.placeholder.set(defDate.copy());
263
+ this.formatter = createFormatter(this.locale());
264
+ const initialSegments = initializeSegmentValues(this.inferredGranularity());
265
+ this.segmentValues.set(this.value()
266
+ ? { ...syncSegmentValues({ value: this.value(), formatter: this.formatter }) }
267
+ : { ...initialSegments });
268
+ }
269
+ ngAfterViewInit() {
270
+ getSegmentElements(this.elementRef.nativeElement).forEach((item) => this.segmentElements().add(item));
271
+ }
272
+ /**
273
+ * @ignore
274
+ */
275
+ onKeydown(event) {
276
+ const code = event.code;
277
+ if ([ARROW_LEFT, ARROW_RIGHT].includes(code)) {
278
+ if (!isSegmentNavigationKey(event.key))
279
+ return;
280
+ if (code === ARROW_LEFT) {
281
+ this.prevFocusableSegment()?.focus();
282
+ }
283
+ if (code === ARROW_RIGHT) {
284
+ this.nextFocusableSegment()?.focus();
285
+ }
286
+ }
287
+ }
288
+ /**
289
+ * @ignore
290
+ */
291
+ setFocusedElement(el) {
292
+ this.currentFocusedElement.set(el);
293
+ }
294
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: RdxDateFieldRootDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
295
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.4", type: RdxDateFieldRootDirective, isStandalone: true, selector: "[rdxDateFieldRoot]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, isDateUnavailable: { classPropertyName: "isDateUnavailable", publicName: "isDateUnavailable", isSignal: true, isRequired: false, transformFunction: null }, hourCycle: { classPropertyName: "hourCycle", publicName: "hourCycle", isSignal: true, isRequired: false, transformFunction: null }, granularity: { classPropertyName: "granularity", publicName: "granularity", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, dir: { classPropertyName: "dir", publicName: "dir", isSignal: true, isRequired: false, transformFunction: null }, minValue: { classPropertyName: "minValue", publicName: "minValue", isSignal: true, isRequired: false, transformFunction: null }, maxValue: { classPropertyName: "maxValue", publicName: "maxValue", isSignal: true, isRequired: false, transformFunction: null }, hideTimeZone: { classPropertyName: "hideTimeZone", publicName: "hideTimeZone", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", placeholder: "placeholderChange" }, host: { attributes: { "role": "group" }, listeners: { "keydown": "onKeydown($event)" }, properties: { "attr.aria-disabled": "disabled() ? \"\" : undefined", "attr.data-disabled": "disabled() ? \"\" : undefined", "attr.data-readonly": "readonly() ? \"\" : undefined", "attr.data-invalid": "isInvalid() ? \"\" : undefined", "attr.dir": "dir()" } }, providers: [provideToken(DATE_FIELDS_ROOT_CONTEXT, RdxDateFieldRootDirective)], exportAs: ["rdxDateFieldRoot"], ngImport: i0 }); }
296
+ }
297
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: RdxDateFieldRootDirective, decorators: [{
298
+ type: Directive,
299
+ args: [{
300
+ selector: '[rdxDateFieldRoot]',
301
+ exportAs: 'rdxDateFieldRoot',
302
+ providers: [provideToken(DATE_FIELDS_ROOT_CONTEXT, RdxDateFieldRootDirective)],
303
+ host: {
304
+ role: 'group',
305
+ '[attr.aria-disabled]': 'disabled() ? "" : undefined',
306
+ '[attr.data-disabled]': 'disabled() ? "" : undefined',
307
+ '[attr.data-readonly]': 'readonly() ? "" : undefined',
308
+ '[attr.data-invalid]': 'isInvalid() ? "" : undefined',
309
+ '[attr.dir]': 'dir()',
310
+ '(keydown)': 'onKeydown($event)'
311
+ }
312
+ }]
313
+ }], ctorParameters: () => [] });
314
+
315
+ const _imports = [RdxDateFieldRootDirective, RdxDateFieldInputDirective];
316
+ class RdxDateFieldModule {
317
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: RdxDateFieldModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
318
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.4", ngImport: i0, type: RdxDateFieldModule, imports: [RdxDateFieldRootDirective, RdxDateFieldInputDirective], exports: [RdxDateFieldRootDirective, RdxDateFieldInputDirective] }); }
319
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: RdxDateFieldModule }); }
320
+ }
321
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: RdxDateFieldModule, decorators: [{
322
+ type: NgModule,
323
+ args: [{
324
+ imports: [..._imports],
325
+ exports: [..._imports]
326
+ }]
327
+ }] });
328
+
329
+ /**
330
+ * Generated bundle index. Do not edit.
331
+ */
332
+
333
+ export { DATE_FIELDS_ROOT_CONTEXT, RdxDateFieldInputDirective, RdxDateFieldModule, RdxDateFieldRootDirective, injectDateFieldsRootContext };
334
+ //# sourceMappingURL=radix-ng-primitives-date-field.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"radix-ng-primitives-date-field.mjs","sources":["../../../packages/primitives/date-field/src/date-field-context.token.ts","../../../packages/primitives/date-field/src/date-field-input.directive.ts","../../../packages/primitives/date-field/src/date-field-root.directive.ts","../../../packages/primitives/date-field/index.ts","../../../packages/primitives/date-field/radix-ng-primitives-date-field.ts"],"sourcesContent":["import { inject, InjectionToken, InputSignal, ModelSignal, Signal, WritableSignal } from '@angular/core';\nimport { DateValue } from '@internationalized/date';\nimport { Formatter, HourCycle, SegmentValueObj } from '@radix-ng/primitives/core';\n\nexport interface DateFieldContextToken {\n locale: InputSignal<string>;\n value: ModelSignal<DateValue | undefined>;\n disabled: InputSignal<boolean>;\n readonly: InputSignal<boolean>;\n isInvalid: Signal<boolean>;\n placeholder: ModelSignal<DateValue>;\n hourCycle: InputSignal<HourCycle>;\n formatter: Formatter;\n segmentValues: WritableSignal<SegmentValueObj>;\n focusNext: () => void;\n setFocusedElement: (el: HTMLElement) => void;\n}\n\nexport const DATE_FIELDS_ROOT_CONTEXT = new InjectionToken<DateFieldContextToken>('DATE_FIELDS_ROOT_CONTEXT');\n\nexport function injectDateFieldsRootContext(): DateFieldContextToken {\n return inject(DATE_FIELDS_ROOT_CONTEXT);\n}\n","import { computed, Directive, effect, ElementRef, input, signal } from '@angular/core';\nimport { SegmentPart, useDateField } from '@radix-ng/primitives/core';\nimport { injectDateFieldsRootContext } from './date-field-context.token';\n\n@Directive({\n selector: '[rdxDateFieldInput]',\n host: {\n '[attr.contenteditable]': 'disabled() || readonly() ? false : part() !== \"literal\"',\n '[attr.data-rdx-date-field-segment]': 'part()',\n '[attr.aria-disabled]': 'disabled() ? \"\" : undefined',\n '[attr.data-disabled]': 'disabled() ? \"\" : undefined',\n '[attr.data-invalid]': 'isInvalid() ? \"\" : undefined',\n '[attr.aria-invalid]': 'isInvalid() ? true : undefined',\n\n '(mousedown)': 'part() !== \"literal\" && handleSegmentClick($event)',\n '(keydown)': 'part() !== \"literal\" && handleSegmentKeydown($event)',\n '(focus)': 'part() !== \"literal\" && onFocus($event)',\n '(focusout)': 'part() !== \"literal\" && onFocusOut()'\n }\n})\nexport class RdxDateFieldInputDirective {\n private readonly rootContext = injectDateFieldsRootContext();\n\n /**\n * The part of the date to render\n * `'day' | 'month' | 'year' | 'hour' | 'minute' | 'second' | 'dayPeriod' | 'literal' | 'timeZoneName'`\n */\n readonly part = input<SegmentPart>();\n\n /**\n * @ignore\n */\n readonly disabled = computed(() => this.rootContext.disabled());\n\n /**\n * @ignore\n */\n readonly readonly = computed(() => this.rootContext.readonly());\n\n /**\n * @ignore\n */\n readonly isInvalid = computed(() => this.rootContext.isInvalid());\n\n /**\n * @ignore\n */\n readonly hasLeftFocus = signal<boolean>(true);\n\n /**\n * @ignore\n */\n readonly lastKeyZero = signal<boolean>(false);\n\n private readonly fieldData = computed(() => {\n return useDateField({\n hasLeftFocus: this.hasLeftFocus,\n lastKeyZero: this.lastKeyZero,\n placeholder: this.rootContext.placeholder,\n hourCycle: this.rootContext.hourCycle(),\n segmentValues: this.rootContext.segmentValues,\n formatter: this.rootContext.formatter,\n part: <SegmentPart>this.part(),\n disabled: this.rootContext.disabled,\n readonly: this.rootContext.readonly,\n modelValue: this.rootContext.value,\n focusNext: this.rootContext.focusNext\n });\n });\n\n private readonly attributes = computed(() => this.fieldData().attributes());\n\n /**\n * @ignore\n */\n handleSegmentClick: (e: MouseEvent) => void;\n\n /**\n * @ignore\n */\n handleSegmentKeydown: (e: KeyboardEvent) => void;\n\n constructor(private el: ElementRef) {\n effect(() => {\n const { handleSegmentClick, handleSegmentKeydown } = this.fieldData();\n this.handleSegmentKeydown = handleSegmentKeydown;\n this.handleSegmentClick = handleSegmentClick;\n });\n\n effect(() => {\n const attrs = this.attributes();\n Object.entries(attrs).forEach(([attr, value]) => {\n this.el.nativeElement.setAttribute(attr, String(value));\n });\n });\n }\n\n /**\n * @ignore\n */\n onFocus(e: FocusEvent) {\n this.rootContext.setFocusedElement(e.target as HTMLElement);\n }\n\n /**\n * @ignore\n */\n onFocusOut() {\n this.hasLeftFocus.set(true);\n }\n}\n","import { Direction } from '@angular/cdk/bidi';\nimport { BooleanInput } from '@angular/cdk/coercion';\nimport {\n AfterViewInit,\n booleanAttribute,\n computed,\n Directive,\n ElementRef,\n inject,\n input,\n model,\n OnInit,\n signal\n} from '@angular/core';\nimport { DateValue } from '@internationalized/date';\nimport {\n ARROW_LEFT,\n ARROW_RIGHT,\n createContent,\n createFormatter,\n DateMatcher,\n Formatter,\n getDefaultDate,\n getSegmentElements,\n Granularity,\n hasTime,\n HourCycle,\n initializeSegmentValues,\n isBefore,\n isNullish,\n isSegmentNavigationKey,\n provideToken,\n SegmentValueObj,\n syncSegmentValues,\n watch\n} from '@radix-ng/primitives/core';\nimport { DATE_FIELDS_ROOT_CONTEXT } from './date-field-context.token';\n\n@Directive({\n selector: '[rdxDateFieldRoot]',\n exportAs: 'rdxDateFieldRoot',\n providers: [provideToken(DATE_FIELDS_ROOT_CONTEXT, RdxDateFieldRootDirective)],\n host: {\n role: 'group',\n '[attr.aria-disabled]': 'disabled() ? \"\" : undefined',\n '[attr.data-disabled]': 'disabled() ? \"\" : undefined',\n '[attr.data-readonly]': 'readonly() ? \"\" : undefined',\n '[attr.data-invalid]': 'isInvalid() ? \"\" : undefined',\n '[attr.dir]': 'dir()',\n\n '(keydown)': 'onKeydown($event)'\n }\n})\nexport class RdxDateFieldRootDirective implements OnInit, AfterViewInit {\n private readonly elementRef = inject(ElementRef<HTMLElement>);\n\n /**\n * The controlled checked state of the calendar.\n */\n readonly value = model<DateValue | undefined>();\n\n /**\n * A callback fired when the date field's value is invalid.\n */\n readonly isDateUnavailable = input<DateMatcher | undefined>(undefined);\n\n /**\n * The hour cycle to use for formatting times. Defaults to the locale preference\n */\n readonly hourCycle = input<HourCycle>();\n\n /**\n * The granularity to use for formatting the field. Defaults to 'day' if a CalendarDate is provided, otherwise defaults to 'minute'.\n * The field will render segments for each part of the date up to and including the specified granularity.\n */\n readonly granularity = input<Granularity>();\n\n /**\n * The locale to use for formatting dates.\n */\n readonly locale = input<string>('en');\n\n readonly dir = input<Direction>('ltr');\n\n /**\n * The minimum valid date that can be entered.\n */\n readonly minValue = input<DateValue>();\n\n /**\n * The maximum valid date that can be entered.\n */\n readonly maxValue = input<DateValue>();\n\n /**\n * Whether or not to hide the time zone segment of the field.\n */\n readonly hideTimeZone = input<boolean, BooleanInput>(false, { transform: booleanAttribute });\n\n readonly disabled = input<boolean, BooleanInput>(false, { transform: booleanAttribute });\n\n /**\n * Whether or not the field is readonly.\n */\n readonly readonly = input<boolean, BooleanInput>(false, { transform: booleanAttribute });\n\n /**\n * @ignore\n */\n readonly defaultDate = computed(() =>\n getDefaultDate({\n defaultPlaceholder: undefined,\n granularity: this.granularity(),\n defaultValue: this.value(),\n locale: this.locale()\n })\n );\n\n /**\n * 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\n */\n readonly placeholder = model<DateValue | undefined>(this.defaultDate().copy());\n\n // Internal state\n\n /**\n * @ignore\n */\n readonly segmentElements = signal<Set<HTMLElement>>(new Set());\n\n /**\n * @ignore\n */\n readonly currentFocusedElement = signal<HTMLElement | null>(null);\n\n /**\n * @ignore\n */\n formatter: Formatter;\n\n /**\n * @ignore\n */\n readonly segmentValues = signal<SegmentValueObj>({\n year: null,\n month: null,\n day: null,\n hour: null,\n minute: null,\n second: null,\n dayPeriod: null\n } as SegmentValueObj);\n\n /**\n * @ignore\n */\n readonly inferredGranularity = computed(() => {\n const placeholder = this.placeholder();\n\n if (this.granularity()) return placeholder && !hasTime(placeholder) ? 'day' : this.granularity();\n\n return placeholder && hasTime(placeholder) ? 'minute' : 'day';\n });\n\n /**\n * @ignore\n */\n readonly isInvalid = computed(() => {\n if (!this.value()) return false;\n\n if (this.isDateUnavailable()?.(<DateValue>this.value())) return true;\n\n if (this.minValue() && isBefore(<DateValue>this.value(), <DateValue>this.minValue())) return true;\n\n if (this.maxValue() && isBefore(<DateValue>this.maxValue(), <DateValue>this.value())) return true;\n\n return false;\n });\n\n /**\n * @ignore\n */\n readonly allSegmentContent = computed(() =>\n createContent({\n granularity: <Granularity>this.inferredGranularity(),\n dateRef: <DateValue>this.placeholder(),\n formatter: this.formatter,\n hideTimeZone: this.hideTimeZone(),\n hourCycle: this.hourCycle(),\n segmentValues: this.segmentValues(),\n locale: this.locale\n })\n );\n\n /**\n * An array of segments that should be readonly, which prevent user input on them.\n */\n readonly segmentContents = computed(() => this.allSegmentContent().arr);\n\n /**\n * @ignore\n */\n readonly currentSegmentIndex = computed(() =>\n Array.from(this.segmentElements()).findIndex(\n (el) =>\n el.getAttribute('data-rdx-date-field-segment') ===\n this.currentFocusedElement()?.getAttribute('data-rdx-date-field-segment')\n )\n );\n\n /**\n * @ignore\n */\n readonly prevFocusableSegment = computed(() => {\n const sign = this.dir() === 'rtl' ? -1 : 1;\n const prevCondition =\n sign > 0 ? this.currentSegmentIndex() < 0 : this.currentSegmentIndex() > this.segmentElements().size - 1;\n if (prevCondition) return null;\n\n const segmentToFocus = Array.from(this.segmentElements())[this.currentSegmentIndex() - sign];\n return segmentToFocus;\n });\n\n /**\n * @ignore\n */\n readonly nextFocusableSegment = computed(() => {\n const sign = this.dir() === 'rtl' ? -1 : 1;\n const nextCondition =\n sign < 0 ? this.currentSegmentIndex() < 0 : this.currentSegmentIndex() > this.segmentElements().size - 1;\n if (nextCondition) return null;\n const segmentToFocus = Array.from(this.segmentElements())[this.currentSegmentIndex() + sign];\n return segmentToFocus;\n });\n\n /**\n * @ignore\n */\n readonly focusNext = () => {\n this.nextFocusableSegment()?.focus();\n };\n\n constructor() {\n watch([this.value], ([modelValue]) => {\n if (!isNullish(modelValue) && this.placeholder()?.compare(modelValue) !== 0) {\n this.placeholder.set(modelValue.copy());\n }\n });\n }\n\n ngOnInit() {\n const defDate = getDefaultDate({\n defaultPlaceholder: undefined,\n granularity: this.granularity(),\n defaultValue: this.value(),\n locale: this.locale()\n });\n\n this.placeholder.set(defDate.copy());\n\n this.formatter = createFormatter(this.locale());\n\n const initialSegments = initializeSegmentValues(this.inferredGranularity()!);\n\n this.segmentValues.set(\n this.value()\n ? { ...syncSegmentValues({ value: <DateValue>this.value(), formatter: this.formatter }) }\n : { ...initialSegments }\n );\n }\n\n ngAfterViewInit() {\n getSegmentElements(this.elementRef.nativeElement).forEach((item) =>\n this.segmentElements().add(item as HTMLElement)\n );\n }\n\n /**\n * @ignore\n */\n onKeydown(event: KeyboardEvent) {\n const code = event.code;\n if ([ARROW_LEFT, ARROW_RIGHT].includes(code)) {\n if (!isSegmentNavigationKey(event.key)) return;\n\n if (code === ARROW_LEFT) {\n this.prevFocusableSegment()?.focus();\n }\n\n if (code === ARROW_RIGHT) {\n this.nextFocusableSegment()?.focus();\n }\n }\n }\n\n /**\n * @ignore\n */\n setFocusedElement(el: HTMLElement) {\n this.currentFocusedElement.set(el);\n }\n}\n","import { NgModule } from '@angular/core';\nimport { RdxDateFieldInputDirective } from './src/date-field-input.directive';\nimport { RdxDateFieldRootDirective } from './src/date-field-root.directive';\n\nexport * from './src/date-field-context.token';\nexport * from './src/date-field-input.directive';\nexport * from './src/date-field-root.directive';\n\nconst _imports = [RdxDateFieldRootDirective, RdxDateFieldInputDirective];\n\n@NgModule({\n imports: [..._imports],\n exports: [..._imports]\n})\nexport class RdxDateFieldModule {}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, Directive, DestroyRef, signal, computed, Injector, Renderer2, Injectable, makeEnvironmentProviders, importProvidersFrom, input, Input, NgModule } from '@angular/core';
2
+ import { signal, computed, inject, Directive, DestroyRef, Injector, RendererFactory2, runInInjectionContext, effect, Renderer2, Injectable, makeEnvironmentProviders, importProvidersFrom, input, Input, NgModule } from '@angular/core';
3
3
  import { map, filter, isObservable, of, take, merge, switchMap, takeUntil } from 'rxjs';
4
4
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
5
5
  import { Dialog, DialogModule, DIALOG_DATA } from '@angular/cdk/dialog';
@@ -21,6 +21,9 @@ class RdxDialogRef {
21
21
  constructor(cdkRef, config) {
22
22
  this.cdkRef = cdkRef;
23
23
  this.config = config;
24
+ // state tracking
25
+ this._openSignal = signal(true);
26
+ this.state = computed(() => (this._openSignal() ? 'open' : 'closed'));
24
27
  this.closed$ = this.cdkRef.closed.pipe(map((res) => (isDismissed(res) ? undefined : res)));
25
28
  this.dismissed$ = this.cdkRef.closed.pipe(filter((res) => res === DISMISSED_VALUE), map(() => undefined));
26
29
  this.result$ = this.cdkRef.closed.pipe(filter((res) => !isDismissed(res)));
@@ -45,7 +48,19 @@ class RdxDialogRef {
45
48
  });
46
49
  }
47
50
  close(result) {
48
- this.cdkRef.close(result);
51
+ // check if dialog is already in closing state to prevent double-closing
52
+ if (this.state() === 'closed') {
53
+ return;
54
+ }
55
+ this._openSignal.set(false);
56
+ if (this._previousTimeout) {
57
+ clearTimeout(this._previousTimeout);
58
+ }
59
+ const closeDelay = this.config.closeDelay ?? 100; // Default to 100ms if not specified
60
+ // Actual closing happens after delay
61
+ this._previousTimeout = setTimeout(() => {
62
+ this.cdkRef.close(result ?? DISMISSED_VALUE);
63
+ }, closeDelay);
49
64
  }
50
65
  }
51
66
 
@@ -183,6 +198,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImpor
183
198
  class RdxDialogService {
184
199
  #cdkDialog = inject(Dialog);
185
200
  #injector = inject(Injector);
201
+ #rendererFactory = inject(RendererFactory2);
202
+ #renderer = this.#rendererFactory.createRenderer(null, null);
186
203
  open(config) {
187
204
  let dialogRef;
188
205
  let modeClasses = [];
@@ -203,6 +220,11 @@ class RdxDialogService {
203
220
  modeClasses = ['mod-sheet', 'mod-top'];
204
221
  break;
205
222
  }
223
+ // Create a new configuration with default closeDelay if not provided
224
+ const extendedConfig = {
225
+ ...config,
226
+ closeDelay: config.closeDelay ?? 0
227
+ };
206
228
  const cdkRef = this.#cdkDialog.open(config.content, {
207
229
  ariaModal: config.modal ?? true,
208
230
  hasBackdrop: config.modal ?? true,
@@ -218,7 +240,33 @@ class RdxDialogService {
218
240
  ariaLabel: config.ariaLabel,
219
241
  templateContext: () => ({ dialogRef: dialogRef }),
220
242
  providers: (ref) => {
221
- dialogRef = new RdxDialogRef(ref, config);
243
+ // Create dialog ref with state tracking
244
+ dialogRef = new RdxDialogRef(ref, extendedConfig);
245
+ // Get overlay and backdrop references
246
+ const overlay = ref.overlayRef.overlayElement;
247
+ const backdrop = ref.overlayRef.backdropElement;
248
+ // Set up effect to track and update state attributes
249
+ runInInjectionContext(this.#injector, () => {
250
+ effect(() => {
251
+ const currentState = dialogRef.state();
252
+ if (overlay) {
253
+ this.#renderer.setAttribute(overlay, 'data-state', currentState);
254
+ }
255
+ if (backdrop) {
256
+ this.#renderer.setAttribute(backdrop, 'data-state', currentState);
257
+ }
258
+ // For sheet dialogs, add data-side attribute
259
+ if (config.mode?.startsWith('sheet-')) {
260
+ const side = config.mode.substring(6);
261
+ if (overlay) {
262
+ this.#renderer.setAttribute(overlay, 'data-side', side);
263
+ }
264
+ if (backdrop) {
265
+ this.#renderer.setAttribute(backdrop, 'data-side', side);
266
+ }
267
+ }
268
+ });
269
+ });
222
270
  return [
223
271
  {
224
272
  provide: RdxDialogRef,
@@ -243,7 +291,9 @@ class RdxDialogService {
243
291
  }), takeUntil(dialogRef.closed$))
244
292
  .subscribe((canClose) => {
245
293
  if (canClose) {
246
- cdkRef.close(DISMISSED_VALUE);
294
+ // rather than `cdkRef.close()`, closing the `dialogRef` directly
295
+ // ensures that the `state` is represented correctly
296
+ dialogRef.close(undefined);
247
297
  }
248
298
  });
249
299
  }