@jigisha_ruparel/taf-client-tabs-angular 0.1.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.
@@ -0,0 +1,195 @@
1
+ import * as i1 from '@angular/common';
2
+ import { CommonModule } from '@angular/common';
3
+ import * as i0 from '@angular/core';
4
+ import { inject, ChangeDetectorRef, EventEmitter, booleanAttribute, Output, Input, ViewChild, ChangeDetectionStrategy, Component } from '@angular/core';
5
+
6
+ /**
7
+ * `<taf-tabs>` — the strip of tabs above a panel. It renders the strip only; the host still decides
8
+ * what the active tab shows, which is how these screens are already written.
9
+ *
10
+ * The strip owns no state: it renders `[active]` and emits `(activeChange)`, so a host keeps the
11
+ * signal or route param it already has. Closing is the same — `(closeTab)` fires and the host
12
+ * decides whether the tab actually goes.
13
+ *
14
+ * `scrollable` adds the overflow affordance a long strip needs: the arrows appear only when the
15
+ * strip actually overflows, and scroll it by roughly a tab's width.
16
+ *
17
+ * Ships NO theme — `taf-tabs__*` class hooks plus `data-active` / `data-variant`, so the host app
18
+ * decides whether a tab reads as an underline, a pill or a filled strip.
19
+ */
20
+ class TafTabsComponent {
21
+ stripRef;
22
+ cdr = inject(ChangeDetectorRef);
23
+ tabs = [];
24
+ /** The active tab's `key`. */
25
+ active = '';
26
+ /** Surfaces as `data-variant` — the host theme decides what each looks like. */
27
+ variant = '';
28
+ /** Show arrows and scroll the strip when it overflows. */
29
+ scrollable = false;
30
+ /** Hide every close affordance, for a strip the user may read but not change. */
31
+ readonly = false;
32
+ activeChange = new EventEmitter();
33
+ /** A tab's ✕ was pressed. The host decides whether it closes. */
34
+ closeTab = new EventEmitter();
35
+ overflowing = false;
36
+ trackKey = (_, t) => t.key;
37
+ ngAfterViewInit() {
38
+ this.syncOverflow();
39
+ }
40
+ syncOverflow() {
41
+ const el = this.stripRef?.nativeElement;
42
+ if (!el)
43
+ return;
44
+ const next = el.scrollWidth > el.clientWidth + 1;
45
+ if (next !== this.overflowing) {
46
+ this.overflowing = next;
47
+ // OnPush: the arrows appear as a result of a measurement, not of an input changing.
48
+ this.cdr.markForCheck();
49
+ }
50
+ }
51
+ scrollBy(direction) {
52
+ const el = this.stripRef?.nativeElement;
53
+ if (!el)
54
+ return;
55
+ const tab = el.querySelector('.taf-tabs__tab');
56
+ el.scrollBy({ left: direction * (tab?.offsetWidth ?? 120), behavior: 'smooth' });
57
+ }
58
+ pick(t) {
59
+ if (t.disabled || t.key === this.active)
60
+ return;
61
+ this.activeChange.emit(t.key);
62
+ }
63
+ close(event, t) {
64
+ event.stopPropagation();
65
+ this.closeTab.emit(t.key);
66
+ }
67
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: TafTabsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
68
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "22.1.5", type: TafTabsComponent, isStandalone: true, selector: "taf-tabs", inputs: { tabs: "tabs", active: "active", variant: "variant", scrollable: ["scrollable", "scrollable", booleanAttribute], readonly: ["readonly", "readonly", booleanAttribute] }, outputs: { activeChange: "activeChange", closeTab: "closeTab" }, viewQueries: [{ propertyName: "stripRef", first: true, predicate: ["strip"], descendants: true }], ngImport: i0, template: `
69
+ <div class="taf-tabs" [attr.data-variant]="variant || null">
70
+ <button
71
+ *ngIf="scrollable && overflowing"
72
+ type="button"
73
+ class="taf-tabs__arrow taf-tabs__arrow--start"
74
+ aria-label="Scroll tabs left"
75
+ (click)="scrollBy(-1)"
76
+ >&#8249;</button>
77
+
78
+ <div class="taf-tabs__strip" role="tablist" #strip (scroll)="syncOverflow()">
79
+ <button
80
+ *ngFor="let t of tabs; trackBy: trackKey"
81
+ type="button"
82
+ role="tab"
83
+ class="taf-tabs__tab"
84
+ [attr.data-key]="t.key"
85
+ [attr.data-active]="t.key === active ? '' : null"
86
+ [attr.aria-selected]="t.key === active"
87
+ [attr.title]="t.hint || null"
88
+ [disabled]="!!t.disabled"
89
+ (click)="pick(t)"
90
+ >
91
+ <span class="taf-tabs__icon" *ngIf="t.icon" aria-hidden="true">{{ t.icon }}</span>
92
+ <span class="taf-tabs__label">{{ t.label }}</span>
93
+ <span class="taf-tabs__count" *ngIf="t.count !== undefined">{{ t.count }}</span>
94
+ <span
95
+ *ngIf="t.closeable && !readonly"
96
+ class="taf-tabs__close"
97
+ role="button"
98
+ tabindex="0"
99
+ [attr.aria-label]="'Close ' + t.label"
100
+ (click)="close($event, t)"
101
+ (keydown.enter)="close($event, t)"
102
+ >&#10005;</span>
103
+ </button>
104
+ </div>
105
+
106
+ <button
107
+ *ngIf="scrollable && overflowing"
108
+ type="button"
109
+ class="taf-tabs__arrow taf-tabs__arrow--end"
110
+ aria-label="Scroll tabs right"
111
+ (click)="scrollBy(1)"
112
+ >&#8250;</button>
113
+
114
+ <ng-content select="[tafTabsEnd]"></ng-content>
115
+ </div>
116
+ `, isInline: true, styles: ["taf-tabs{display:contents}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
117
+ }
118
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: TafTabsComponent, decorators: [{
119
+ type: Component,
120
+ args: [{ selector: 'taf-tabs', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
121
+ <div class="taf-tabs" [attr.data-variant]="variant || null">
122
+ <button
123
+ *ngIf="scrollable && overflowing"
124
+ type="button"
125
+ class="taf-tabs__arrow taf-tabs__arrow--start"
126
+ aria-label="Scroll tabs left"
127
+ (click)="scrollBy(-1)"
128
+ >&#8249;</button>
129
+
130
+ <div class="taf-tabs__strip" role="tablist" #strip (scroll)="syncOverflow()">
131
+ <button
132
+ *ngFor="let t of tabs; trackBy: trackKey"
133
+ type="button"
134
+ role="tab"
135
+ class="taf-tabs__tab"
136
+ [attr.data-key]="t.key"
137
+ [attr.data-active]="t.key === active ? '' : null"
138
+ [attr.aria-selected]="t.key === active"
139
+ [attr.title]="t.hint || null"
140
+ [disabled]="!!t.disabled"
141
+ (click)="pick(t)"
142
+ >
143
+ <span class="taf-tabs__icon" *ngIf="t.icon" aria-hidden="true">{{ t.icon }}</span>
144
+ <span class="taf-tabs__label">{{ t.label }}</span>
145
+ <span class="taf-tabs__count" *ngIf="t.count !== undefined">{{ t.count }}</span>
146
+ <span
147
+ *ngIf="t.closeable && !readonly"
148
+ class="taf-tabs__close"
149
+ role="button"
150
+ tabindex="0"
151
+ [attr.aria-label]="'Close ' + t.label"
152
+ (click)="close($event, t)"
153
+ (keydown.enter)="close($event, t)"
154
+ >&#10005;</span>
155
+ </button>
156
+ </div>
157
+
158
+ <button
159
+ *ngIf="scrollable && overflowing"
160
+ type="button"
161
+ class="taf-tabs__arrow taf-tabs__arrow--end"
162
+ aria-label="Scroll tabs right"
163
+ (click)="scrollBy(1)"
164
+ >&#8250;</button>
165
+
166
+ <ng-content select="[tafTabsEnd]"></ng-content>
167
+ </div>
168
+ `, styles: ["taf-tabs{display:contents}\n"] }]
169
+ }], propDecorators: { stripRef: [{
170
+ type: ViewChild,
171
+ args: ['strip']
172
+ }], tabs: [{
173
+ type: Input
174
+ }], active: [{
175
+ type: Input
176
+ }], variant: [{
177
+ type: Input
178
+ }], scrollable: [{
179
+ type: Input,
180
+ args: [{ transform: booleanAttribute }]
181
+ }], readonly: [{
182
+ type: Input,
183
+ args: [{ transform: booleanAttribute }]
184
+ }], activeChange: [{
185
+ type: Output
186
+ }], closeTab: [{
187
+ type: Output
188
+ }] } });
189
+
190
+ /**
191
+ * Generated bundle index. Do not edit.
192
+ */
193
+
194
+ export { TafTabsComponent };
195
+ //# sourceMappingURL=jigisha_ruparel-taf-client-tabs-angular.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jigisha_ruparel-taf-client-tabs-angular.mjs","sources":["../../src/taf-tabs.component.ts","../../src/jigisha_ruparel-taf-client-tabs-angular.ts"],"sourcesContent":["import { CommonModule } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n Component,\n ElementRef,\n EventEmitter,\n Input,\n Output,\n ViewChild,\n booleanAttribute,\n inject,\n} from '@angular/core';\nimport type { AfterViewInit } from '@angular/core';\n\n/** One tab. `key` is what `active` matches and what the outputs emit. */\nexport interface TafTab {\n key: string;\n label: string;\n /** A count beside the label — how many rows sit behind this tab. */\n count?: number;\n /** A leading glyph or icon ligature. */\n icon?: string;\n disabled?: boolean;\n /** Shows a ✕ on this tab; closing is the host's decision, via `(closeTab)`. */\n closeable?: boolean;\n /** A title attribute, where the label is truncated. */\n hint?: string;\n}\n\n/**\n * `<taf-tabs>` — the strip of tabs above a panel. It renders the strip only; the host still decides\n * what the active tab shows, which is how these screens are already written.\n *\n * The strip owns no state: it renders `[active]` and emits `(activeChange)`, so a host keeps the\n * signal or route param it already has. Closing is the same — `(closeTab)` fires and the host\n * decides whether the tab actually goes.\n *\n * `scrollable` adds the overflow affordance a long strip needs: the arrows appear only when the\n * strip actually overflows, and scroll it by roughly a tab's width.\n *\n * Ships NO theme — `taf-tabs__*` class hooks plus `data-active` / `data-variant`, so the host app\n * decides whether a tab reads as an underline, a pill or a filled strip.\n */\n@Component({\n selector: 'taf-tabs',\n standalone: true,\n imports: [CommonModule],\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <div class=\"taf-tabs\" [attr.data-variant]=\"variant || null\">\n <button\n *ngIf=\"scrollable && overflowing\"\n type=\"button\"\n class=\"taf-tabs__arrow taf-tabs__arrow--start\"\n aria-label=\"Scroll tabs left\"\n (click)=\"scrollBy(-1)\"\n >&#8249;</button>\n\n <div class=\"taf-tabs__strip\" role=\"tablist\" #strip (scroll)=\"syncOverflow()\">\n <button\n *ngFor=\"let t of tabs; trackBy: trackKey\"\n type=\"button\"\n role=\"tab\"\n class=\"taf-tabs__tab\"\n [attr.data-key]=\"t.key\"\n [attr.data-active]=\"t.key === active ? '' : null\"\n [attr.aria-selected]=\"t.key === active\"\n [attr.title]=\"t.hint || null\"\n [disabled]=\"!!t.disabled\"\n (click)=\"pick(t)\"\n >\n <span class=\"taf-tabs__icon\" *ngIf=\"t.icon\" aria-hidden=\"true\">{{ t.icon }}</span>\n <span class=\"taf-tabs__label\">{{ t.label }}</span>\n <span class=\"taf-tabs__count\" *ngIf=\"t.count !== undefined\">{{ t.count }}</span>\n <span\n *ngIf=\"t.closeable && !readonly\"\n class=\"taf-tabs__close\"\n role=\"button\"\n tabindex=\"0\"\n [attr.aria-label]=\"'Close ' + t.label\"\n (click)=\"close($event, t)\"\n (keydown.enter)=\"close($event, t)\"\n >&#10005;</span>\n </button>\n </div>\n\n <button\n *ngIf=\"scrollable && overflowing\"\n type=\"button\"\n class=\"taf-tabs__arrow taf-tabs__arrow--end\"\n aria-label=\"Scroll tabs right\"\n (click)=\"scrollBy(1)\"\n >&#8250;</button>\n\n <ng-content select=\"[tafTabsEnd]\"></ng-content>\n </div>\n `,\n styles: [\n `\n taf-tabs { display: contents; }\n `,\n ],\n})\nexport class TafTabsComponent implements AfterViewInit {\n @ViewChild('strip') private stripRef?: ElementRef<HTMLElement>;\n private readonly cdr = inject(ChangeDetectorRef);\n\n @Input() tabs: readonly TafTab[] = [];\n /** The active tab's `key`. */\n @Input() active = '';\n /** Surfaces as `data-variant` — the host theme decides what each looks like. */\n @Input() variant = '';\n /** Show arrows and scroll the strip when it overflows. */\n @Input({ transform: booleanAttribute }) scrollable = false;\n /** Hide every close affordance, for a strip the user may read but not change. */\n @Input({ transform: booleanAttribute }) readonly = false;\n\n @Output() readonly activeChange = new EventEmitter<string>();\n /** A tab's ✕ was pressed. The host decides whether it closes. */\n @Output() readonly closeTab = new EventEmitter<string>();\n\n protected overflowing = false;\n\n protected trackKey = (_: number, t: TafTab) => t.key;\n\n ngAfterViewInit(): void {\n this.syncOverflow();\n }\n\n protected syncOverflow(): void {\n const el = this.stripRef?.nativeElement;\n if (!el) return;\n const next = el.scrollWidth > el.clientWidth + 1;\n if (next !== this.overflowing) {\n this.overflowing = next;\n // OnPush: the arrows appear as a result of a measurement, not of an input changing.\n this.cdr.markForCheck();\n }\n }\n\n protected scrollBy(direction: 1 | -1): void {\n const el = this.stripRef?.nativeElement;\n if (!el) return;\n const tab = el.querySelector<HTMLElement>('.taf-tabs__tab');\n el.scrollBy({ left: direction * (tab?.offsetWidth ?? 120), behavior: 'smooth' });\n }\n\n protected pick(t: TafTab): void {\n if (t.disabled || t.key === this.active) return;\n this.activeChange.emit(t.key);\n }\n\n protected close(event: Event, t: TafTab): void {\n event.stopPropagation();\n this.closeTab.emit(t.key);\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "@jigisha_ruparel/taf-client-tabs-angular",
3
+ "version": "0.1.0",
4
+ "description": "<taf-tabs> — the themeless tab strip above a panel: counts, icons, closeable tabs, overflow scrolling.",
5
+ "publishConfig": {
6
+ "access": "public",
7
+ "directory": "dist"
8
+ },
9
+ "peerDependencies": {
10
+ "@angular/core": ">=17",
11
+ "@angular/common": ">=17"
12
+ },
13
+ "dependencies": {
14
+ "tslib": "^2.3.0"
15
+ },
16
+ "module": "fesm2022/jigisha_ruparel-taf-client-tabs-angular.mjs",
17
+ "typings": "types/jigisha_ruparel-taf-client-tabs-angular.d.ts",
18
+ "exports": {
19
+ "./package.json": {
20
+ "default": "./package.json"
21
+ },
22
+ ".": {
23
+ "types": "./types/jigisha_ruparel-taf-client-tabs-angular.d.ts",
24
+ "default": "./fesm2022/jigisha_ruparel-taf-client-tabs-angular.mjs"
25
+ }
26
+ },
27
+ "sideEffects": false,
28
+ "type": "module"
29
+ }
@@ -0,0 +1,61 @@
1
+ import * as i0 from '@angular/core';
2
+ import { AfterViewInit, EventEmitter } from '@angular/core';
3
+
4
+ /** One tab. `key` is what `active` matches and what the outputs emit. */
5
+ interface TafTab {
6
+ key: string;
7
+ label: string;
8
+ /** A count beside the label — how many rows sit behind this tab. */
9
+ count?: number;
10
+ /** A leading glyph or icon ligature. */
11
+ icon?: string;
12
+ disabled?: boolean;
13
+ /** Shows a ✕ on this tab; closing is the host's decision, via `(closeTab)`. */
14
+ closeable?: boolean;
15
+ /** A title attribute, where the label is truncated. */
16
+ hint?: string;
17
+ }
18
+ /**
19
+ * `<taf-tabs>` — the strip of tabs above a panel. It renders the strip only; the host still decides
20
+ * what the active tab shows, which is how these screens are already written.
21
+ *
22
+ * The strip owns no state: it renders `[active]` and emits `(activeChange)`, so a host keeps the
23
+ * signal or route param it already has. Closing is the same — `(closeTab)` fires and the host
24
+ * decides whether the tab actually goes.
25
+ *
26
+ * `scrollable` adds the overflow affordance a long strip needs: the arrows appear only when the
27
+ * strip actually overflows, and scroll it by roughly a tab's width.
28
+ *
29
+ * Ships NO theme — `taf-tabs__*` class hooks plus `data-active` / `data-variant`, so the host app
30
+ * decides whether a tab reads as an underline, a pill or a filled strip.
31
+ */
32
+ declare class TafTabsComponent implements AfterViewInit {
33
+ private stripRef?;
34
+ private readonly cdr;
35
+ tabs: readonly TafTab[];
36
+ /** The active tab's `key`. */
37
+ active: string;
38
+ /** Surfaces as `data-variant` — the host theme decides what each looks like. */
39
+ variant: string;
40
+ /** Show arrows and scroll the strip when it overflows. */
41
+ scrollable: boolean;
42
+ /** Hide every close affordance, for a strip the user may read but not change. */
43
+ readonly: boolean;
44
+ readonly activeChange: EventEmitter<string>;
45
+ /** A tab's ✕ was pressed. The host decides whether it closes. */
46
+ readonly closeTab: EventEmitter<string>;
47
+ protected overflowing: boolean;
48
+ protected trackKey: (_: number, t: TafTab) => string;
49
+ ngAfterViewInit(): void;
50
+ protected syncOverflow(): void;
51
+ protected scrollBy(direction: 1 | -1): void;
52
+ protected pick(t: TafTab): void;
53
+ protected close(event: Event, t: TafTab): void;
54
+ static ɵfac: i0.ɵɵFactoryDeclaration<TafTabsComponent, never>;
55
+ static ɵcmp: i0.ɵɵComponentDeclaration<TafTabsComponent, "taf-tabs", never, { "tabs": { "alias": "tabs"; "required": false; }; "active": { "alias": "active"; "required": false; }; "variant": { "alias": "variant"; "required": false; }; "scrollable": { "alias": "scrollable"; "required": false; }; "readonly": { "alias": "readonly"; "required": false; }; }, { "activeChange": "activeChange"; "closeTab": "closeTab"; }, never, ["[tafTabsEnd]"], true, never>;
56
+ static ngAcceptInputType_scrollable: unknown;
57
+ static ngAcceptInputType_readonly: unknown;
58
+ }
59
+
60
+ export { TafTabsComponent };
61
+ export type { TafTab };