@kanso-protocol/tabs 0.1.2 → 0.2.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.
@@ -45,9 +45,17 @@ class KpTabComponent {
45
45
  }
46
46
  this.selectedChange.emit(true);
47
47
  }
48
+ handleKey(event) {
49
+ if (event.key !== 'Enter' && event.key !== ' ')
50
+ return;
51
+ if (this.disabled)
52
+ return;
53
+ event.preventDefault();
54
+ this.selectedChange.emit(true);
55
+ }
48
56
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: KpTabComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
49
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.7", type: KpTabComponent, isStandalone: true, selector: "kp-tab", inputs: { size: "size", label: "label", selected: "selected", disabled: "disabled", fullWidth: "fullWidth" }, outputs: { selectedChange: "selectedChange" }, host: { properties: { "class": "hostClasses", "attr.role": "\"tab\"", "attr.aria-selected": "selected", "attr.aria-disabled": "disabled || null", "attr.tabindex": "disabled ? -1 : (selected ? 0 : -1)" } }, ngImport: i0, template: `
50
- <button type="button" class="kp-tab__btn" [disabled]="disabled" (click)="handleClick($event)">
57
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.7", type: KpTabComponent, isStandalone: true, selector: "kp-tab", inputs: { size: "size", label: "label", selected: "selected", disabled: "disabled", fullWidth: "fullWidth" }, outputs: { selectedChange: "selectedChange" }, host: { listeners: { "click": "handleClick($event)", "keydown": "handleKey($event)" }, properties: { "class": "hostClasses", "attr.role": "\"tab\"", "attr.aria-selected": "selected", "attr.aria-disabled": "disabled || null", "attr.tabindex": "disabled ? -1 : (selected ? 0 : -1)" } }, ngImport: i0, template: `
58
+ <span class="kp-tab__btn">
51
59
  <span class="kp-tab__icon" aria-hidden="true">
52
60
  <ng-content select="[kpTabIcon]"/>
53
61
  </span>
@@ -55,7 +63,7 @@ class KpTabComponent {
55
63
  <span class="kp-tab__badge">
56
64
  <ng-content select="[kpTabBadge]"/>
57
65
  </span>
58
- </button>
66
+ </span>
59
67
  `, isInline: true, styles: [":host{display:inline-flex;box-sizing:border-box;height:var(--kp-tab-h);border-bottom:2px solid var(--kp-color-tabs-tab-underline-rest, transparent);font-family:var(--kp-font-family-sans, \"Onest\", system-ui, sans-serif);transition:border-color var(--kp-motion-duration-fast) ease,color .12s ease}:host(.kp-tab--full-width){flex:1 1 0}.kp-tab__btn{all:unset;display:inline-flex;align-items:center;justify-content:center;gap:var(--kp-tab-gap);padding:0 var(--kp-tab-pad-x);height:100%;width:100%;color:var(--kp-color-tabs-tab-fg-rest, var(--kp-color-gray-600));cursor:pointer;font-size:var(--kp-tab-font-size);line-height:var(--kp-tab-line-height);font-weight:500}.kp-tab__btn:focus-visible{outline:2px solid var(--kp-color-focus-ring, var(--kp-color-blue-400));outline-offset:-2px}.kp-tab__icon{display:inline-flex;align-items:center;color:var(--kp-color-tabs-tab-icon-rest, var(--kp-color-gray-500))}.kp-tab__icon:empty{display:none}.kp-tab__icon ::ng-deep svg{width:var(--kp-tab-icon-size);height:var(--kp-tab-icon-size)}.kp-tab__badge{display:inline-flex}.kp-tab__badge:empty{display:none}:host(:not(.kp-tab--selected):not(.kp-tab--disabled):hover){border-bottom-color:var(--kp-color-tabs-tab-underline-hover, var(--kp-color-gray-300))}:host(:not(.kp-tab--selected):not(.kp-tab--disabled):hover) .kp-tab__btn{color:var(--kp-color-tabs-tab-fg-hover, var(--kp-color-gray-900))}:host(:not(.kp-tab--selected):not(.kp-tab--disabled):hover) .kp-tab__icon{color:var(--kp-color-tabs-tab-icon-hover, var(--kp-color-gray-700))}:host(.kp-tab--selected){border-bottom-color:var(--kp-color-tabs-tab-underline-selected, var(--kp-color-blue-600))}:host(.kp-tab--selected) .kp-tab__btn{color:var(--kp-color-tabs-tab-fg-selected, var(--kp-color-blue-600))}:host(.kp-tab--selected) .kp-tab__icon{color:var(--kp-color-tabs-tab-icon-selected, var(--kp-color-blue-600))}:host(.kp-tab--disabled){border-bottom-color:var(--kp-color-tabs-tab-underline-disabled, transparent)}:host(.kp-tab--disabled) .kp-tab__btn{color:var(--kp-color-tabs-tab-fg-disabled, var(--kp-color-gray-300));cursor:not-allowed}:host(.kp-tab--disabled) .kp-tab__icon{color:var(--kp-color-tabs-tab-icon-disabled, var(--kp-color-gray-300))}:host(.kp-tab--sm){--kp-tab-h: 32px;--kp-tab-pad-x: 12px;--kp-tab-gap: 6px;--kp-tab-font-size: 14px;--kp-tab-line-height: 20px;--kp-tab-icon-size: 14px}:host(.kp-tab--md){--kp-tab-h: 40px;--kp-tab-pad-x: 16px;--kp-tab-gap: 8px;--kp-tab-font-size: 14px;--kp-tab-line-height: 20px;--kp-tab-icon-size: 16px}:host(.kp-tab--lg){--kp-tab-h: 48px;--kp-tab-pad-x: 20px;--kp-tab-gap: 8px;--kp-tab-font-size: 16px;--kp-tab-line-height: 24px;--kp-tab-icon-size: 16px}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
60
68
  }
61
69
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: KpTabComponent, decorators: [{
@@ -66,8 +74,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
66
74
  '[attr.aria-selected]': 'selected',
67
75
  '[attr.aria-disabled]': 'disabled || null',
68
76
  '[attr.tabindex]': 'disabled ? -1 : (selected ? 0 : -1)',
77
+ '(click)': 'handleClick($event)',
78
+ '(keydown)': 'handleKey($event)',
69
79
  }, template: `
70
- <button type="button" class="kp-tab__btn" [disabled]="disabled" (click)="handleClick($event)">
80
+ <span class="kp-tab__btn">
71
81
  <span class="kp-tab__icon" aria-hidden="true">
72
82
  <ng-content select="[kpTabIcon]"/>
73
83
  </span>
@@ -75,7 +85,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
75
85
  <span class="kp-tab__badge">
76
86
  <ng-content select="[kpTabBadge]"/>
77
87
  </span>
78
- </button>
88
+ </span>
79
89
  `, styles: [":host{display:inline-flex;box-sizing:border-box;height:var(--kp-tab-h);border-bottom:2px solid var(--kp-color-tabs-tab-underline-rest, transparent);font-family:var(--kp-font-family-sans, \"Onest\", system-ui, sans-serif);transition:border-color var(--kp-motion-duration-fast) ease,color .12s ease}:host(.kp-tab--full-width){flex:1 1 0}.kp-tab__btn{all:unset;display:inline-flex;align-items:center;justify-content:center;gap:var(--kp-tab-gap);padding:0 var(--kp-tab-pad-x);height:100%;width:100%;color:var(--kp-color-tabs-tab-fg-rest, var(--kp-color-gray-600));cursor:pointer;font-size:var(--kp-tab-font-size);line-height:var(--kp-tab-line-height);font-weight:500}.kp-tab__btn:focus-visible{outline:2px solid var(--kp-color-focus-ring, var(--kp-color-blue-400));outline-offset:-2px}.kp-tab__icon{display:inline-flex;align-items:center;color:var(--kp-color-tabs-tab-icon-rest, var(--kp-color-gray-500))}.kp-tab__icon:empty{display:none}.kp-tab__icon ::ng-deep svg{width:var(--kp-tab-icon-size);height:var(--kp-tab-icon-size)}.kp-tab__badge{display:inline-flex}.kp-tab__badge:empty{display:none}:host(:not(.kp-tab--selected):not(.kp-tab--disabled):hover){border-bottom-color:var(--kp-color-tabs-tab-underline-hover, var(--kp-color-gray-300))}:host(:not(.kp-tab--selected):not(.kp-tab--disabled):hover) .kp-tab__btn{color:var(--kp-color-tabs-tab-fg-hover, var(--kp-color-gray-900))}:host(:not(.kp-tab--selected):not(.kp-tab--disabled):hover) .kp-tab__icon{color:var(--kp-color-tabs-tab-icon-hover, var(--kp-color-gray-700))}:host(.kp-tab--selected){border-bottom-color:var(--kp-color-tabs-tab-underline-selected, var(--kp-color-blue-600))}:host(.kp-tab--selected) .kp-tab__btn{color:var(--kp-color-tabs-tab-fg-selected, var(--kp-color-blue-600))}:host(.kp-tab--selected) .kp-tab__icon{color:var(--kp-color-tabs-tab-icon-selected, var(--kp-color-blue-600))}:host(.kp-tab--disabled){border-bottom-color:var(--kp-color-tabs-tab-underline-disabled, transparent)}:host(.kp-tab--disabled) .kp-tab__btn{color:var(--kp-color-tabs-tab-fg-disabled, var(--kp-color-gray-300));cursor:not-allowed}:host(.kp-tab--disabled) .kp-tab__icon{color:var(--kp-color-tabs-tab-icon-disabled, var(--kp-color-gray-300))}:host(.kp-tab--sm){--kp-tab-h: 32px;--kp-tab-pad-x: 12px;--kp-tab-gap: 6px;--kp-tab-font-size: 14px;--kp-tab-line-height: 20px;--kp-tab-icon-size: 14px}:host(.kp-tab--md){--kp-tab-h: 40px;--kp-tab-pad-x: 16px;--kp-tab-gap: 8px;--kp-tab-font-size: 14px;--kp-tab-line-height: 20px;--kp-tab-icon-size: 16px}:host(.kp-tab--lg){--kp-tab-h: 48px;--kp-tab-pad-x: 20px;--kp-tab-gap: 8px;--kp-tab-font-size: 16px;--kp-tab-line-height: 24px;--kp-tab-icon-size: 16px}\n"] }]
80
90
  }], propDecorators: { size: [{
81
91
  type: Input
@@ -179,8 +189,9 @@ class KpTabsComponent {
179
189
  return bySelection >= 0 ? bySelection : 0;
180
190
  }
181
191
  focusTab(tab) {
182
- const btn = tab.elementRef.nativeElement.querySelector('button.kp-tab__btn');
183
- btn?.focus();
192
+ // The host element itself is the focusable target — it carries role="tab"
193
+ // and tabindex. The inner span is non-interactive (axe nested-interactive).
194
+ tab.elementRef.nativeElement.focus();
184
195
  }
185
196
  get hostClasses() {
186
197
  const c = ['kp-tabs'];
@@ -1 +1 @@
1
- {"version":3,"file":"kanso-protocol-tabs.mjs","sources":["../../../../../packages/components/tabs/src/tab.component.ts","../../../../../packages/components/tabs/src/tabs.component.ts","../../../../../packages/components/tabs/src/kanso-protocol-tabs.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n EventEmitter,\n Input,\n Output,\n inject,\n} from '@angular/core';\n\nexport type KpTabSize = 'sm' | 'md' | 'lg';\n\n/**\n * Kanso Protocol — Tab (atom)\n *\n * Single tab for use inside `<kp-tabs>`. Projects an optional leading icon\n * and an optional trailing badge. The `selected` / `disabled` inputs drive\n * the visual state; hover is handled in CSS and focus via `:focus-visible`\n * on the underlying button.\n *\n * @example\n * <kp-tab label=\"Inbox\" [selected]=\"current === 'inbox'\" (click)=\"current='inbox'\">\n * <svg kpTabIcon .../>\n * <kp-badge kpTabBadge>12</kp-badge>\n * </kp-tab>\n */\n@Component({\n selector: 'kp-tab',\n imports: [],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[class]': 'hostClasses',\n '[attr.role]': '\"tab\"',\n '[attr.aria-selected]': 'selected',\n '[attr.aria-disabled]': 'disabled || null',\n '[attr.tabindex]': 'disabled ? -1 : (selected ? 0 : -1)',\n },\n template: `\n <button type=\"button\" class=\"kp-tab__btn\" [disabled]=\"disabled\" (click)=\"handleClick($event)\">\n <span class=\"kp-tab__icon\" aria-hidden=\"true\">\n <ng-content select=\"[kpTabIcon]\"/>\n </span>\n <span class=\"kp-tab__label\">{{ label }}</span>\n <span class=\"kp-tab__badge\">\n <ng-content select=\"[kpTabBadge]\"/>\n </span>\n </button>\n `,\n styles: [`\n :host {\n display: inline-flex;\n box-sizing: border-box;\n height: var(--kp-tab-h);\n border-bottom: 2px solid var(--kp-color-tabs-tab-underline-rest, transparent);\n font-family: var(--kp-font-family-sans, 'Onest', system-ui, sans-serif);\n transition: border-color var(--kp-motion-duration-fast) ease, color 120ms ease;\n }\n :host(.kp-tab--full-width) { flex: 1 1 0; }\n\n .kp-tab__btn {\n all: unset;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--kp-tab-gap);\n padding: 0 var(--kp-tab-pad-x);\n height: 100%;\n width: 100%;\n color: var(--kp-color-tabs-tab-fg-rest, var(--kp-color-gray-600));\n cursor: pointer;\n font-size: var(--kp-tab-font-size);\n line-height: var(--kp-tab-line-height);\n font-weight: 500;\n }\n .kp-tab__btn:focus-visible {\n outline: 2px solid var(--kp-color-focus-ring, var(--kp-color-blue-400));\n outline-offset: -2px;\n }\n\n .kp-tab__icon {\n display: inline-flex;\n align-items: center;\n color: var(--kp-color-tabs-tab-icon-rest, var(--kp-color-gray-500));\n }\n .kp-tab__icon:empty { display: none; }\n .kp-tab__icon ::ng-deep svg {\n width: var(--kp-tab-icon-size);\n height: var(--kp-tab-icon-size);\n }\n\n .kp-tab__badge { display: inline-flex; }\n .kp-tab__badge:empty { display: none; }\n\n /* Hover (rest only — disabled / selected handled explicitly) */\n :host(:not(.kp-tab--selected):not(.kp-tab--disabled):hover) {\n border-bottom-color: var(--kp-color-tabs-tab-underline-hover, var(--kp-color-gray-300));\n }\n :host(:not(.kp-tab--selected):not(.kp-tab--disabled):hover) .kp-tab__btn {\n color: var(--kp-color-tabs-tab-fg-hover, var(--kp-color-gray-900));\n }\n :host(:not(.kp-tab--selected):not(.kp-tab--disabled):hover) .kp-tab__icon {\n color: var(--kp-color-tabs-tab-icon-hover, var(--kp-color-gray-700));\n }\n\n /* Selected */\n :host(.kp-tab--selected) {\n border-bottom-color: var(--kp-color-tabs-tab-underline-selected, var(--kp-color-blue-600));\n }\n :host(.kp-tab--selected) .kp-tab__btn {\n color: var(--kp-color-tabs-tab-fg-selected, var(--kp-color-blue-600));\n }\n :host(.kp-tab--selected) .kp-tab__icon {\n color: var(--kp-color-tabs-tab-icon-selected, var(--kp-color-blue-600));\n }\n\n /* Disabled */\n :host(.kp-tab--disabled) {\n border-bottom-color: var(--kp-color-tabs-tab-underline-disabled, transparent);\n }\n :host(.kp-tab--disabled) .kp-tab__btn {\n color: var(--kp-color-tabs-tab-fg-disabled, var(--kp-color-gray-300));\n cursor: not-allowed;\n }\n :host(.kp-tab--disabled) .kp-tab__icon {\n color: var(--kp-color-tabs-tab-icon-disabled, var(--kp-color-gray-300));\n }\n\n /* Sizes */\n :host(.kp-tab--sm) {\n --kp-tab-h: 32px;\n --kp-tab-pad-x: 12px;\n --kp-tab-gap: 6px;\n --kp-tab-font-size: 14px;\n --kp-tab-line-height: 20px;\n --kp-tab-icon-size: 14px;\n }\n :host(.kp-tab--md) {\n --kp-tab-h: 40px;\n --kp-tab-pad-x: 16px;\n --kp-tab-gap: 8px;\n --kp-tab-font-size: 14px;\n --kp-tab-line-height: 20px;\n --kp-tab-icon-size: 16px;\n }\n :host(.kp-tab--lg) {\n --kp-tab-h: 48px;\n --kp-tab-pad-x: 20px;\n --kp-tab-gap: 8px;\n --kp-tab-font-size: 16px;\n --kp-tab-line-height: 24px;\n --kp-tab-icon-size: 16px;\n }\n `],\n})\nexport class KpTabComponent {\n @Input() size: KpTabSize = 'md';\n @Input() label = '';\n @Input() selected = false;\n @Input() disabled = false;\n /** Set by the parent `<kp-tabs>` when `fullWidth` is enabled on the container */\n @Input() fullWidth = false;\n\n @Output() selectedChange = new EventEmitter<boolean>();\n\n /** @internal — exposed so the parent `<kp-tabs>` can focus this tab's\n * inner button as part of its arrow-key roving-tabindex navigation. */\n readonly elementRef = inject(ElementRef) as ElementRef<HTMLElement>;\n\n get hostClasses(): string {\n const c = ['kp-tab', `kp-tab--${this.size}`];\n if (this.selected) c.push('kp-tab--selected');\n if (this.disabled) c.push('kp-tab--disabled');\n if (this.fullWidth) c.push('kp-tab--full-width');\n return c.join(' ');\n }\n\n handleClick(event: MouseEvent): void {\n if (this.disabled) {\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n this.selectedChange.emit(true);\n }\n}\n","import {\n AfterContentInit,\n ChangeDetectionStrategy,\n Component,\n ContentChildren,\n ElementRef,\n Input,\n OnDestroy,\n QueryList,\n inject,\n} from '@angular/core';\nimport { Subject, takeUntil } from 'rxjs';\n\nimport { KpTabComponent, KpTabSize } from './tab.component';\n\n/**\n * Kanso Protocol — Tabs (container)\n *\n * Horizontal strip of `<kp-tab>` children with a shared bottom border.\n * Cascades `size` and `fullWidth` down to every projected `<kp-tab>`\n * automatically, so callers only set those two inputs in one place.\n *\n * A `[kpTabsMore]` slot projects an optional \"More ▾\" affordance to the\n * right of the strip — useful when tabs overflow and you want a dropdown\n * to hold the rest.\n *\n * @example\n * <kp-tabs size=\"md\" [fullWidth]=\"false\">\n * <kp-tab label=\"Overview\" [selected]=\"tab === 'overview'\" (selectedChange)=\"tab = 'overview'\"/>\n * <kp-tab label=\"Activity\" [selected]=\"tab === 'activity'\" (selectedChange)=\"tab = 'activity'\"/>\n * <kp-tab label=\"Settings\" [selected]=\"tab === 'settings'\" (selectedChange)=\"tab = 'settings'\"/>\n *\n * <button kpTabsMore>More ▾</button>\n * </kp-tabs>\n */\n@Component({\n selector: 'kp-tabs',\n imports: [],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[class]': 'hostClasses',\n '[attr.role]': '\"tablist\"',\n '(keydown)': 'onKeyDown($event)',\n },\n template: `\n <div class=\"kp-tabs__row\"><ng-content/></div>\n <div class=\"kp-tabs__more\"><ng-content select=\"[kpTabsMore]\"/></div>\n `,\n styles: [`\n :host {\n position: relative;\n display: flex;\n align-items: stretch;\n border-bottom: 1px solid var(--kp-color-tabs-track-border, var(--kp-color-gray-200));\n font-family: var(--kp-font-family-sans, 'Onest', system-ui, sans-serif);\n }\n\n .kp-tabs__row {\n display: flex;\n flex: 1 1 auto;\n /* The Tab atoms already carry their own border-bottom; no extra row chrome needed. */\n }\n :host(.kp-tabs--full-width) .kp-tabs__row > * { flex: 1 1 0; }\n\n .kp-tabs__more { display: inline-flex; flex: 0 0 auto; }\n .kp-tabs__more:empty { display: none; }\n `],\n})\nexport class KpTabsComponent implements AfterContentInit, OnDestroy {\n @Input() size: KpTabSize = 'md';\n @Input() fullWidth = false;\n\n @ContentChildren(KpTabComponent) tabs!: QueryList<KpTabComponent>;\n\n private readonly host = inject(ElementRef) as ElementRef<HTMLElement>;\n private readonly destroyed$ = new Subject<void>();\n\n ngAfterContentInit(): void {\n this.applyToTabs();\n this.tabs.changes.pipe(takeUntil(this.destroyed$)).subscribe(() => this.applyToTabs());\n }\n\n ngOnDestroy(): void {\n this.destroyed$.next();\n this.destroyed$.complete();\n }\n\n private applyToTabs(): void {\n this.tabs?.forEach((t) => {\n t.size = this.size;\n t.fullWidth = this.fullWidth;\n });\n }\n\n /**\n * WAI-ARIA tablist keyboard pattern:\n * ArrowLeft / ArrowRight — move to previous / next enabled tab (wraps around)\n * Home / End — jump to first / last enabled tab\n * Enter / Space — select the focused tab (native button handles this too)\n * Disabled tabs are skipped. Selection activates on focus change (automatic\n * activation) since our tab bodies are lightweight to render.\n */\n onKeyDown(event: KeyboardEvent): void {\n const all = this.tabs?.toArray() ?? [];\n const enabled = all.filter((t) => !t.disabled);\n if (!enabled.length) return;\n\n const active = this.activeTabIndex(enabled);\n let next: number | null = null;\n switch (event.key) {\n case 'ArrowRight': next = (active + 1) % enabled.length; break;\n case 'ArrowLeft': next = (active - 1 + enabled.length) % enabled.length; break;\n case 'Home': next = 0; break;\n case 'End': next = enabled.length - 1; break;\n default: return;\n }\n event.preventDefault();\n const target = enabled[next];\n // \"Consumer owns state\" — same pattern as click. Emit (selectedChange)\n // on the target tab and let the parent's [selected] binding propagate.\n if (!target.selected) target.selectedChange.emit(true);\n this.focusTab(target);\n }\n\n private activeTabIndex(enabled: KpTabComponent[]): number {\n const doc = this.host.nativeElement.ownerDocument;\n const focused = doc?.activeElement ?? null;\n const byFocus = enabled.findIndex((t) => t.elementRef.nativeElement.contains(focused));\n if (byFocus >= 0) return byFocus;\n const bySelection = enabled.findIndex((t) => t.selected);\n return bySelection >= 0 ? bySelection : 0;\n }\n\n private focusTab(tab: KpTabComponent): void {\n const btn = tab.elementRef.nativeElement.querySelector<HTMLButtonElement>('button.kp-tab__btn');\n btn?.focus();\n }\n\n get hostClasses(): string {\n const c = ['kp-tabs'];\n if (this.fullWidth) c.push('kp-tabs--full-width');\n return c.join(' ');\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"kanso-protocol-tabs.mjs","sources":["../../../../../packages/components/tabs/src/tab.component.ts","../../../../../packages/components/tabs/src/tabs.component.ts","../../../../../packages/components/tabs/src/kanso-protocol-tabs.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n EventEmitter,\n Input,\n Output,\n inject,\n} from '@angular/core';\n\nexport type KpTabSize = 'sm' | 'md' | 'lg';\n\n/**\n * Kanso Protocol — Tab (atom)\n *\n * Single tab for use inside `<kp-tabs>`. Projects an optional leading icon\n * and an optional trailing badge. The `selected` / `disabled` inputs drive\n * the visual state; hover is handled in CSS and focus via `:focus-visible`\n * on the underlying button.\n *\n * @example\n * <kp-tab label=\"Inbox\" [selected]=\"current === 'inbox'\" (click)=\"current='inbox'\">\n * <svg kpTabIcon .../>\n * <kp-badge kpTabBadge>12</kp-badge>\n * </kp-tab>\n */\n@Component({\n selector: 'kp-tab',\n imports: [],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[class]': 'hostClasses',\n '[attr.role]': '\"tab\"',\n '[attr.aria-selected]': 'selected',\n '[attr.aria-disabled]': 'disabled || null',\n '[attr.tabindex]': 'disabled ? -1 : (selected ? 0 : -1)',\n '(click)': 'handleClick($event)',\n '(keydown)': 'handleKey($event)',\n },\n // Inner content is a non-interactive span. The previous <button> inside the\n // role=\"tab\" host triggered axe's nested-interactive rule. Click + keyboard\n // activation now live on the host directly; arrow-key navigation between\n // tabs is owned by the parent <kp-tabs> via roving tabindex (see tabs.component.ts).\n template: `\n <span class=\"kp-tab__btn\">\n <span class=\"kp-tab__icon\" aria-hidden=\"true\">\n <ng-content select=\"[kpTabIcon]\"/>\n </span>\n <span class=\"kp-tab__label\">{{ label }}</span>\n <span class=\"kp-tab__badge\">\n <ng-content select=\"[kpTabBadge]\"/>\n </span>\n </span>\n `,\n styles: [`\n :host {\n display: inline-flex;\n box-sizing: border-box;\n height: var(--kp-tab-h);\n border-bottom: 2px solid var(--kp-color-tabs-tab-underline-rest, transparent);\n font-family: var(--kp-font-family-sans, 'Onest', system-ui, sans-serif);\n transition: border-color var(--kp-motion-duration-fast) ease, color 120ms ease;\n }\n :host(.kp-tab--full-width) { flex: 1 1 0; }\n\n .kp-tab__btn {\n all: unset;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--kp-tab-gap);\n padding: 0 var(--kp-tab-pad-x);\n height: 100%;\n width: 100%;\n color: var(--kp-color-tabs-tab-fg-rest, var(--kp-color-gray-600));\n cursor: pointer;\n font-size: var(--kp-tab-font-size);\n line-height: var(--kp-tab-line-height);\n font-weight: 500;\n }\n .kp-tab__btn:focus-visible {\n outline: 2px solid var(--kp-color-focus-ring, var(--kp-color-blue-400));\n outline-offset: -2px;\n }\n\n .kp-tab__icon {\n display: inline-flex;\n align-items: center;\n color: var(--kp-color-tabs-tab-icon-rest, var(--kp-color-gray-500));\n }\n .kp-tab__icon:empty { display: none; }\n .kp-tab__icon ::ng-deep svg {\n width: var(--kp-tab-icon-size);\n height: var(--kp-tab-icon-size);\n }\n\n .kp-tab__badge { display: inline-flex; }\n .kp-tab__badge:empty { display: none; }\n\n /* Hover (rest only — disabled / selected handled explicitly) */\n :host(:not(.kp-tab--selected):not(.kp-tab--disabled):hover) {\n border-bottom-color: var(--kp-color-tabs-tab-underline-hover, var(--kp-color-gray-300));\n }\n :host(:not(.kp-tab--selected):not(.kp-tab--disabled):hover) .kp-tab__btn {\n color: var(--kp-color-tabs-tab-fg-hover, var(--kp-color-gray-900));\n }\n :host(:not(.kp-tab--selected):not(.kp-tab--disabled):hover) .kp-tab__icon {\n color: var(--kp-color-tabs-tab-icon-hover, var(--kp-color-gray-700));\n }\n\n /* Selected */\n :host(.kp-tab--selected) {\n border-bottom-color: var(--kp-color-tabs-tab-underline-selected, var(--kp-color-blue-600));\n }\n :host(.kp-tab--selected) .kp-tab__btn {\n color: var(--kp-color-tabs-tab-fg-selected, var(--kp-color-blue-600));\n }\n :host(.kp-tab--selected) .kp-tab__icon {\n color: var(--kp-color-tabs-tab-icon-selected, var(--kp-color-blue-600));\n }\n\n /* Disabled */\n :host(.kp-tab--disabled) {\n border-bottom-color: var(--kp-color-tabs-tab-underline-disabled, transparent);\n }\n :host(.kp-tab--disabled) .kp-tab__btn {\n color: var(--kp-color-tabs-tab-fg-disabled, var(--kp-color-gray-300));\n cursor: not-allowed;\n }\n :host(.kp-tab--disabled) .kp-tab__icon {\n color: var(--kp-color-tabs-tab-icon-disabled, var(--kp-color-gray-300));\n }\n\n /* Sizes */\n :host(.kp-tab--sm) {\n --kp-tab-h: 32px;\n --kp-tab-pad-x: 12px;\n --kp-tab-gap: 6px;\n --kp-tab-font-size: 14px;\n --kp-tab-line-height: 20px;\n --kp-tab-icon-size: 14px;\n }\n :host(.kp-tab--md) {\n --kp-tab-h: 40px;\n --kp-tab-pad-x: 16px;\n --kp-tab-gap: 8px;\n --kp-tab-font-size: 14px;\n --kp-tab-line-height: 20px;\n --kp-tab-icon-size: 16px;\n }\n :host(.kp-tab--lg) {\n --kp-tab-h: 48px;\n --kp-tab-pad-x: 20px;\n --kp-tab-gap: 8px;\n --kp-tab-font-size: 16px;\n --kp-tab-line-height: 24px;\n --kp-tab-icon-size: 16px;\n }\n `],\n})\nexport class KpTabComponent {\n @Input() size: KpTabSize = 'md';\n @Input() label = '';\n @Input() selected = false;\n @Input() disabled = false;\n /** Set by the parent `<kp-tabs>` when `fullWidth` is enabled on the container */\n @Input() fullWidth = false;\n\n @Output() selectedChange = new EventEmitter<boolean>();\n\n /** @internal — exposed so the parent `<kp-tabs>` can focus this tab's\n * inner button as part of its arrow-key roving-tabindex navigation. */\n readonly elementRef = inject(ElementRef) as ElementRef<HTMLElement>;\n\n get hostClasses(): string {\n const c = ['kp-tab', `kp-tab--${this.size}`];\n if (this.selected) c.push('kp-tab--selected');\n if (this.disabled) c.push('kp-tab--disabled');\n if (this.fullWidth) c.push('kp-tab--full-width');\n return c.join(' ');\n }\n\n handleClick(event: MouseEvent): void {\n if (this.disabled) {\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n this.selectedChange.emit(true);\n }\n\n handleKey(event: KeyboardEvent): void {\n if (event.key !== 'Enter' && event.key !== ' ') return;\n if (this.disabled) return;\n event.preventDefault();\n this.selectedChange.emit(true);\n }\n}\n","import {\n AfterContentInit,\n ChangeDetectionStrategy,\n Component,\n ContentChildren,\n ElementRef,\n Input,\n OnDestroy,\n QueryList,\n inject,\n} from '@angular/core';\nimport { Subject, takeUntil } from 'rxjs';\n\nimport { KpTabComponent, KpTabSize } from './tab.component';\n\n/**\n * Kanso Protocol — Tabs (container)\n *\n * Horizontal strip of `<kp-tab>` children with a shared bottom border.\n * Cascades `size` and `fullWidth` down to every projected `<kp-tab>`\n * automatically, so callers only set those two inputs in one place.\n *\n * A `[kpTabsMore]` slot projects an optional \"More ▾\" affordance to the\n * right of the strip — useful when tabs overflow and you want a dropdown\n * to hold the rest.\n *\n * @example\n * <kp-tabs size=\"md\" [fullWidth]=\"false\">\n * <kp-tab label=\"Overview\" [selected]=\"tab === 'overview'\" (selectedChange)=\"tab = 'overview'\"/>\n * <kp-tab label=\"Activity\" [selected]=\"tab === 'activity'\" (selectedChange)=\"tab = 'activity'\"/>\n * <kp-tab label=\"Settings\" [selected]=\"tab === 'settings'\" (selectedChange)=\"tab = 'settings'\"/>\n *\n * <button kpTabsMore>More ▾</button>\n * </kp-tabs>\n */\n@Component({\n selector: 'kp-tabs',\n imports: [],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[class]': 'hostClasses',\n '[attr.role]': '\"tablist\"',\n '(keydown)': 'onKeyDown($event)',\n },\n template: `\n <div class=\"kp-tabs__row\"><ng-content/></div>\n <div class=\"kp-tabs__more\"><ng-content select=\"[kpTabsMore]\"/></div>\n `,\n styles: [`\n :host {\n position: relative;\n display: flex;\n align-items: stretch;\n border-bottom: 1px solid var(--kp-color-tabs-track-border, var(--kp-color-gray-200));\n font-family: var(--kp-font-family-sans, 'Onest', system-ui, sans-serif);\n }\n\n .kp-tabs__row {\n display: flex;\n flex: 1 1 auto;\n /* The Tab atoms already carry their own border-bottom; no extra row chrome needed. */\n }\n :host(.kp-tabs--full-width) .kp-tabs__row > * { flex: 1 1 0; }\n\n .kp-tabs__more { display: inline-flex; flex: 0 0 auto; }\n .kp-tabs__more:empty { display: none; }\n `],\n})\nexport class KpTabsComponent implements AfterContentInit, OnDestroy {\n @Input() size: KpTabSize = 'md';\n @Input() fullWidth = false;\n\n @ContentChildren(KpTabComponent) tabs!: QueryList<KpTabComponent>;\n\n private readonly host = inject(ElementRef) as ElementRef<HTMLElement>;\n private readonly destroyed$ = new Subject<void>();\n\n ngAfterContentInit(): void {\n this.applyToTabs();\n this.tabs.changes.pipe(takeUntil(this.destroyed$)).subscribe(() => this.applyToTabs());\n }\n\n ngOnDestroy(): void {\n this.destroyed$.next();\n this.destroyed$.complete();\n }\n\n private applyToTabs(): void {\n this.tabs?.forEach((t) => {\n t.size = this.size;\n t.fullWidth = this.fullWidth;\n });\n }\n\n /**\n * WAI-ARIA tablist keyboard pattern:\n * ArrowLeft / ArrowRight — move to previous / next enabled tab (wraps around)\n * Home / End — jump to first / last enabled tab\n * Enter / Space — select the focused tab (native button handles this too)\n * Disabled tabs are skipped. Selection activates on focus change (automatic\n * activation) since our tab bodies are lightweight to render.\n */\n onKeyDown(event: KeyboardEvent): void {\n const all = this.tabs?.toArray() ?? [];\n const enabled = all.filter((t) => !t.disabled);\n if (!enabled.length) return;\n\n const active = this.activeTabIndex(enabled);\n let next: number | null = null;\n switch (event.key) {\n case 'ArrowRight': next = (active + 1) % enabled.length; break;\n case 'ArrowLeft': next = (active - 1 + enabled.length) % enabled.length; break;\n case 'Home': next = 0; break;\n case 'End': next = enabled.length - 1; break;\n default: return;\n }\n event.preventDefault();\n const target = enabled[next];\n // \"Consumer owns state\" — same pattern as click. Emit (selectedChange)\n // on the target tab and let the parent's [selected] binding propagate.\n if (!target.selected) target.selectedChange.emit(true);\n this.focusTab(target);\n }\n\n private activeTabIndex(enabled: KpTabComponent[]): number {\n const doc = this.host.nativeElement.ownerDocument;\n const focused = doc?.activeElement ?? null;\n const byFocus = enabled.findIndex((t) => t.elementRef.nativeElement.contains(focused));\n if (byFocus >= 0) return byFocus;\n const bySelection = enabled.findIndex((t) => t.selected);\n return bySelection >= 0 ? bySelection : 0;\n }\n\n private focusTab(tab: KpTabComponent): void {\n // The host element itself is the focusable target — it carries role=\"tab\"\n // and tabindex. The inner span is non-interactive (axe nested-interactive).\n tab.elementRef.nativeElement.focus();\n }\n\n get hostClasses(): string {\n const c = ['kp-tabs'];\n if (this.fullWidth) c.push('kp-tabs--full-width');\n return c.join(' ');\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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kanso-protocol/tabs",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "license": "MIT",
5
5
  "peerDependencies": {
6
6
  "@angular/core": "^18.0.0",
@@ -29,6 +29,7 @@ declare class KpTabComponent {
29
29
  readonly elementRef: ElementRef<HTMLElement>;
30
30
  get hostClasses(): string;
31
31
  handleClick(event: MouseEvent): void;
32
+ handleKey(event: KeyboardEvent): void;
32
33
  static ɵfac: i0.ɵɵFactoryDeclaration<KpTabComponent, never>;
33
34
  static ɵcmp: i0.ɵɵComponentDeclaration<KpTabComponent, "kp-tab", never, { "size": { "alias": "size"; "required": false; }; "label": { "alias": "label"; "required": false; }; "selected": { "alias": "selected"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "fullWidth": { "alias": "fullWidth"; "required": false; }; }, { "selectedChange": "selectedChange"; }, never, ["[kpTabIcon]", "[kpTabBadge]"], true, never>;
34
35
  }