@kanso-protocol/page-header 3.0.1 → 3.0.2

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.
@@ -37,12 +37,19 @@ class KpPageHeaderComponent {
37
37
  showActions = false;
38
38
  showTabs = false;
39
39
  showBottomDivider = true;
40
+ /**
41
+ * Cross-axis alignment of the back-button + title + actions row.
42
+ * Default 'start' (optical baseline alignment for multi-line headers
43
+ * with a description). 'center' for single-line headers where the
44
+ * back-button should sit mid-height with the title.
45
+ */
46
+ align = 'start';
40
47
  backClick = new EventEmitter();
41
48
  get hostClasses() {
42
- return `kp-page-header kp-page-header--${this.size}`;
49
+ return `kp-page-header kp-page-header--${this.size} kp-page-header--align-${this.align}`;
43
50
  }
44
51
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: KpPageHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
45
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.7", type: KpPageHeaderComponent, isStandalone: true, selector: "kp-page-header", inputs: { size: "size", title: "title", description: "description", showBreadcrumbs: "showBreadcrumbs", showBackButton: "showBackButton", showDescription: "showDescription", showActions: "showActions", showTabs: "showTabs", showBottomDivider: "showBottomDivider" }, outputs: { backClick: "backClick" }, host: { properties: { "class": "hostClasses" } }, ngImport: i0, template: `
52
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.7", type: KpPageHeaderComponent, isStandalone: true, selector: "kp-page-header", inputs: { size: "size", title: "title", description: "description", showBreadcrumbs: "showBreadcrumbs", showBackButton: "showBackButton", showDescription: "showDescription", showActions: "showActions", showTabs: "showTabs", showBottomDivider: "showBottomDivider", align: "align" }, outputs: { backClick: "backClick" }, host: { properties: { "class": "hostClasses", "style.--kp-ph-pad-bottom": "showBottomDivider ? null : '0px'" } }, ngImport: i0, template: `
46
53
  @if (showBreadcrumbs) {
47
54
  <div class="kp-page-header__crumbs">
48
55
  <ng-content select="[kpPageHeaderBreadcrumbs]"/>
@@ -81,11 +88,17 @@ class KpPageHeaderComponent {
81
88
  @if (showBottomDivider) {
82
89
  <div class="kp-page-header__divider" aria-hidden="true"></div>
83
90
  }
84
- `, isInline: true, styles: [":host{box-sizing:border-box;display:flex;flex-direction:column;width:100%;font-family:var(--kp-font-family-sans, \"Onest\", system-ui, sans-serif)}.kp-page-header__crumbs{margin-bottom:var(--kp-ph-gap-crumbs, 16px)}.kp-page-header__row{display:flex;align-items:flex-start;gap:16px;justify-content:space-between}.kp-page-header__left{display:flex;align-items:flex-start;gap:12px;flex:1 1 auto;min-width:0}.kp-page-header__back{all:unset;display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;margin-top:2px;border-radius:8px;color:var(--kp-color-text-muted);cursor:pointer;transition:background var(--kp-motion-duration-fast) ease}.kp-page-header__back:hover{background:var(--kp-color-surface-muted);color:var(--kp-color-text-strong)}.kp-page-header__back svg{width:20px;height:20px}.kp-page-header__text{display:flex;flex-direction:column;gap:var(--kp-ph-gap-text, 6px);min-width:0;flex:1 1 auto}.kp-page-header__title{margin:0;font-size:var(--kp-ph-title-fs, 24px);font-weight:var(--kp-ph-title-weight, 500);color:var(--kp-color-text-strong);line-height:1.2}.kp-page-header__desc{margin:0;font-size:var(--kp-ph-desc-fs, 14px);color:var(--kp-color-text-muted);line-height:1.5}.kp-page-header__actions{display:flex;align-items:center;gap:8px;flex:0 0 auto}.kp-page-header__tabs{margin-top:var(--kp-ph-gap-tabs, 24px)}.kp-page-header__divider{margin-top:var(--kp-ph-pad-bottom, 24px);height:1px;background:var(--kp-color-surface-strong)}:host(.kp-page-header--sm){--kp-ph-title-fs: 18px;--kp-ph-title-weight: 500;--kp-ph-desc-fs: 13px;--kp-ph-gap-text: 4px;--kp-ph-gap-crumbs: 12px;--kp-ph-gap-tabs: 16px;--kp-ph-pad-bottom: 16px}:host(.kp-page-header--md){--kp-ph-title-fs: 24px;--kp-ph-title-weight: 500;--kp-ph-desc-fs: 14px;--kp-ph-gap-text: 6px;--kp-ph-gap-crumbs: 16px;--kp-ph-gap-tabs: 24px;--kp-ph-pad-bottom: 24px}:host(.kp-page-header--lg){--kp-ph-title-fs: 30px;--kp-ph-title-weight: 600;--kp-ph-desc-fs: 16px;--kp-ph-gap-text: 8px;--kp-ph-gap-crumbs: 16px;--kp-ph-gap-tabs: 32px;--kp-ph-pad-bottom: 32px}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
91
+ `, isInline: true, styles: [":host{box-sizing:border-box;display:flex;flex-direction:column;width:100%;font-family:var(--kp-font-family-sans, \"Onest\", system-ui, sans-serif)}.kp-page-header__crumbs{margin-bottom:var(--kp-ph-gap-crumbs, 16px)}.kp-page-header__row{display:flex;align-items:flex-start;gap:16px;justify-content:space-between}:host(.kp-page-header--align-center) .kp-page-header__row,:host(.kp-page-header--align-center) .kp-page-header__left{align-items:center}:host(.kp-page-header--align-end) .kp-page-header__row,:host(.kp-page-header--align-end) .kp-page-header__left{align-items:flex-end}:host(.kp-page-header--align-center) .kp-page-header__back,:host(.kp-page-header--align-end) .kp-page-header__back{margin-top:0}.kp-page-header__left{display:flex;align-items:flex-start;gap:12px;flex:1 1 auto;min-width:0}.kp-page-header__back{all:unset;display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;margin-top:2px;border-radius:8px;color:var(--kp-color-text-muted);cursor:pointer;transition:background var(--kp-motion-duration-fast) ease}.kp-page-header__back:hover{background:var(--kp-color-surface-muted);color:var(--kp-color-text-strong)}.kp-page-header__back svg{width:20px;height:20px}.kp-page-header__text{display:flex;flex-direction:column;gap:var(--kp-ph-gap-text, 6px);min-width:0;flex:1 1 auto}.kp-page-header__title{margin:0;font-size:var(--kp-ph-title-fs, 24px);font-weight:var(--kp-ph-title-weight, 500);color:var(--kp-color-text-strong);line-height:1.2}.kp-page-header__desc{margin:0;font-size:var(--kp-ph-desc-fs, 14px);color:var(--kp-color-text-muted);line-height:1.5}.kp-page-header__actions{display:flex;align-items:center;gap:8px;flex:0 0 auto}.kp-page-header__tabs{margin-top:var(--kp-ph-gap-tabs, 24px)}.kp-page-header__divider{margin-top:var(--kp-ph-pad-bottom, 24px);height:1px;background:var(--kp-color-surface-strong)}:host(.kp-page-header--sm){--kp-ph-title-fs: 18px;--kp-ph-title-weight: 500;--kp-ph-desc-fs: 13px;--kp-ph-gap-text: 4px;--kp-ph-gap-crumbs: 12px;--kp-ph-gap-tabs: 16px;--kp-ph-pad-bottom: 16px}:host(.kp-page-header--md){--kp-ph-title-fs: 24px;--kp-ph-title-weight: 500;--kp-ph-desc-fs: 14px;--kp-ph-gap-text: 6px;--kp-ph-gap-crumbs: 16px;--kp-ph-gap-tabs: 24px;--kp-ph-pad-bottom: 24px}:host(.kp-page-header--lg){--kp-ph-title-fs: 30px;--kp-ph-title-weight: 600;--kp-ph-desc-fs: 16px;--kp-ph-gap-text: 8px;--kp-ph-gap-crumbs: 16px;--kp-ph-gap-tabs: 32px;--kp-ph-pad-bottom: 32px}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
85
92
  }
86
93
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: KpPageHeaderComponent, decorators: [{
87
94
  type: Component,
88
- args: [{ selector: 'kp-page-header', imports: [], changeDetection: ChangeDetectionStrategy.OnPush, host: { '[class]': 'hostClasses' }, template: `
95
+ args: [{ selector: 'kp-page-header', imports: [], changeDetection: ChangeDetectionStrategy.OnPush, host: {
96
+ '[class]': 'hostClasses',
97
+ /* When the bottom divider is hidden, zero the public --kp-ph-pad-bottom
98
+ hook so consumers using it for downstream layout don't see a phantom
99
+ 24px gap below the header. */
100
+ '[style.--kp-ph-pad-bottom]': "showBottomDivider ? null : '0px'",
101
+ }, template: `
89
102
  @if (showBreadcrumbs) {
90
103
  <div class="kp-page-header__crumbs">
91
104
  <ng-content select="[kpPageHeaderBreadcrumbs]"/>
@@ -124,7 +137,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
124
137
  @if (showBottomDivider) {
125
138
  <div class="kp-page-header__divider" aria-hidden="true"></div>
126
139
  }
127
- `, styles: [":host{box-sizing:border-box;display:flex;flex-direction:column;width:100%;font-family:var(--kp-font-family-sans, \"Onest\", system-ui, sans-serif)}.kp-page-header__crumbs{margin-bottom:var(--kp-ph-gap-crumbs, 16px)}.kp-page-header__row{display:flex;align-items:flex-start;gap:16px;justify-content:space-between}.kp-page-header__left{display:flex;align-items:flex-start;gap:12px;flex:1 1 auto;min-width:0}.kp-page-header__back{all:unset;display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;margin-top:2px;border-radius:8px;color:var(--kp-color-text-muted);cursor:pointer;transition:background var(--kp-motion-duration-fast) ease}.kp-page-header__back:hover{background:var(--kp-color-surface-muted);color:var(--kp-color-text-strong)}.kp-page-header__back svg{width:20px;height:20px}.kp-page-header__text{display:flex;flex-direction:column;gap:var(--kp-ph-gap-text, 6px);min-width:0;flex:1 1 auto}.kp-page-header__title{margin:0;font-size:var(--kp-ph-title-fs, 24px);font-weight:var(--kp-ph-title-weight, 500);color:var(--kp-color-text-strong);line-height:1.2}.kp-page-header__desc{margin:0;font-size:var(--kp-ph-desc-fs, 14px);color:var(--kp-color-text-muted);line-height:1.5}.kp-page-header__actions{display:flex;align-items:center;gap:8px;flex:0 0 auto}.kp-page-header__tabs{margin-top:var(--kp-ph-gap-tabs, 24px)}.kp-page-header__divider{margin-top:var(--kp-ph-pad-bottom, 24px);height:1px;background:var(--kp-color-surface-strong)}:host(.kp-page-header--sm){--kp-ph-title-fs: 18px;--kp-ph-title-weight: 500;--kp-ph-desc-fs: 13px;--kp-ph-gap-text: 4px;--kp-ph-gap-crumbs: 12px;--kp-ph-gap-tabs: 16px;--kp-ph-pad-bottom: 16px}:host(.kp-page-header--md){--kp-ph-title-fs: 24px;--kp-ph-title-weight: 500;--kp-ph-desc-fs: 14px;--kp-ph-gap-text: 6px;--kp-ph-gap-crumbs: 16px;--kp-ph-gap-tabs: 24px;--kp-ph-pad-bottom: 24px}:host(.kp-page-header--lg){--kp-ph-title-fs: 30px;--kp-ph-title-weight: 600;--kp-ph-desc-fs: 16px;--kp-ph-gap-text: 8px;--kp-ph-gap-crumbs: 16px;--kp-ph-gap-tabs: 32px;--kp-ph-pad-bottom: 32px}\n"] }]
140
+ `, styles: [":host{box-sizing:border-box;display:flex;flex-direction:column;width:100%;font-family:var(--kp-font-family-sans, \"Onest\", system-ui, sans-serif)}.kp-page-header__crumbs{margin-bottom:var(--kp-ph-gap-crumbs, 16px)}.kp-page-header__row{display:flex;align-items:flex-start;gap:16px;justify-content:space-between}:host(.kp-page-header--align-center) .kp-page-header__row,:host(.kp-page-header--align-center) .kp-page-header__left{align-items:center}:host(.kp-page-header--align-end) .kp-page-header__row,:host(.kp-page-header--align-end) .kp-page-header__left{align-items:flex-end}:host(.kp-page-header--align-center) .kp-page-header__back,:host(.kp-page-header--align-end) .kp-page-header__back{margin-top:0}.kp-page-header__left{display:flex;align-items:flex-start;gap:12px;flex:1 1 auto;min-width:0}.kp-page-header__back{all:unset;display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;margin-top:2px;border-radius:8px;color:var(--kp-color-text-muted);cursor:pointer;transition:background var(--kp-motion-duration-fast) ease}.kp-page-header__back:hover{background:var(--kp-color-surface-muted);color:var(--kp-color-text-strong)}.kp-page-header__back svg{width:20px;height:20px}.kp-page-header__text{display:flex;flex-direction:column;gap:var(--kp-ph-gap-text, 6px);min-width:0;flex:1 1 auto}.kp-page-header__title{margin:0;font-size:var(--kp-ph-title-fs, 24px);font-weight:var(--kp-ph-title-weight, 500);color:var(--kp-color-text-strong);line-height:1.2}.kp-page-header__desc{margin:0;font-size:var(--kp-ph-desc-fs, 14px);color:var(--kp-color-text-muted);line-height:1.5}.kp-page-header__actions{display:flex;align-items:center;gap:8px;flex:0 0 auto}.kp-page-header__tabs{margin-top:var(--kp-ph-gap-tabs, 24px)}.kp-page-header__divider{margin-top:var(--kp-ph-pad-bottom, 24px);height:1px;background:var(--kp-color-surface-strong)}:host(.kp-page-header--sm){--kp-ph-title-fs: 18px;--kp-ph-title-weight: 500;--kp-ph-desc-fs: 13px;--kp-ph-gap-text: 4px;--kp-ph-gap-crumbs: 12px;--kp-ph-gap-tabs: 16px;--kp-ph-pad-bottom: 16px}:host(.kp-page-header--md){--kp-ph-title-fs: 24px;--kp-ph-title-weight: 500;--kp-ph-desc-fs: 14px;--kp-ph-gap-text: 6px;--kp-ph-gap-crumbs: 16px;--kp-ph-gap-tabs: 24px;--kp-ph-pad-bottom: 24px}:host(.kp-page-header--lg){--kp-ph-title-fs: 30px;--kp-ph-title-weight: 600;--kp-ph-desc-fs: 16px;--kp-ph-gap-text: 8px;--kp-ph-gap-crumbs: 16px;--kp-ph-gap-tabs: 32px;--kp-ph-pad-bottom: 32px}\n"] }]
128
141
  }], propDecorators: { size: [{
129
142
  type: Input
130
143
  }], title: [{
@@ -143,6 +156,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
143
156
  type: Input
144
157
  }], showBottomDivider: [{
145
158
  type: Input
159
+ }], align: [{
160
+ type: Input
146
161
  }], backClick: [{
147
162
  type: Output
148
163
  }] } });
@@ -1 +1 @@
1
- {"version":3,"file":"kanso-protocol-page-header.mjs","sources":["../../../../../packages/patterns/page-header/src/page-header.component.ts","../../../../../packages/patterns/page-header/src/kanso-protocol-page-header.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n EventEmitter,\n Input,\n Output,\n} from '@angular/core';\n\nexport type KpPageHeaderSize = 'sm' | 'md' | 'lg';\n\n/**\n * Kanso Protocol — PageHeader\n *\n * Content-area header. Three sizes, optional breadcrumbs, back button,\n * description, actions slot, tabs slot, and bottom divider.\n *\n * Slots (all optional):\n * - `[kpPageHeaderBreadcrumbs]` — Breadcrumbs instance\n * - `[kpPageHeaderTitle]` — custom title (e.g. title + inline Badge)\n * - `[kpPageHeaderActions]` — action buttons on the right\n * - `[kpPageHeaderTabs]` — Tabs instance under the header\n *\n * @example\n * <kp-page-header\n * size=\"md\"\n * title=\"All projects\"\n * description=\"12 active projects\"\n * [showActions]=\"true\"\n * >\n * <kp-breadcrumbs kpPageHeaderBreadcrumbs [items]=\"crumbs\"/>\n * <div kpPageHeaderActions>\n * <button kpButton appearance=\"ghost\">Import</button>\n * <button kpButton>Create</button>\n * </div>\n * </kp-page-header>\n */\n@Component({\n selector: 'kp-page-header',\n imports: [],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: { '[class]': 'hostClasses' },\n template: `\n @if (showBreadcrumbs) {\n <div class=\"kp-page-header__crumbs\">\n <ng-content select=\"[kpPageHeaderBreadcrumbs]\"/>\n </div>\n }\n\n <div class=\"kp-page-header__row\">\n <div class=\"kp-page-header__left\">\n @if (showBackButton) {\n <button type=\"button\" class=\"kp-page-header__back\" aria-label=\"Back\" (click)=\"backClick.emit()\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.75\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M5 12h14M5 12l6-6M5 12l6 6\"/></svg>\n </button>\n }\n <div class=\"kp-page-header__text\">\n <ng-content select=\"[kpPageHeaderTitle]\">\n <h1 class=\"kp-page-header__title\">{{ title }}</h1>\n </ng-content>\n @if (showDescription && description) {\n <p class=\"kp-page-header__desc\">{{ description }}</p>\n }\n </div>\n </div>\n @if (showActions) {\n <div class=\"kp-page-header__actions\">\n <ng-content select=\"[kpPageHeaderActions]\"/>\n </div>\n }\n </div>\n\n @if (showTabs) {\n <div class=\"kp-page-header__tabs\">\n <ng-content select=\"[kpPageHeaderTabs]\"/>\n </div>\n }\n\n @if (showBottomDivider) {\n <div class=\"kp-page-header__divider\" aria-hidden=\"true\"></div>\n }\n `,\n styles: [`\n :host {\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n width: 100%;\n font-family: var(--kp-font-family-sans, 'Onest', system-ui, sans-serif);\n }\n\n .kp-page-header__crumbs {\n margin-bottom: var(--kp-ph-gap-crumbs, 16px);\n }\n\n .kp-page-header__row {\n display: flex;\n align-items: flex-start;\n gap: 16px;\n justify-content: space-between;\n }\n\n .kp-page-header__left {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n flex: 1 1 auto;\n min-width: 0;\n }\n\n .kp-page-header__back {\n all: unset;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 36px;\n height: 36px;\n margin-top: 2px;\n border-radius: 8px;\n color: var(--kp-color-text-muted);\n cursor: pointer;\n transition: background var(--kp-motion-duration-fast) ease;\n }\n .kp-page-header__back:hover { background: var(--kp-color-surface-muted); color: var(--kp-color-text-strong); }\n .kp-page-header__back svg { width: 20px; height: 20px; }\n\n .kp-page-header__text {\n display: flex;\n flex-direction: column;\n gap: var(--kp-ph-gap-text, 6px);\n min-width: 0;\n flex: 1 1 auto;\n }\n\n .kp-page-header__title {\n margin: 0;\n font-size: var(--kp-ph-title-fs, 24px);\n font-weight: var(--kp-ph-title-weight, 500);\n color: var(--kp-color-text-strong);\n line-height: 1.2;\n }\n\n .kp-page-header__desc {\n margin: 0;\n font-size: var(--kp-ph-desc-fs, 14px);\n color: var(--kp-color-text-muted);\n line-height: 1.5;\n }\n\n .kp-page-header__actions {\n display: flex;\n align-items: center;\n gap: 8px;\n flex: 0 0 auto;\n }\n\n .kp-page-header__tabs {\n margin-top: var(--kp-ph-gap-tabs, 24px);\n }\n\n .kp-page-header__divider {\n margin-top: var(--kp-ph-pad-bottom, 24px);\n height: 1px;\n background: var(--kp-color-surface-strong);\n }\n\n :host(.kp-page-header--sm) {\n --kp-ph-title-fs: 18px;\n --kp-ph-title-weight: 500;\n --kp-ph-desc-fs: 13px;\n --kp-ph-gap-text: 4px;\n --kp-ph-gap-crumbs: 12px;\n --kp-ph-gap-tabs: 16px;\n --kp-ph-pad-bottom: 16px;\n }\n :host(.kp-page-header--md) {\n --kp-ph-title-fs: 24px;\n --kp-ph-title-weight: 500;\n --kp-ph-desc-fs: 14px;\n --kp-ph-gap-text: 6px;\n --kp-ph-gap-crumbs: 16px;\n --kp-ph-gap-tabs: 24px;\n --kp-ph-pad-bottom: 24px;\n }\n :host(.kp-page-header--lg) {\n --kp-ph-title-fs: 30px;\n --kp-ph-title-weight: 600;\n --kp-ph-desc-fs: 16px;\n --kp-ph-gap-text: 8px;\n --kp-ph-gap-crumbs: 16px;\n --kp-ph-gap-tabs: 32px;\n --kp-ph-pad-bottom: 32px;\n }\n `],\n})\nexport class KpPageHeaderComponent {\n @Input() size: KpPageHeaderSize = 'md';\n\n @Input() title = 'Page title';\n @Input() description: string | null = null;\n\n @Input() showBreadcrumbs = false;\n @Input() showBackButton = false;\n @Input() showDescription = false;\n @Input() showActions = false;\n @Input() showTabs = false;\n @Input() showBottomDivider = true;\n\n @Output() backClick = new EventEmitter<void>();\n\n get hostClasses(): string {\n return `kp-page-header kp-page-header--${this.size}`;\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;AAUA;;;;;;;;;;;;;;;;;;;;;;;;;AAyBG;MA+JU,qBAAqB,CAAA;IACvB,IAAI,GAAqB,IAAI;IAE7B,KAAK,GAAG,YAAY;IACpB,WAAW,GAAkB,IAAI;IAEjC,eAAe,GAAG,KAAK;IACvB,cAAc,GAAG,KAAK;IACtB,eAAe,GAAG,KAAK;IACvB,WAAW,GAAG,KAAK;IACnB,QAAQ,GAAG,KAAK;IAChB,iBAAiB,GAAG,IAAI;AAEvB,IAAA,SAAS,GAAG,IAAI,YAAY,EAAQ;AAE9C,IAAA,IAAI,WAAW,GAAA;AACb,QAAA,OAAO,CAAA,+BAAA,EAAkC,IAAI,CAAC,IAAI,EAAE;IACtD;uGAjBW,qBAAqB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAArB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,qBAAqB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,gBAAA,EAAA,MAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,KAAA,EAAA,OAAA,EAAA,WAAA,EAAA,aAAA,EAAA,eAAA,EAAA,iBAAA,EAAA,cAAA,EAAA,gBAAA,EAAA,eAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,aAAA,EAAA,QAAA,EAAA,UAAA,EAAA,iBAAA,EAAA,mBAAA,EAAA,EAAA,OAAA,EAAA,EAAA,SAAA,EAAA,WAAA,EAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,OAAA,EAAA,aAAA,EAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAzJtB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,ggEAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAkHU,qBAAqB,EAAA,UAAA,EAAA,CAAA;kBA9JjC,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,gBAAgB,EAAA,OAAA,EACjB,EAAE,EAAA,eAAA,EACM,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC,EAAE,SAAS,EAAE,aAAa,EAAE,EAAA,QAAA,EACxB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCT,EAAA,CAAA,EAAA,MAAA,EAAA,CAAA,ggEAAA,CAAA,EAAA;;sBAmHA;;sBAEA;;sBACA;;sBAEA;;sBACA;;sBACA;;sBACA;;sBACA;;sBACA;;sBAEA;;;AC/MH;;AAEG;;;;"}
1
+ {"version":3,"file":"kanso-protocol-page-header.mjs","sources":["../../../../../packages/patterns/page-header/src/page-header.component.ts","../../../../../packages/patterns/page-header/src/kanso-protocol-page-header.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n EventEmitter,\n Input,\n Output,\n} from '@angular/core';\n\nexport type KpPageHeaderSize = 'sm' | 'md' | 'lg';\nexport type KpPageHeaderAlign = 'start' | 'center' | 'end';\n\n/**\n * Kanso Protocol — PageHeader\n *\n * Content-area header. Three sizes, optional breadcrumbs, back button,\n * description, actions slot, tabs slot, and bottom divider.\n *\n * Slots (all optional):\n * - `[kpPageHeaderBreadcrumbs]` — Breadcrumbs instance\n * - `[kpPageHeaderTitle]` — custom title (e.g. title + inline Badge)\n * - `[kpPageHeaderActions]` — action buttons on the right\n * - `[kpPageHeaderTabs]` — Tabs instance under the header\n *\n * @example\n * <kp-page-header\n * size=\"md\"\n * title=\"All projects\"\n * description=\"12 active projects\"\n * [showActions]=\"true\"\n * >\n * <kp-breadcrumbs kpPageHeaderBreadcrumbs [items]=\"crumbs\"/>\n * <div kpPageHeaderActions>\n * <button kpButton appearance=\"ghost\">Import</button>\n * <button kpButton>Create</button>\n * </div>\n * </kp-page-header>\n */\n@Component({\n selector: 'kp-page-header',\n imports: [],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[class]': 'hostClasses',\n /* When the bottom divider is hidden, zero the public --kp-ph-pad-bottom\n hook so consumers using it for downstream layout don't see a phantom\n 24px gap below the header. */\n '[style.--kp-ph-pad-bottom]': \"showBottomDivider ? null : '0px'\",\n },\n template: `\n @if (showBreadcrumbs) {\n <div class=\"kp-page-header__crumbs\">\n <ng-content select=\"[kpPageHeaderBreadcrumbs]\"/>\n </div>\n }\n\n <div class=\"kp-page-header__row\">\n <div class=\"kp-page-header__left\">\n @if (showBackButton) {\n <button type=\"button\" class=\"kp-page-header__back\" aria-label=\"Back\" (click)=\"backClick.emit()\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.75\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M5 12h14M5 12l6-6M5 12l6 6\"/></svg>\n </button>\n }\n <div class=\"kp-page-header__text\">\n <ng-content select=\"[kpPageHeaderTitle]\">\n <h1 class=\"kp-page-header__title\">{{ title }}</h1>\n </ng-content>\n @if (showDescription && description) {\n <p class=\"kp-page-header__desc\">{{ description }}</p>\n }\n </div>\n </div>\n @if (showActions) {\n <div class=\"kp-page-header__actions\">\n <ng-content select=\"[kpPageHeaderActions]\"/>\n </div>\n }\n </div>\n\n @if (showTabs) {\n <div class=\"kp-page-header__tabs\">\n <ng-content select=\"[kpPageHeaderTabs]\"/>\n </div>\n }\n\n @if (showBottomDivider) {\n <div class=\"kp-page-header__divider\" aria-hidden=\"true\"></div>\n }\n `,\n styles: [`\n :host {\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n width: 100%;\n font-family: var(--kp-font-family-sans, 'Onest', system-ui, sans-serif);\n }\n\n .kp-page-header__crumbs {\n margin-bottom: var(--kp-ph-gap-crumbs, 16px);\n }\n\n .kp-page-header__row {\n display: flex;\n align-items: flex-start;\n gap: 16px;\n justify-content: space-between;\n }\n :host(.kp-page-header--align-center) .kp-page-header__row,\n :host(.kp-page-header--align-center) .kp-page-header__left {\n align-items: center;\n }\n :host(.kp-page-header--align-end) .kp-page-header__row,\n :host(.kp-page-header--align-end) .kp-page-header__left {\n align-items: flex-end;\n }\n /* The default 2px back-button offset is a baseline-alignment trick\n for the start case (multi-line text block). When align=center/end,\n parent flex already lines things up — kill the manual offset. */\n :host(.kp-page-header--align-center) .kp-page-header__back,\n :host(.kp-page-header--align-end) .kp-page-header__back {\n margin-top: 0;\n }\n\n .kp-page-header__left {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n flex: 1 1 auto;\n min-width: 0;\n }\n\n .kp-page-header__back {\n all: unset;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 36px;\n height: 36px;\n margin-top: 2px;\n border-radius: 8px;\n color: var(--kp-color-text-muted);\n cursor: pointer;\n transition: background var(--kp-motion-duration-fast) ease;\n }\n .kp-page-header__back:hover { background: var(--kp-color-surface-muted); color: var(--kp-color-text-strong); }\n .kp-page-header__back svg { width: 20px; height: 20px; }\n\n .kp-page-header__text {\n display: flex;\n flex-direction: column;\n gap: var(--kp-ph-gap-text, 6px);\n min-width: 0;\n flex: 1 1 auto;\n }\n\n .kp-page-header__title {\n margin: 0;\n font-size: var(--kp-ph-title-fs, 24px);\n font-weight: var(--kp-ph-title-weight, 500);\n color: var(--kp-color-text-strong);\n line-height: 1.2;\n }\n\n .kp-page-header__desc {\n margin: 0;\n font-size: var(--kp-ph-desc-fs, 14px);\n color: var(--kp-color-text-muted);\n line-height: 1.5;\n }\n\n .kp-page-header__actions {\n display: flex;\n align-items: center;\n gap: 8px;\n flex: 0 0 auto;\n }\n\n .kp-page-header__tabs {\n margin-top: var(--kp-ph-gap-tabs, 24px);\n }\n\n .kp-page-header__divider {\n margin-top: var(--kp-ph-pad-bottom, 24px);\n height: 1px;\n background: var(--kp-color-surface-strong);\n }\n\n :host(.kp-page-header--sm) {\n --kp-ph-title-fs: 18px;\n --kp-ph-title-weight: 500;\n --kp-ph-desc-fs: 13px;\n --kp-ph-gap-text: 4px;\n --kp-ph-gap-crumbs: 12px;\n --kp-ph-gap-tabs: 16px;\n --kp-ph-pad-bottom: 16px;\n }\n :host(.kp-page-header--md) {\n --kp-ph-title-fs: 24px;\n --kp-ph-title-weight: 500;\n --kp-ph-desc-fs: 14px;\n --kp-ph-gap-text: 6px;\n --kp-ph-gap-crumbs: 16px;\n --kp-ph-gap-tabs: 24px;\n --kp-ph-pad-bottom: 24px;\n }\n :host(.kp-page-header--lg) {\n --kp-ph-title-fs: 30px;\n --kp-ph-title-weight: 600;\n --kp-ph-desc-fs: 16px;\n --kp-ph-gap-text: 8px;\n --kp-ph-gap-crumbs: 16px;\n --kp-ph-gap-tabs: 32px;\n --kp-ph-pad-bottom: 32px;\n }\n `],\n})\nexport class KpPageHeaderComponent {\n @Input() size: KpPageHeaderSize = 'md';\n\n @Input() title = 'Page title';\n @Input() description: string | null = null;\n\n @Input() showBreadcrumbs = false;\n @Input() showBackButton = false;\n @Input() showDescription = false;\n @Input() showActions = false;\n @Input() showTabs = false;\n @Input() showBottomDivider = true;\n /**\n * Cross-axis alignment of the back-button + title + actions row.\n * Default 'start' (optical baseline alignment for multi-line headers\n * with a description). 'center' for single-line headers where the\n * back-button should sit mid-height with the title.\n */\n @Input() align: KpPageHeaderAlign = 'start';\n\n @Output() backClick = new EventEmitter<void>();\n\n get hostClasses(): string {\n return `kp-page-header kp-page-header--${this.size} kp-page-header--align-${this.align}`;\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;AAWA;;;;;;;;;;;;;;;;;;;;;;;;;AAyBG;MAoLU,qBAAqB,CAAA;IACvB,IAAI,GAAqB,IAAI;IAE7B,KAAK,GAAG,YAAY;IACpB,WAAW,GAAkB,IAAI;IAEjC,eAAe,GAAG,KAAK;IACvB,cAAc,GAAG,KAAK;IACtB,eAAe,GAAG,KAAK;IACvB,WAAW,GAAG,KAAK;IACnB,QAAQ,GAAG,KAAK;IAChB,iBAAiB,GAAG,IAAI;AACjC;;;;;AAKG;IACM,KAAK,GAAsB,OAAO;AAEjC,IAAA,SAAS,GAAG,IAAI,YAAY,EAAQ;AAE9C,IAAA,IAAI,WAAW,GAAA;QACb,OAAO,CAAA,+BAAA,EAAkC,IAAI,CAAC,IAAI,0BAA0B,IAAI,CAAC,KAAK,CAAA,CAAE;IAC1F;uGAxBW,qBAAqB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAArB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,qBAAqB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,gBAAA,EAAA,MAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,KAAA,EAAA,OAAA,EAAA,WAAA,EAAA,aAAA,EAAA,eAAA,EAAA,iBAAA,EAAA,cAAA,EAAA,gBAAA,EAAA,eAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,aAAA,EAAA,QAAA,EAAA,UAAA,EAAA,iBAAA,EAAA,mBAAA,EAAA,KAAA,EAAA,OAAA,EAAA,EAAA,OAAA,EAAA,EAAA,SAAA,EAAA,WAAA,EAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,OAAA,EAAA,aAAA,EAAA,0BAAA,EAAA,kCAAA,EAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAxKtB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,44EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAiIU,qBAAqB,EAAA,UAAA,EAAA,CAAA;kBAnLjC,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,gBAAgB,WACjB,EAAE,EAAA,eAAA,EACM,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC;AACJ,wBAAA,SAAS,EAAE,aAAa;AACxB;;AAEgC;AAChC,wBAAA,4BAA4B,EAAE,kCAAkC;qBACjE,EAAA,QAAA,EACS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCT,EAAA,CAAA,EAAA,MAAA,EAAA,CAAA,44EAAA,CAAA,EAAA;;sBAkIA;;sBAEA;;sBACA;;sBAEA;;sBACA;;sBACA;;sBACA;;sBACA;;sBACA;;sBAOA;;sBAEA;;;AC5OH;;AAEG;;;;"}
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@kanso-protocol/page-header",
3
- "version": "3.0.1",
3
+ "version": "3.0.2",
4
4
  "license": "MIT",
5
5
  "peerDependencies": {
6
6
  "@angular/core": ">=21.0.0",
7
7
  "@angular/common": ">=21.0.0",
8
- "@kanso-protocol/core": ">=3.0.1"
8
+ "@kanso-protocol/core": ">=3.0.2"
9
9
  },
10
10
  "description": "Kanso Protocol — page-header (pattern).",
11
11
  "author": "GregNBlack",
@@ -2,6 +2,7 @@ import * as i0 from '@angular/core';
2
2
  import { EventEmitter } from '@angular/core';
3
3
 
4
4
  type KpPageHeaderSize = 'sm' | 'md' | 'lg';
5
+ type KpPageHeaderAlign = 'start' | 'center' | 'end';
5
6
  /**
6
7
  * Kanso Protocol — PageHeader
7
8
  *
@@ -38,11 +39,18 @@ declare class KpPageHeaderComponent {
38
39
  showActions: boolean;
39
40
  showTabs: boolean;
40
41
  showBottomDivider: boolean;
42
+ /**
43
+ * Cross-axis alignment of the back-button + title + actions row.
44
+ * Default 'start' (optical baseline alignment for multi-line headers
45
+ * with a description). 'center' for single-line headers where the
46
+ * back-button should sit mid-height with the title.
47
+ */
48
+ align: KpPageHeaderAlign;
41
49
  backClick: EventEmitter<void>;
42
50
  get hostClasses(): string;
43
51
  static ɵfac: i0.ɵɵFactoryDeclaration<KpPageHeaderComponent, never>;
44
- static ɵcmp: i0.ɵɵComponentDeclaration<KpPageHeaderComponent, "kp-page-header", never, { "size": { "alias": "size"; "required": false; }; "title": { "alias": "title"; "required": false; }; "description": { "alias": "description"; "required": false; }; "showBreadcrumbs": { "alias": "showBreadcrumbs"; "required": false; }; "showBackButton": { "alias": "showBackButton"; "required": false; }; "showDescription": { "alias": "showDescription"; "required": false; }; "showActions": { "alias": "showActions"; "required": false; }; "showTabs": { "alias": "showTabs"; "required": false; }; "showBottomDivider": { "alias": "showBottomDivider"; "required": false; }; }, { "backClick": "backClick"; }, never, ["[kpPageHeaderBreadcrumbs]", "[kpPageHeaderTitle]", "[kpPageHeaderActions]", "[kpPageHeaderTabs]"], true, never>;
52
+ static ɵcmp: i0.ɵɵComponentDeclaration<KpPageHeaderComponent, "kp-page-header", never, { "size": { "alias": "size"; "required": false; }; "title": { "alias": "title"; "required": false; }; "description": { "alias": "description"; "required": false; }; "showBreadcrumbs": { "alias": "showBreadcrumbs"; "required": false; }; "showBackButton": { "alias": "showBackButton"; "required": false; }; "showDescription": { "alias": "showDescription"; "required": false; }; "showActions": { "alias": "showActions"; "required": false; }; "showTabs": { "alias": "showTabs"; "required": false; }; "showBottomDivider": { "alias": "showBottomDivider"; "required": false; }; "align": { "alias": "align"; "required": false; }; }, { "backClick": "backClick"; }, never, ["[kpPageHeaderBreadcrumbs]", "[kpPageHeaderTitle]", "[kpPageHeaderActions]", "[kpPageHeaderTabs]"], true, never>;
45
53
  }
46
54
 
47
55
  export { KpPageHeaderComponent };
48
- export type { KpPageHeaderSize };
56
+ export type { KpPageHeaderAlign, KpPageHeaderSize };