@memberjunction/ng-ui-components 5.35.0 → 5.36.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.
- package/dist/lib/button/button.scss +7 -3
- package/dist/lib/filter-popover/filter-popover.component.d.ts.map +1 -1
- package/dist/lib/filter-popover/filter-popover.component.js +3 -3
- package/dist/lib/filter-popover/filter-popover.component.js.map +1 -1
- package/dist/lib/left-nav/left-nav-content.component.d.ts +53 -0
- package/dist/lib/left-nav/left-nav-content.component.d.ts.map +1 -0
- package/dist/lib/left-nav/left-nav-content.component.js +121 -0
- package/dist/lib/left-nav/left-nav-content.component.js.map +1 -0
- package/dist/lib/left-nav/left-nav.component.d.ts +137 -0
- package/dist/lib/left-nav/left-nav.component.d.ts.map +1 -0
- package/dist/lib/left-nav/left-nav.component.js +399 -0
- package/dist/lib/left-nav/left-nav.component.js.map +1 -0
- package/dist/lib/page-body/page-body.component.d.ts +12 -2
- package/dist/lib/page-body/page-body.component.d.ts.map +1 -1
- package/dist/lib/page-body/page-body.component.js +24 -7
- package/dist/lib/page-body/page-body.component.js.map +1 -1
- package/dist/lib/page-body-interior/page-body-interior.component.d.ts +62 -0
- package/dist/lib/page-body-interior/page-body-interior.component.d.ts.map +1 -0
- package/dist/lib/page-body-interior/page-body-interior.component.js +95 -0
- package/dist/lib/page-body-interior/page-body-interior.component.js.map +1 -0
- package/dist/lib/page-header/page-header.component.d.ts +12 -4
- package/dist/lib/page-header/page-header.component.d.ts.map +1 -1
- package/dist/lib/page-header/page-header.component.js +33 -28
- package/dist/lib/page-header/page-header.component.js.map +1 -1
- package/dist/lib/page-header/page-header.scss +30 -9
- package/dist/lib/page-header-interior/page-header-interior.component.d.ts +96 -0
- package/dist/lib/page-header-interior/page-header-interior.component.d.ts.map +1 -0
- package/dist/lib/page-header-interior/page-header-interior.component.js +176 -0
- package/dist/lib/page-header-interior/page-header-interior.component.js.map +1 -0
- package/dist/public-api.d.ts +4 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +4 -0
- package/dist/public-api.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import * as i0 from "@angular/core";
|
|
2
|
+
/**
|
|
3
|
+
* `<mj-page-body-interior>` — Body-region sibling of `<mj-page-header-interior>`.
|
|
4
|
+
*
|
|
5
|
+
* Paired primitive for sub-pages that render inside a left-nav workspace shell.
|
|
6
|
+
* Where `<mj-page-body>` is for top-level pages (sits inside `<mj-page-layout>`),
|
|
7
|
+
* this component is for sub-pages whose host element already has the flex-column
|
|
8
|
+
* layout (typically via `_admin-patterns.css`'s `:host` rule or an equivalent).
|
|
9
|
+
*
|
|
10
|
+
* Owns:
|
|
11
|
+
* - `flex: 1` so it fills the space below `<mj-page-header-interior>`.
|
|
12
|
+
* - `overflow-y: auto` so the body scrolls (the host typically has `overflow: hidden`).
|
|
13
|
+
* - Responsive padding: 16px on mobile, 24px at 768px+, 32px at 1024px+.
|
|
14
|
+
* Mirrors the bespoke `.scrollable-content` rules in
|
|
15
|
+
* `packages/Angular/Explorer/explorer-settings/src/lib/shared/styles/_admin-patterns.css`.
|
|
16
|
+
*
|
|
17
|
+
* Background is fixed to `--mj-bg-page` to match `<mj-left-nav-content>`'s
|
|
18
|
+
* background (the typical parent in shell sub-page contexts). The interior
|
|
19
|
+
* chrome's own surface + shadow provides the visual delineation between chrome
|
|
20
|
+
* and body — no second background tone needed.
|
|
21
|
+
*
|
|
22
|
+
* Escape hatches:
|
|
23
|
+
* - `[Padding]="false"` — remove the gutter (e.g. when inner content owns padding).
|
|
24
|
+
* - `[Flex]="true"` + `[Direction]="'row'"` — switch the body to a flex container
|
|
25
|
+
* so children with `flex: 1` can grow (e.g. sidebar + content panes).
|
|
26
|
+
*
|
|
27
|
+
* Example:
|
|
28
|
+
* ```html
|
|
29
|
+
* <mj-page-header-interior Title="Users" Subtitle="...">
|
|
30
|
+
* <div toolbar>...</div>
|
|
31
|
+
* <div actions>...</div>
|
|
32
|
+
* </mj-page-header-interior>
|
|
33
|
+
* <mj-page-body-interior>
|
|
34
|
+
* <!-- content; scroll, padding, background all handled -->
|
|
35
|
+
* </mj-page-body-interior>
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* See Section 10 of `plans/explorer-chrome-conventions.md` for the full
|
|
39
|
+
* "interior chrome" contract.
|
|
40
|
+
*/
|
|
41
|
+
export declare class MJPageBodyInteriorComponent {
|
|
42
|
+
/** When `false`, removes the responsive gutter. Defaults to `true`. */
|
|
43
|
+
Padding: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* When `true`, switches the body to a flex container so children with
|
|
46
|
+
* `flex: 1` can fill remaining space (e.g. sidebar + content). Defaults to
|
|
47
|
+
* `false` (block flow with vertical scroll).
|
|
48
|
+
*/
|
|
49
|
+
Flex: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* When `Flex=true`, controls flex direction. `'column'` (default) stacks
|
|
52
|
+
* children vertically; `'row'` for left-rail + content sub-page layouts.
|
|
53
|
+
* Ignored when `Flex=false`.
|
|
54
|
+
*/
|
|
55
|
+
Direction: 'row' | 'column';
|
|
56
|
+
get NoPaddingClass(): boolean;
|
|
57
|
+
get FlexClass(): boolean;
|
|
58
|
+
get RowClass(): boolean;
|
|
59
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<MJPageBodyInteriorComponent, never>;
|
|
60
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<MJPageBodyInteriorComponent, "mj-page-body-interior", never, { "Padding": { "alias": "Padding"; "required": false; }; "Flex": { "alias": "Flex"; "required": false; }; "Direction": { "alias": "Direction"; "required": false; }; }, {}, never, ["*"], true, never>;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=page-body-interior.component.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-body-interior.component.d.ts","sourceRoot":"","sources":["../../../src/lib/page-body-interior/page-body-interior.component.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,qBA6Ca,2BAA2B;IACtC,uEAAuE;IAC9D,OAAO,EAAE,OAAO,CAAQ;IAEjC;;;;OAIG;IACM,IAAI,EAAE,OAAO,CAAS;IAE/B;;;;OAIG;IACM,SAAS,EAAE,KAAK,GAAG,QAAQ,CAAY;IAEhD,IACI,cAAc,IAAI,OAAO,CAE5B;IAED,IACI,SAAS,IAAI,OAAO,CAEvB;IAED,IACI,QAAQ,IAAI,OAAO,CAEtB;yCA/BU,2BAA2B;2CAA3B,2BAA2B;CAgCvC"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { Component, HostBinding, Input } from '@angular/core';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
const _c0 = ["*"];
|
|
4
|
+
/**
|
|
5
|
+
* `<mj-page-body-interior>` — Body-region sibling of `<mj-page-header-interior>`.
|
|
6
|
+
*
|
|
7
|
+
* Paired primitive for sub-pages that render inside a left-nav workspace shell.
|
|
8
|
+
* Where `<mj-page-body>` is for top-level pages (sits inside `<mj-page-layout>`),
|
|
9
|
+
* this component is for sub-pages whose host element already has the flex-column
|
|
10
|
+
* layout (typically via `_admin-patterns.css`'s `:host` rule or an equivalent).
|
|
11
|
+
*
|
|
12
|
+
* Owns:
|
|
13
|
+
* - `flex: 1` so it fills the space below `<mj-page-header-interior>`.
|
|
14
|
+
* - `overflow-y: auto` so the body scrolls (the host typically has `overflow: hidden`).
|
|
15
|
+
* - Responsive padding: 16px on mobile, 24px at 768px+, 32px at 1024px+.
|
|
16
|
+
* Mirrors the bespoke `.scrollable-content` rules in
|
|
17
|
+
* `packages/Angular/Explorer/explorer-settings/src/lib/shared/styles/_admin-patterns.css`.
|
|
18
|
+
*
|
|
19
|
+
* Background is fixed to `--mj-bg-page` to match `<mj-left-nav-content>`'s
|
|
20
|
+
* background (the typical parent in shell sub-page contexts). The interior
|
|
21
|
+
* chrome's own surface + shadow provides the visual delineation between chrome
|
|
22
|
+
* and body — no second background tone needed.
|
|
23
|
+
*
|
|
24
|
+
* Escape hatches:
|
|
25
|
+
* - `[Padding]="false"` — remove the gutter (e.g. when inner content owns padding).
|
|
26
|
+
* - `[Flex]="true"` + `[Direction]="'row'"` — switch the body to a flex container
|
|
27
|
+
* so children with `flex: 1` can grow (e.g. sidebar + content panes).
|
|
28
|
+
*
|
|
29
|
+
* Example:
|
|
30
|
+
* ```html
|
|
31
|
+
* <mj-page-header-interior Title="Users" Subtitle="...">
|
|
32
|
+
* <div toolbar>...</div>
|
|
33
|
+
* <div actions>...</div>
|
|
34
|
+
* </mj-page-header-interior>
|
|
35
|
+
* <mj-page-body-interior>
|
|
36
|
+
* <!-- content; scroll, padding, background all handled -->
|
|
37
|
+
* </mj-page-body-interior>
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* See Section 10 of `plans/explorer-chrome-conventions.md` for the full
|
|
41
|
+
* "interior chrome" contract.
|
|
42
|
+
*/
|
|
43
|
+
export class MJPageBodyInteriorComponent {
|
|
44
|
+
/** When `false`, removes the responsive gutter. Defaults to `true`. */
|
|
45
|
+
Padding = true;
|
|
46
|
+
/**
|
|
47
|
+
* When `true`, switches the body to a flex container so children with
|
|
48
|
+
* `flex: 1` can fill remaining space (e.g. sidebar + content). Defaults to
|
|
49
|
+
* `false` (block flow with vertical scroll).
|
|
50
|
+
*/
|
|
51
|
+
Flex = false;
|
|
52
|
+
/**
|
|
53
|
+
* When `Flex=true`, controls flex direction. `'column'` (default) stacks
|
|
54
|
+
* children vertically; `'row'` for left-rail + content sub-page layouts.
|
|
55
|
+
* Ignored when `Flex=false`.
|
|
56
|
+
*/
|
|
57
|
+
Direction = 'column';
|
|
58
|
+
get NoPaddingClass() {
|
|
59
|
+
return !this.Padding;
|
|
60
|
+
}
|
|
61
|
+
get FlexClass() {
|
|
62
|
+
return this.Flex;
|
|
63
|
+
}
|
|
64
|
+
get RowClass() {
|
|
65
|
+
return this.Flex && this.Direction === 'row';
|
|
66
|
+
}
|
|
67
|
+
static ɵfac = function MJPageBodyInteriorComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MJPageBodyInteriorComponent)(); };
|
|
68
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MJPageBodyInteriorComponent, selectors: [["mj-page-body-interior"]], hostVars: 6, hostBindings: function MJPageBodyInteriorComponent_HostBindings(rf, ctx) { if (rf & 2) {
|
|
69
|
+
i0.ɵɵclassProp("mj-page-body-interior--no-padding", ctx.NoPaddingClass)("mj-page-body-interior--flex", ctx.FlexClass)("mj-page-body-interior--row", ctx.RowClass);
|
|
70
|
+
} }, inputs: { Padding: "Padding", Flex: "Flex", Direction: "Direction" }, ngContentSelectors: _c0, decls: 1, vars: 0, template: function MJPageBodyInteriorComponent_Template(rf, ctx) { if (rf & 1) {
|
|
71
|
+
i0.ɵɵprojectionDef();
|
|
72
|
+
i0.ɵɵprojection(0);
|
|
73
|
+
} }, styles: ["[_nghost-%COMP%] {\n display: block;\n flex: 1 1 auto;\n min-height: 0;\n overflow-y: auto;\n overflow-x: hidden;\n -webkit-overflow-scrolling: touch;\n \n\n\n\n\n padding: var(--mj-space-2) var(--mj-space-4) var(--mj-space-4);\n background: var(--mj-bg-page);\n }\n\n @media (min-width: 768px) {\n [_nghost-%COMP%] { padding: var(--mj-space-2) var(--mj-space-6) var(--mj-space-6); }\n }\n\n @media (min-width: 1024px) {\n [_nghost-%COMP%] { padding: var(--mj-space-2) var(--mj-space-8) var(--mj-space-8); }\n }\n\n \n\n .mj-page-body-interior--no-padding[_nghost-%COMP%] {\n padding: 0;\n }\n\n \n\n .mj-page-body-interior--flex[_nghost-%COMP%] {\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n .mj-page-body-interior--flex.mj-page-body-interior--row[_nghost-%COMP%] {\n flex-direction: row;\n }"] });
|
|
74
|
+
}
|
|
75
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJPageBodyInteriorComponent, [{
|
|
76
|
+
type: Component,
|
|
77
|
+
args: [{ selector: 'mj-page-body-interior', standalone: true, template: `<ng-content></ng-content>`, styles: ["\n :host {\n display: block;\n flex: 1 1 auto;\n min-height: 0;\n overflow-y: auto;\n overflow-x: hidden;\n -webkit-overflow-scrolling: touch;\n /* Top padding is intentionally tighter than sides/bottom \u2014 the body is\n almost always preceded by an <mj-page-header-interior> whose own\n bottom margin provides the visual breathing room above the body\n content. Sides + bottom scale responsively for comfortable gutters. */\n padding: var(--mj-space-2) var(--mj-space-4) var(--mj-space-4);\n background: var(--mj-bg-page);\n }\n\n @media (min-width: 768px) {\n :host { padding: var(--mj-space-2) var(--mj-space-6) var(--mj-space-6); }\n }\n\n @media (min-width: 1024px) {\n :host { padding: var(--mj-space-2) var(--mj-space-8) var(--mj-space-8); }\n }\n\n /* No-padding escape hatch \u2014 for sub-pages whose inner content owns the gutter. */\n :host(.mj-page-body-interior--no-padding) {\n padding: 0;\n }\n\n /* Flex container mode \u2014 for sub-pages with sidebar + content layouts. */\n :host(.mj-page-body-interior--flex) {\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n :host(.mj-page-body-interior--flex.mj-page-body-interior--row) {\n flex-direction: row;\n }\n "] }]
|
|
78
|
+
}], null, { Padding: [{
|
|
79
|
+
type: Input
|
|
80
|
+
}], Flex: [{
|
|
81
|
+
type: Input
|
|
82
|
+
}], Direction: [{
|
|
83
|
+
type: Input
|
|
84
|
+
}], NoPaddingClass: [{
|
|
85
|
+
type: HostBinding,
|
|
86
|
+
args: ['class.mj-page-body-interior--no-padding']
|
|
87
|
+
}], FlexClass: [{
|
|
88
|
+
type: HostBinding,
|
|
89
|
+
args: ['class.mj-page-body-interior--flex']
|
|
90
|
+
}], RowClass: [{
|
|
91
|
+
type: HostBinding,
|
|
92
|
+
args: ['class.mj-page-body-interior--row']
|
|
93
|
+
}] }); })();
|
|
94
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJPageBodyInteriorComponent, { className: "MJPageBodyInteriorComponent", filePath: "lib/page-body-interior/page-body-interior.component.ts", lineNumber: 87 }); })();
|
|
95
|
+
//# sourceMappingURL=page-body-interior.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-body-interior.component.js","sourceRoot":"","sources":["../../../src/lib/page-body-interior/page-body-interior.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;;;AAE9D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AA8CH,MAAM,OAAO,2BAA2B;IACtC,uEAAuE;IAC9D,OAAO,GAAY,IAAI,CAAC;IAEjC;;;;OAIG;IACM,IAAI,GAAY,KAAK,CAAC;IAE/B;;;;OAIG;IACM,SAAS,GAAqB,QAAQ,CAAC;IAEhD,IACI,cAAc;QAChB,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC;IACvB,CAAC;IAED,IACI,SAAS;QACX,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED,IACI,QAAQ;QACV,OAAO,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC;IAC/C,CAAC;qHA/BU,2BAA2B;6DAA3B,2BAA2B;YAA3B,uEAA2B,8CAAA,4CAAA;;;YA1C3B,kBAAyB;;;iFA0CzB,2BAA2B;cA7CvC,SAAS;2BACE,uBAAuB,cACrB,IAAI,YACN,2BAA2B;;kBA4CpC,KAAK;;kBAOL,KAAK;;kBAOL,KAAK;;kBAEL,WAAW;mBAAC,yCAAyC;;kBAKrD,WAAW;mBAAC,mCAAmC;;kBAK/C,WAAW;mBAAC,kCAAkC;;kFA5BpC,2BAA2B","sourcesContent":["import { Component, HostBinding, Input } from '@angular/core';\n\n/**\n * `<mj-page-body-interior>` — Body-region sibling of `<mj-page-header-interior>`.\n *\n * Paired primitive for sub-pages that render inside a left-nav workspace shell.\n * Where `<mj-page-body>` is for top-level pages (sits inside `<mj-page-layout>`),\n * this component is for sub-pages whose host element already has the flex-column\n * layout (typically via `_admin-patterns.css`'s `:host` rule or an equivalent).\n *\n * Owns:\n * - `flex: 1` so it fills the space below `<mj-page-header-interior>`.\n * - `overflow-y: auto` so the body scrolls (the host typically has `overflow: hidden`).\n * - Responsive padding: 16px on mobile, 24px at 768px+, 32px at 1024px+.\n * Mirrors the bespoke `.scrollable-content` rules in\n * `packages/Angular/Explorer/explorer-settings/src/lib/shared/styles/_admin-patterns.css`.\n *\n * Background is fixed to `--mj-bg-page` to match `<mj-left-nav-content>`'s\n * background (the typical parent in shell sub-page contexts). The interior\n * chrome's own surface + shadow provides the visual delineation between chrome\n * and body — no second background tone needed.\n *\n * Escape hatches:\n * - `[Padding]=\"false\"` — remove the gutter (e.g. when inner content owns padding).\n * - `[Flex]=\"true\"` + `[Direction]=\"'row'\"` — switch the body to a flex container\n * so children with `flex: 1` can grow (e.g. sidebar + content panes).\n *\n * Example:\n * ```html\n * <mj-page-header-interior Title=\"Users\" Subtitle=\"...\">\n * <div toolbar>...</div>\n * <div actions>...</div>\n * </mj-page-header-interior>\n * <mj-page-body-interior>\n * <!-- content; scroll, padding, background all handled -->\n * </mj-page-body-interior>\n * ```\n *\n * See Section 10 of `plans/explorer-chrome-conventions.md` for the full\n * \"interior chrome\" contract.\n */\n@Component({\n selector: 'mj-page-body-interior',\n standalone: true,\n template: `<ng-content></ng-content>`,\n styles: [`\n :host {\n display: block;\n flex: 1 1 auto;\n min-height: 0;\n overflow-y: auto;\n overflow-x: hidden;\n -webkit-overflow-scrolling: touch;\n /* Top padding is intentionally tighter than sides/bottom — the body is\n almost always preceded by an <mj-page-header-interior> whose own\n bottom margin provides the visual breathing room above the body\n content. Sides + bottom scale responsively for comfortable gutters. */\n padding: var(--mj-space-2) var(--mj-space-4) var(--mj-space-4);\n background: var(--mj-bg-page);\n }\n\n @media (min-width: 768px) {\n :host { padding: var(--mj-space-2) var(--mj-space-6) var(--mj-space-6); }\n }\n\n @media (min-width: 1024px) {\n :host { padding: var(--mj-space-2) var(--mj-space-8) var(--mj-space-8); }\n }\n\n /* No-padding escape hatch — for sub-pages whose inner content owns the gutter. */\n :host(.mj-page-body-interior--no-padding) {\n padding: 0;\n }\n\n /* Flex container mode — for sub-pages with sidebar + content layouts. */\n :host(.mj-page-body-interior--flex) {\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n :host(.mj-page-body-interior--flex.mj-page-body-interior--row) {\n flex-direction: row;\n }\n `]\n})\nexport class MJPageBodyInteriorComponent {\n /** When `false`, removes the responsive gutter. Defaults to `true`. */\n @Input() Padding: boolean = true;\n\n /**\n * When `true`, switches the body to a flex container so children with\n * `flex: 1` can fill remaining space (e.g. sidebar + content). Defaults to\n * `false` (block flow with vertical scroll).\n */\n @Input() Flex: boolean = false;\n\n /**\n * When `Flex=true`, controls flex direction. `'column'` (default) stacks\n * children vertically; `'row'` for left-rail + content sub-page layouts.\n * Ignored when `Flex=false`.\n */\n @Input() Direction: 'row' | 'column' = 'column';\n\n @HostBinding('class.mj-page-body-interior--no-padding')\n get NoPaddingClass(): boolean {\n return !this.Padding;\n }\n\n @HostBinding('class.mj-page-body-interior--flex')\n get FlexClass(): boolean {\n return this.Flex;\n }\n\n @HostBinding('class.mj-page-body-interior--row')\n get RowClass(): boolean {\n return this.Flex && this.Direction === 'row';\n }\n}\n"]}
|
|
@@ -4,10 +4,14 @@ import * as i0 from "@angular/core";
|
|
|
4
4
|
*
|
|
5
5
|
* Renders the standard icon · title · subtitle layout with three named projection
|
|
6
6
|
* slots for additional content:
|
|
7
|
-
* - `[meta]` —
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* - `[meta]` — supporting info that lives **below the subtitle** in the
|
|
8
|
+
* identity column (result counts, status badges, stat-pills).
|
|
9
|
+
* Reads as data attached to the identity, not as a peer of
|
|
10
|
+
* the title — keeps the title the dominant visual anchor.
|
|
11
|
+
* Wraps when there are many badges.
|
|
12
|
+
* - `[actions]` — right-aligned action buttons or sub-navigation, top-aligned
|
|
13
|
+
* with the title row so they stay anchored regardless of how
|
|
14
|
+
* tall the identity column grows.
|
|
11
15
|
* - `[toolbar]` — optional secondary row beneath the title for dense controls
|
|
12
16
|
* (filters, time-range pickers, breadcrumbs)
|
|
13
17
|
*
|
|
@@ -24,6 +28,10 @@ import * as i0 from "@angular/core";
|
|
|
24
28
|
* </div>
|
|
25
29
|
* </mj-page-header>
|
|
26
30
|
* ```
|
|
31
|
+
*
|
|
32
|
+
* For the body-level interior chrome variant used by left-nav sub-pages, use
|
|
33
|
+
* `<mj-page-header-interior>` instead — same slot conventions, different
|
|
34
|
+
* visual shape (single-row card, no titlebar).
|
|
27
35
|
*/
|
|
28
36
|
export declare class MJPageHeaderComponent {
|
|
29
37
|
Title: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"page-header.component.d.ts","sourceRoot":"","sources":["../../../src/lib/page-header/page-header.component.ts"],"names":[],"mappings":";AAEA
|
|
1
|
+
{"version":3,"file":"page-header.component.d.ts","sourceRoot":"","sources":["../../../src/lib/page-header/page-header.component.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,qBAiCa,qBAAqB;IACvB,KAAK,EAAE,MAAM,CAAM;IACnB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC3B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;yCAH7B,qBAAqB;2CAArB,qBAAqB;CAIjC"}
|
|
@@ -11,8 +11,8 @@ function MJPageHeaderComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
|
11
11
|
i0.ɵɵadvance();
|
|
12
12
|
i0.ɵɵclassMap(ctx_r0.Icon);
|
|
13
13
|
} }
|
|
14
|
-
function
|
|
15
|
-
i0.ɵɵdomElementStart(0, "p",
|
|
14
|
+
function MJPageHeaderComponent_Conditional_7_Template(rf, ctx) { if (rf & 1) {
|
|
15
|
+
i0.ɵɵdomElementStart(0, "p", 6);
|
|
16
16
|
i0.ɵɵtext(1);
|
|
17
17
|
i0.ɵɵdomElementEnd();
|
|
18
18
|
} if (rf & 2) {
|
|
@@ -25,10 +25,14 @@ function MJPageHeaderComponent_Conditional_10_Template(rf, ctx) { if (rf & 1) {
|
|
|
25
25
|
*
|
|
26
26
|
* Renders the standard icon · title · subtitle layout with three named projection
|
|
27
27
|
* slots for additional content:
|
|
28
|
-
* - `[meta]` —
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
28
|
+
* - `[meta]` — supporting info that lives **below the subtitle** in the
|
|
29
|
+
* identity column (result counts, status badges, stat-pills).
|
|
30
|
+
* Reads as data attached to the identity, not as a peer of
|
|
31
|
+
* the title — keeps the title the dominant visual anchor.
|
|
32
|
+
* Wraps when there are many badges.
|
|
33
|
+
* - `[actions]` — right-aligned action buttons or sub-navigation, top-aligned
|
|
34
|
+
* with the title row so they stay anchored regardless of how
|
|
35
|
+
* tall the identity column grows.
|
|
32
36
|
* - `[toolbar]` — optional secondary row beneath the title for dense controls
|
|
33
37
|
* (filters, time-range pickers, breadcrumbs)
|
|
34
38
|
*
|
|
@@ -45,38 +49,41 @@ function MJPageHeaderComponent_Conditional_10_Template(rf, ctx) { if (rf & 1) {
|
|
|
45
49
|
* </div>
|
|
46
50
|
* </mj-page-header>
|
|
47
51
|
* ```
|
|
52
|
+
*
|
|
53
|
+
* For the body-level interior chrome variant used by left-nav sub-pages, use
|
|
54
|
+
* `<mj-page-header-interior>` instead — same slot conventions, different
|
|
55
|
+
* visual shape (single-row card, no titlebar).
|
|
48
56
|
*/
|
|
49
57
|
export class MJPageHeaderComponent {
|
|
50
58
|
Title = '';
|
|
51
59
|
Icon = null;
|
|
52
60
|
Subtitle = null;
|
|
53
61
|
static ɵfac = function MJPageHeaderComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MJPageHeaderComponent)(); };
|
|
54
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MJPageHeaderComponent, selectors: [["mj-page-header"]], inputs: { Title: "Title", Icon: "Icon", Subtitle: "Subtitle" }, ngContentSelectors: _c1, decls:
|
|
62
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MJPageHeaderComponent, selectors: [["mj-page-header"]], inputs: { Title: "Title", Icon: "Icon", Subtitle: "Subtitle" }, ngContentSelectors: _c1, decls: 14, vars: 3, consts: [[1, "mj-page-header"], [1, "mj-page-header-row", "mj-page-header-row--primary"], [1, "mj-page-header-titlebar"], ["aria-hidden", "true", 1, "mj-page-header-icon"], [1, "mj-page-header-text"], [1, "mj-page-header-title"], [1, "mj-page-header-subtitle"], [1, "mj-page-header-meta"], [1, "mj-page-header-actions"], [1, "mj-page-header-row", "mj-page-header-row--toolbar"]], template: function MJPageHeaderComponent_Template(rf, ctx) { if (rf & 1) {
|
|
55
63
|
i0.ɵɵprojectionDef(_c0);
|
|
56
64
|
i0.ɵɵdomElementStart(0, "header", 0)(1, "div", 1)(2, "div", 2);
|
|
57
65
|
i0.ɵɵconditionalCreate(3, MJPageHeaderComponent_Conditional_3_Template, 2, 2, "div", 3);
|
|
58
|
-
i0.ɵɵdomElementStart(4, "div", 4)(5, "
|
|
59
|
-
i0.ɵɵtext(
|
|
66
|
+
i0.ɵɵdomElementStart(4, "div", 4)(5, "h1", 5);
|
|
67
|
+
i0.ɵɵtext(6);
|
|
60
68
|
i0.ɵɵdomElementEnd();
|
|
69
|
+
i0.ɵɵconditionalCreate(7, MJPageHeaderComponent_Conditional_7_Template, 2, 1, "p", 6);
|
|
61
70
|
i0.ɵɵdomElementStart(8, "div", 7);
|
|
62
71
|
i0.ɵɵprojection(9);
|
|
72
|
+
i0.ɵɵdomElementEnd()()();
|
|
73
|
+
i0.ɵɵdomElementStart(10, "div", 8);
|
|
74
|
+
i0.ɵɵprojection(11, 1);
|
|
63
75
|
i0.ɵɵdomElementEnd()();
|
|
64
|
-
i0.ɵɵ
|
|
65
|
-
i0.ɵɵ
|
|
66
|
-
i0.ɵɵdomElementStart(11, "div", 9);
|
|
67
|
-
i0.ɵɵprojection(12, 1);
|
|
68
|
-
i0.ɵɵdomElementEnd()();
|
|
69
|
-
i0.ɵɵdomElementStart(13, "div", 10);
|
|
70
|
-
i0.ɵɵprojection(14, 2);
|
|
76
|
+
i0.ɵɵdomElementStart(12, "div", 9);
|
|
77
|
+
i0.ɵɵprojection(13, 2);
|
|
71
78
|
i0.ɵɵdomElementEnd()();
|
|
72
79
|
} if (rf & 2) {
|
|
73
80
|
i0.ɵɵadvance(3);
|
|
74
81
|
i0.ɵɵconditional(ctx.Icon ? 3 : -1);
|
|
75
|
-
i0.ɵɵadvance(4);
|
|
76
|
-
i0.ɵɵtextInterpolate(ctx.Title);
|
|
77
82
|
i0.ɵɵadvance(3);
|
|
78
|
-
i0.ɵɵ
|
|
79
|
-
|
|
83
|
+
i0.ɵɵtextInterpolate(ctx.Title);
|
|
84
|
+
i0.ɵɵadvance();
|
|
85
|
+
i0.ɵɵconditional(ctx.Subtitle ? 7 : -1);
|
|
86
|
+
} }, styles: ["[_nghost-%COMP%] {\n display: block;\n \n\n\n\n margin-bottom: var(--mj-space-6);\n}\n\n\n\n\n\n\nmj-page-layout[_nghost-%COMP%], mj-page-layout [_nghost-%COMP%] {\n margin-bottom: 0;\n}\n\n\n\n\n\n\n\n\n[_nghost-%COMP%] [meta], \n[_nghost-%COMP%] [actions], \n[_nghost-%COMP%] [toolbar] {\n display: contents;\n}\n\n.mj-page-header[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface);\n \n\n\n\n\n\n\n box-shadow: var(--mj-shadow-md);\n position: relative;\n z-index: 1;\n}\n\n.mj-page-header-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: var(--mj-space-3);\n padding: 0 var(--mj-space-6);\n}\n\n\n\n\n\n\n\n\n.mj-page-header-row--primary[_ngcontent-%COMP%] {\n justify-content: space-between;\n align-items: center;\n gap: var(--mj-space-4);\n padding-top: var(--mj-space-4);\n padding-bottom: var(--mj-space-4);\n}\n\n.mj-page-header-row--toolbar[_ngcontent-%COMP%] {\n flex-wrap: wrap;\n padding-top: 0;\n padding-bottom: var(--mj-space-4);\n border-top: 1px solid var(--mj-border-subtle);\n margin-top: 0;\n padding-top: var(--mj-space-3);\n}\n\n.mj-page-header-row--toolbar[_ngcontent-%COMP%]:empty {\n display: none;\n border-top: 0;\n padding: 0;\n}\n\n.mj-page-header-titlebar[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: var(--mj-space-3);\n flex: 1 1 auto;\n min-width: 0;\n}\n\n.mj-page-header-icon[_ngcontent-%COMP%] {\n flex-shrink: 0;\n width: 40px;\n height: 40px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n color: var(--mj-brand-primary);\n border-radius: var(--mj-radius-md);\n font-size: var(--mj-text-lg);\n}\n\n\n\n.mj-page-header-text[_ngcontent-%COMP%] {\n min-width: 0;\n flex: 1 1 auto;\n display: flex;\n flex-direction: column;\n}\n\n.mj-page-header-title[_ngcontent-%COMP%] {\n margin: 0;\n font-size: var(--mj-text-xl);\n font-weight: var(--mj-font-semibold);\n color: var(--mj-text-primary);\n line-height: 1.25;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mj-page-header-subtitle[_ngcontent-%COMP%] {\n margin: var(--mj-space-1) 0 0;\n font-size: var(--mj-text-sm);\n color: var(--mj-text-secondary);\n line-height: 1.4;\n}\n\n\n\n\n\n\n.mj-page-header-meta[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--mj-space-2);\n margin-top: var(--mj-space-2);\n}\n\n.mj-page-header-actions[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: var(--mj-space-3);\n flex-shrink: 0;\n}\n\n.mj-page-header-meta[_ngcontent-%COMP%]:empty, \n.mj-page-header-actions[_ngcontent-%COMP%]:empty {\n display: none;\n}\n\n@media (max-width: 768px) {\n .mj-page-header-row--primary[_ngcontent-%COMP%] {\n flex-direction: column;\n align-items: stretch;\n gap: var(--mj-space-3);\n }\n .mj-page-header-actions[_ngcontent-%COMP%] {\n justify-content: flex-end;\n }\n}"] });
|
|
80
87
|
}
|
|
81
88
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJPageHeaderComponent, [{
|
|
82
89
|
type: Component,
|
|
@@ -90,15 +97,13 @@ export class MJPageHeaderComponent {
|
|
|
90
97
|
</div>
|
|
91
98
|
}
|
|
92
99
|
<div class="mj-page-header-text">
|
|
93
|
-
<
|
|
94
|
-
<h1 class="mj-page-header-title">{{ Title }}</h1>
|
|
95
|
-
<div class="mj-page-header-meta">
|
|
96
|
-
<ng-content select="[meta]"></ng-content>
|
|
97
|
-
</div>
|
|
98
|
-
</div>
|
|
100
|
+
<h1 class="mj-page-header-title">{{ Title }}</h1>
|
|
99
101
|
@if (Subtitle) {
|
|
100
102
|
<p class="mj-page-header-subtitle">{{ Subtitle }}</p>
|
|
101
103
|
}
|
|
104
|
+
<div class="mj-page-header-meta">
|
|
105
|
+
<ng-content select="[meta]"></ng-content>
|
|
106
|
+
</div>
|
|
102
107
|
</div>
|
|
103
108
|
</div>
|
|
104
109
|
<div class="mj-page-header-actions">
|
|
@@ -109,7 +114,7 @@ export class MJPageHeaderComponent {
|
|
|
109
114
|
<ng-content select="[toolbar]"></ng-content>
|
|
110
115
|
</div>
|
|
111
116
|
</header>
|
|
112
|
-
`, styles: [":host {\n display: block;\n /* External consumers using <mj-page-header> outside <mj-page-layout> get a\n 24px bottom margin so the header has breathing room from whatever follows.\n This preserves backward compatibility with the published v5.x contract. */\n margin-bottom: var(--mj-space-6);\n}\n\n/* When nested inside <mj-page-layout>, the spacing between header and body is\n owned by <mj-page-body>'s padding-top \u2014 so the header sits flush against the\n body. This lets pages using <mj-page-body [Padding]=\"false\"> (e.g. AI\n Analytics flush sidebar) render truly flush against the header. */\n:host-context(mj-page-layout) {\n margin-bottom: 0;\n}\n\n/* Slot-wrapper passthrough \u2014 any element a consumer projects with the `meta`,\n `actions`, or `toolbar` attribute (regardless of class name) becomes a\n transparent container so its children become direct flex children of the\n page-header row and inherit the row's gap. Eliminates the per-page\n `.{section}-header-meta { display: contents }` rules that pages had to\n declare in their own CSS files. */\n:host ::ng-deep [meta],\n:host ::ng-deep [actions],\n:host ::ng-deep [toolbar] {\n display: contents;\n}\n\n.mj-page-header {\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface);\n box-shadow: var(--mj-shadow-
|
|
117
|
+
`, styles: [":host {\n display: block;\n /* External consumers using <mj-page-header> outside <mj-page-layout> get a\n 24px bottom margin so the header has breathing room from whatever follows.\n This preserves backward compatibility with the published v5.x contract. */\n margin-bottom: var(--mj-space-6);\n}\n\n/* When nested inside <mj-page-layout>, the spacing between header and body is\n owned by <mj-page-body>'s padding-top \u2014 so the header sits flush against the\n body. This lets pages using <mj-page-body [Padding]=\"false\"> (e.g. AI\n Analytics flush sidebar) render truly flush against the header. */\n:host-context(mj-page-layout) {\n margin-bottom: 0;\n}\n\n/* Slot-wrapper passthrough \u2014 any element a consumer projects with the `meta`,\n `actions`, or `toolbar` attribute (regardless of class name) becomes a\n transparent container so its children become direct flex children of the\n page-header row and inherit the row's gap. Eliminates the per-page\n `.{section}-header-meta { display: contents }` rules that pages had to\n declare in their own CSS files. */\n:host ::ng-deep [meta],\n:host ::ng-deep [actions],\n:host ::ng-deep [toolbar] {\n display: contents;\n}\n\n.mj-page-header {\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface);\n /* Drop shadow for visual separation from the body below.\n `position: relative; z-index: 1` lifts the header into its own stacking\n context above <mj-page-body> (which has `position: relative` and would\n otherwise paint over the downward shadow as a later flex sibling).\n --mj-shadow-md is used instead of --mj-shadow-sm because the latter is\n rgba(0,0,0,0.05) in light mode \u2014 too faint to read as separation. */\n box-shadow: var(--mj-shadow-md);\n position: relative;\n z-index: 1;\n}\n\n.mj-page-header-row {\n display: flex;\n align-items: center;\n gap: var(--mj-space-3);\n padding: 0 var(--mj-space-6);\n}\n\n/* Primary row centers the actions cluster vertically against the identity\n column. The identity column stacks title \u2192 subtitle \u2192 (optional meta);\n centering keeps the actions visually balanced against the whole block\n instead of pinning them to the title baseline. When meta badges are\n present the actions drift down a touch \u2014 acceptable trade for the more\n common no-meta case where flex-start looks top-heavy. */\n.mj-page-header-row--primary {\n justify-content: space-between;\n align-items: center;\n gap: var(--mj-space-4);\n padding-top: var(--mj-space-4);\n padding-bottom: var(--mj-space-4);\n}\n\n.mj-page-header-row--toolbar {\n flex-wrap: wrap;\n padding-top: 0;\n padding-bottom: var(--mj-space-4);\n border-top: 1px solid var(--mj-border-subtle);\n margin-top: 0;\n padding-top: var(--mj-space-3);\n}\n\n.mj-page-header-row--toolbar:empty {\n display: none;\n border-top: 0;\n padding: 0;\n}\n\n.mj-page-header-titlebar {\n display: flex;\n align-items: center;\n gap: var(--mj-space-3);\n flex: 1 1 auto;\n min-width: 0;\n}\n\n.mj-page-header-icon {\n flex-shrink: 0;\n width: 40px;\n height: 40px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n color: var(--mj-brand-primary);\n border-radius: var(--mj-radius-md);\n font-size: var(--mj-text-lg);\n}\n\n/* Identity column \u2014 title, subtitle, meta stacked vertically. */\n.mj-page-header-text {\n min-width: 0;\n flex: 1 1 auto;\n display: flex;\n flex-direction: column;\n}\n\n.mj-page-header-title {\n margin: 0;\n font-size: var(--mj-text-xl);\n font-weight: var(--mj-font-semibold);\n color: var(--mj-text-primary);\n line-height: 1.25;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mj-page-header-subtitle {\n margin: var(--mj-space-1) 0 0;\n font-size: var(--mj-text-sm);\n color: var(--mj-text-secondary);\n line-height: 1.4;\n}\n\n/* Meta lives in the identity column UNDER the subtitle \u2014 supporting info\n for the identity, not a peer to the title. Wraps when there are many\n badges. Matches the mj-page-header-interior pattern so both chrome\n surfaces have one mental model. */\n.mj-page-header-meta {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--mj-space-2);\n margin-top: var(--mj-space-2);\n}\n\n.mj-page-header-actions {\n display: flex;\n align-items: center;\n gap: var(--mj-space-3);\n flex-shrink: 0;\n}\n\n.mj-page-header-meta:empty,\n.mj-page-header-actions:empty {\n display: none;\n}\n\n@media (max-width: 768px) {\n .mj-page-header-row--primary {\n flex-direction: column;\n align-items: stretch;\n gap: var(--mj-space-3);\n }\n .mj-page-header-actions {\n justify-content: flex-end;\n }\n}\n"] }]
|
|
113
118
|
}], null, { Title: [{
|
|
114
119
|
type: Input
|
|
115
120
|
}], Icon: [{
|
|
@@ -117,5 +122,5 @@ export class MJPageHeaderComponent {
|
|
|
117
122
|
}], Subtitle: [{
|
|
118
123
|
type: Input
|
|
119
124
|
}] }); })();
|
|
120
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJPageHeaderComponent, { className: "MJPageHeaderComponent", filePath: "lib/page-header/page-header.component.ts", lineNumber:
|
|
125
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJPageHeaderComponent, { className: "MJPageHeaderComponent", filePath: "lib/page-header/page-header.component.ts", lineNumber: 70 }); })();
|
|
121
126
|
//# sourceMappingURL=page-header.component.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"page-header.component.js","sourceRoot":"","sources":["../../../src/lib/page-header/page-header.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;;;;;
|
|
1
|
+
{"version":3,"file":"page-header.component.js","sourceRoot":"","sources":["../../../src/lib/page-header/page-header.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;;;;;IA6CrC,iCAAoD;IAClD,uBAAsB;IACxB,oBAAM;;;IADD,cAAc;IAAd,0BAAc;;;IAMjB,+BAAmC;IAAA,YAAc;IAAA,oBAAI;;;IAAlB,cAAc;IAAd,qCAAc;;AAlD/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAkCH,MAAM,OAAO,qBAAqB;IACvB,KAAK,GAAW,EAAE,CAAC;IACnB,IAAI,GAAkB,IAAI,CAAC;IAC3B,QAAQ,GAAkB,IAAI,CAAC;+GAH7B,qBAAqB;6DAArB,qBAAqB;;YA1B1B,AADF,AADF,oCAA+B,aAC+B,aACrB;YACnC,uFAAY;YAMV,AADF,iCAAiC,YACE;YAAA,YAAW;YAAA,oBAAK;YACjD,qFAAgB;YAGhB,iCAAiC;YAC/B,kBAAyC;YAG/C,AADE,AADE,oBAAM,EACF,EACF;YACN,kCAAoC;YAClC,sBAA4C;YAEhD,AADE,oBAAM,EACF;YACN,kCAA4D;YAC1D,sBAA4C;YAEhD,AADE,oBAAM,EACC;;YAtBH,eAIC;YAJD,mCAIC;YAEkC,eAAW;YAAX,+BAAW;YAC5C,cAEC;YAFD,uCAEC;;;iFAgBA,qBAAqB;cAjCjC,SAAS;2BACE,gBAAgB,cACd,IAAI,YAEN;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BT;;kBAGA,KAAK;;kBACL,KAAK;;kBACL,KAAK;;kFAHK,qBAAqB","sourcesContent":["import { Component, Input } from '@angular/core';\n\n/**\n * mj-page-header — Canonical page/dashboard header for MJ Explorer.\n *\n * Renders the standard icon · title · subtitle layout with three named projection\n * slots for additional content:\n * - `[meta]` — supporting info that lives **below the subtitle** in the\n * identity column (result counts, status badges, stat-pills).\n * Reads as data attached to the identity, not as a peer of\n * the title — keeps the title the dominant visual anchor.\n * Wraps when there are many badges.\n * - `[actions]` — right-aligned action buttons or sub-navigation, top-aligned\n * with the title row so they stay anchored regardless of how\n * tall the identity column grows.\n * - `[toolbar]` — optional secondary row beneath the title for dense controls\n * (filters, time-range pickers, breadcrumbs)\n *\n * Example:\n * ```html\n * <mj-page-header Title=\"Dashboard\" Icon=\"fa-solid fa-gauge\" Subtitle=\"Overview\">\n * <span meta class=\"badge\">{{ count }}</span>\n * <div actions>\n * <button mjButton variant=\"primary\">New</button>\n * </div>\n * <div toolbar>\n * <app-time-range-picker></app-time-range-picker>\n * <app-filter-bar></app-filter-bar>\n * </div>\n * </mj-page-header>\n * ```\n *\n * For the body-level interior chrome variant used by left-nav sub-pages, use\n * `<mj-page-header-interior>` instead — same slot conventions, different\n * visual shape (single-row card, no titlebar).\n */\n@Component({\n selector: 'mj-page-header',\n standalone: true,\n styleUrls: ['./page-header.scss'],\n template: `\n <header class=\"mj-page-header\">\n <div class=\"mj-page-header-row mj-page-header-row--primary\">\n <div class=\"mj-page-header-titlebar\">\n @if (Icon) {\n <div class=\"mj-page-header-icon\" aria-hidden=\"true\">\n <i [class]=\"Icon\"></i>\n </div>\n }\n <div class=\"mj-page-header-text\">\n <h1 class=\"mj-page-header-title\">{{ Title }}</h1>\n @if (Subtitle) {\n <p class=\"mj-page-header-subtitle\">{{ Subtitle }}</p>\n }\n <div class=\"mj-page-header-meta\">\n <ng-content select=\"[meta]\"></ng-content>\n </div>\n </div>\n </div>\n <div class=\"mj-page-header-actions\">\n <ng-content select=\"[actions]\"></ng-content>\n </div>\n </div>\n <div class=\"mj-page-header-row mj-page-header-row--toolbar\">\n <ng-content select=\"[toolbar]\"></ng-content>\n </div>\n </header>\n `\n})\nexport class MJPageHeaderComponent {\n @Input() Title: string = '';\n @Input() Icon: string | null = null;\n @Input() Subtitle: string | null = null;\n}\n"]}
|
|
@@ -30,7 +30,15 @@
|
|
|
30
30
|
display: flex;
|
|
31
31
|
flex-direction: column;
|
|
32
32
|
background: var(--mj-bg-surface);
|
|
33
|
-
|
|
33
|
+
/* Drop shadow for visual separation from the body below.
|
|
34
|
+
`position: relative; z-index: 1` lifts the header into its own stacking
|
|
35
|
+
context above <mj-page-body> (which has `position: relative` and would
|
|
36
|
+
otherwise paint over the downward shadow as a later flex sibling).
|
|
37
|
+
--mj-shadow-md is used instead of --mj-shadow-sm because the latter is
|
|
38
|
+
rgba(0,0,0,0.05) in light mode — too faint to read as separation. */
|
|
39
|
+
box-shadow: var(--mj-shadow-md);
|
|
40
|
+
position: relative;
|
|
41
|
+
z-index: 1;
|
|
34
42
|
}
|
|
35
43
|
|
|
36
44
|
.mj-page-header-row {
|
|
@@ -40,8 +48,15 @@
|
|
|
40
48
|
padding: 0 var(--mj-space-6);
|
|
41
49
|
}
|
|
42
50
|
|
|
51
|
+
/* Primary row centers the actions cluster vertically against the identity
|
|
52
|
+
column. The identity column stacks title → subtitle → (optional meta);
|
|
53
|
+
centering keeps the actions visually balanced against the whole block
|
|
54
|
+
instead of pinning them to the title baseline. When meta badges are
|
|
55
|
+
present the actions drift down a touch — acceptable trade for the more
|
|
56
|
+
common no-meta case where flex-start looks top-heavy. */
|
|
43
57
|
.mj-page-header-row--primary {
|
|
44
58
|
justify-content: space-between;
|
|
59
|
+
align-items: center;
|
|
45
60
|
gap: var(--mj-space-4);
|
|
46
61
|
padding-top: var(--mj-space-4);
|
|
47
62
|
padding-bottom: var(--mj-space-4);
|
|
@@ -83,17 +98,12 @@
|
|
|
83
98
|
font-size: var(--mj-text-lg);
|
|
84
99
|
}
|
|
85
100
|
|
|
101
|
+
/* Identity column — title, subtitle, meta stacked vertically. */
|
|
86
102
|
.mj-page-header-text {
|
|
87
103
|
min-width: 0;
|
|
88
104
|
flex: 1 1 auto;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
.mj-page-header-title-row {
|
|
92
105
|
display: flex;
|
|
93
|
-
|
|
94
|
-
gap: var(--mj-space-3);
|
|
95
|
-
flex-wrap: wrap;
|
|
96
|
-
min-width: 0;
|
|
106
|
+
flex-direction: column;
|
|
97
107
|
}
|
|
98
108
|
|
|
99
109
|
.mj-page-header-title {
|
|
@@ -114,7 +124,18 @@
|
|
|
114
124
|
line-height: 1.4;
|
|
115
125
|
}
|
|
116
126
|
|
|
117
|
-
|
|
127
|
+
/* Meta lives in the identity column UNDER the subtitle — supporting info
|
|
128
|
+
for the identity, not a peer to the title. Wraps when there are many
|
|
129
|
+
badges. Matches the mj-page-header-interior pattern so both chrome
|
|
130
|
+
surfaces have one mental model. */
|
|
131
|
+
.mj-page-header-meta {
|
|
132
|
+
display: flex;
|
|
133
|
+
flex-wrap: wrap;
|
|
134
|
+
align-items: center;
|
|
135
|
+
gap: var(--mj-space-2);
|
|
136
|
+
margin-top: var(--mj-space-2);
|
|
137
|
+
}
|
|
138
|
+
|
|
118
139
|
.mj-page-header-actions {
|
|
119
140
|
display: flex;
|
|
120
141
|
align-items: center;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import * as i0 from "@angular/core";
|
|
2
|
+
/**
|
|
3
|
+
* `<mj-page-header-interior>` — Interior-chrome sibling of `<mj-page-header>`.
|
|
4
|
+
*
|
|
5
|
+
* Same slot conventions as `<mj-page-header>` (`[meta]` / `[actions]` / `[toolbar]`)
|
|
6
|
+
* so consumers learn one set of names for both surfaces. Different visual shape:
|
|
7
|
+
* a single-row card with surface background + radius + shadow that sits at the
|
|
8
|
+
* top of a sub-page's body, NOT a page-level chrome band.
|
|
9
|
+
*
|
|
10
|
+
* Use this when a sub-page renders inside a left-nav shell that already owns the
|
|
11
|
+
* page-level `<mj-page-header>` — the rail's active-item highlight is the section
|
|
12
|
+
* indicator, so the sub-page doesn't need its own title row; just the filter /
|
|
13
|
+
* action surface in a clean card.
|
|
14
|
+
*
|
|
15
|
+
* ## Layout
|
|
16
|
+
*
|
|
17
|
+
* Two-row card. The primary row has an identity column on the left (Title →
|
|
18
|
+
* Subtitle → Meta, stacked) and an actions cluster on the right; the toolbar
|
|
19
|
+
* row holds dense controls (search, tab nav, filter chips) that would compete
|
|
20
|
+
* with the title for space if they shared a row. When `[toolbar]` has no
|
|
21
|
+
* projected content, the row collapses entirely.
|
|
22
|
+
*
|
|
23
|
+
* ```
|
|
24
|
+
* ┌─────────────────────────────────────────────────────────────────────────┐
|
|
25
|
+
* │ Title [—— spacer ——] [actions] │
|
|
26
|
+
* │ subtitle │
|
|
27
|
+
* │ [meta] │
|
|
28
|
+
* ├─────────────────────────────────────────────────────────────────────────┤
|
|
29
|
+
* │ [ toolbar content … search / tab-nav / filter chips … ] │
|
|
30
|
+
* └─────────────────────────────────────────────────────────────────────────┘
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* - **`[Title]`** (input, optional) — short page name. Usually redundant with
|
|
34
|
+
* the parent shell's left-rail label; most sub-pages still set it as a visual
|
|
35
|
+
* anchor.
|
|
36
|
+
* - **`[Subtitle]`** (input, optional) — short prose explaining what the page
|
|
37
|
+
* does. Recommended for pages that aren't self-explanatory from the rail
|
|
38
|
+
* label alone (e.g. Dev Tools inspectors).
|
|
39
|
+
* - **`[meta]`** — **below the subtitle, inside the identity column**: status
|
|
40
|
+
* badges, result counts, stat pills. Reads as supporting info for the
|
|
41
|
+
* identity (not a peer of the title), so the title stays the dominant
|
|
42
|
+
* visual anchor. Wraps to multiple lines when there are many badges.
|
|
43
|
+
* - **`[toolbar]`** — second row: search, tab nav, filter chips, view toggles
|
|
44
|
+
* - **`[actions]`** — top row, right edge: filter popover, refresh, secondary
|
|
45
|
+
* buttons, primary CTA
|
|
46
|
+
*
|
|
47
|
+
* ## Example
|
|
48
|
+
*
|
|
49
|
+
* ```html
|
|
50
|
+
* <mj-page-header-interior Subtitle="Read-only snapshot of Explorer runtime state">
|
|
51
|
+
* <div toolbar>
|
|
52
|
+
* <mj-page-search [Value]="searchTerm" (ValueChange)="onSearch($event)" />
|
|
53
|
+
* <mj-filter-chip Label="Active" [Active]="status === 'active'"
|
|
54
|
+
* (Clicked)="setStatus('active')" />
|
|
55
|
+
* </div>
|
|
56
|
+
* <div actions>
|
|
57
|
+
* <mj-filter-popover ...><mj-filter-panel ...></mj-filter-panel></mj-filter-popover>
|
|
58
|
+
* <mj-refresh-button [Loading]="isLoading" (Clicked)="refresh()" />
|
|
59
|
+
* <button mjButton variant="primary" size="sm">+ Add</button>
|
|
60
|
+
* </div>
|
|
61
|
+
* </mj-page-header-interior>
|
|
62
|
+
* ```
|
|
63
|
+
*
|
|
64
|
+
* See Section 10 of `plans/explorer-chrome-conventions.md` for the full
|
|
65
|
+
* "interior chrome" contract.
|
|
66
|
+
*/
|
|
67
|
+
export declare class MJPageHeaderInteriorComponent {
|
|
68
|
+
/**
|
|
69
|
+
* ARIA role applied to the rendered card. Defaults to `'search'` since the
|
|
70
|
+
* dominant use case is a filter / search region. Pass `null` to omit the
|
|
71
|
+
* role attribute (for non-filter chrome — e.g. a settings-only action band).
|
|
72
|
+
*/
|
|
73
|
+
Role: string | null;
|
|
74
|
+
/**
|
|
75
|
+
* Accessible label for the rendered card. When set, the card becomes a
|
|
76
|
+
* labeled landmark for assistive tech. Recommended to set this for any
|
|
77
|
+
* chrome that represents a meaningful region (e.g. "Filter users").
|
|
78
|
+
*/
|
|
79
|
+
AriaLabel: string | null;
|
|
80
|
+
/**
|
|
81
|
+
* Optional short page name rendered as the identity block on the left of the
|
|
82
|
+
* card. Usually redundant with the parent shell's left-rail label, so most
|
|
83
|
+
* sub-pages omit this and rely on Subtitle alone.
|
|
84
|
+
*/
|
|
85
|
+
Title: string | null;
|
|
86
|
+
/**
|
|
87
|
+
* Optional one-line description rendered under Title (or alone, if Title is
|
|
88
|
+
* not set). Recommended for pages whose purpose isn't obvious from the rail
|
|
89
|
+
* label — e.g. Dev Tools inspectors. Keep it short — one line at typical
|
|
90
|
+
* widths.
|
|
91
|
+
*/
|
|
92
|
+
Subtitle: string | null;
|
|
93
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<MJPageHeaderInteriorComponent, never>;
|
|
94
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<MJPageHeaderInteriorComponent, "mj-page-header-interior", never, { "Role": { "alias": "Role"; "required": false; }; "AriaLabel": { "alias": "AriaLabel"; "required": false; }; "Title": { "alias": "Title"; "required": false; }; "Subtitle": { "alias": "Subtitle"; "required": false; }; }, {}, never, ["[meta]", "[actions]", "[toolbar]"], true, never>;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=page-header-interior.component.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-header-interior.component.d.ts","sourceRoot":"","sources":["../../../src/lib/page-header-interior/page-header-interior.component.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgEG;AACH,qBA2Ka,6BAA6B;IACxC;;;;OAIG;IACM,IAAI,EAAE,MAAM,GAAG,IAAI,CAAY;IAExC;;;;OAIG;IACM,SAAS,EAAE,MAAM,GAAG,IAAI,CAAQ;IAEzC;;;;OAIG;IACM,KAAK,EAAE,MAAM,GAAG,IAAI,CAAQ;IAErC;;;;;OAKG;IACM,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;yCA5B7B,6BAA6B;2CAA7B,6BAA6B;CA6BzC"}
|