@truenas/ui-components 0.1.39 → 0.1.41

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.
@@ -8071,6 +8071,207 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
8071
8071
  }, template: "<div class=\"tn-date-input-container\">\n <div #wrapper ixInput class=\"tn-date-input-wrapper\" style=\"padding-right: 40px;\">\n <!-- Date segments MM/DD/YYYY -->\n <div class=\"tn-date-segment-group\">\n <input\n #monthInput\n type=\"text\"\n class=\"tn-date-segment tn-date-segment-month\"\n placeholder=\"MM\"\n maxlength=\"2\"\n [disabled]=\"isDisabled()\"\n (focus)=\"onSegmentFocus('month')\"\n (blur)=\"onSegmentBlur('month')\"\n (keydown)=\"onSegmentKeydown($event, 'month')\">\n <span class=\"tn-date-segment-separator\">/</span>\n <input\n #dayInput\n type=\"text\"\n class=\"tn-date-segment tn-date-segment-day\"\n placeholder=\"DD\"\n maxlength=\"2\"\n [disabled]=\"isDisabled()\"\n (focus)=\"onSegmentFocus('day')\"\n (blur)=\"onSegmentBlur('day')\"\n (keydown)=\"onSegmentKeydown($event, 'day')\">\n <span class=\"tn-date-segment-separator\">/</span>\n <input\n #yearInput\n type=\"text\"\n class=\"tn-date-segment tn-date-segment-year\"\n placeholder=\"YYYY\"\n maxlength=\"4\"\n [disabled]=\"isDisabled()\"\n (focus)=\"onSegmentFocus('year')\"\n (blur)=\"onSegmentBlur('year')\"\n (keydown)=\"onSegmentKeydown($event, 'year')\">\n </div>\n\n <button\n type=\"button\"\n class=\"tn-date-input-toggle\"\n aria-label=\"Open calendar\"\n [disabled]=\"isDisabled()\"\n (click)=\"openDatepicker()\">\n <span aria-hidden=\"true\">\uD83D\uDCC5</span>\n </button>\n </div>\n\n <ng-template #calendarTemplate>\n <tn-calendar\n class=\"tn-calendar\"\n [startView]=\"'month'\"\n [rangeMode]=\"false\"\n [selected]=\"value()\"\n (selectedChange)=\"onDateSelected($event)\" />\n </ng-template>\n</div>\n", styles: [":host{display:block;width:100%}.tn-date-input-container{position:relative;display:flex;align-items:center}.tn-date-input-wrapper{display:flex;align-items:center;width:100%;position:relative}.tn-date-segment-group{display:flex;align-items:center}.tn-date-segment{background:transparent;border:none;outline:none;font:inherit;color:inherit;padding:0;min-width:0;text-align:center;width:2.6ch}.tn-date-segment::placeholder{color:var(--tn-alt-fg1, #999);opacity:1}.tn-date-segment:focus{outline:none;background:var(--tn-bg2, rgba(0, 0, 0, .05));border-radius:2px}.tn-date-segment:focus::placeholder{opacity:0}.tn-date-segment.tn-date-segment-year{width:4ch}.tn-date-segment-separator{padding:0 2px;-webkit-user-select:none;user-select:none;color:var(--tn-alt-fg1, #999)}.tn-date-input-toggle{position:absolute;right:8px;z-index:2;pointer-events:auto;background:transparent;border:none;cursor:pointer;padding:4px;font-size:16px}.tn-date-input-toggle:hover{background:var(--tn-bg2, #f0f0f0);border-radius:4px}.tn-date-input-toggle:disabled{cursor:not-allowed;opacity:.5}:host ::ng-deep .tn-datepicker-overlay .tn-calendar{background:var(--tn-bg1, white);border:1px solid var(--tn-lines, #e0e0e0);border-radius:8px;box-shadow:0 4px 12px #00000026;padding:24px;min-width:380px;--calendar-cell-size: 48px;--calendar-header-height: 44px;--calendar-cell-font-size: 16px;--calendar-header-font-size: 14px}:host ::ng-deep .tn-datepicker-overlay .tn-calendar .tn-calendar-content{padding:0}\n"] }]
8072
8072
  }], propDecorators: { disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], dateFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFilter", required: false }] }], monthRef: [{ type: i0.ViewChild, args: ['monthInput', { isSignal: true }] }], dayRef: [{ type: i0.ViewChild, args: ['dayInput', { isSignal: true }] }], yearRef: [{ type: i0.ViewChild, args: ['yearInput', { isSignal: true }] }], calendarTemplate: [{ type: i0.ViewChild, args: ['calendarTemplate', { isSignal: true }] }], calendar: [{ type: i0.ViewChild, args: [i0.forwardRef(() => TnCalendarComponent), { isSignal: true }] }], wrapperEl: [{ type: i0.ViewChild, args: ['wrapper', { isSignal: true }] }] } });
8073
8073
 
8074
+ /**
8075
+ * Formats a Date into zero-padded month, day, and year strings.
8076
+ *
8077
+ * @param date The date to format.
8078
+ * @returns An object with `month` (MM), `day` (DD), and `year` (YYYY) strings.
8079
+ */
8080
+ function formatDateParts(date) {
8081
+ return {
8082
+ month: (date.getMonth() + 1).toString().padStart(2, '0'),
8083
+ day: date.getDate().toString().padStart(2, '0'),
8084
+ year: date.getFullYear().toString(),
8085
+ };
8086
+ }
8087
+ /**
8088
+ * Reads the current value from an input element.
8089
+ *
8090
+ * @param el The test element to read from.
8091
+ * @returns The input's value, or an empty string if unset.
8092
+ */
8093
+ async function getInputValue(el) {
8094
+ return (await el.getProperty('value')) || '';
8095
+ }
8096
+ /**
8097
+ * Clears an input element and types a new value, then blurs to trigger validation.
8098
+ *
8099
+ * @param el The test element to write to.
8100
+ * @param value The value to type. Pass empty string to clear only.
8101
+ */
8102
+ async function setInputValue(el, value) {
8103
+ await el.clear();
8104
+ if (value) {
8105
+ await el.sendKeys(value);
8106
+ }
8107
+ await el.blur();
8108
+ }
8109
+ const MONTHS = [
8110
+ 'JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN',
8111
+ 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC',
8112
+ ];
8113
+ /**
8114
+ * Navigates the calendar overlay to the target month/year, then clicks the day cell.
8115
+ * Assumes the calendar popup is already open.
8116
+ *
8117
+ * @param rootLocator The document root locator factory (for finding overlay elements).
8118
+ * @param date The target date to select.
8119
+ */
8120
+ async function selectCalendarDate(rootLocator, date) {
8121
+ await navigateCalendarTo(rootLocator, date);
8122
+ const dayStr = date.getDate().toString();
8123
+ const cells = await rootLocator.locatorForAll('.tn-calendar-body-cell:not([disabled])')();
8124
+ for (const cell of cells) {
8125
+ if ((await cell.text()).trim() === dayStr) {
8126
+ await cell.click();
8127
+ return;
8128
+ }
8129
+ }
8130
+ throw new Error(`Could not find enabled calendar cell for day ${dayStr}`);
8131
+ }
8132
+ /**
8133
+ * Navigates the calendar to show the month/year of the target date by
8134
+ * clicking previous/next buttons as needed.
8135
+ */
8136
+ async function navigateCalendarTo(rootLocator, date) {
8137
+ const targetLabel = `${MONTHS[date.getMonth()]} ${date.getFullYear()}`;
8138
+ // Safety limit to prevent infinite loops
8139
+ for (let i = 0; i < 120; i++) {
8140
+ const periodButton = await rootLocator.locatorFor('.tn-calendar-period-button')();
8141
+ const currentLabel = (await periodButton.text()).trim();
8142
+ if (currentLabel === targetLabel) {
8143
+ return;
8144
+ }
8145
+ const currentDate = parseCalendarLabel(currentLabel);
8146
+ const targetTime = date.getFullYear() * 12 + date.getMonth();
8147
+ const currentTime = currentDate.year * 12 + currentDate.month;
8148
+ const navSelector = targetTime > currentTime
8149
+ ? '.tn-calendar-next-button'
8150
+ : '.tn-calendar-previous-button';
8151
+ const navButton = await rootLocator.locatorFor(navSelector)();
8152
+ await navButton.click();
8153
+ }
8154
+ throw new Error(`Could not navigate calendar to ${targetLabel}`);
8155
+ }
8156
+ function parseCalendarLabel(label) {
8157
+ const parts = label.split(' ');
8158
+ const monthIndex = MONTHS.indexOf(parts[0]);
8159
+ const year = parseInt(parts[1], 10);
8160
+ return { year, month: monthIndex >= 0 ? monthIndex : 0 };
8161
+ }
8162
+
8163
+ /**
8164
+ * Harness for interacting with `tn-date-input` in tests.
8165
+ * Provides methods for getting/setting the date value, opening the calendar,
8166
+ * and querying disabled state.
8167
+ *
8168
+ * The calendar popup is portaled to the CDK overlay, so use
8169
+ * `TestbedHarnessEnvironment.documentRootLoader(fixture)` if you need to
8170
+ * interact with the calendar cells directly.
8171
+ *
8172
+ * @example
8173
+ * ```typescript
8174
+ * const dateInput = await loader.getHarness(TnDateInputHarness);
8175
+ * await dateInput.setValue(new Date(2026, 3, 15));
8176
+ * expect(await dateInput.getDisplayText()).toBe('04/15/2026');
8177
+ *
8178
+ * await dateInput.openCalendar();
8179
+ * expect(await dateInput.isCalendarOpen()).toBe(true);
8180
+ * ```
8181
+ */
8182
+ class TnDateInputHarness extends ComponentHarness {
8183
+ static hostSelector = 'tn-date-input';
8184
+ _monthInput = this.locatorFor('.tn-date-segment-month');
8185
+ _dayInput = this.locatorFor('.tn-date-segment-day');
8186
+ _yearInput = this.locatorFor('.tn-date-segment-year');
8187
+ _toggle = this.locatorFor('.tn-date-input-toggle');
8188
+ /**
8189
+ * Gets a `HarnessPredicate` that can be used to search for a date input
8190
+ * with specific attributes.
8191
+ *
8192
+ * @param options Options for filtering which instances are considered a match.
8193
+ * @returns A `HarnessPredicate` configured with the given options.
8194
+ */
8195
+ static with(options = {}) {
8196
+ return new HarnessPredicate(TnDateInputHarness, options);
8197
+ }
8198
+ /**
8199
+ * Gets the displayed date text as "MM/DD/YYYY".
8200
+ * Returns placeholder segments if no date is set.
8201
+ *
8202
+ * @returns Promise resolving to the formatted display string.
8203
+ */
8204
+ async getDisplayText() {
8205
+ const month = await getInputValue(await this._monthInput());
8206
+ const day = await getInputValue(await this._dayInput());
8207
+ const year = await getInputValue(await this._yearInput());
8208
+ return `${month || 'MM'}/${day || 'DD'}/${year || 'YYYY'}`;
8209
+ }
8210
+ /**
8211
+ * Sets the date by typing into the segment inputs.
8212
+ *
8213
+ * @param date The date to set.
8214
+ */
8215
+ async setValue(date) {
8216
+ const { month, day, year } = formatDateParts(date);
8217
+ await setInputValue(await this._monthInput(), month);
8218
+ await setInputValue(await this._dayInput(), day);
8219
+ await setInputValue(await this._yearInput(), year);
8220
+ }
8221
+ /**
8222
+ * Clears all date segments.
8223
+ */
8224
+ async clear() {
8225
+ await setInputValue(await this._monthInput(), '');
8226
+ await setInputValue(await this._dayInput(), '');
8227
+ await setInputValue(await this._yearInput(), '');
8228
+ }
8229
+ /**
8230
+ * Checks whether the input is disabled.
8231
+ *
8232
+ * @returns Promise resolving to true if the input is disabled.
8233
+ */
8234
+ async isDisabled() {
8235
+ const month = await this._monthInput();
8236
+ return (await month.getProperty('disabled')) ?? false;
8237
+ }
8238
+ /**
8239
+ * Opens the calendar popup by clicking the toggle button.
8240
+ */
8241
+ async openCalendar() {
8242
+ const toggle = await this._toggle();
8243
+ await toggle.click();
8244
+ }
8245
+ /**
8246
+ * Whether the calendar popup is currently open.
8247
+ *
8248
+ * @returns Promise resolving to true if the calendar overlay is visible.
8249
+ */
8250
+ async isCalendarOpen() {
8251
+ const overlay = await this.documentRootLocatorFactory().locatorForOptional('.tn-datepicker-overlay')();
8252
+ return overlay !== null;
8253
+ }
8254
+ /**
8255
+ * Selects a date via the calendar popup. Opens the calendar if not already
8256
+ * open, navigates to the target month, and clicks the day cell.
8257
+ *
8258
+ * @param date The date to select.
8259
+ *
8260
+ * @example
8261
+ * ```typescript
8262
+ * const dateInput = await loader.getHarness(TnDateInputHarness);
8263
+ * await dateInput.selectDate(new Date(2026, 3, 15));
8264
+ * expect(await dateInput.getDisplayText()).toBe('04/15/2026');
8265
+ * ```
8266
+ */
8267
+ async selectDate(date) {
8268
+ if (!(await this.isCalendarOpen())) {
8269
+ await this.openCalendar();
8270
+ }
8271
+ await selectCalendarDate(this.documentRootLocatorFactory(), date);
8272
+ }
8273
+ }
8274
+
8074
8275
  class TnDateRangeInputComponent {
8075
8276
  disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
8076
8277
  placeholder = input('Select date range', ...(ngDevMode ? [{ debugName: "placeholder" }] : []));
@@ -8430,6 +8631,150 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
8430
8631
  }, template: "<div class=\"tn-date-range-container\">\n <div #wrapper ixInput class=\"tn-date-range-wrapper\" style=\"padding-right: 40px;\">\n <!-- Start date segments -->\n <div class=\"tn-date-segment-group\">\n <input\n #startMonthInput\n type=\"text\"\n class=\"tn-date-segment tn-date-segment-month\"\n placeholder=\"MM\"\n maxlength=\"2\"\n [disabled]=\"isDisabled()\"\n (focus)=\"onSegmentFocus('start', 'month')\"\n (blur)=\"onSegmentBlur('start', 'month')\"\n (keydown)=\"onSegmentKeydown($event, 'start', 'month')\">\n <span class=\"tn-date-segment-separator\">/</span>\n <input\n #startDayInput\n type=\"text\"\n class=\"tn-date-segment tn-date-segment-day\"\n placeholder=\"DD\"\n maxlength=\"2\"\n [disabled]=\"isDisabled()\"\n (focus)=\"onSegmentFocus('start', 'day')\"\n (blur)=\"onSegmentBlur('start', 'day')\"\n (keydown)=\"onSegmentKeydown($event, 'start', 'day')\">\n <span class=\"tn-date-segment-separator\">/</span>\n <input\n #startYearInput\n type=\"text\"\n class=\"tn-date-segment tn-date-segment-year\"\n placeholder=\"YYYY\"\n maxlength=\"4\"\n [disabled]=\"isDisabled()\"\n (focus)=\"onSegmentFocus('start', 'year')\"\n (blur)=\"onSegmentBlur('start', 'year')\"\n (keydown)=\"onSegmentKeydown($event, 'start', 'year')\">\n </div>\n\n <span class=\"tn-date-range-separator\">\u2013</span>\n\n <!-- End date segments -->\n <div class=\"tn-date-segment-group\">\n <input\n #endMonthInput\n type=\"text\"\n class=\"tn-date-segment tn-date-segment-month\"\n placeholder=\"MM\"\n maxlength=\"2\"\n [disabled]=\"isDisabled()\"\n (focus)=\"onSegmentFocus('end', 'month')\"\n (blur)=\"onSegmentBlur('end', 'month')\"\n (keydown)=\"onSegmentKeydown($event, 'end', 'month')\">\n <span class=\"tn-date-segment-separator\">/</span>\n <input\n #endDayInput\n type=\"text\"\n class=\"tn-date-segment tn-date-segment-day\"\n placeholder=\"DD\"\n maxlength=\"2\"\n [disabled]=\"isDisabled()\"\n (focus)=\"onSegmentFocus('end', 'day')\"\n (blur)=\"onSegmentBlur('end', 'day')\"\n (keydown)=\"onSegmentKeydown($event, 'end', 'day')\">\n <span class=\"tn-date-segment-separator\">/</span>\n <input\n #endYearInput\n type=\"text\"\n class=\"tn-date-segment tn-date-segment-year\"\n placeholder=\"YYYY\"\n maxlength=\"4\"\n [disabled]=\"isDisabled()\"\n (focus)=\"onSegmentFocus('end', 'year')\"\n (blur)=\"onSegmentBlur('end', 'year')\"\n (keydown)=\"onSegmentKeydown($event, 'end', 'year')\">\n </div>\n\n <button\n type=\"button\"\n class=\"tn-date-range-toggle\"\n aria-label=\"Open calendar\"\n [disabled]=\"isDisabled()\"\n (click)=\"openDatepicker()\">\n <span aria-hidden=\"true\">\uD83D\uDCC5</span>\n </button>\n </div>\n\n <ng-template #calendarTemplate>\n <tn-calendar\n class=\"tn-calendar\"\n [startView]=\"'month'\"\n [rangeMode]=\"true\"\n [selectedRange]=\"initialRange()\"\n (selectedRangeChange)=\"onRangeSelected($event)\" />\n </ng-template>\n</div>\n", styles: [":host{display:block;width:100%}.tn-date-range-container{position:relative;display:flex;align-items:center}.tn-date-range-wrapper{display:flex;align-items:center;width:100%;position:relative}.tn-date-segment-group{display:flex;align-items:center}.tn-date-segment{background:transparent;border:none;outline:none;font:inherit;color:inherit;padding:0;min-width:0;text-align:center;width:2.6ch}.tn-date-segment::placeholder{color:var(--tn-alt-fg1, #999);opacity:1}.tn-date-segment:focus{outline:none;background:var(--tn-bg2, rgba(0, 0, 0, .05));border-radius:2px}.tn-date-segment:focus::placeholder{opacity:0}.tn-date-segment.tn-date-segment-year{width:4ch}.tn-date-segment-separator{padding:0 2px;-webkit-user-select:none;user-select:none;color:var(--tn-alt-fg1, #999)}.tn-date-range-separator{padding:0 .25em;-webkit-user-select:none;user-select:none;color:var(--tn-fg2, #666);flex-shrink:0}.tn-date-range-toggle{position:absolute;right:8px;z-index:2;pointer-events:auto;background:transparent;border:none;cursor:pointer;padding:4px;font-size:16px}.tn-date-range-toggle:hover{background:var(--tn-bg2, #f0f0f0);border-radius:4px}.tn-date-range-toggle:disabled{cursor:not-allowed;opacity:.5}:host ::ng-deep .tn-datepicker-overlay .tn-calendar{background:var(--tn-bg1, white);border:1px solid var(--tn-lines, #e0e0e0);border-radius:8px;box-shadow:0 4px 12px #00000026;padding:24px;min-width:380px;--calendar-cell-size: 48px;--calendar-header-height: 44px;--calendar-cell-font-size: 16px;--calendar-header-font-size: 14px}:host ::ng-deep .tn-datepicker-overlay .tn-calendar .tn-calendar-content{padding:0}\n"] }]
8431
8632
  }], propDecorators: { disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], startMonthRef: [{ type: i0.ViewChild, args: ['startMonthInput', { isSignal: true }] }], startDayRef: [{ type: i0.ViewChild, args: ['startDayInput', { isSignal: true }] }], startYearRef: [{ type: i0.ViewChild, args: ['startYearInput', { isSignal: true }] }], endMonthRef: [{ type: i0.ViewChild, args: ['endMonthInput', { isSignal: true }] }], endDayRef: [{ type: i0.ViewChild, args: ['endDayInput', { isSignal: true }] }], endYearRef: [{ type: i0.ViewChild, args: ['endYearInput', { isSignal: true }] }], calendarTemplate: [{ type: i0.ViewChild, args: ['calendarTemplate', { isSignal: true }] }], calendar: [{ type: i0.ViewChild, args: [i0.forwardRef(() => TnCalendarComponent), { isSignal: true }] }], wrapperEl: [{ type: i0.ViewChild, args: ['wrapper', { isSignal: true }] }] } });
8432
8633
 
8634
+ /**
8635
+ * Harness for interacting with `tn-date-range-input` in tests.
8636
+ * Provides methods for getting/setting the date range, opening the calendar,
8637
+ * and querying disabled state.
8638
+ *
8639
+ * The calendar popup is portaled to the CDK overlay, so use
8640
+ * `TestbedHarnessEnvironment.documentRootLoader(fixture)` if you need to
8641
+ * interact with the calendar cells directly.
8642
+ *
8643
+ * @example
8644
+ * ```typescript
8645
+ * const rangeInput = await loader.getHarness(TnDateRangeInputHarness);
8646
+ * await rangeInput.setStartDate(new Date(2026, 0, 1));
8647
+ * await rangeInput.setEndDate(new Date(2026, 0, 31));
8648
+ * expect(await rangeInput.getStartText()).toBe('01/01/2026');
8649
+ * expect(await rangeInput.getEndText()).toBe('01/31/2026');
8650
+ * ```
8651
+ */
8652
+ class TnDateRangeInputHarness extends ComponentHarness {
8653
+ static hostSelector = 'tn-date-range-input';
8654
+ _startMonth = this.locatorFor('.tn-date-segment-group:first-of-type .tn-date-segment-month');
8655
+ _startDay = this.locatorFor('.tn-date-segment-group:first-of-type .tn-date-segment-day');
8656
+ _startYear = this.locatorFor('.tn-date-segment-group:first-of-type .tn-date-segment-year');
8657
+ _endMonth = this.locatorFor('.tn-date-segment-group:last-of-type .tn-date-segment-month');
8658
+ _endDay = this.locatorFor('.tn-date-segment-group:last-of-type .tn-date-segment-day');
8659
+ _endYear = this.locatorFor('.tn-date-segment-group:last-of-type .tn-date-segment-year');
8660
+ _toggle = this.locatorFor('.tn-date-range-toggle');
8661
+ /**
8662
+ * Gets a `HarnessPredicate` that can be used to search for a date range input
8663
+ * with specific attributes.
8664
+ *
8665
+ * @param options Options for filtering which instances are considered a match.
8666
+ * @returns A `HarnessPredicate` configured with the given options.
8667
+ */
8668
+ static with(options = {}) {
8669
+ return new HarnessPredicate(TnDateRangeInputHarness, options);
8670
+ }
8671
+ /**
8672
+ * Gets the start date display text as "MM/DD/YYYY".
8673
+ *
8674
+ * @returns Promise resolving to the formatted start date string.
8675
+ */
8676
+ async getStartText() {
8677
+ const month = await getInputValue(await this._startMonth());
8678
+ const day = await getInputValue(await this._startDay());
8679
+ const year = await getInputValue(await this._startYear());
8680
+ return `${month || 'MM'}/${day || 'DD'}/${year || 'YYYY'}`;
8681
+ }
8682
+ /**
8683
+ * Gets the end date display text as "MM/DD/YYYY".
8684
+ *
8685
+ * @returns Promise resolving to the formatted end date string.
8686
+ */
8687
+ async getEndText() {
8688
+ const month = await getInputValue(await this._endMonth());
8689
+ const day = await getInputValue(await this._endDay());
8690
+ const year = await getInputValue(await this._endYear());
8691
+ return `${month || 'MM'}/${day || 'DD'}/${year || 'YYYY'}`;
8692
+ }
8693
+ /**
8694
+ * Sets the start date by typing into the segment inputs.
8695
+ *
8696
+ * @param date The start date to set.
8697
+ */
8698
+ async setStartDate(date) {
8699
+ const { month, day, year } = formatDateParts(date);
8700
+ await setInputValue(await this._startMonth(), month);
8701
+ await setInputValue(await this._startDay(), day);
8702
+ await setInputValue(await this._startYear(), year);
8703
+ }
8704
+ /**
8705
+ * Sets the end date by typing into the segment inputs.
8706
+ *
8707
+ * @param date The end date to set.
8708
+ */
8709
+ async setEndDate(date) {
8710
+ const { month, day, year } = formatDateParts(date);
8711
+ await setInputValue(await this._endMonth(), month);
8712
+ await setInputValue(await this._endDay(), day);
8713
+ await setInputValue(await this._endYear(), year);
8714
+ }
8715
+ /**
8716
+ * Clears both start and end date segments.
8717
+ */
8718
+ async clear() {
8719
+ await setInputValue(await this._startMonth(), '');
8720
+ await setInputValue(await this._startDay(), '');
8721
+ await setInputValue(await this._startYear(), '');
8722
+ await setInputValue(await this._endMonth(), '');
8723
+ await setInputValue(await this._endDay(), '');
8724
+ await setInputValue(await this._endYear(), '');
8725
+ }
8726
+ /**
8727
+ * Checks whether the input is disabled.
8728
+ *
8729
+ * @returns Promise resolving to true if the input is disabled.
8730
+ */
8731
+ async isDisabled() {
8732
+ const month = await this._startMonth();
8733
+ return (await month.getProperty('disabled')) ?? false;
8734
+ }
8735
+ /**
8736
+ * Opens the calendar popup by clicking the toggle button.
8737
+ */
8738
+ async openCalendar() {
8739
+ const toggle = await this._toggle();
8740
+ await toggle.click();
8741
+ }
8742
+ /**
8743
+ * Whether the calendar popup is currently open.
8744
+ *
8745
+ * @returns Promise resolving to true if the calendar overlay is visible.
8746
+ */
8747
+ async isCalendarOpen() {
8748
+ const overlay = await this.documentRootLocatorFactory().locatorForOptional('.tn-datepicker-overlay')();
8749
+ return overlay !== null;
8750
+ }
8751
+ /**
8752
+ * Selects a date range via the calendar popup. Opens the calendar if not
8753
+ * already open, navigates to each target month, and clicks the day cells.
8754
+ *
8755
+ * @param range An object with `start` and `end` dates.
8756
+ *
8757
+ * @example
8758
+ * ```typescript
8759
+ * const rangeInput = await loader.getHarness(TnDateRangeInputHarness);
8760
+ * await rangeInput.selectRange({
8761
+ * start: new Date(2026, 0, 1),
8762
+ * end: new Date(2026, 0, 31),
8763
+ * });
8764
+ * expect(await rangeInput.getStartText()).toBe('01/01/2026');
8765
+ * expect(await rangeInput.getEndText()).toBe('01/31/2026');
8766
+ * ```
8767
+ */
8768
+ async selectRange(range) {
8769
+ if (!(await this.isCalendarOpen())) {
8770
+ await this.openCalendar();
8771
+ }
8772
+ const rootLocator = this.documentRootLocatorFactory();
8773
+ await selectCalendarDate(rootLocator, range.start);
8774
+ await selectCalendarDate(rootLocator, range.end);
8775
+ }
8776
+ }
8777
+
8433
8778
  class TnTimeInputComponent {
8434
8779
  disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
8435
8780
  format = input('12h', ...(ngDevMode ? [{ debugName: "format" }] : []));
@@ -12099,5 +12444,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
12099
12444
  * Generated bundle index. Do not edit.
12100
12445
  */
12101
12446
 
12102
- export { CommonShortcuts, DEFAULT_THEME, DiskIconComponent, DiskType, FileSizePipe, InputType, LIGHT_THEME, LinuxModifierKeys, LinuxShortcuts, ModifierKeys, QuickShortcuts, ShortcutBuilder, StripMntPrefixPipe, THEME_MAP, THEME_STORAGE_KEY, TN_THEME_DEFINITIONS, TnAutocompleteComponent, TnAutocompleteHarness, TnBannerActionDirective, TnBannerComponent, TnBannerHarness, TnBrandedSpinnerComponent, TnButtonComponent, TnButtonHarness, TnButtonToggleComponent, TnButtonToggleGroupComponent, TnButtonToggleGroupHarness, TnButtonToggleHarness, TnCalendarComponent, TnCalendarHeaderComponent, TnCardComponent, TnCellDefDirective, TnCheckboxComponent, TnCheckboxHarness, TnCheckboxLabelDirective, TnChipComponent, TnConfirmDialogComponent, TnDateInputComponent, TnDateRangeInputComponent, TnDialog, TnDialogHarness, TnDialogShellComponent, TnDialogTesting, TnDividerComponent, TnDividerDirective, TnDrawerComponent, TnDrawerContainerComponent, TnDrawerContainerHarness, TnDrawerContentComponent, TnDrawerHarness, TnEmptyComponent, TnEmptyHarness, TnExpansionPanelComponent, TnExpansionPanelHarness, TnFilePickerComponent, TnFilePickerPopupComponent, TnFormFieldComponent, TnFormFieldHarness, TnHeaderCellDefDirective, TnIconButtonComponent, TnIconButtonHarness, TnIconComponent, TnIconHarness, TnIconRegistryService, TnIconTesting, TnInputComponent, TnInputDirective, TnInputHarness, TnKeyboardShortcutComponent, TnKeyboardShortcutService, TnListAvatarDirective, TnListComponent, TnListIconDirective, TnListItemComponent, TnListItemLineDirective, TnListItemPrimaryDirective, TnListItemSecondaryDirective, TnListItemTitleDirective, TnListItemTrailingDirective, TnListOptionComponent, TnListSubheaderComponent, TnMenuActivateHoverDirective, TnMenuComponent, TnMenuHarness, TnMenuTesting, TnMenuTriggerDirective, TnMonthViewComponent, TnMultiYearViewComponent, TnNestedTreeNodeComponent, TnParticleProgressBarComponent, TnProgressBarComponent, TnRadioComponent, TnRadioHarness, TnSelectComponent, TnSelectHarness, TnSelectionListComponent, TnSidePanelActionDirective, TnSidePanelComponent, TnSidePanelHarness, TnSidePanelHeaderActionDirective, TnSlideToggleComponent, TnSlideToggleHarness, TnSliderComponent, TnSliderThumbDirective, TnSliderWithLabelDirective, TnSpinnerComponent, TnSpriteLoaderService, TnStepComponent, TnStepperComponent, TnTabComponent, TnTabHarness, TnTabPanelComponent, TnTabPanelHarness, TnTableColumnDirective, TnTableComponent, TnTabsComponent, TnTabsHarness, TnTheme, TnThemeService, TnTimeInputComponent, TnToastComponent, TnToastMock, TnToastPosition, TnToastRef, TnToastService, TnToastTesting, TnToastType, TnTooltipComponent, TnTooltipDirective, TnTreeComponent, TnTreeFlatDataSource, TnTreeFlattener, TnTreeNodeComponent, TnTreeNodeOutletDirective, TruncatePathPipe, WindowsModifierKeys, WindowsShortcuts, createLucideLibrary, createShortcut, defaultSpriteBasePath, defaultSpriteConfigPath, libIconMarker, registerLucideIcons, setupLucideIntegration, tnIconMarker };
12447
+ export { CommonShortcuts, DEFAULT_THEME, DiskIconComponent, DiskType, FileSizePipe, InputType, LIGHT_THEME, LinuxModifierKeys, LinuxShortcuts, ModifierKeys, QuickShortcuts, ShortcutBuilder, StripMntPrefixPipe, THEME_MAP, THEME_STORAGE_KEY, TN_THEME_DEFINITIONS, TnAutocompleteComponent, TnAutocompleteHarness, TnBannerActionDirective, TnBannerComponent, TnBannerHarness, TnBrandedSpinnerComponent, TnButtonComponent, TnButtonHarness, TnButtonToggleComponent, TnButtonToggleGroupComponent, TnButtonToggleGroupHarness, TnButtonToggleHarness, TnCalendarComponent, TnCalendarHeaderComponent, TnCardComponent, TnCellDefDirective, TnCheckboxComponent, TnCheckboxHarness, TnCheckboxLabelDirective, TnChipComponent, TnConfirmDialogComponent, TnDateInputComponent, TnDateInputHarness, TnDateRangeInputComponent, TnDateRangeInputHarness, TnDialog, TnDialogHarness, TnDialogShellComponent, TnDialogTesting, TnDividerComponent, TnDividerDirective, TnDrawerComponent, TnDrawerContainerComponent, TnDrawerContainerHarness, TnDrawerContentComponent, TnDrawerHarness, TnEmptyComponent, TnEmptyHarness, TnExpansionPanelComponent, TnExpansionPanelHarness, TnFilePickerComponent, TnFilePickerPopupComponent, TnFormFieldComponent, TnFormFieldHarness, TnHeaderCellDefDirective, TnIconButtonComponent, TnIconButtonHarness, TnIconComponent, TnIconHarness, TnIconRegistryService, TnIconTesting, TnInputComponent, TnInputDirective, TnInputHarness, TnKeyboardShortcutComponent, TnKeyboardShortcutService, TnListAvatarDirective, TnListComponent, TnListIconDirective, TnListItemComponent, TnListItemLineDirective, TnListItemPrimaryDirective, TnListItemSecondaryDirective, TnListItemTitleDirective, TnListItemTrailingDirective, TnListOptionComponent, TnListSubheaderComponent, TnMenuActivateHoverDirective, TnMenuComponent, TnMenuHarness, TnMenuTesting, TnMenuTriggerDirective, TnMonthViewComponent, TnMultiYearViewComponent, TnNestedTreeNodeComponent, TnParticleProgressBarComponent, TnProgressBarComponent, TnRadioComponent, TnRadioHarness, TnSelectComponent, TnSelectHarness, TnSelectionListComponent, TnSidePanelActionDirective, TnSidePanelComponent, TnSidePanelHarness, TnSidePanelHeaderActionDirective, TnSlideToggleComponent, TnSlideToggleHarness, TnSliderComponent, TnSliderThumbDirective, TnSliderWithLabelDirective, TnSpinnerComponent, TnSpriteLoaderService, TnStepComponent, TnStepperComponent, TnTabComponent, TnTabHarness, TnTabPanelComponent, TnTabPanelHarness, TnTableColumnDirective, TnTableComponent, TnTabsComponent, TnTabsHarness, TnTheme, TnThemeService, TnTimeInputComponent, TnToastComponent, TnToastMock, TnToastPosition, TnToastRef, TnToastService, TnToastTesting, TnToastType, TnTooltipComponent, TnTooltipDirective, TnTreeComponent, TnTreeFlatDataSource, TnTreeFlattener, TnTreeNodeComponent, TnTreeNodeOutletDirective, TruncatePathPipe, WindowsModifierKeys, WindowsShortcuts, createLucideLibrary, createShortcut, defaultSpriteBasePath, defaultSpriteConfigPath, libIconMarker, registerLucideIcons, setupLucideIntegration, tnIconMarker };
12103
12448
  //# sourceMappingURL=truenas-ui-components.mjs.map