@truenas/ui-components 0.1.35 → 0.1.36

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.
@@ -2836,6 +2836,139 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
2836
2836
  args: [{ selector: 'tn-expansion-panel', standalone: true, imports: [CommonModule], animations: [expandCollapseAnimation], template: "<div [ngClass]=\"classes()\">\n <button class=\"tn-expansion-panel__header\"\n [disabled]=\"disabled()\"\n [attr.aria-expanded]=\"effectiveExpanded()\"\n [attr.aria-controls]=\"contentId\"\n [attr.aria-disabled]=\"disabled()\"\n (click)=\"toggle()\">\n @if (title()) {\n <div class=\"tn-expansion-panel__title\">\n {{ title() }}\n </div>\n }\n <ng-content select=\"[slot=title]\" />\n\n <div class=\"tn-expansion-panel__indicator\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"m6 9 6 6 6-6\"/>\n </svg>\n </div>\n </button>\n\n <div class=\"tn-expansion-panel__content\"\n [id]=\"contentId\"\n [attr.aria-hidden]=\"!effectiveExpanded()\"\n [@expandCollapse]=\"effectiveExpanded() ? 'expanded' : 'collapsed'\">\n <ng-content />\n </div>\n</div>", styles: [".tn-expansion-panel{border-radius:8px;transition:box-shadow .3s ease;overflow:hidden}.tn-expansion-panel--elevation-none{box-shadow:none}.tn-expansion-panel--elevation-low{box-shadow:0 1px 3px #0000001a}.tn-expansion-panel--elevation-medium{box-shadow:0 4px 6px #0000001a}.tn-expansion-panel--elevation-high{box-shadow:0 10px 15px #0000001a}.tn-expansion-panel--bordered{border:1px solid var(--tn-lines, #e5e7eb)}.tn-expansion-panel--background{background-color:var(--tn-bg2, #ffffff)}.tn-expansion-panel--disabled{opacity:.6;cursor:not-allowed}.tn-expansion-panel--disabled .tn-expansion-panel__header{cursor:not-allowed}.tn-expansion-panel--expanded .tn-expansion-panel__indicator svg{transform:rotate(180deg)}.tn-expansion-panel--padding-small .tn-expansion-panel__header{padding:12px 16px}.tn-expansion-panel--padding-small .tn-expansion-panel__content{padding:0 16px 16px}.tn-expansion-panel--padding-medium .tn-expansion-panel__header{padding:16px 24px}.tn-expansion-panel--padding-medium .tn-expansion-panel__content{padding:0 24px 24px}.tn-expansion-panel--padding-large .tn-expansion-panel__header{padding:24px 32px}.tn-expansion-panel--padding-large .tn-expansion-panel__content{padding:0 32px 32px}.tn-expansion-panel--title-header .tn-expansion-panel__title{font-size:1.125rem;font-weight:600;color:var(--tn-fg1, #1f2937)}.tn-expansion-panel--title-header .tn-expansion-panel__indicator{color:var(--tn-fg1, #1f2937)}.tn-expansion-panel--title-body .tn-expansion-panel__title{font-size:1rem;font-weight:400;color:var(--tn-fg1, #1f2937)}.tn-expansion-panel--title-body .tn-expansion-panel__indicator{color:var(--tn-fg1, #1f2937)}.tn-expansion-panel--title-link .tn-expansion-panel__title{font-size:1rem;font-weight:400;color:var(--tn-primary, #3b82f6);text-decoration:none}.tn-expansion-panel--title-link .tn-expansion-panel__indicator{color:var(--tn-primary, #3b82f6)}.tn-expansion-panel--title-link .tn-expansion-panel__header:hover:not(:disabled) .tn-expansion-panel__title{text-decoration:underline}.tn-expansion-panel--title-link .tn-expansion-panel__header:focus .tn-expansion-panel__title{text-decoration:underline}.tn-expansion-panel__header{width:100%;background:none;border:none;display:flex;align-items:center;justify-content:space-between;cursor:pointer;font-family:inherit;text-align:left;transition:background-color .2s ease}.tn-expansion-panel--bordered .tn-expansion-panel__header,.tn-expansion-panel--bordered.tn-expansion-panel--expanded .tn-expansion-panel__header{border-bottom:1px solid var(--tn-lines, #e5e7eb)}.tn-expansion-panel__header:hover:not(:disabled){background-color:var(--tn-alt-bg1, rgba(0, 0, 0, .05))}.tn-expansion-panel__header:focus{outline:2px solid var(--tn-primary, #3b82f6);outline-offset:-2px}.tn-expansion-panel__header:disabled{cursor:not-allowed}.tn-expansion-panel__title{margin:0;line-height:1.5;flex:1;transition:text-decoration .2s ease}.tn-expansion-panel__indicator{display:flex;align-items:center;justify-content:center;margin-left:16px;transition:transform .2s ease,color .2s ease}.tn-expansion-panel__indicator svg{transition:transform .2s ease}.tn-expansion-panel__content{overflow:hidden}.tn-expansion-panel__content:not(.tn-expansion-panel--expanded){border-bottom:none}\n"] }]
2837
2837
  }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], elevation: [{ type: i0.Input, args: [{ isSignal: true, alias: "elevation", required: false }] }], padding: [{ type: i0.Input, args: [{ isSignal: true, alias: "padding", required: false }] }], bordered: [{ type: i0.Input, args: [{ isSignal: true, alias: "bordered", required: false }] }], background: [{ type: i0.Input, args: [{ isSignal: true, alias: "background", required: false }] }], expanded: [{ type: i0.Input, args: [{ isSignal: true, alias: "expanded", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], titleStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "titleStyle", required: false }] }], expandedChange: [{ type: i0.Output, args: ["expandedChange"] }], toggleEvent: [{ type: i0.Output, args: ["toggleEvent"] }] } });
2838
2838
 
2839
+ /**
2840
+ * Harness for interacting with `tn-expansion-panel` in tests.
2841
+ * Provides methods for expanding, collapsing, and querying panel state.
2842
+ *
2843
+ * @example
2844
+ * ```typescript
2845
+ * // Find and expand a panel
2846
+ * const panel = await loader.getHarness(TnExpansionPanelHarness.with({ title: 'Settings' }));
2847
+ * await panel.expand();
2848
+ * expect(await panel.isExpanded()).toBe(true);
2849
+ *
2850
+ * // Collapse a panel
2851
+ * await panel.collapse();
2852
+ * expect(await panel.isExpanded()).toBe(false);
2853
+ * ```
2854
+ */
2855
+ class TnExpansionPanelHarness extends ComponentHarness {
2856
+ /**
2857
+ * The selector for the host element of a `TnExpansionPanelComponent` instance.
2858
+ */
2859
+ static hostSelector = 'tn-expansion-panel';
2860
+ _header = this.locatorFor('.tn-expansion-panel__header');
2861
+ _title = this.locatorForOptional('.tn-expansion-panel__title');
2862
+ /**
2863
+ * Gets a `HarnessPredicate` that can be used to search for an expansion panel
2864
+ * with specific attributes.
2865
+ *
2866
+ * @param options Options for filtering which panel instances are considered a match.
2867
+ * @returns A `HarnessPredicate` configured with the given options.
2868
+ *
2869
+ * @example
2870
+ * ```typescript
2871
+ * // Find by title text
2872
+ * const panel = await loader.getHarness(TnExpansionPanelHarness.with({ title: 'Settings' }));
2873
+ *
2874
+ * // Find by title regex
2875
+ * const panel = await loader.getHarness(TnExpansionPanelHarness.with({ title: /settings/i }));
2876
+ * ```
2877
+ */
2878
+ static with(options = {}) {
2879
+ return new HarnessPredicate(TnExpansionPanelHarness, options)
2880
+ .addOption('title', options.title, (harness, title) => HarnessPredicate.stringMatches(harness.getTitle(), title));
2881
+ }
2882
+ /**
2883
+ * Gets the expansion panel title text.
2884
+ *
2885
+ * @returns Promise resolving to the title text, or empty string if no title.
2886
+ *
2887
+ * @example
2888
+ * ```typescript
2889
+ * const panel = await loader.getHarness(TnExpansionPanelHarness);
2890
+ * expect(await panel.getTitle()).toBe('Settings');
2891
+ * ```
2892
+ */
2893
+ async getTitle() {
2894
+ const title = await this._title();
2895
+ return title ? (await title.text()).trim() : '';
2896
+ }
2897
+ /**
2898
+ * Checks whether the expansion panel is currently expanded.
2899
+ *
2900
+ * @returns Promise resolving to true if the panel is expanded.
2901
+ *
2902
+ * @example
2903
+ * ```typescript
2904
+ * const panel = await loader.getHarness(TnExpansionPanelHarness);
2905
+ * expect(await panel.isExpanded()).toBe(false);
2906
+ * ```
2907
+ */
2908
+ async isExpanded() {
2909
+ const header = await this._header();
2910
+ return (await header.getAttribute('aria-expanded')) === 'true';
2911
+ }
2912
+ /**
2913
+ * Checks whether the expansion panel is disabled.
2914
+ *
2915
+ * @returns Promise resolving to true if the panel is disabled.
2916
+ *
2917
+ * @example
2918
+ * ```typescript
2919
+ * const panel = await loader.getHarness(TnExpansionPanelHarness);
2920
+ * expect(await panel.isDisabled()).toBe(false);
2921
+ * ```
2922
+ */
2923
+ async isDisabled() {
2924
+ const header = await this._header();
2925
+ return (await header.getProperty('disabled')) ?? false;
2926
+ }
2927
+ /**
2928
+ * Toggles the expansion panel by clicking the header.
2929
+ *
2930
+ * @example
2931
+ * ```typescript
2932
+ * const panel = await loader.getHarness(TnExpansionPanelHarness);
2933
+ * await panel.toggle();
2934
+ * ```
2935
+ */
2936
+ async toggle() {
2937
+ const header = await this._header();
2938
+ await header.click();
2939
+ }
2940
+ /**
2941
+ * Expands the panel. No-op if already expanded.
2942
+ *
2943
+ * @example
2944
+ * ```typescript
2945
+ * const panel = await loader.getHarness(TnExpansionPanelHarness);
2946
+ * await panel.expand();
2947
+ * expect(await panel.isExpanded()).toBe(true);
2948
+ * ```
2949
+ */
2950
+ async expand() {
2951
+ if (!(await this.isExpanded())) {
2952
+ await this.toggle();
2953
+ }
2954
+ }
2955
+ /**
2956
+ * Collapses the panel. No-op if already collapsed.
2957
+ *
2958
+ * @example
2959
+ * ```typescript
2960
+ * const panel = await loader.getHarness(TnExpansionPanelHarness);
2961
+ * await panel.collapse();
2962
+ * expect(await panel.isExpanded()).toBe(false);
2963
+ * ```
2964
+ */
2965
+ async collapse() {
2966
+ if (await this.isExpanded()) {
2967
+ await this.toggle();
2968
+ }
2969
+ }
2970
+ }
2971
+
2839
2972
  /**
2840
2973
  * Directive to mark content for projection into the checkbox label area.
2841
2974
  * Use when the label needs rich content (links, icons, etc.) instead of plain text.
@@ -3242,6 +3375,133 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
3242
3375
  ], template: "<div [ngClass]=\"classes()\">\n <label class=\"tn-radio__label\" [for]=\"id\">\n <input\n #radioEl\n type=\"radio\"\n class=\"tn-radio__input\"\n [id]=\"id\"\n [name]=\"name()\"\n [value]=\"value()\"\n [checked]=\"checked\"\n [disabled]=\"isDisabled()\"\n [required]=\"required()\"\n [attr.data-testid]=\"testId()\"\n [attr.aria-describedby]=\"error() ? id + '-error' : null\"\n [attr.aria-invalid]=\"error() ? 'true' : null\"\n (change)=\"onRadioChange($event)\"\n />\n <span class=\"tn-radio__checkmark\"></span>\n <span class=\"tn-radio__text\">{{ label() }}</span>\n </label>\n\n @if (error()) {\n <div\n class=\"tn-radio__error\"\n role=\"alert\"\n aria-live=\"polite\"\n [id]=\"id + '-error'\"\n >\n {{ error() }}\n </div>\n }\n</div>", styles: [".tn-radio{display:inline-block;margin-bottom:.5rem}.tn-radio__label{display:flex;align-items:center;cursor:pointer;-webkit-user-select:none;user-select:none;gap:.5rem}.tn-radio__label:hover .tn-radio__checkmark{border-color:var(--tn-primary, #007cba)}.tn-radio__input{position:absolute;opacity:0;cursor:pointer;height:0;width:0}.tn-radio__input:focus+.tn-radio__checkmark{outline:2px solid var(--tn-primary, #007cba);outline-offset:2px}.tn-radio__input:checked+.tn-radio__checkmark{border-color:var(--tn-primary, #007cba);background-color:var(--tn-primary, #007cba)}.tn-radio__input:checked+.tn-radio__checkmark:after{display:block}.tn-radio__input:disabled+.tn-radio__checkmark{border-color:var(--tn-lines, #e5e7eb);background-color:var(--tn-alt-bg1, #f8f9fa);cursor:not-allowed}.tn-radio__checkmark{position:relative;height:18px;width:18px;border:2px solid var(--tn-lines, #e5e7eb);border-radius:50%;background-color:transparent;transition:all .2s ease;flex-shrink:0}.tn-radio__checkmark:after{content:\"\";position:absolute;display:none;top:50%;left:50%;width:8px;height:8px;border-radius:50%;background-color:#fff;transform:translate(-50%,-50%)}.tn-radio__text{color:var(--tn-fg1, #000000);font-size:14px;line-height:1.4}.tn-radio__error{margin-top:.25rem;font-size:12px;color:var(--tn-red, #dc3545)}.tn-radio--disabled .tn-radio__label{cursor:not-allowed;opacity:.6}.tn-radio--disabled .tn-radio__text{color:var(--tn-fg2, #6c757d)}.tn-radio--error .tn-radio__checkmark{border-color:var(--tn-red, #dc3545)}\n"] }]
3243
3376
  }], propDecorators: { radioEl: [{ type: i0.ViewChild, args: ['radioEl', { isSignal: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], testId: [{ type: i0.Input, args: [{ isSignal: true, alias: "testId", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], change: [{ type: i0.Output, args: ["change"] }] } });
3244
3377
 
3378
+ /**
3379
+ * Harness for interacting with `tn-radio` in tests.
3380
+ * Provides methods for selecting and querying radio button state.
3381
+ *
3382
+ * @example
3383
+ * ```typescript
3384
+ * // Find and select a radio button
3385
+ * const radio = await loader.getHarness(TnRadioHarness.with({ label: 'Option A' }));
3386
+ * await radio.check();
3387
+ * expect(await radio.isChecked()).toBe(true);
3388
+ *
3389
+ * // Find by testId
3390
+ * const option = await loader.getHarness(TnRadioHarness.with({ testId: 'color-red' }));
3391
+ * ```
3392
+ */
3393
+ class TnRadioHarness extends ComponentHarness {
3394
+ /**
3395
+ * The selector for the host element of a `TnRadioComponent` instance.
3396
+ */
3397
+ static hostSelector = 'tn-radio';
3398
+ _input = this.locatorFor('.tn-radio__input');
3399
+ _label = this.locatorFor('.tn-radio__label');
3400
+ _text = this.locatorFor('.tn-radio__text');
3401
+ /**
3402
+ * Gets a `HarnessPredicate` that can be used to search for a radio button
3403
+ * with specific attributes.
3404
+ *
3405
+ * @param options Options for filtering which radio instances are considered a match.
3406
+ * @returns A `HarnessPredicate` configured with the given options.
3407
+ *
3408
+ * @example
3409
+ * ```typescript
3410
+ * // Find by label text
3411
+ * const radio = await loader.getHarness(TnRadioHarness.with({ label: 'Option A' }));
3412
+ *
3413
+ * // Find by label regex
3414
+ * const radio = await loader.getHarness(TnRadioHarness.with({ label: /option/i }));
3415
+ *
3416
+ * // Find by testId
3417
+ * const radio = await loader.getHarness(TnRadioHarness.with({ testId: 'my-radio' }));
3418
+ * ```
3419
+ */
3420
+ static with(options = {}) {
3421
+ return new HarnessPredicate(TnRadioHarness, options)
3422
+ .addOption('label', options.label, (harness, label) => HarnessPredicate.stringMatches(harness.getLabelText(), label))
3423
+ .addOption('testId', options.testId, async (harness, testId) => {
3424
+ return (await harness.getTestId()) === testId;
3425
+ });
3426
+ }
3427
+ /**
3428
+ * Gets the radio button label text content.
3429
+ *
3430
+ * @returns Promise resolving to the label text.
3431
+ *
3432
+ * @example
3433
+ * ```typescript
3434
+ * const radio = await loader.getHarness(TnRadioHarness);
3435
+ * expect(await radio.getLabelText()).toBe('Option A');
3436
+ * ```
3437
+ */
3438
+ async getLabelText() {
3439
+ const text = await this._text();
3440
+ return (await text.text()).trim();
3441
+ }
3442
+ /**
3443
+ * Checks whether the radio button is currently checked.
3444
+ *
3445
+ * @returns Promise resolving to true if the radio button is checked.
3446
+ *
3447
+ * @example
3448
+ * ```typescript
3449
+ * const radio = await loader.getHarness(TnRadioHarness);
3450
+ * expect(await radio.isChecked()).toBe(false);
3451
+ * ```
3452
+ */
3453
+ async isChecked() {
3454
+ const input = await this._input();
3455
+ return (await input.getProperty('checked')) ?? false;
3456
+ }
3457
+ /**
3458
+ * Checks whether the radio button is disabled.
3459
+ *
3460
+ * @returns Promise resolving to true if the radio button is disabled.
3461
+ *
3462
+ * @example
3463
+ * ```typescript
3464
+ * const radio = await loader.getHarness(TnRadioHarness);
3465
+ * expect(await radio.isDisabled()).toBe(false);
3466
+ * ```
3467
+ */
3468
+ async isDisabled() {
3469
+ const input = await this._input();
3470
+ return (await input.getProperty('disabled')) ?? false;
3471
+ }
3472
+ /**
3473
+ * Gets the test ID attribute value.
3474
+ *
3475
+ * @returns Promise resolving to the test ID string, or null.
3476
+ *
3477
+ * @example
3478
+ * ```typescript
3479
+ * const radio = await loader.getHarness(TnRadioHarness);
3480
+ * expect(await radio.getTestId()).toBe('color-red');
3481
+ * ```
3482
+ */
3483
+ async getTestId() {
3484
+ const input = await this._input();
3485
+ return input.getAttribute('data-testid');
3486
+ }
3487
+ /**
3488
+ * Selects the radio button by clicking the label. No-op if already checked.
3489
+ *
3490
+ * @example
3491
+ * ```typescript
3492
+ * const radio = await loader.getHarness(TnRadioHarness);
3493
+ * await radio.check();
3494
+ * expect(await radio.isChecked()).toBe(true);
3495
+ * ```
3496
+ */
3497
+ async check() {
3498
+ if (!(await this.isChecked())) {
3499
+ const label = await this._label();
3500
+ await label.click();
3501
+ }
3502
+ }
3503
+ }
3504
+
3245
3505
  /**
3246
3506
  * Harness for interacting with `tn-slide-toggle` in tests.
3247
3507
  *
@@ -8918,6 +9178,195 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
8918
9178
  }, template: "<div class=\"tn-button-toggle-group\"\n [attr.role]=\"multiple() ? 'group' : 'radiogroup'\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledby()\">\n <ng-content />\n</div>\n", styles: [".tn-button-toggle-group{display:inline-flex;align-items:stretch;border-radius:6px;box-shadow:0 1px 2px #0000000d}\n"] }]
8919
9179
  }], ctorParameters: () => [], propDecorators: { buttonToggles: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => TnButtonToggleComponent), { ...{ descendants: true }, isSignal: true }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], ariaLabelledby: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabelledby", required: false }] }], change: [{ type: i0.Output, args: ["change"] }] } });
8920
9180
 
9181
+ /**
9182
+ * Harness for interacting with `tn-button-toggle` in tests.
9183
+ * Provides methods for toggling, checking, unchecking, and querying toggle state.
9184
+ *
9185
+ * @example
9186
+ * ```typescript
9187
+ * // Find and check a button toggle
9188
+ * const toggle = await loader.getHarness(TnButtonToggleHarness.with({ label: 'Bold' }));
9189
+ * await toggle.check();
9190
+ * expect(await toggle.isChecked()).toBe(true);
9191
+ *
9192
+ * // Toggle state
9193
+ * await toggle.toggle();
9194
+ * expect(await toggle.isChecked()).toBe(false);
9195
+ * ```
9196
+ */
9197
+ class TnButtonToggleHarness extends ComponentHarness {
9198
+ /**
9199
+ * The selector for the host element of a `TnButtonToggleComponent` instance.
9200
+ */
9201
+ static hostSelector = 'tn-button-toggle';
9202
+ _button = this.locatorFor('.tn-button-toggle__button');
9203
+ _label = this.locatorFor('.tn-button-toggle__label');
9204
+ /**
9205
+ * Gets a `HarnessPredicate` that can be used to search for a button toggle
9206
+ * with specific attributes.
9207
+ *
9208
+ * @param options Options for filtering which toggle instances are considered a match.
9209
+ * @returns A `HarnessPredicate` configured with the given options.
9210
+ *
9211
+ * @example
9212
+ * ```typescript
9213
+ * // Find by label text
9214
+ * const toggle = await loader.getHarness(TnButtonToggleHarness.with({ label: 'Bold' }));
9215
+ *
9216
+ * // Find by label regex
9217
+ * const toggle = await loader.getHarness(TnButtonToggleHarness.with({ label: /bold/i }));
9218
+ * ```
9219
+ */
9220
+ static with(options = {}) {
9221
+ return new HarnessPredicate(TnButtonToggleHarness, options)
9222
+ .addOption('label', options.label, (harness, label) => HarnessPredicate.stringMatches(harness.getLabelText(), label));
9223
+ }
9224
+ /**
9225
+ * Gets the button toggle label text content.
9226
+ *
9227
+ * @returns Promise resolving to the label text.
9228
+ *
9229
+ * @example
9230
+ * ```typescript
9231
+ * const toggle = await loader.getHarness(TnButtonToggleHarness);
9232
+ * expect(await toggle.getLabelText()).toBe('Bold');
9233
+ * ```
9234
+ */
9235
+ async getLabelText() {
9236
+ const label = await this._label();
9237
+ return (await label.text()).trim();
9238
+ }
9239
+ /**
9240
+ * Checks whether the button toggle is currently checked.
9241
+ *
9242
+ * @returns Promise resolving to true if the toggle is checked.
9243
+ *
9244
+ * @example
9245
+ * ```typescript
9246
+ * const toggle = await loader.getHarness(TnButtonToggleHarness);
9247
+ * expect(await toggle.isChecked()).toBe(false);
9248
+ * ```
9249
+ */
9250
+ async isChecked() {
9251
+ const button = await this._button();
9252
+ return (await button.getAttribute('aria-pressed')) === 'true';
9253
+ }
9254
+ /**
9255
+ * Checks whether the button toggle is disabled.
9256
+ *
9257
+ * @returns Promise resolving to true if the toggle is disabled.
9258
+ *
9259
+ * @example
9260
+ * ```typescript
9261
+ * const toggle = await loader.getHarness(TnButtonToggleHarness);
9262
+ * expect(await toggle.isDisabled()).toBe(false);
9263
+ * ```
9264
+ */
9265
+ async isDisabled() {
9266
+ const button = await this._button();
9267
+ return (await button.getProperty('disabled')) ?? false;
9268
+ }
9269
+ /**
9270
+ * Toggles the button toggle by clicking it.
9271
+ *
9272
+ * @example
9273
+ * ```typescript
9274
+ * const toggle = await loader.getHarness(TnButtonToggleHarness);
9275
+ * await toggle.toggle();
9276
+ * ```
9277
+ */
9278
+ async toggle() {
9279
+ const button = await this._button();
9280
+ await button.click();
9281
+ }
9282
+ /**
9283
+ * Checks the button toggle. No-op if already checked.
9284
+ *
9285
+ * @example
9286
+ * ```typescript
9287
+ * const toggle = await loader.getHarness(TnButtonToggleHarness);
9288
+ * await toggle.check();
9289
+ * expect(await toggle.isChecked()).toBe(true);
9290
+ * ```
9291
+ */
9292
+ async check() {
9293
+ if (!(await this.isChecked())) {
9294
+ await this.toggle();
9295
+ }
9296
+ }
9297
+ /**
9298
+ * Unchecks the button toggle. No-op if already unchecked.
9299
+ *
9300
+ * @example
9301
+ * ```typescript
9302
+ * const toggle = await loader.getHarness(TnButtonToggleHarness);
9303
+ * await toggle.uncheck();
9304
+ * expect(await toggle.isChecked()).toBe(false);
9305
+ * ```
9306
+ */
9307
+ async uncheck() {
9308
+ if (await this.isChecked()) {
9309
+ await this.toggle();
9310
+ }
9311
+ }
9312
+ }
9313
+ /**
9314
+ * Harness for interacting with `tn-button-toggle-group` in tests.
9315
+ * Provides methods for querying the group's toggles and finding checked toggles.
9316
+ *
9317
+ * @example
9318
+ * ```typescript
9319
+ * const group = await loader.getHarness(TnButtonToggleGroupHarness);
9320
+ * const toggles = await group.getToggles();
9321
+ * expect(toggles.length).toBe(3);
9322
+ *
9323
+ * const checked = await group.getCheckedToggle();
9324
+ * expect(await checked?.getLabelText()).toBe('Option A');
9325
+ * ```
9326
+ */
9327
+ class TnButtonToggleGroupHarness extends ComponentHarness {
9328
+ /**
9329
+ * The selector for the host element of a `TnButtonToggleGroupComponent` instance.
9330
+ */
9331
+ static hostSelector = 'tn-button-toggle-group';
9332
+ /**
9333
+ * Gets all toggle harnesses within this group.
9334
+ *
9335
+ * @returns Promise resolving to an array of `TnButtonToggleHarness` instances.
9336
+ *
9337
+ * @example
9338
+ * ```typescript
9339
+ * const group = await loader.getHarness(TnButtonToggleGroupHarness);
9340
+ * const toggles = await group.getToggles();
9341
+ * expect(toggles.length).toBe(3);
9342
+ * ```
9343
+ */
9344
+ async getToggles() {
9345
+ return this.locatorForAll(TnButtonToggleHarness)();
9346
+ }
9347
+ /**
9348
+ * Gets the currently checked toggle, or null if none is checked.
9349
+ *
9350
+ * @returns Promise resolving to the checked `TnButtonToggleHarness`, or null.
9351
+ *
9352
+ * @example
9353
+ * ```typescript
9354
+ * const group = await loader.getHarness(TnButtonToggleGroupHarness);
9355
+ * const checked = await group.getCheckedToggle();
9356
+ * expect(await checked?.getLabelText()).toBe('Option A');
9357
+ * ```
9358
+ */
9359
+ async getCheckedToggle() {
9360
+ const toggles = await this.getToggles();
9361
+ for (const toggle of toggles) {
9362
+ if (await toggle.isChecked()) {
9363
+ return toggle;
9364
+ }
9365
+ }
9366
+ return null;
9367
+ }
9368
+ }
9369
+
8921
9370
  class TnTooltipComponent {
8922
9371
  message = input('', ...(ngDevMode ? [{ debugName: "message" }] : []));
8923
9372
  id = input('', ...(ngDevMode ? [{ debugName: "id" }] : []));
@@ -11647,5 +12096,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
11647
12096
  * Generated bundle index. Do not edit.
11648
12097
  */
11649
12098
 
11650
- 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, 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, 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, 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 };
12099
+ 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 };
11651
12100
  //# sourceMappingURL=truenas-ui-components.mjs.map