@mintplayer/ng-spark 22.5.0 → 22.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mintplayer-ng-spark-shell.mjs","sources":["../../shell/src/spark-program-units.component.ts","../../shell/src/spark-program-units.component.html","../../shell/src/spark-language-selector.component.ts","../../shell/src/spark-shell-slots.ts","../../shell/src/spark-shell.component.ts","../../shell/src/spark-shell.component.html","../../shell/mintplayer-ng-spark-shell.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, effect, inject, input, signal, untracked } from '@angular/core';\nimport { NgTemplateOutlet } from '@angular/common';\nimport { RouterLink, RouterLinkActive } from '@angular/router';\nimport { BsAccordionComponent, BsAccordionTabComponent, BsAccordionTabHeaderDirective } from '@mintplayer/ng-bootstrap/accordion';\nimport { SPARK_AUTH_STATE } from '@mintplayer/ng-spark';\nimport { ProgramUnitGroup } from '@mintplayer/ng-spark/models';\nimport { SparkService } from '@mintplayer/ng-spark/services';\nimport { IconNamePipe, ResolveTranslationPipe, RouterLinkPipe } from '@mintplayer/ng-spark/pipes';\nimport { SparkIconComponent } from '@mintplayer/ng-spark/icon';\nimport { SparkSidebarTab } from './spark-shell-slots';\n\n/**\n * The server-driven navigation menu: an accordion of program-unit groups fetched from\n * `GET /spark/program-units`, which the server has already filtered to what the caller's rights\n * allow. Hosts write ZERO router links for navigation — every group, unit, icon, label and link\n * comes from `programUnits.json`; content around the menu belongs in `<spark-shell>`'s slots,\n * and a host tempted to hand-write a unit anchor should add a unit to `programUnits.json`\n * instead.\n *\n * Because the response is caller-scoped it must be re-fetched when the caller changes: the\n * component tracks the optional `SPARK_AUTH_STATE` signal (supplied by ng-spark-auth's\n * `provideSparkAuth()`, or by the app's own auth stack) and reloads on every change. Without a\n * provider it fetches once. `reloadToken` is the manual escape hatch (any changed value triggers\n * a reload), and `reload()` the imperative one.\n *\n * Usually rendered by `<spark-shell>`; exported standalone for hosts that own their own layout.\n */\n@Component({\n selector: 'spark-program-units',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [\n NgTemplateOutlet,\n RouterLink, RouterLinkActive,\n BsAccordionComponent, BsAccordionTabComponent, BsAccordionTabHeaderDirective,\n SparkIconComponent, ResolveTranslationPipe, IconNamePipe, RouterLinkPipe,\n ],\n templateUrl: './spark-program-units.component.html',\n styleUrl: './spark-program-units.component.scss',\n})\nexport class SparkProgramUnitsComponent {\n private readonly sparkService = inject(SparkService);\n private readonly authState = inject(SPARK_AUTH_STATE, { optional: true });\n\n /** Any changed value triggers a reload — for apps whose auth state isn't a provided signal. */\n readonly reloadToken = input<unknown>(null);\n\n /**\n * Extra tabs to render after the generated groups, normally forwarded by `<spark-shell>` from\n * its `*sparkShellTab` directives. They must be rendered by THIS template — see\n * `SparkShellTabDirective` for why a host-declared `<bs-accordion-tab>` cannot work.\n */\n readonly extraTabs = input<readonly SparkSidebarTab[]>([]);\n\n protected readonly groups = signal<ProgramUnitGroup[]>([]);\n\n constructor() {\n effect(() => {\n this.authState?.();\n this.reloadToken();\n untracked(() => this.reload());\n });\n }\n\n /** Re-fetches the menu. The response is already rights-filtered per caller. */\n async reload(): Promise<void> {\n const config = await this.sparkService.getProgramUnits();\n // Order is the server file's contract, but sort both levels here so the rendered menu never\n // depends on JSON array order — groups were sorted, units were not (#324 F5).\n const groups = [...config.programUnitGroups]\n .sort((a, b) => a.order - b.order)\n .map(g => ({ ...g, programUnits: [...g.programUnits].sort((a, b) => a.order - b.order) }));\n this.groups.set(groups);\n }\n}\n","<bs-accordion class=\"d-block\">\n @for (group of groups(); track group.id) {\n <bs-accordion-tab>\n <ng-container *bsAccordionTabHeader>\n <spark-icon [name]=\"group.icon | iconName:'bi-folder'\" />\n <span class=\"ms-2\">{{ group.name | resolveTranslation }}</span>\n </ng-container>\n @for (unit of group.programUnits; track unit.id) {\n @if (unit | routerLink; as link) {\n <a [routerLink]=\"link\"\n routerLinkActive=\"active\"\n class=\"d-block px-3 py-2 text-decoration-none nav-link\">\n <spark-icon [name]=\"unit.icon | iconName:'bi-file'\" />\n <span class=\"ms-2\">{{ unit.name | resolveTranslation }}</span>\n </a>\n } @else {\n <!-- A url unit is an external address: a plain anchor, never a router link. -->\n <a [href]=\"unit.url\" target=\"_blank\" rel=\"noopener\"\n class=\"d-block px-3 py-2 text-decoration-none nav-link\">\n <spark-icon [name]=\"unit.icon | iconName:'bi-box-arrow-up-right'\" />\n <span class=\"ms-2\">{{ unit.name | resolveTranslation }}</span>\n </a>\n }\n }\n </bs-accordion-tab>\n }\n <!-- Host-contributed tabs are rendered HERE, by this template, so that the accordion's content\n query registers them and they join the generated groups' single-open group. -->\n @for (tab of extraTabs(); track tab.content) {\n <bs-accordion-tab>\n <ng-container *bsAccordionTabHeader>\n @if (tab.headerTemplate; as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl\" />\n } @else {\n <spark-icon [name]=\"tab.icon | iconName:'bi-folder'\" />\n <span class=\"ms-2\">{{ tab.header }}</span>\n }\n </ng-container>\n <ng-container *ngTemplateOutlet=\"tab.content\" />\n </bs-accordion-tab>\n }\n</bs-accordion>\n","import { ChangeDetectionStrategy, Component, inject } from '@angular/core';\nimport { KeyValuePipe } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport { BsSelectComponent, BsSelectOption } from '@mintplayer/ng-bootstrap/select';\nimport { SparkLanguageService } from '@mintplayer/ng-spark/services';\nimport { ResolveTranslationPipe } from '@mintplayer/ng-spark/pipes';\n\n/**\n * The culture switcher: a `bs-select` over `SparkLanguageService`'s languages, persisting the\n * choice. Renders nothing when the app declares one language (or none), so hosts can include it\n * unconditionally — `<spark-shell>`'s topbar does exactly that as its trailing default.\n */\n@Component({\n selector: 'spark-language-selector',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [KeyValuePipe, FormsModule, BsSelectComponent, BsSelectOption, ResolveTranslationPipe],\n template: `\n @if (lang.languages() | keyvalue; as langs) {\n @if (langs.length > 1) {\n <bs-select [ngModel]=\"lang.language()\" (ngModelChange)=\"lang.setLanguage($event)\">\n @for (l of langs; track l.key) {\n <option [ngValue]=\"l.key\">{{ l.value | resolveTranslation }}</option>\n }\n </bs-select>\n }\n }\n `,\n})\nexport class SparkLanguageSelectorComponent {\n protected readonly lang = inject(SparkLanguageService);\n}\n","import { Directive, inject, input, TemplateRef } from '@angular/core';\n\n/**\n * Region slots for `<spark-shell>`.\n *\n * Each directive marks a template that REPLACES one region of the shell chrome (or fills an\n * empty one). An omitted slot is not an empty slot: the shell renders its default — the toggler,\n * the language selector, the title heading — so a host that supplies nothing still gets a\n * complete working shell, and a host that supplies one slot leaves the rest alone.\n *\n * The menu itself is deliberately NOT a slot. Navigation is sourced entirely from\n * `programUnits.json` through the rights-filtered `/spark/program-units` endpoint and re-fetched\n * on sign-in/out; a host that finds itself writing unit anchors in a slot should be adding units\n * to `programUnits.json` instead. Slots exist for the content AROUND the menu: an auth bar, a\n * user chip, branding, a one-off extra link, an alert strip above the routed content.\n *\n * Naming follows the house convention (prefix, component, slot — see `*sparkQueryIcon` in\n * `@mintplayer/ng-spark/grid`): `sparkShell` + region. Every slot also exists as a `TemplateRef`\n * input on `SparkShellComponent` for hosts that cannot use content projection.\n *\n * ```html\n * <spark-shell title=\"My App\">\n * <spark-auth-bar *sparkShellTopbarEnd />\n * <div *sparkShellSidebarTop>\n * <a routerLink=\"/github-projects\" class=\"nav-link\">GitHub projects</a>\n * </div>\n * <router-outlet />\n * </spark-shell>\n * ```\n */\n\n/** Topbar, leading edge. Default: a `bs-navbar-toggler` mirroring the shell's open state. */\n@Directive({ selector: '[sparkShellTopbarStart]' })\nexport class SparkShellTopbarStartDirective {\n readonly templateRef = inject<TemplateRef<unknown>>(TemplateRef);\n}\n\n/**\n * Topbar, trailing edge. Default: the language selector (which hides itself when the app has\n * one language). This is where an auth bar goes — the shell cannot ship one itself, since\n * `@mintplayer/ng-spark` does not (and must not) depend on `@mintplayer/ng-spark-auth`.\n */\n@Directive({ selector: '[sparkShellTopbarEnd]' })\nexport class SparkShellTopbarEndDirective {\n readonly templateRef = inject<TemplateRef<unknown>>(TemplateRef);\n}\n\n/** Sidebar, above everything. Default: `<h5>{{ title }}</h5>`. */\n@Directive({ selector: '[sparkShellSidebarHeader]' })\nexport class SparkShellSidebarHeaderDirective {\n readonly templateRef = inject<TemplateRef<unknown>>(TemplateRef);\n}\n\n/** Sidebar, between the header and the program-units menu. No default. */\n@Directive({ selector: '[sparkShellSidebarTop]' })\nexport class SparkShellSidebarTopDirective {\n readonly templateRef = inject<TemplateRef<unknown>>(TemplateRef);\n}\n\n/**\n * An extra accordion tab in the sidebar menu, rendered after the generated program-unit groups\n * and sharing their single-open behavior.\n *\n * A tab is contributed as DATA (header + body template), not as markup, and that is load-bearing:\n * `bs-accordion` discovers its tabs with an Angular content query, which matches by declaration\n * view, so a `<bs-accordion-tab>` written in a host's template and inserted into the library's\n * accordion is never registered — it would land at index -1, get no hoisted header and no slot.\n * Declaring a second `<bs-accordion>` instead is what puts the tab in its own exclusivity group:\n * `mp-accordion` enforces single-open per element, over children it owns and over\n * `<details name>`, whose grouping cannot cross a shadow root. So the tab element must be created\n * by the menu itself, from what this directive carries.\n *\n * ```html\n * <ng-container *sparkShellTab=\"'Component demos'; icon: 'palette'\">\n * <a routerLink=\"/query-slots\" routerLinkActive=\"active\" class=\"nav-link\">Query card slots</a>\n * </ng-container>\n * ```\n *\n * Navigation still belongs in `programUnits.json` — this is for pages the model cannot describe\n * (client-side demos, external tools). For sidebar content that is NOT an accordion tab, use\n * `*sparkShellSidebarTop` or `*sparkShellSidebarFooter`.\n */\n@Directive({ selector: '[sparkShellTab]' })\nexport class SparkShellTabDirective {\n readonly templateRef = inject<TemplateRef<unknown>>(TemplateRef);\n\n /** The tab's header label. */\n readonly header = input.required<string>({ alias: 'sparkShellTab' });\n\n /** Bootstrap icon name for the header, as in `programUnits.json`. Defaults to a folder. */\n readonly icon = input<string | undefined>(undefined, { alias: 'sparkShellTabIcon' });\n\n /** Replaces the icon+label header entirely, for a header that needs its own markup. */\n readonly headerTemplate = input<TemplateRef<unknown> | null>(null, { alias: 'sparkShellTabHeader' });\n}\n\n/**\n * A sidebar accordion tab in the shape the menu renders it. Hosts normally contribute tabs with\n * `*sparkShellTab`; this is the same thing as data, for a host that computes its tabs.\n */\nexport interface SparkSidebarTab {\n readonly header: string;\n readonly icon?: string;\n readonly headerTemplate?: TemplateRef<unknown> | null;\n readonly content: TemplateRef<unknown>;\n}\n\n/** Sidebar, at the very bottom. No default. */\n@Directive({ selector: '[sparkShellSidebarFooter]' })\nexport class SparkShellSidebarFooterDirective {\n readonly templateRef = inject<TemplateRef<unknown>>(TemplateRef);\n}\n\n/** Main region, above the projected content (the host's `<router-outlet>`). No default. */\n@Directive({ selector: '[sparkShellMainHeader]' })\nexport class SparkShellMainHeaderDirective {\n readonly templateRef = inject<TemplateRef<unknown>>(TemplateRef);\n}\n","import { ChangeDetectionStrategy, Component, computed, contentChild, contentChildren, input, signal, TemplateRef } from '@angular/core';\nimport { NgTemplateOutlet } from '@angular/common';\nimport { BsShellComponent, BsShellSidebarDirective, BsShellState } from '@mintplayer/ng-bootstrap/shell';\nimport { BsNavbarTogglerComponent } from '@mintplayer/ng-bootstrap/navbar-toggler';\nimport type { Breakpoint } from '@mintplayer/ng-bootstrap';\nimport type { ShellStateChangeEventDetail } from '@mintplayer/web-components/shell';\nimport { SparkProgramUnitsComponent } from './spark-program-units.component';\nimport { SparkLanguageSelectorComponent } from './spark-language-selector.component';\nimport {\n SparkShellMainHeaderDirective,\n SparkShellSidebarFooterDirective,\n SparkShellSidebarHeaderDirective,\n SparkShellSidebarTopDirective,\n SparkShellTabDirective,\n SparkShellTopbarEndDirective,\n SparkShellTopbarStartDirective,\n SparkSidebarTab,\n} from './spark-shell-slots';\n\n/**\n * The application frame: topbar + sidebar + main, wrapping ng-bootstrap's `bs-shell` (whose\n * `mp-shell` web component owns ALL responsive behavior — breakpoints, the overlay drawer,\n * dismiss-on-navigate — in CSS; nothing here re-derives a pixel width). The sidebar renders the\n * server-driven program-units menu; the host projects its `<router-outlet>` as the default\n * content and customizes the chrome through the `*sparkShell*` slots (see `spark-shell-slots.ts`\n * for the doctrine: an omitted slot renders its default, and the menu itself is never a slot).\n *\n * ```html\n * <spark-shell title=\"My App\">\n * <spark-auth-bar *sparkShellTopbarEnd />\n * <router-outlet />\n * </spark-shell>\n * ```\n *\n * The one piece of state the shell keeps is the toggler↔drawer mirror: the built-in hamburger is\n * hidden (`::part(hamburger)`) in favor of a `bs-navbar-toggler` in the topbar, so the shell\n * listens to `statechange` to keep the toggler's icon truthful in `auto` mode and only forces\n * `show`/`hide` on explicit toggles.\n *\n * Theming: the chrome colors are CSS custom properties with the classic dark-sidebar defaults —\n * `--spark-shell-topbar-bg`, `--spark-shell-sidebar-bg`, `--spark-shell-main-bg` — overridable on\n * the `<spark-shell>` element. `sidebarTheme` flips the sidebar's `data-bs-theme` (which is what\n * recolors the accordion internals across the shadow boundary) together with its default palette.\n */\n@Component({\n selector: 'spark-shell',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [\n NgTemplateOutlet,\n BsShellComponent, BsShellSidebarDirective, BsNavbarTogglerComponent,\n SparkProgramUnitsComponent, SparkLanguageSelectorComponent,\n ],\n templateUrl: './spark-shell.component.html',\n styleUrl: './spark-shell.component.scss',\n})\nexport class SparkShellComponent {\n /** The sidebar heading. Ignored when a `*sparkShellSidebarHeader` slot is supplied. */\n readonly title = input('');\n\n /** Forwarded to `bs-shell`: below it the sidebar is an overlay drawer. */\n readonly breakpoint = input<Breakpoint>('md');\n\n /**\n * `data-bs-theme` for the sidebar — what flips the accordion's shadow-DOM internals between\n * palettes — plus the matching default background. `null` sets no theme (inherit the page's).\n */\n readonly sidebarTheme = input<'dark' | 'light' | null>('dark');\n\n /** Forwarded to the menu: any changed value re-fetches the program units. */\n readonly reloadToken = input<unknown>(null);\n\n /** Extra sidebar tabs as data, for hosts that compute them; `*sparkShellTab` is the usual way. */\n readonly sidebarTabs = input<readonly SparkSidebarTab[]>([]);\n\n // One TemplateRef input per slot, for hosts that cannot use content projection\n // (the spark-query-card precedent). The projected directive wins when both are present.\n readonly topbarStartTemplate = input<TemplateRef<unknown> | null>(null);\n readonly topbarEndTemplate = input<TemplateRef<unknown> | null>(null);\n readonly sidebarHeaderTemplate = input<TemplateRef<unknown> | null>(null);\n readonly sidebarTopTemplate = input<TemplateRef<unknown> | null>(null);\n readonly sidebarFooterTemplate = input<TemplateRef<unknown> | null>(null);\n readonly mainHeaderTemplate = input<TemplateRef<unknown> | null>(null);\n\n private readonly topbarStartSlot = contentChild(SparkShellTopbarStartDirective);\n private readonly topbarEndSlot = contentChild(SparkShellTopbarEndDirective);\n private readonly sidebarHeaderSlot = contentChild(SparkShellSidebarHeaderDirective);\n private readonly sidebarTopSlot = contentChild(SparkShellSidebarTopDirective);\n private readonly sidebarFooterSlot = contentChild(SparkShellSidebarFooterDirective);\n private readonly mainHeaderSlot = contentChild(SparkShellMainHeaderDirective);\n\n protected readonly topbarStartTpl = computed(() => this.topbarStartSlot()?.templateRef ?? this.topbarStartTemplate());\n protected readonly topbarEndTpl = computed(() => this.topbarEndSlot()?.templateRef ?? this.topbarEndTemplate());\n protected readonly sidebarHeaderTpl = computed(() => this.sidebarHeaderSlot()?.templateRef ?? this.sidebarHeaderTemplate());\n protected readonly sidebarTopTpl = computed(() => this.sidebarTopSlot()?.templateRef ?? this.sidebarTopTemplate());\n protected readonly sidebarFooterTpl = computed(() => this.sidebarFooterSlot()?.templateRef ?? this.sidebarFooterTemplate());\n protected readonly mainHeaderTpl = computed(() => this.mainHeaderSlot()?.templateRef ?? this.mainHeaderTemplate());\n\n /**\n * Extra accordion tabs, forwarded to the menu so IT creates the `<bs-accordion-tab>` elements —\n * the only way they share the generated groups' single-open behavior (see\n * `SparkShellTabDirective`). Data-supplied tabs come first, then projected ones in declaration\n * order.\n */\n private readonly tabSlots = contentChildren(SparkShellTabDirective);\n\n protected readonly tabs = computed<readonly SparkSidebarTab[]>(() => [\n ...this.sidebarTabs(),\n ...this.tabSlots().map(slot => ({\n header: slot.header(),\n icon: slot.icon(),\n headerTemplate: slot.headerTemplate(),\n content: slot.templateRef,\n })),\n ]);\n\n protected readonly shellState = signal<BsShellState>('auto');\n protected readonly isSidebarVisible = signal(false);\n\n // Explicit toggles force show/hide; 'auto' responsive behavior is otherwise preserved by\n // never writing state on our own. The mirror below keeps the toggler icon truthful when the\n // shell opens/closes itself at the breakpoint.\n protected toggleSidebar(open: boolean): void {\n this.shellState.set(open ? 'show' : 'hide');\n }\n\n protected onShellToggle(detail: ShellStateChangeEventDetail): void {\n this.isSidebarVisible.set(detail.open);\n }\n}\n","<bs-shell [state]=\"shellState()\" [breakpoint]=\"breakpoint()\" [dismissOnNavigate]=\"true\"\n (statechange)=\"onShellToggle($event)\">\n <div slot=\"topbar\" class=\"spark-topbar w-100 d-flex align-items-center\">\n @if (topbarStartTpl(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl\" />\n } @else {\n <bs-navbar-toggler [state]=\"isSidebarVisible()\" (stateChange)=\"toggleSidebar($event)\" />\n }\n <div class=\"ms-auto me-3 d-flex align-items-center gap-2\">\n @if (topbarEndTpl(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl\" />\n } @else {\n <spark-language-selector />\n }\n </div>\n </div>\n\n <nav bsShellSidebar class=\"spark-sidebar p-2\"\n [class.spark-sidebar-dark]=\"sidebarTheme() === 'dark'\"\n [attr.data-bs-theme]=\"sidebarTheme()\">\n @if (sidebarHeaderTpl(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl\" />\n } @else {\n <h5 class=\"p-3 border-bottom\">{{ title() }}</h5>\n }\n @if (sidebarTopTpl(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl\" />\n }\n <spark-program-units [reloadToken]=\"reloadToken()\" [extraTabs]=\"tabs()\" />\n @if (sidebarFooterTpl(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl\" />\n }\n </nav>\n\n <main class=\"p-4\">\n @if (mainHeaderTpl(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl\" />\n }\n <ng-content />\n </main>\n</bs-shell>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;;;;;;;;;;;AAWA;;;;;;;;;;;;;;;AAeG;MAcU,0BAA0B,CAAA;AACpB,IAAA,YAAY,GAAG,MAAM,CAAC,YAAY,CAAC;IACnC,SAAS,GAAG,MAAM,CAAC,gBAAgB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;IAGhE,WAAW,GAAG,KAAK,CAAU,IAAI;oFAAC;AAE3C;;;;AAIG;IACM,SAAS,GAAG,KAAK,CAA6B,EAAE;kFAAC;IAEvC,MAAM,GAAG,MAAM,CAAqB,EAAE;+EAAC;AAE1D,IAAA,WAAA,GAAA;QACE,MAAM,CAAC,MAAK;AACV,YAAA,IAAI,CAAC,SAAS,IAAI;YAClB,IAAI,CAAC,WAAW,EAAE;YAClB,SAAS,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;AAChC,QAAA,CAAC,CAAC;IACJ;;AAGA,IAAA,MAAM,MAAM,GAAA;QACV,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,eAAe,EAAE;;;AAGxD,QAAA,MAAM,MAAM,GAAG,CAAC,GAAG,MAAM,CAAC,iBAAiB;AACxC,aAAA,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK;AAChC,aAAA,GAAG,CAAC,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,YAAY,EAAE,CAAC,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;AAC5F,QAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC;IACzB;uGAjCW,0BAA0B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAA1B,0BAA0B,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,qBAAA,EAAA,MAAA,EAAA,EAAA,WAAA,EAAA,EAAA,iBAAA,EAAA,aAAA,EAAA,UAAA,EAAA,aAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,ECxCvC,62DA0CA,EAAA,MAAA,EAAA,CAAA,wQAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EDVI,gBAAgB,oJAChB,UAAU,EAAA,QAAA,EAAA,cAAA,EAAA,MAAA,EAAA,CAAA,QAAA,EAAA,aAAA,EAAA,UAAA,EAAA,qBAAA,EAAA,OAAA,EAAA,MAAA,EAAA,YAAA,EAAA,kBAAA,EAAA,oBAAA,EAAA,YAAA,EAAA,YAAA,EAAA,YAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,gBAAgB,EAAA,QAAA,EAAA,oBAAA,EAAA,MAAA,EAAA,CAAA,yBAAA,EAAA,uBAAA,EAAA,kBAAA,CAAA,EAAA,OAAA,EAAA,CAAA,gBAAA,CAAA,EAAA,QAAA,EAAA,CAAA,kBAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAC5B,oBAAoB,kGAAE,uBAAuB,EAAA,QAAA,EAAA,kBAAA,EAAA,MAAA,EAAA,CAAA,UAAA,EAAA,UAAA,CAAA,EAAA,OAAA,EAAA,CAAA,gBAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,6BAA6B,EAAA,QAAA,EAAA,wBAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAC5E,kBAAkB,oEAAE,sBAAsB,EAAA,IAAA,EAAA,oBAAA,EAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EAAE,YAAY,EAAA,IAAA,EAAA,UAAA,EAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EAAE,cAAc,EAAA,IAAA,EAAA,YAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAK/D,0BAA0B,EAAA,UAAA,EAAA,CAAA;kBAbtC,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,qBAAqB,cACnB,IAAI,EAAA,eAAA,EACC,uBAAuB,CAAC,MAAM,EAAA,OAAA,EACtC;wBACP,gBAAgB;AAChB,wBAAA,UAAU,EAAE,gBAAgB;wBAC5B,oBAAoB,EAAE,uBAAuB,EAAE,6BAA6B;AAC5E,wBAAA,kBAAkB,EAAE,sBAAsB,EAAE,YAAY,EAAE,cAAc;AACzE,qBAAA,EAAA,QAAA,EAAA,62DAAA,EAAA,MAAA,EAAA,CAAA,wQAAA,CAAA,EAAA;;;AE7BH;;;;AAIG;MAkBU,8BAA8B,CAAA;AACtB,IAAA,IAAI,GAAG,MAAM,CAAC,oBAAoB,CAAC;uGAD3C,8BAA8B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAA9B,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,8BAA8B,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,yBAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAZ/B;;;;;;;;;;GAUT,EAAA,QAAA,EAAA,IAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAXuB,WAAW,4iBAAE,iBAAiB,EAAA,QAAA,EAAA,WAAA,EAAA,MAAA,EAAA,CAAA,YAAA,EAAA,MAAA,EAAA,UAAA,EAAA,eAAA,EAAA,UAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,cAAc,EAAA,QAAA,EAAA,QAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,OAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EAA5D,YAAY,4CAAkD,sBAAsB,EAAA,IAAA,EAAA,oBAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAanF,8BAA8B,EAAA,UAAA,EAAA,CAAA;kBAjB1C,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,yBAAyB;AACnC,oBAAA,UAAU,EAAE,IAAI;oBAChB,eAAe,EAAE,uBAAuB,CAAC,MAAM;oBAC/C,OAAO,EAAE,CAAC,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,cAAc,EAAE,sBAAsB,CAAC;AAC/F,oBAAA,QAAQ,EAAE;;;;;;;;;;AAUT,EAAA,CAAA;AACF,iBAAA;;;AC1BD;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BG;AAEH;MAEa,8BAA8B,CAAA;AAChC,IAAA,WAAW,GAAG,MAAM,CAAuB,WAAW,CAAC;uGADrD,8BAA8B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAA9B,8BAA8B,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,yBAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAA9B,8BAA8B,EAAA,UAAA,EAAA,CAAA;kBAD1C,SAAS;mBAAC,EAAE,QAAQ,EAAE,yBAAyB,EAAE;;AAKlD;;;;AAIG;MAEU,4BAA4B,CAAA;AAC9B,IAAA,WAAW,GAAG,MAAM,CAAuB,WAAW,CAAC;uGADrD,4BAA4B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAA5B,4BAA4B,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,uBAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAA5B,4BAA4B,EAAA,UAAA,EAAA,CAAA;kBADxC,SAAS;mBAAC,EAAE,QAAQ,EAAE,uBAAuB,EAAE;;AAKhD;MAEa,gCAAgC,CAAA;AAClC,IAAA,WAAW,GAAG,MAAM,CAAuB,WAAW,CAAC;uGADrD,gCAAgC,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAhC,gCAAgC,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,2BAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAAhC,gCAAgC,EAAA,UAAA,EAAA,CAAA;kBAD5C,SAAS;mBAAC,EAAE,QAAQ,EAAE,2BAA2B,EAAE;;AAKpD;MAEa,6BAA6B,CAAA;AAC/B,IAAA,WAAW,GAAG,MAAM,CAAuB,WAAW,CAAC;uGADrD,6BAA6B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAA7B,6BAA6B,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,wBAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAA7B,6BAA6B,EAAA,UAAA,EAAA,CAAA;kBADzC,SAAS;mBAAC,EAAE,QAAQ,EAAE,wBAAwB,EAAE;;AAKjD;;;;;;;;;;;;;;;;;;;;;;AAsBG;MAEU,sBAAsB,CAAA;AACxB,IAAA,WAAW,GAAG,MAAM,CAAuB,WAAW,CAAC;;IAGvD,MAAM,GAAG,KAAK,CAAC,QAAQ,6EAAW,KAAK,EAAE,eAAe,EAAA,CAAG;;IAG3D,IAAI,GAAG,KAAK,CAAqB,SAAS,4EAAI,KAAK,EAAE,mBAAmB,EAAA,CAAG;;IAG3E,cAAc,GAAG,KAAK,CAA8B,IAAI,sFAAI,KAAK,EAAE,qBAAqB,EAAA,CAAG;uGAVzF,sBAAsB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAtB,sBAAsB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,eAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,IAAA,EAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,UAAA,EAAA,mBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,EAAA,iBAAA,EAAA,gBAAA,EAAA,UAAA,EAAA,qBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAAtB,sBAAsB,EAAA,UAAA,EAAA,CAAA;kBADlC,SAAS;mBAAC,EAAE,QAAQ,EAAE,iBAAiB,EAAE;;AAyB1C;MAEa,gCAAgC,CAAA;AAClC,IAAA,WAAW,GAAG,MAAM,CAAuB,WAAW,CAAC;uGADrD,gCAAgC,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAhC,gCAAgC,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,2BAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAAhC,gCAAgC,EAAA,UAAA,EAAA,CAAA;kBAD5C,SAAS;mBAAC,EAAE,QAAQ,EAAE,2BAA2B,EAAE;;AAKpD;MAEa,6BAA6B,CAAA;AAC/B,IAAA,WAAW,GAAG,MAAM,CAAuB,WAAW,CAAC;uGADrD,6BAA6B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAA7B,6BAA6B,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,wBAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAA7B,6BAA6B,EAAA,UAAA,EAAA,CAAA;kBADzC,SAAS;mBAAC,EAAE,QAAQ,EAAE,wBAAwB,EAAE;;;AC/FjD;;;;;;;;;;;;;;;;;;;;;;;;AAwBG;MAaU,mBAAmB,CAAA;;IAErB,KAAK,GAAG,KAAK,CAAC,EAAE;8EAAC;;IAGjB,UAAU,GAAG,KAAK,CAAa,IAAI;mFAAC;AAE7C;;;AAGG;IACM,YAAY,GAAG,KAAK,CAA0B,MAAM;qFAAC;;IAGrD,WAAW,GAAG,KAAK,CAAU,IAAI;oFAAC;;IAGlC,WAAW,GAAG,KAAK,CAA6B,EAAE;oFAAC;;;IAInD,mBAAmB,GAAG,KAAK,CAA8B,IAAI;4FAAC;IAC9D,iBAAiB,GAAG,KAAK,CAA8B,IAAI;0FAAC;IAC5D,qBAAqB,GAAG,KAAK,CAA8B,IAAI;8FAAC;IAChE,kBAAkB,GAAG,KAAK,CAA8B,IAAI;2FAAC;IAC7D,qBAAqB,GAAG,KAAK,CAA8B,IAAI;8FAAC;IAChE,kBAAkB,GAAG,KAAK,CAA8B,IAAI;2FAAC;IAErD,eAAe,GAAG,YAAY,CAAC,8BAA8B;wFAAC;IAC9D,aAAa,GAAG,YAAY,CAAC,4BAA4B;sFAAC;IAC1D,iBAAiB,GAAG,YAAY,CAAC,gCAAgC;0FAAC;IAClE,cAAc,GAAG,YAAY,CAAC,6BAA6B;uFAAC;IAC5D,iBAAiB,GAAG,YAAY,CAAC,gCAAgC;0FAAC;IAClE,cAAc,GAAG,YAAY,CAAC,6BAA6B;uFAAC;AAE1D,IAAA,cAAc,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,eAAe,EAAE,EAAE,WAAW,IAAI,IAAI,CAAC,mBAAmB,EAAE;uFAAC;AAClG,IAAA,YAAY,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,aAAa,EAAE,EAAE,WAAW,IAAI,IAAI,CAAC,iBAAiB,EAAE;qFAAC;AAC5F,IAAA,gBAAgB,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,iBAAiB,EAAE,EAAE,WAAW,IAAI,IAAI,CAAC,qBAAqB,EAAE;yFAAC;AACxG,IAAA,aAAa,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,cAAc,EAAE,EAAE,WAAW,IAAI,IAAI,CAAC,kBAAkB,EAAE;sFAAC;AAC/F,IAAA,gBAAgB,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,iBAAiB,EAAE,EAAE,WAAW,IAAI,IAAI,CAAC,qBAAqB,EAAE;yFAAC;AACxG,IAAA,aAAa,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,cAAc,EAAE,EAAE,WAAW,IAAI,IAAI,CAAC,kBAAkB,EAAE;sFAAC;AAElH;;;;;AAKG;IACc,QAAQ,GAAG,eAAe,CAAC,sBAAsB;iFAAC;AAEhD,IAAA,IAAI,GAAG,QAAQ,CAA6B,MAAM;QACnE,GAAG,IAAI,CAAC,WAAW,EAAE;QACrB,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK;AAC9B,YAAA,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE;AACrB,YAAA,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE;AACjB,YAAA,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE;YACrC,OAAO,EAAE,IAAI,CAAC,WAAW;AAC1B,SAAA,CAAC,CAAC;AACJ,KAAA;6EAAC;IAEiB,UAAU,GAAG,MAAM,CAAe,MAAM;mFAAC;IACzC,gBAAgB,GAAG,MAAM,CAAC,KAAK;yFAAC;;;;AAKzC,IAAA,aAAa,CAAC,IAAa,EAAA;AACnC,QAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC;IAC7C;AAEU,IAAA,aAAa,CAAC,MAAmC,EAAA;QACzD,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;IACxC;uGAxEW,mBAAmB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAnB,mBAAmB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,aAAA,EAAA,MAAA,EAAA,EAAA,KAAA,EAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,iBAAA,EAAA,YAAA,EAAA,UAAA,EAAA,YAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,YAAA,EAAA,EAAA,iBAAA,EAAA,cAAA,EAAA,UAAA,EAAA,cAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,WAAA,EAAA,EAAA,iBAAA,EAAA,aAAA,EAAA,UAAA,EAAA,aAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,WAAA,EAAA,EAAA,iBAAA,EAAA,aAAA,EAAA,UAAA,EAAA,aAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,mBAAA,EAAA,EAAA,iBAAA,EAAA,qBAAA,EAAA,UAAA,EAAA,qBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,iBAAA,EAAA,EAAA,iBAAA,EAAA,mBAAA,EAAA,UAAA,EAAA,mBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,qBAAA,EAAA,EAAA,iBAAA,EAAA,uBAAA,EAAA,UAAA,EAAA,uBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,kBAAA,EAAA,EAAA,iBAAA,EAAA,oBAAA,EAAA,UAAA,EAAA,oBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,qBAAA,EAAA,EAAA,iBAAA,EAAA,uBAAA,EAAA,UAAA,EAAA,uBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,kBAAA,EAAA,EAAA,iBAAA,EAAA,oBAAA,EAAA,UAAA,EAAA,oBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,CAAA,EAAA,YAAA,EAAA,iBAAA,EAAA,KAAA,EAAA,IAAA,EAAA,SAAA,EA4BkB,8BAA8B,EAAA,WAAA,EAAA,IAAA,EAAA,QAAA,EAAA,IAAA,EAAA,EAAA,EAAA,YAAA,EAAA,eAAA,EAAA,KAAA,EAAA,IAAA,EAAA,SAAA,EAChC,4BAA4B,EAAA,WAAA,EAAA,IAAA,EAAA,QAAA,EAAA,IAAA,EAAA,EAAA,EAAA,YAAA,EAAA,mBAAA,EAAA,KAAA,EAAA,IAAA,EAAA,SAAA,EACxB,gCAAgC,EAAA,WAAA,EAAA,IAAA,EAAA,QAAA,EAAA,IAAA,EAAA,EAAA,EAAA,YAAA,EAAA,gBAAA,EAAA,KAAA,EAAA,IAAA,EAAA,SAAA,EACnC,6BAA6B,EAAA,WAAA,EAAA,IAAA,EAAA,QAAA,EAAA,IAAA,EAAA,EAAA,EAAA,YAAA,EAAA,mBAAA,EAAA,KAAA,EAAA,IAAA,EAAA,SAAA,EAC1B,gCAAgC,EAAA,WAAA,EAAA,IAAA,EAAA,QAAA,EAAA,IAAA,EAAA,EAAA,EAAA,YAAA,EAAA,gBAAA,EAAA,KAAA,EAAA,IAAA,EAAA,SAAA,EACnC,6BAA6B,EAAA,WAAA,EAAA,IAAA,EAAA,QAAA,EAAA,IAAA,EAAA,EAAA,EAAA,YAAA,EAAA,UAAA,EAAA,SAAA,EAehC,sBAAsB,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,ECxGpE,07CAyCA,EAAA,MAAA,EAAA,CAAA,q+BAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EDQI,gBAAgB,EAAA,QAAA,EAAA,oBAAA,EAAA,MAAA,EAAA,CAAA,yBAAA,EAAA,kBAAA,EAAA,0BAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAChB,gBAAgB,EAAA,QAAA,EAAA,UAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,YAAA,EAAA,mBAAA,CAAA,EAAA,OAAA,EAAA,CAAA,aAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,uBAAuB,EAAA,QAAA,EAAA,kBAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,wBAAwB,EAAA,QAAA,EAAA,mBAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,eAAA,EAAA,WAAA,EAAA,UAAA,CAAA,EAAA,OAAA,EAAA,CAAA,aAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACnE,0BAA0B,EAAA,QAAA,EAAA,qBAAA,EAAA,MAAA,EAAA,CAAA,aAAA,EAAA,WAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,8BAA8B,EAAA,QAAA,EAAA,yBAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAKjD,mBAAmB,EAAA,UAAA,EAAA,CAAA;kBAZ/B,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,aAAa,cACX,IAAI,EAAA,eAAA,EACC,uBAAuB,CAAC,MAAM,EAAA,OAAA,EACtC;wBACP,gBAAgB;wBAChB,gBAAgB,EAAE,uBAAuB,EAAE,wBAAwB;AACnE,wBAAA,0BAA0B,EAAE,8BAA8B;AAC3D,qBAAA,EAAA,QAAA,EAAA,07CAAA,EAAA,MAAA,EAAA,CAAA,q+BAAA,CAAA,EAAA;0xCAgC+C,8BAA8B,CAAA,EAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,aAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,YAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,UAAA,CAAA,MAChC,4BAA4B,CAAA,EAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,iBAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,YAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,UAAA,CAAA,MACxB,gCAAgC,CAAA,EAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,cAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,YAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,UAAA,CAAA,MACnC,6BAA6B,CAAA,EAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,iBAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,YAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,UAAA,CAAA,MAC1B,gCAAgC,CAAA,EAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,cAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,YAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,UAAA,CAAA,MACnC,6BAA6B,CAAA,EAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,QAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,eAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,UAAA,CAAA,MAehC,sBAAsB,CAAA,EAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,EAAA,CAAA;;AExGpE;;AAEG;;;;"}
@@ -5,6 +5,21 @@ const defaultSparkConfig = {
5
5
  baseUrl: '/spark'
6
6
  };
7
7
 
8
+ /**
9
+ * A signal that changes whenever the authenticated user changes — the bridge that lets ng-spark
10
+ * components react to sign-in/out without a dependency on `@mintplayer/ng-spark-auth` (no
11
+ * dependency exists between the two packages, in either direction, on purpose).
12
+ *
13
+ * `@mintplayer/ng-spark-auth`'s `provideSparkAuth()` supplies it from `SparkAuthService.user`;
14
+ * an app with its own auth stack provides any signal that changes on sign-in/out. Consumers
15
+ * inject it `{ optional: true }` — absent, auth-sensitive data (the program-units menu) is
16
+ * fetched once and never re-fetched.
17
+ *
18
+ * The signal's VALUE is deliberately opaque (`unknown`): consumers only track it for change,
19
+ * never read it — what "the user" looks like belongs to the auth package.
20
+ */
21
+ const SPARK_AUTH_STATE = new InjectionToken('SPARK_AUTH_STATE');
22
+
8
23
  function provideSpark(config) {
9
24
  return [
10
25
  {
@@ -28,10 +43,11 @@ function provideSpark(config) {
28
43
  // @mintplayer/ng-spark/query-list (SparkQueryListComponent)
29
44
  // @mintplayer/ng-spark/retry-action-modal (SparkRetryActionModalComponent)
30
45
  // @mintplayer/ng-spark/icon (SparkIconComponent)
46
+ // @mintplayer/ng-spark/shell (SparkShellComponent + slots, SparkProgramUnitsComponent, SparkLanguageSelectorComponent)
31
47
 
32
48
  /**
33
49
  * Generated bundle index. Do not edit.
34
50
  */
35
51
 
36
- export { SPARK_CONFIG, defaultSparkConfig, provideSpark };
52
+ export { SPARK_AUTH_STATE, SPARK_CONFIG, defaultSparkConfig, provideSpark };
37
53
  //# sourceMappingURL=mintplayer-ng-spark.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"mintplayer-ng-spark.mjs","sources":["../../src/lib/spark-config.ts","../../src/lib/provide-spark.ts","../../src/public-api.ts","../../src/mintplayer-ng-spark.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\n\nexport interface SparkConfig {\n baseUrl: string;\n}\n\nexport const SPARK_CONFIG = new InjectionToken<SparkConfig>('SPARK_CONFIG');\n\nexport const defaultSparkConfig: SparkConfig = {\n baseUrl: '/spark'\n};\n","import { Provider } from '@angular/core';\nimport { SPARK_CONFIG, SparkConfig, defaultSparkConfig } from './spark-config';\n\nexport function provideSpark(config?: Partial<SparkConfig>): Provider[] {\n return [\n {\n provide: SPARK_CONFIG,\n useValue: { ...defaultSparkConfig, ...config }\n }\n ];\n}\n","// Root entry point — bootstrap API only.\n// For other members import from sub-paths:\n// @mintplayer/ng-spark/models (PersistentObject, EntityType, SparkQuery, etc. + currentLanguage/resolveTranslation/ShowedOn/ELookupDisplayType)\n// @mintplayer/ng-spark/services (SparkService, SparkStreamingService, SparkLanguageService, RetryActionService, SparkIconRegistry)\n// @mintplayer/ng-spark/pipes (all 22 pipes)\n// @mintplayer/ng-spark/renderers (SPARK_ATTRIBUTE_RENDERERS, provideSparkAttributeRenderers, renderer interfaces)\n// @mintplayer/ng-spark/routes (sparkRoutes, SparkRouteConfig)\n// @mintplayer/ng-spark/po-form (SparkPoFormComponent)\n// @mintplayer/ng-spark/po-create (SparkPoCreateComponent)\n// @mintplayer/ng-spark/po-edit (SparkPoEditComponent)\n// @mintplayer/ng-spark/po-detail (SparkPoDetailComponent)\n// @mintplayer/ng-spark/query-list (SparkQueryListComponent)\n// @mintplayer/ng-spark/retry-action-modal (SparkRetryActionModalComponent)\n// @mintplayer/ng-spark/icon (SparkIconComponent)\n\nexport type { SparkConfig } from './lib/spark-config';\nexport { SPARK_CONFIG, defaultSparkConfig } from './lib/spark-config';\nexport { provideSpark } from './lib/provide-spark';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;MAMa,YAAY,GAAG,IAAI,cAAc,CAAc,cAAc;AAEnE,MAAM,kBAAkB,GAAgB;AAC7C,IAAA,OAAO,EAAE;;;ACNL,SAAU,YAAY,CAAC,MAA6B,EAAA;IACxD,OAAO;AACL,QAAA;AACE,YAAA,OAAO,EAAE,YAAY;AACrB,YAAA,QAAQ,EAAE,EAAE,GAAG,kBAAkB,EAAE,GAAG,MAAM;AAC7C;KACF;AACH;;ACVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACbA;;AAEG;;;;"}
1
+ {"version":3,"file":"mintplayer-ng-spark.mjs","sources":["../../src/lib/spark-config.ts","../../src/lib/spark-auth-state.ts","../../src/lib/provide-spark.ts","../../src/public-api.ts","../../src/mintplayer-ng-spark.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\n\nexport interface SparkConfig {\n baseUrl: string;\n}\n\nexport const SPARK_CONFIG = new InjectionToken<SparkConfig>('SPARK_CONFIG');\n\nexport const defaultSparkConfig: SparkConfig = {\n baseUrl: '/spark'\n};\n","import { InjectionToken, Signal } from '@angular/core';\n\n/**\n * A signal that changes whenever the authenticated user changes — the bridge that lets ng-spark\n * components react to sign-in/out without a dependency on `@mintplayer/ng-spark-auth` (no\n * dependency exists between the two packages, in either direction, on purpose).\n *\n * `@mintplayer/ng-spark-auth`'s `provideSparkAuth()` supplies it from `SparkAuthService.user`;\n * an app with its own auth stack provides any signal that changes on sign-in/out. Consumers\n * inject it `{ optional: true }` — absent, auth-sensitive data (the program-units menu) is\n * fetched once and never re-fetched.\n *\n * The signal's VALUE is deliberately opaque (`unknown`): consumers only track it for change,\n * never read it — what \"the user\" looks like belongs to the auth package.\n */\nexport const SPARK_AUTH_STATE = new InjectionToken<Signal<unknown>>('SPARK_AUTH_STATE');\n","import { Provider } from '@angular/core';\nimport { SPARK_CONFIG, SparkConfig, defaultSparkConfig } from './spark-config';\n\nexport function provideSpark(config?: Partial<SparkConfig>): Provider[] {\n return [\n {\n provide: SPARK_CONFIG,\n useValue: { ...defaultSparkConfig, ...config }\n }\n ];\n}\n","// Root entry point — bootstrap API only.\n// For other members import from sub-paths:\n// @mintplayer/ng-spark/models (PersistentObject, EntityType, SparkQuery, etc. + currentLanguage/resolveTranslation/ShowedOn/ELookupDisplayType)\n// @mintplayer/ng-spark/services (SparkService, SparkStreamingService, SparkLanguageService, RetryActionService, SparkIconRegistry)\n// @mintplayer/ng-spark/pipes (all 22 pipes)\n// @mintplayer/ng-spark/renderers (SPARK_ATTRIBUTE_RENDERERS, provideSparkAttributeRenderers, renderer interfaces)\n// @mintplayer/ng-spark/routes (sparkRoutes, SparkRouteConfig)\n// @mintplayer/ng-spark/po-form (SparkPoFormComponent)\n// @mintplayer/ng-spark/po-create (SparkPoCreateComponent)\n// @mintplayer/ng-spark/po-edit (SparkPoEditComponent)\n// @mintplayer/ng-spark/po-detail (SparkPoDetailComponent)\n// @mintplayer/ng-spark/query-list (SparkQueryListComponent)\n// @mintplayer/ng-spark/retry-action-modal (SparkRetryActionModalComponent)\n// @mintplayer/ng-spark/icon (SparkIconComponent)\n// @mintplayer/ng-spark/shell (SparkShellComponent + slots, SparkProgramUnitsComponent, SparkLanguageSelectorComponent)\n\nexport type { SparkConfig } from './lib/spark-config';\nexport { SPARK_CONFIG, defaultSparkConfig } from './lib/spark-config';\nexport { SPARK_AUTH_STATE } from './lib/spark-auth-state';\nexport { provideSpark } from './lib/provide-spark';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;MAMa,YAAY,GAAG,IAAI,cAAc,CAAc,cAAc;AAEnE,MAAM,kBAAkB,GAAgB;AAC7C,IAAA,OAAO,EAAE;;;ACPX;;;;;;;;;;;;AAYG;MACU,gBAAgB,GAAG,IAAI,cAAc,CAAkB,kBAAkB;;ACZhF,SAAU,YAAY,CAAC,MAA6B,EAAA;IACxD,OAAO;AACL,QAAA;AACE,YAAA,OAAO,EAAE,YAAY;AACrB,YAAA,QAAQ,EAAE,EAAE,GAAG,kBAAkB,EAAE,GAAG,MAAM;AAC7C;KACF;AACH;;ACVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACdA;;AAEG;;;;"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mintplayer/ng-spark",
3
3
  "private": false,
4
- "version": "22.5.0",
4
+ "version": "22.6.0",
5
5
  "description": "Angular component library for MintPlayer.Spark CRUD applications",
6
6
  "repository": {
7
7
  "type": "git",
@@ -84,6 +84,10 @@
84
84
  "./services": {
85
85
  "types": "./types/mintplayer-ng-spark-services.d.ts",
86
86
  "default": "./fesm2022/mintplayer-ng-spark-services.mjs"
87
+ },
88
+ "./shell": {
89
+ "types": "./types/mintplayer-ng-spark-shell.d.ts",
90
+ "default": "./fesm2022/mintplayer-ng-spark-shell.mjs"
87
91
  }
88
92
  },
89
93
  "type": "module",
@@ -241,9 +241,21 @@ interface ProgramUnit {
241
241
  id: string;
242
242
  name: TranslatedString;
243
243
  icon?: string;
244
+ /**
245
+ * Canonical unit type, exact-cased by the server's loader: 'query' | 'persistentObject' | 'url'.
246
+ * Kept as string rather than a union so an older client tolerates a newer server.
247
+ */
244
248
  type: string;
245
249
  queryId?: string;
246
250
  persistentObjectId?: string;
251
+ /**
252
+ * For a persistentObject unit: the specific object to open — the menu entry deep-links to
253
+ * `/po/{type}/{objectId}`. Absent means the type's default list. For a composed page this is
254
+ * whatever stable string the app declared; the server's Actions class may ignore it.
255
+ */
256
+ objectId?: string;
257
+ /** For a url unit: the external address, rendered as a plain anchor (never a router link). */
258
+ url?: string;
247
259
  order: number;
248
260
  alias?: string;
249
261
  }
@@ -70,8 +70,16 @@ declare class ReferenceChipsPipe implements PipeTransform {
70
70
  static ɵpipe: i0.ɵɵPipeDeclaration<ReferenceChipsPipe, "referenceChips", true>;
71
71
  }
72
72
 
73
+ /**
74
+ * Maps a program unit to the router commands that open it. Type comparisons are exact: the
75
+ * server's loader canonicalizes `type` casing, so tolerating variants here would only mask a
76
+ * server that stopped doing so.
77
+ *
78
+ * Returns null for a `url` unit — an external address is an `<a href>`, not a router link; the
79
+ * component rendering the menu owns that branch.
80
+ */
73
81
  declare class RouterLinkPipe implements PipeTransform {
74
- transform(unit: ProgramUnit): string[];
82
+ transform(unit: ProgramUnit): string[] | null;
75
83
  static ɵfac: i0.ɵɵFactoryDeclaration<RouterLinkPipe, never>;
76
84
  static ɵpipe: i0.ɵɵPipeDeclaration<RouterLinkPipe, "routerLink", true>;
77
85
  }
@@ -0,0 +1,242 @@
1
+ import * as _angular_core from '@angular/core';
2
+ import { TemplateRef } from '@angular/core';
3
+ import { BsShellState } from '@mintplayer/ng-bootstrap/shell';
4
+ import { Breakpoint } from '@mintplayer/ng-bootstrap';
5
+ import { ShellStateChangeEventDetail } from '@mintplayer/web-components/shell';
6
+ import { ProgramUnitGroup } from '@mintplayer/ng-spark/models';
7
+ import { SparkLanguageService } from '@mintplayer/ng-spark/services';
8
+
9
+ /**
10
+ * Region slots for `<spark-shell>`.
11
+ *
12
+ * Each directive marks a template that REPLACES one region of the shell chrome (or fills an
13
+ * empty one). An omitted slot is not an empty slot: the shell renders its default — the toggler,
14
+ * the language selector, the title heading — so a host that supplies nothing still gets a
15
+ * complete working shell, and a host that supplies one slot leaves the rest alone.
16
+ *
17
+ * The menu itself is deliberately NOT a slot. Navigation is sourced entirely from
18
+ * `programUnits.json` through the rights-filtered `/spark/program-units` endpoint and re-fetched
19
+ * on sign-in/out; a host that finds itself writing unit anchors in a slot should be adding units
20
+ * to `programUnits.json` instead. Slots exist for the content AROUND the menu: an auth bar, a
21
+ * user chip, branding, a one-off extra link, an alert strip above the routed content.
22
+ *
23
+ * Naming follows the house convention (prefix, component, slot — see `*sparkQueryIcon` in
24
+ * `@mintplayer/ng-spark/grid`): `sparkShell` + region. Every slot also exists as a `TemplateRef`
25
+ * input on `SparkShellComponent` for hosts that cannot use content projection.
26
+ *
27
+ * ```html
28
+ * <spark-shell title="My App">
29
+ * <spark-auth-bar *sparkShellTopbarEnd />
30
+ * <div *sparkShellSidebarTop>
31
+ * <a routerLink="/github-projects" class="nav-link">GitHub projects</a>
32
+ * </div>
33
+ * <router-outlet />
34
+ * </spark-shell>
35
+ * ```
36
+ */
37
+ /** Topbar, leading edge. Default: a `bs-navbar-toggler` mirroring the shell's open state. */
38
+ declare class SparkShellTopbarStartDirective {
39
+ readonly templateRef: TemplateRef<unknown>;
40
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SparkShellTopbarStartDirective, never>;
41
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<SparkShellTopbarStartDirective, "[sparkShellTopbarStart]", never, {}, {}, never, never, true, never>;
42
+ }
43
+ /**
44
+ * Topbar, trailing edge. Default: the language selector (which hides itself when the app has
45
+ * one language). This is where an auth bar goes — the shell cannot ship one itself, since
46
+ * `@mintplayer/ng-spark` does not (and must not) depend on `@mintplayer/ng-spark-auth`.
47
+ */
48
+ declare class SparkShellTopbarEndDirective {
49
+ readonly templateRef: TemplateRef<unknown>;
50
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SparkShellTopbarEndDirective, never>;
51
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<SparkShellTopbarEndDirective, "[sparkShellTopbarEnd]", never, {}, {}, never, never, true, never>;
52
+ }
53
+ /** Sidebar, above everything. Default: `<h5>{{ title }}</h5>`. */
54
+ declare class SparkShellSidebarHeaderDirective {
55
+ readonly templateRef: TemplateRef<unknown>;
56
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SparkShellSidebarHeaderDirective, never>;
57
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<SparkShellSidebarHeaderDirective, "[sparkShellSidebarHeader]", never, {}, {}, never, never, true, never>;
58
+ }
59
+ /** Sidebar, between the header and the program-units menu. No default. */
60
+ declare class SparkShellSidebarTopDirective {
61
+ readonly templateRef: TemplateRef<unknown>;
62
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SparkShellSidebarTopDirective, never>;
63
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<SparkShellSidebarTopDirective, "[sparkShellSidebarTop]", never, {}, {}, never, never, true, never>;
64
+ }
65
+ /**
66
+ * An extra accordion tab in the sidebar menu, rendered after the generated program-unit groups
67
+ * and sharing their single-open behavior.
68
+ *
69
+ * A tab is contributed as DATA (header + body template), not as markup, and that is load-bearing:
70
+ * `bs-accordion` discovers its tabs with an Angular content query, which matches by declaration
71
+ * view, so a `<bs-accordion-tab>` written in a host's template and inserted into the library's
72
+ * accordion is never registered — it would land at index -1, get no hoisted header and no slot.
73
+ * Declaring a second `<bs-accordion>` instead is what puts the tab in its own exclusivity group:
74
+ * `mp-accordion` enforces single-open per element, over children it owns and over
75
+ * `<details name>`, whose grouping cannot cross a shadow root. So the tab element must be created
76
+ * by the menu itself, from what this directive carries.
77
+ *
78
+ * ```html
79
+ * <ng-container *sparkShellTab="'Component demos'; icon: 'palette'">
80
+ * <a routerLink="/query-slots" routerLinkActive="active" class="nav-link">Query card slots</a>
81
+ * </ng-container>
82
+ * ```
83
+ *
84
+ * Navigation still belongs in `programUnits.json` — this is for pages the model cannot describe
85
+ * (client-side demos, external tools). For sidebar content that is NOT an accordion tab, use
86
+ * `*sparkShellSidebarTop` or `*sparkShellSidebarFooter`.
87
+ */
88
+ declare class SparkShellTabDirective {
89
+ readonly templateRef: TemplateRef<unknown>;
90
+ /** The tab's header label. */
91
+ readonly header: _angular_core.InputSignal<string>;
92
+ /** Bootstrap icon name for the header, as in `programUnits.json`. Defaults to a folder. */
93
+ readonly icon: _angular_core.InputSignal<string | undefined>;
94
+ /** Replaces the icon+label header entirely, for a header that needs its own markup. */
95
+ readonly headerTemplate: _angular_core.InputSignal<TemplateRef<unknown> | null>;
96
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SparkShellTabDirective, never>;
97
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<SparkShellTabDirective, "[sparkShellTab]", never, { "header": { "alias": "sparkShellTab"; "required": true; "isSignal": true; }; "icon": { "alias": "sparkShellTabIcon"; "required": false; "isSignal": true; }; "headerTemplate": { "alias": "sparkShellTabHeader"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
98
+ }
99
+ /**
100
+ * A sidebar accordion tab in the shape the menu renders it. Hosts normally contribute tabs with
101
+ * `*sparkShellTab`; this is the same thing as data, for a host that computes its tabs.
102
+ */
103
+ interface SparkSidebarTab {
104
+ readonly header: string;
105
+ readonly icon?: string;
106
+ readonly headerTemplate?: TemplateRef<unknown> | null;
107
+ readonly content: TemplateRef<unknown>;
108
+ }
109
+ /** Sidebar, at the very bottom. No default. */
110
+ declare class SparkShellSidebarFooterDirective {
111
+ readonly templateRef: TemplateRef<unknown>;
112
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SparkShellSidebarFooterDirective, never>;
113
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<SparkShellSidebarFooterDirective, "[sparkShellSidebarFooter]", never, {}, {}, never, never, true, never>;
114
+ }
115
+ /** Main region, above the projected content (the host's `<router-outlet>`). No default. */
116
+ declare class SparkShellMainHeaderDirective {
117
+ readonly templateRef: TemplateRef<unknown>;
118
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SparkShellMainHeaderDirective, never>;
119
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<SparkShellMainHeaderDirective, "[sparkShellMainHeader]", never, {}, {}, never, never, true, never>;
120
+ }
121
+
122
+ /**
123
+ * The application frame: topbar + sidebar + main, wrapping ng-bootstrap's `bs-shell` (whose
124
+ * `mp-shell` web component owns ALL responsive behavior — breakpoints, the overlay drawer,
125
+ * dismiss-on-navigate — in CSS; nothing here re-derives a pixel width). The sidebar renders the
126
+ * server-driven program-units menu; the host projects its `<router-outlet>` as the default
127
+ * content and customizes the chrome through the `*sparkShell*` slots (see `spark-shell-slots.ts`
128
+ * for the doctrine: an omitted slot renders its default, and the menu itself is never a slot).
129
+ *
130
+ * ```html
131
+ * <spark-shell title="My App">
132
+ * <spark-auth-bar *sparkShellTopbarEnd />
133
+ * <router-outlet />
134
+ * </spark-shell>
135
+ * ```
136
+ *
137
+ * The one piece of state the shell keeps is the toggler↔drawer mirror: the built-in hamburger is
138
+ * hidden (`::part(hamburger)`) in favor of a `bs-navbar-toggler` in the topbar, so the shell
139
+ * listens to `statechange` to keep the toggler's icon truthful in `auto` mode and only forces
140
+ * `show`/`hide` on explicit toggles.
141
+ *
142
+ * Theming: the chrome colors are CSS custom properties with the classic dark-sidebar defaults —
143
+ * `--spark-shell-topbar-bg`, `--spark-shell-sidebar-bg`, `--spark-shell-main-bg` — overridable on
144
+ * the `<spark-shell>` element. `sidebarTheme` flips the sidebar's `data-bs-theme` (which is what
145
+ * recolors the accordion internals across the shadow boundary) together with its default palette.
146
+ */
147
+ declare class SparkShellComponent {
148
+ /** The sidebar heading. Ignored when a `*sparkShellSidebarHeader` slot is supplied. */
149
+ readonly title: _angular_core.InputSignal<string>;
150
+ /** Forwarded to `bs-shell`: below it the sidebar is an overlay drawer. */
151
+ readonly breakpoint: _angular_core.InputSignal<Breakpoint>;
152
+ /**
153
+ * `data-bs-theme` for the sidebar — what flips the accordion's shadow-DOM internals between
154
+ * palettes — plus the matching default background. `null` sets no theme (inherit the page's).
155
+ */
156
+ readonly sidebarTheme: _angular_core.InputSignal<"dark" | "light" | null>;
157
+ /** Forwarded to the menu: any changed value re-fetches the program units. */
158
+ readonly reloadToken: _angular_core.InputSignal<unknown>;
159
+ /** Extra sidebar tabs as data, for hosts that compute them; `*sparkShellTab` is the usual way. */
160
+ readonly sidebarTabs: _angular_core.InputSignal<readonly SparkSidebarTab[]>;
161
+ readonly topbarStartTemplate: _angular_core.InputSignal<TemplateRef<unknown> | null>;
162
+ readonly topbarEndTemplate: _angular_core.InputSignal<TemplateRef<unknown> | null>;
163
+ readonly sidebarHeaderTemplate: _angular_core.InputSignal<TemplateRef<unknown> | null>;
164
+ readonly sidebarTopTemplate: _angular_core.InputSignal<TemplateRef<unknown> | null>;
165
+ readonly sidebarFooterTemplate: _angular_core.InputSignal<TemplateRef<unknown> | null>;
166
+ readonly mainHeaderTemplate: _angular_core.InputSignal<TemplateRef<unknown> | null>;
167
+ private readonly topbarStartSlot;
168
+ private readonly topbarEndSlot;
169
+ private readonly sidebarHeaderSlot;
170
+ private readonly sidebarTopSlot;
171
+ private readonly sidebarFooterSlot;
172
+ private readonly mainHeaderSlot;
173
+ protected readonly topbarStartTpl: _angular_core.Signal<TemplateRef<unknown> | null>;
174
+ protected readonly topbarEndTpl: _angular_core.Signal<TemplateRef<unknown> | null>;
175
+ protected readonly sidebarHeaderTpl: _angular_core.Signal<TemplateRef<unknown> | null>;
176
+ protected readonly sidebarTopTpl: _angular_core.Signal<TemplateRef<unknown> | null>;
177
+ protected readonly sidebarFooterTpl: _angular_core.Signal<TemplateRef<unknown> | null>;
178
+ protected readonly mainHeaderTpl: _angular_core.Signal<TemplateRef<unknown> | null>;
179
+ /**
180
+ * Extra accordion tabs, forwarded to the menu so IT creates the `<bs-accordion-tab>` elements —
181
+ * the only way they share the generated groups' single-open behavior (see
182
+ * `SparkShellTabDirective`). Data-supplied tabs come first, then projected ones in declaration
183
+ * order.
184
+ */
185
+ private readonly tabSlots;
186
+ protected readonly tabs: _angular_core.Signal<readonly SparkSidebarTab[]>;
187
+ protected readonly shellState: _angular_core.WritableSignal<BsShellState>;
188
+ protected readonly isSidebarVisible: _angular_core.WritableSignal<boolean>;
189
+ protected toggleSidebar(open: boolean): void;
190
+ protected onShellToggle(detail: ShellStateChangeEventDetail): void;
191
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SparkShellComponent, never>;
192
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SparkShellComponent, "spark-shell", never, { "title": { "alias": "title"; "required": false; "isSignal": true; }; "breakpoint": { "alias": "breakpoint"; "required": false; "isSignal": true; }; "sidebarTheme": { "alias": "sidebarTheme"; "required": false; "isSignal": true; }; "reloadToken": { "alias": "reloadToken"; "required": false; "isSignal": true; }; "sidebarTabs": { "alias": "sidebarTabs"; "required": false; "isSignal": true; }; "topbarStartTemplate": { "alias": "topbarStartTemplate"; "required": false; "isSignal": true; }; "topbarEndTemplate": { "alias": "topbarEndTemplate"; "required": false; "isSignal": true; }; "sidebarHeaderTemplate": { "alias": "sidebarHeaderTemplate"; "required": false; "isSignal": true; }; "sidebarTopTemplate": { "alias": "sidebarTopTemplate"; "required": false; "isSignal": true; }; "sidebarFooterTemplate": { "alias": "sidebarFooterTemplate"; "required": false; "isSignal": true; }; "mainHeaderTemplate": { "alias": "mainHeaderTemplate"; "required": false; "isSignal": true; }; }, {}, ["topbarStartSlot", "topbarEndSlot", "sidebarHeaderSlot", "sidebarTopSlot", "sidebarFooterSlot", "mainHeaderSlot", "tabSlots"], ["*"], true, never>;
193
+ }
194
+
195
+ /**
196
+ * The server-driven navigation menu: an accordion of program-unit groups fetched from
197
+ * `GET /spark/program-units`, which the server has already filtered to what the caller's rights
198
+ * allow. Hosts write ZERO router links for navigation — every group, unit, icon, label and link
199
+ * comes from `programUnits.json`; content around the menu belongs in `<spark-shell>`'s slots,
200
+ * and a host tempted to hand-write a unit anchor should add a unit to `programUnits.json`
201
+ * instead.
202
+ *
203
+ * Because the response is caller-scoped it must be re-fetched when the caller changes: the
204
+ * component tracks the optional `SPARK_AUTH_STATE` signal (supplied by ng-spark-auth's
205
+ * `provideSparkAuth()`, or by the app's own auth stack) and reloads on every change. Without a
206
+ * provider it fetches once. `reloadToken` is the manual escape hatch (any changed value triggers
207
+ * a reload), and `reload()` the imperative one.
208
+ *
209
+ * Usually rendered by `<spark-shell>`; exported standalone for hosts that own their own layout.
210
+ */
211
+ declare class SparkProgramUnitsComponent {
212
+ private readonly sparkService;
213
+ private readonly authState;
214
+ /** Any changed value triggers a reload — for apps whose auth state isn't a provided signal. */
215
+ readonly reloadToken: _angular_core.InputSignal<unknown>;
216
+ /**
217
+ * Extra tabs to render after the generated groups, normally forwarded by `<spark-shell>` from
218
+ * its `*sparkShellTab` directives. They must be rendered by THIS template — see
219
+ * `SparkShellTabDirective` for why a host-declared `<bs-accordion-tab>` cannot work.
220
+ */
221
+ readonly extraTabs: _angular_core.InputSignal<readonly SparkSidebarTab[]>;
222
+ protected readonly groups: _angular_core.WritableSignal<ProgramUnitGroup[]>;
223
+ constructor();
224
+ /** Re-fetches the menu. The response is already rights-filtered per caller. */
225
+ reload(): Promise<void>;
226
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SparkProgramUnitsComponent, never>;
227
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SparkProgramUnitsComponent, "spark-program-units", never, { "reloadToken": { "alias": "reloadToken"; "required": false; "isSignal": true; }; "extraTabs": { "alias": "extraTabs"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
228
+ }
229
+
230
+ /**
231
+ * The culture switcher: a `bs-select` over `SparkLanguageService`'s languages, persisting the
232
+ * choice. Renders nothing when the app declares one language (or none), so hosts can include it
233
+ * unconditionally — `<spark-shell>`'s topbar does exactly that as its trailing default.
234
+ */
235
+ declare class SparkLanguageSelectorComponent {
236
+ protected readonly lang: SparkLanguageService;
237
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SparkLanguageSelectorComponent, never>;
238
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SparkLanguageSelectorComponent, "spark-language-selector", never, {}, {}, never, never, true, never>;
239
+ }
240
+
241
+ export { SparkLanguageSelectorComponent, SparkProgramUnitsComponent, SparkShellComponent, SparkShellMainHeaderDirective, SparkShellSidebarFooterDirective, SparkShellSidebarHeaderDirective, SparkShellSidebarTopDirective, SparkShellTabDirective, SparkShellTopbarEndDirective, SparkShellTopbarStartDirective };
242
+ export type { SparkSidebarTab };
@@ -1,4 +1,4 @@
1
- import { InjectionToken, Provider } from '@angular/core';
1
+ import { InjectionToken, Signal, Provider } from '@angular/core';
2
2
 
3
3
  interface SparkConfig {
4
4
  baseUrl: string;
@@ -6,7 +6,22 @@ interface SparkConfig {
6
6
  declare const SPARK_CONFIG: InjectionToken<SparkConfig>;
7
7
  declare const defaultSparkConfig: SparkConfig;
8
8
 
9
+ /**
10
+ * A signal that changes whenever the authenticated user changes — the bridge that lets ng-spark
11
+ * components react to sign-in/out without a dependency on `@mintplayer/ng-spark-auth` (no
12
+ * dependency exists between the two packages, in either direction, on purpose).
13
+ *
14
+ * `@mintplayer/ng-spark-auth`'s `provideSparkAuth()` supplies it from `SparkAuthService.user`;
15
+ * an app with its own auth stack provides any signal that changes on sign-in/out. Consumers
16
+ * inject it `{ optional: true }` — absent, auth-sensitive data (the program-units menu) is
17
+ * fetched once and never re-fetched.
18
+ *
19
+ * The signal's VALUE is deliberately opaque (`unknown`): consumers only track it for change,
20
+ * never read it — what "the user" looks like belongs to the auth package.
21
+ */
22
+ declare const SPARK_AUTH_STATE: InjectionToken<Signal<unknown>>;
23
+
9
24
  declare function provideSpark(config?: Partial<SparkConfig>): Provider[];
10
25
 
11
- export { SPARK_CONFIG, defaultSparkConfig, provideSpark };
26
+ export { SPARK_AUTH_STATE, SPARK_CONFIG, defaultSparkConfig, provideSpark };
12
27
  export type { SparkConfig };