@frame-kit/ui-ng-patterns 0.1.6 → 0.1.7

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.
@@ -1,18 +1,20 @@
1
1
  import * as i0 from '@angular/core';
2
- import { input, ChangeDetectionStrategy, ViewEncapsulation, Component, computed, HostBinding, inject, TemplateRef, Directive, ViewContainerRef, DestroyRef, Injector, viewChild, contentChild, signal, effect, afterNextRender, output } from '@angular/core';
2
+ import { input, ChangeDetectionStrategy, ViewEncapsulation, Component, computed, HostBinding, inject, TemplateRef, Directive, ViewContainerRef, DestroyRef, Injector, viewChild, contentChild, signal, effect, afterNextRender, output, ElementRef, linkedSignal } from '@angular/core';
3
3
  import { HeadlineComponent } from '@frame-kit/ui-ng/core/headline';
4
4
  import { TextComponent } from '@frame-kit/ui-ng/core/text';
5
5
  import { IconComponent } from '@frame-kit/ui-ng/core/icon';
6
6
  import { Overlay } from '@angular/cdk/overlay';
7
7
  import { TemplatePortal } from '@angular/cdk/portal';
8
8
  import { NgTemplateOutlet } from '@angular/common';
9
- import { toSignal } from '@angular/core/rxjs-interop';
9
+ import { toSignal, takeUntilDestroyed } from '@angular/core/rxjs-interop';
10
10
  import { Router, ActivatedRoute, NavigationEnd, RouterLink } from '@angular/router';
11
11
  import { filter, map, Subscription } from 'rxjs';
12
12
  import { TooltipDirective } from '@frame-kit/ui-ng/directives/tooltip';
13
13
  import { AppShellComponent } from '@frame-kit/ui-ng/layouts/app-shell';
14
14
  import { ButtonComponent } from '@frame-kit/ui-ng/ui/button';
15
15
  import { IconBadgeComponent } from '@frame-kit/ui-ng/ui/icon-badge';
16
+ import * as i1 from '@angular/cdk/drag-drop';
17
+ import { CdkDrag, CdkDragHandle } from '@angular/cdk/drag-drop';
16
18
 
17
19
  /**
18
20
  * Page-level dashboard header: title + optional description on the left, up to
@@ -924,9 +926,292 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
924
926
  args: ['attr.id']
925
927
  }] } });
926
928
 
929
+ const VIEWPORT_MARGIN = 24;
930
+ /**
931
+ * A floating, draggable onboarding-progress widget. It presents a checklist of
932
+ * steps with a progress bar, collapses to a compact pill with a progress ring,
933
+ * and can be dragged anywhere on screen (CDK drag). It renders over the app in
934
+ * a fixed layer — drop it once near the app root.
935
+ *
936
+ * **Controlled model, no domain data.** The `steps` model is a required,
937
+ * reactive input: the widget is a pure view of it and emits events when the
938
+ * user acts (`stepAction`, `stepMarkDone`, `substepToggle`, `goLive`). The
939
+ * consumer owns the step state — so if it is keyed by, say, the active account
940
+ * or environment, swapping the input re-renders the widget instantly. The
941
+ * widget never persists step state.
942
+ *
943
+ * **Presentation state is internal + persisted.** Collapsed and drag position
944
+ * live in the widget and persist to `localStorage` under `storageKey` — these
945
+ * are UI preferences, not part of the model.
946
+ *
947
+ * **Appearance-agnostic.** All colour flows through `--fk-*` tokens with neutral
948
+ * (near-black / grey) raw fallbacks, so with no theme it renders monochrome;
949
+ * point the tokens at a brand scale to colour it.
950
+ *
951
+ * ```html
952
+ * <fk-onboarding-guide
953
+ * [steps]="steps()"
954
+ * title="Setup guide"
955
+ * (stepAction)="onStart($event)"
956
+ * (substepToggle)="onToggle($event)"
957
+ * (goLive)="onGoLive()"
958
+ * (dismiss)="onDismiss()"
959
+ * />
960
+ * ```
961
+ */
962
+ class OnboardingGuideComponent {
963
+ host = inject(ElementRef);
964
+ drag = inject(CdkDrag);
965
+ destroyRef = inject(DestroyRef);
966
+ // ===== INPUTS =====
967
+ /** The step model. Controlled by the consumer; the widget is a view of it. */
968
+ steps = input.required(...(ngDevMode ? [{ debugName: "steps" }] : /* istanbul ignore next */ []));
969
+ /** Widget title. */
970
+ title = input('Setup guide', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
971
+ /** `localStorage` key for the collapsed + drag-position preferences. */
972
+ storageKey = input('fk-onboarding-guide', ...(ngDevMode ? [{ debugName: "storageKey" }] : /* istanbul ignore next */ []));
973
+ /** Initial collapsed state, used only when nothing is persisted yet. */
974
+ startCollapsed = input(false, ...(ngDevMode ? [{ debugName: "startCollapsed" }] : /* istanbul ignore next */ []));
975
+ // --- Text (English defaults; pass translated strings as needed) ---
976
+ /** Default CTA label when a step doesn't supply its own `actionLabel`. */
977
+ startLabel = input('Start', ...(ngDevMode ? [{ debugName: "startLabel" }] : /* istanbul ignore next */ []));
978
+ /** Secondary "mark this step done" action label. */
979
+ markDoneLabel = input('Mark done', ...(ngDevMode ? [{ debugName: "markDoneLabel" }] : /* istanbul ignore next */ []));
980
+ /** Footer / final go-live action label. */
981
+ goLiveLabel = input('Go live', ...(ngDevMode ? [{ debugName: "goLiveLabel" }] : /* istanbul ignore next */ []));
982
+ /** Footer noun for the "{done} of {total} {stepsWord} {doneWord}" summary. */
983
+ stepsWord = input('steps', ...(ngDevMode ? [{ debugName: "stepsWord" }] : /* istanbul ignore next */ []));
984
+ /** Footer verb for the summary. */
985
+ doneWord = input('done', ...(ngDevMode ? [{ debugName: "doneWord" }] : /* istanbul ignore next */ []));
986
+ /** Collapsed-pill suffix, e.g. "3 steps left". */
987
+ stepsLeftWord = input('left', ...(ngDevMode ? [{ debugName: "stepsLeftWord" }] : /* istanbul ignore next */ []));
988
+ /** Collapsed-pill copy shown when everything is complete. */
989
+ allDoneLabel = input('All set', ...(ngDevMode ? [{ debugName: "allDoneLabel" }] : /* istanbul ignore next */ []));
990
+ /** ARIA labels for the icon-only header controls. */
991
+ renameLabel = input('Rename', ...(ngDevMode ? [{ debugName: "renameLabel" }] : /* istanbul ignore next */ []));
992
+ collapseLabel = input('Collapse', ...(ngDevMode ? [{ debugName: "collapseLabel" }] : /* istanbul ignore next */ []));
993
+ dismissLabel = input('Dismiss', ...(ngDevMode ? [{ debugName: "dismissLabel" }] : /* istanbul ignore next */ []));
994
+ expandLabel = input('Expand', ...(ngDevMode ? [{ debugName: "expandLabel" }] : /* istanbul ignore next */ []));
995
+ // --- Icon glyph names (resolved by the app's icon registry) ---
996
+ checkIcon = input('check', ...(ngDevMode ? [{ debugName: "checkIcon" }] : /* istanbul ignore next */ []));
997
+ caretIcon = input('chevron-down', ...(ngDevMode ? [{ debugName: "caretIcon" }] : /* istanbul ignore next */ []));
998
+ editIcon = input('pen', ...(ngDevMode ? [{ debugName: "editIcon" }] : /* istanbul ignore next */ []));
999
+ collapseIcon = input('collapse', ...(ngDevMode ? [{ debugName: "collapseIcon" }] : /* istanbul ignore next */ []));
1000
+ dismissIcon = input('close', ...(ngDevMode ? [{ debugName: "dismissIcon" }] : /* istanbul ignore next */ []));
1001
+ expandIcon = input('expand', ...(ngDevMode ? [{ debugName: "expandIcon" }] : /* istanbul ignore next */ []));
1002
+ actionIcon = input('arrow-right', ...(ngDevMode ? [{ debugName: "actionIcon" }] : /* istanbul ignore next */ []));
1003
+ // ===== OUTPUTS =====
1004
+ /** A step's primary CTA was clicked. Emits the step id. */
1005
+ stepAction = output();
1006
+ /** A step's "mark done" was clicked. Emits the step id. */
1007
+ stepMarkDone = output();
1008
+ /** A substep checkbox was toggled. */
1009
+ substepToggle = output();
1010
+ /** The final go-live action was invoked (footer or the go-live step CTA). */
1011
+ goLive = output();
1012
+ /** The rename (edit) affordance was clicked; the consumer owns renaming. */
1013
+ renameClick = output();
1014
+ /** The dismiss control was clicked; the consumer decides whether to hide it. */
1015
+ dismiss = output();
1016
+ /** Fires when the collapsed state changes. */
1017
+ collapsedChange = output();
1018
+ // ===== BASE PROPS =====
1019
+ className = input('', ...(ngDevMode ? [{ debugName: "className" }] : /* istanbul ignore next */ []));
1020
+ id = input(null, ...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
1021
+ // ===== PRESENTATION STATE =====
1022
+ collapsed = signal(false, ...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
1023
+ dragPosition = signal({ x: 0, y: 0 }, ...(ngDevMode ? [{ debugName: "dragPosition" }] : /* istanbul ignore next */ []));
1024
+ /** True immediately after a real drag, so the drag-handle's click (e.g. the
1025
+ * pill's expand) is suppressed rather than firing at the drop point. */
1026
+ justDragged = false;
1027
+ /**
1028
+ * The expanded step. A `linkedSignal` over `steps` so that whenever the model
1029
+ * changes (e.g. the consumer swaps in another account/environment's steps) it
1030
+ * resets to the first incomplete step; user toggles override until the next
1031
+ * model change.
1032
+ */
1033
+ openStepId = linkedSignal({ ...(ngDevMode ? { debugName: "openStepId" } : /* istanbul ignore next */ {}), source: this.steps,
1034
+ computation: (steps) => steps.find((s) => !this.isComplete(s))?.id ?? null });
1035
+ // ===== DERIVED =====
1036
+ total = computed(() => this.steps().length, ...(ngDevMode ? [{ debugName: "total" }] : /* istanbul ignore next */ []));
1037
+ doneCount = computed(() => this.steps().filter((s) => this.isComplete(s)).length, ...(ngDevMode ? [{ debugName: "doneCount" }] : /* istanbul ignore next */ []));
1038
+ percent = computed(() => {
1039
+ const total = this.total();
1040
+ return total === 0 ? 0 : Math.round((this.doneCount() / total) * 100);
1041
+ }, ...(ngDevMode ? [{ debugName: "percent" }] : /* istanbul ignore next */ []));
1042
+ stepsLeft = computed(() => this.total() - this.doneCount(), ...(ngDevMode ? [{ debugName: "stepsLeft" }] : /* istanbul ignore next */ []));
1043
+ complete = computed(() => this.total() > 0 && this.stepsLeft() === 0, ...(ngDevMode ? [{ debugName: "complete" }] : /* istanbul ignore next */ []));
1044
+ /** Circumference for the pill's progress ring (r = 16). */
1045
+ ringCircumference = 2 * Math.PI * 16;
1046
+ ringOffset = computed(() => {
1047
+ const total = this.total();
1048
+ const fraction = total === 0 ? 0 : this.doneCount() / total;
1049
+ return this.ringCircumference * (1 - fraction);
1050
+ }, ...(ngDevMode ? [{ debugName: "ringOffset" }] : /* istanbul ignore next */ []));
1051
+ classes = computed(() => [
1052
+ 'fk-onboarding-guide',
1053
+ this.collapsed() ? 'fk-onboarding-guide--collapsed' : '',
1054
+ this.complete() ? 'fk-onboarding-guide--complete' : '',
1055
+ this.className(),
1056
+ ]
1057
+ .filter(Boolean)
1058
+ .join(' '), ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
1059
+ get hostClass() {
1060
+ return this.classes();
1061
+ }
1062
+ get hostId() {
1063
+ return this.id();
1064
+ }
1065
+ constructor() {
1066
+ this.drag.ended
1067
+ .pipe(takeUntilDestroyed(this.destroyRef))
1068
+ .subscribe((event) => this.onDragEnded(event));
1069
+ afterNextRender(() => this.hydrate());
1070
+ }
1071
+ // ===== COMPLETION LOGIC =====
1072
+ isComplete(step) {
1073
+ if (step.substeps && step.substeps.length > 0) {
1074
+ return step.substeps.every((sub) => sub.done);
1075
+ }
1076
+ return step.done;
1077
+ }
1078
+ isActive(step) {
1079
+ return !this.isComplete(step) && this.openStepId() === step.id;
1080
+ }
1081
+ actionLabelFor(step) {
1082
+ return step.actionLabel || this.startLabel();
1083
+ }
1084
+ // ===== INTERACTIONS =====
1085
+ toggleStep(stepId) {
1086
+ this.openStepId.update((cur) => (cur === stepId ? null : stepId));
1087
+ }
1088
+ onAction(step) {
1089
+ this.stepAction.emit(step.id);
1090
+ }
1091
+ onMarkDone(step) {
1092
+ this.stepMarkDone.emit(step.id);
1093
+ }
1094
+ onSubstep(step, substep) {
1095
+ this.substepToggle.emit({ stepId: step.id, substepId: substep.id });
1096
+ }
1097
+ onCollapse() {
1098
+ this.setCollapsed(true);
1099
+ }
1100
+ onExpand() {
1101
+ if (this.justDragged) {
1102
+ return;
1103
+ }
1104
+ this.setCollapsed(false);
1105
+ }
1106
+ onRename() {
1107
+ this.renameClick.emit();
1108
+ }
1109
+ onDismiss() {
1110
+ this.dismiss.emit();
1111
+ }
1112
+ onGoLive() {
1113
+ this.goLive.emit();
1114
+ }
1115
+ setCollapsed(value) {
1116
+ this.collapsed.set(value);
1117
+ this.collapsedChange.emit(value);
1118
+ this.persist();
1119
+ }
1120
+ // ===== DRAG =====
1121
+ onDragEnded(event) {
1122
+ const clamped = this.clamp(this.drag.getFreeDragPosition());
1123
+ this.dragPosition.set(clamped);
1124
+ this.drag.setFreeDragPosition(clamped);
1125
+ this.persist();
1126
+ const moved = Math.abs(event.distance.x) > 3 || Math.abs(event.distance.y) > 3;
1127
+ if (moved) {
1128
+ this.justDragged = true;
1129
+ setTimeout(() => (this.justDragged = false));
1130
+ }
1131
+ }
1132
+ clamp(point) {
1133
+ if (typeof window === 'undefined') {
1134
+ return point;
1135
+ }
1136
+ const rect = this.host.nativeElement.getBoundingClientRect();
1137
+ const maxX = window.innerWidth - rect.width - VIEWPORT_MARGIN;
1138
+ const maxY = window.innerHeight - rect.height - VIEWPORT_MARGIN;
1139
+ return {
1140
+ x: Math.max(VIEWPORT_MARGIN, Math.min(point.x, maxX)),
1141
+ y: Math.max(VIEWPORT_MARGIN, Math.min(point.y, maxY)),
1142
+ };
1143
+ }
1144
+ // ===== PERSISTENCE =====
1145
+ hydrate() {
1146
+ const saved = this.read();
1147
+ this.collapsed.set(saved.collapsed ?? this.startCollapsed());
1148
+ const pos = saved.pos ? this.clamp(saved.pos) : this.defaultBottomRight();
1149
+ this.dragPosition.set(pos);
1150
+ this.drag.setFreeDragPosition(pos);
1151
+ }
1152
+ defaultBottomRight() {
1153
+ if (typeof window === 'undefined') {
1154
+ return { x: 0, y: 0 };
1155
+ }
1156
+ const rect = this.host.nativeElement.getBoundingClientRect();
1157
+ return {
1158
+ x: Math.max(VIEWPORT_MARGIN, window.innerWidth - rect.width - VIEWPORT_MARGIN),
1159
+ y: Math.max(VIEWPORT_MARGIN, window.innerHeight - rect.height - VIEWPORT_MARGIN),
1160
+ };
1161
+ }
1162
+ read() {
1163
+ const store = this.storage();
1164
+ if (!store) {
1165
+ return {};
1166
+ }
1167
+ try {
1168
+ return JSON.parse(store.getItem(this.storageKey()) || '{}');
1169
+ }
1170
+ catch {
1171
+ return {};
1172
+ }
1173
+ }
1174
+ persist() {
1175
+ const store = this.storage();
1176
+ if (!store) {
1177
+ return;
1178
+ }
1179
+ const state = {
1180
+ collapsed: this.collapsed(),
1181
+ pos: this.dragPosition(),
1182
+ };
1183
+ try {
1184
+ store.setItem(this.storageKey(), JSON.stringify(state));
1185
+ }
1186
+ catch {
1187
+ // Storage unavailable (private mode / quota) — preferences just don't stick.
1188
+ }
1189
+ }
1190
+ storage() {
1191
+ try {
1192
+ return typeof window === 'undefined' ? null : window.localStorage;
1193
+ }
1194
+ catch {
1195
+ return null;
1196
+ }
1197
+ }
1198
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: OnboardingGuideComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1199
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: OnboardingGuideComponent, isStandalone: true, selector: "fk-onboarding-guide", inputs: { steps: { classPropertyName: "steps", publicName: "steps", isSignal: true, isRequired: true, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, storageKey: { classPropertyName: "storageKey", publicName: "storageKey", isSignal: true, isRequired: false, transformFunction: null }, startCollapsed: { classPropertyName: "startCollapsed", publicName: "startCollapsed", isSignal: true, isRequired: false, transformFunction: null }, startLabel: { classPropertyName: "startLabel", publicName: "startLabel", isSignal: true, isRequired: false, transformFunction: null }, markDoneLabel: { classPropertyName: "markDoneLabel", publicName: "markDoneLabel", isSignal: true, isRequired: false, transformFunction: null }, goLiveLabel: { classPropertyName: "goLiveLabel", publicName: "goLiveLabel", isSignal: true, isRequired: false, transformFunction: null }, stepsWord: { classPropertyName: "stepsWord", publicName: "stepsWord", isSignal: true, isRequired: false, transformFunction: null }, doneWord: { classPropertyName: "doneWord", publicName: "doneWord", isSignal: true, isRequired: false, transformFunction: null }, stepsLeftWord: { classPropertyName: "stepsLeftWord", publicName: "stepsLeftWord", isSignal: true, isRequired: false, transformFunction: null }, allDoneLabel: { classPropertyName: "allDoneLabel", publicName: "allDoneLabel", isSignal: true, isRequired: false, transformFunction: null }, renameLabel: { classPropertyName: "renameLabel", publicName: "renameLabel", isSignal: true, isRequired: false, transformFunction: null }, collapseLabel: { classPropertyName: "collapseLabel", publicName: "collapseLabel", isSignal: true, isRequired: false, transformFunction: null }, dismissLabel: { classPropertyName: "dismissLabel", publicName: "dismissLabel", isSignal: true, isRequired: false, transformFunction: null }, expandLabel: { classPropertyName: "expandLabel", publicName: "expandLabel", isSignal: true, isRequired: false, transformFunction: null }, checkIcon: { classPropertyName: "checkIcon", publicName: "checkIcon", isSignal: true, isRequired: false, transformFunction: null }, caretIcon: { classPropertyName: "caretIcon", publicName: "caretIcon", isSignal: true, isRequired: false, transformFunction: null }, editIcon: { classPropertyName: "editIcon", publicName: "editIcon", isSignal: true, isRequired: false, transformFunction: null }, collapseIcon: { classPropertyName: "collapseIcon", publicName: "collapseIcon", isSignal: true, isRequired: false, transformFunction: null }, dismissIcon: { classPropertyName: "dismissIcon", publicName: "dismissIcon", isSignal: true, isRequired: false, transformFunction: null }, expandIcon: { classPropertyName: "expandIcon", publicName: "expandIcon", isSignal: true, isRequired: false, transformFunction: null }, actionIcon: { classPropertyName: "actionIcon", publicName: "actionIcon", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { stepAction: "stepAction", stepMarkDone: "stepMarkDone", substepToggle: "substepToggle", goLive: "goLive", renameClick: "renameClick", dismiss: "dismiss", collapsedChange: "collapsedChange" }, host: { properties: { "class": "this.hostClass", "attr.id": "this.hostId" } }, hostDirectives: [{ directive: i1.CdkDrag }], ngImport: i0, template: "<!-- ===================== EXPANDED CARD ===================== -->\n<div class=\"fk-onboarding-guide__card\">\n <div class=\"fk-onboarding-guide__head\">\n <div class=\"fk-onboarding-guide__head-top\">\n <span class=\"fk-onboarding-guide__grip\" cdkDragHandle aria-hidden=\"true\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\">\n <circle cx=\"9\" cy=\"6\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"6\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"9\" cy=\"12\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"12\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"9\" cy=\"18\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"18\" r=\"1.5\" fill=\"currentColor\" />\n </svg>\n </span>\n\n <span class=\"fk-onboarding-guide__title\" cdkDragHandle>{{\n title()\n }}</span>\n\n <button\n type=\"button\"\n class=\"fk-onboarding-guide__icon-btn fk-onboarding-guide__edit\"\n [attr.aria-label]=\"renameLabel()\"\n (click)=\"onRename()\"\n >\n <fk-icon [name]=\"editIcon()\" size=\"sm\" />\n </button>\n\n <div class=\"fk-onboarding-guide__head-actions\">\n <button\n type=\"button\"\n class=\"fk-onboarding-guide__icon-btn\"\n [attr.aria-label]=\"collapseLabel()\"\n (click)=\"onCollapse()\"\n >\n <fk-icon [name]=\"collapseIcon()\" size=\"sm\" />\n </button>\n <button\n type=\"button\"\n class=\"fk-onboarding-guide__icon-btn\"\n [attr.aria-label]=\"dismissLabel()\"\n (click)=\"onDismiss()\"\n >\n <fk-icon [name]=\"dismissIcon()\" size=\"sm\" />\n </button>\n </div>\n </div>\n\n <div class=\"fk-onboarding-guide__progress\">\n <div\n class=\"fk-onboarding-guide__track\"\n role=\"progressbar\"\n [attr.aria-valuenow]=\"percent()\"\n aria-valuemin=\"0\"\n aria-valuemax=\"100\"\n >\n <div\n class=\"fk-onboarding-guide__fill\"\n [style.width.%]=\"percent()\"\n ></div>\n </div>\n <span class=\"fk-onboarding-guide__pct\">{{ percent() }}%</span>\n </div>\n </div>\n\n <div class=\"fk-onboarding-guide__steps\" role=\"list\">\n @for (step of steps(); track step.id) {\n @let done = isComplete(step);\n @let open = openStepId() === step.id;\n @let active = isActive(step);\n\n <div\n class=\"fk-onboarding-guide__step\"\n role=\"listitem\"\n [class.fk-onboarding-guide__step--done]=\"done\"\n [class.fk-onboarding-guide__step--open]=\"open\"\n >\n <button\n type=\"button\"\n class=\"fk-onboarding-guide__step-row\"\n [attr.aria-expanded]=\"open\"\n (click)=\"toggleStep(step.id)\"\n >\n <span\n class=\"fk-onboarding-guide__check\"\n [class.fk-onboarding-guide__check--done]=\"done\"\n [class.fk-onboarding-guide__check--active]=\"active\"\n [class.fk-onboarding-guide__check--todo]=\"!done && !active\"\n aria-hidden=\"true\"\n >\n @if (done) {\n <fk-icon [name]=\"checkIcon()\" size=\"xs\" />\n } @else if (active) {\n <i class=\"fk-onboarding-guide__dot\"></i>\n }\n </span>\n\n <span class=\"fk-onboarding-guide__step-label\">{{ step.label }}</span>\n\n <span class=\"fk-onboarding-guide__caret\" aria-hidden=\"true\">\n <fk-icon [name]=\"caretIcon()\" size=\"sm\" />\n </span>\n </button>\n\n @if (open) {\n <div class=\"fk-onboarding-guide__step-body\">\n @if (step.substeps && step.substeps.length > 0) {\n @for (sub of step.substeps; track sub.id) {\n <button\n type=\"button\"\n class=\"fk-onboarding-guide__sub\"\n [class.fk-onboarding-guide__sub--done]=\"sub.done\"\n (click)=\"onSubstep(step, sub)\"\n >\n <span\n class=\"fk-onboarding-guide__sub-check\"\n aria-hidden=\"true\"\n >\n @if (sub.done) {\n <fk-icon [name]=\"checkIcon()\" size=\"xs\" />\n }\n </span>\n <span class=\"fk-onboarding-guide__sub-label\">{{\n sub.label\n }}</span>\n </button>\n }\n } @else {\n @if (step.description) {\n <p class=\"fk-onboarding-guide__desc\">{{ step.description }}</p>\n }\n\n @if (!done) {\n <div class=\"fk-onboarding-guide__actions\">\n <fk-button\n variant=\"primary\"\n size=\"sm\"\n (click)=\"onAction(step)\"\n >\n {{ actionLabelFor(step) }}\n <fk-icon fkButtonIconEnd [name]=\"actionIcon()\" size=\"xs\" />\n </fk-button>\n <button\n type=\"button\"\n class=\"fk-onboarding-guide__skip\"\n (click)=\"onMarkDone(step)\"\n >\n {{ markDoneLabel() }}\n </button>\n </div>\n }\n }\n </div>\n }\n </div>\n }\n </div>\n\n <div class=\"fk-onboarding-guide__foot\">\n <span class=\"fk-onboarding-guide__foot-text\">\n <b>{{ doneCount() }}</b> / {{ total() }} {{ stepsWord() }}\n {{ doneWord() }}\n </span>\n <button type=\"button\" class=\"fk-onboarding-guide__go\" (click)=\"onGoLive()\">\n {{ goLiveLabel() }}\n <fk-icon [name]=\"actionIcon()\" size=\"xs\" />\n </button>\n </div>\n</div>\n\n<!-- ===================== COLLAPSED PILL ===================== -->\n<button\n type=\"button\"\n class=\"fk-onboarding-guide__pill\"\n cdkDragHandle\n [attr.aria-label]=\"expandLabel()\"\n (click)=\"onExpand()\"\n>\n <span class=\"fk-onboarding-guide__ring\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 38 38\">\n <circle class=\"fk-onboarding-guide__ring-track\" cx=\"19\" cy=\"19\" r=\"16\" />\n <circle\n class=\"fk-onboarding-guide__ring-prog\"\n cx=\"19\"\n cy=\"19\"\n r=\"16\"\n [style.stroke-dasharray]=\"ringCircumference\"\n [style.stroke-dashoffset]=\"ringOffset()\"\n />\n </svg>\n <span class=\"fk-onboarding-guide__ring-num\">{{ percent() }}%</span>\n </span>\n\n <span class=\"fk-onboarding-guide__pill-meta\">\n <span class=\"fk-onboarding-guide__pill-title\">{{ title() }}</span>\n <span class=\"fk-onboarding-guide__pill-sub\">\n @if (complete()) {\n {{ allDoneLabel() }}\n } @else {\n <b>{{ stepsLeft() }}</b> {{ stepsWord() }} {{ stepsLeftWord() }}\n }\n </span>\n </span>\n\n <span class=\"fk-onboarding-guide__pill-expand\" aria-hidden=\"true\">\n <fk-icon [name]=\"expandIcon()\" size=\"sm\" />\n </span>\n</button>\n", styles: ["@keyframes fk-onboarding-guide-pop{0%{opacity:0;transform:translateY(8px) scale(.97)}to{opacity:1;transform:none}}:host{position:fixed;top:0;left:0;z-index:var(--fk-onboarding-guide-z, 60);font-family:var(--fk-onboarding-guide-font-body, var(--fk-font-family-body, system-ui, sans-serif));color:var(--fk-onboarding-guide-text, var(--fk-color-text, #1e293b));touch-action:none}.fk-onboarding-guide__card,.fk-onboarding-guide__pill{--fk-button-primary-bg: var( --fk-onboarding-guide-accent, var(--fk-color-text, #1a1a1a) );--fk-button-primary-bg-hover: color-mix( in srgb, var(--fk-onboarding-guide-accent, var(--fk-color-text, #1a1a1a)) 88%, #000 );--fk-button-primary-color: var( --fk-onboarding-guide-accent-contrast, var(--fk-color-surface, #fff) )}.fk-onboarding-guide__card{width:var(--fk-onboarding-guide-width, 360px);max-width:calc(100vw - 2 * var(--fk-rhythm-4, 1rem));background:var(--fk-onboarding-guide-surface, var(--fk-color-surface, #fff));border:1px solid var(--fk-onboarding-guide-border, var(--fk-color-border, #e2e8f0));border-radius:var(--fk-onboarding-guide-radius, var(--fk-radius-lg, 16px));box-shadow:var(--fk-onboarding-guide-shadow, 0 24px 54px -18px rgba(15, 23, 42, .28));overflow:hidden;transform-origin:bottom right;animation:fk-onboarding-guide-pop .24s cubic-bezier(.2,.9,.3,1.1)}.fk-onboarding-guide__head{padding:16px 18px 14px}.fk-onboarding-guide__head-top{display:flex;align-items:center;gap:9px}.fk-onboarding-guide__grip,.fk-onboarding-guide__title{cursor:grab}.fk-onboarding-guide__grip:active,.fk-onboarding-guide__title:active{cursor:grabbing}.fk-onboarding-guide__grip{display:inline-flex;flex:none;margin-left:-3px;color:var(--fk-onboarding-guide-text-faint, var(--fk-color-muted, #94a3b8))}.fk-onboarding-guide__grip svg{width:15px;height:15px}.fk-onboarding-guide__title{font-family:var(--fk-onboarding-guide-font-display, var(--fk-font-family-display, inherit));font-size:16px;font-weight:700;color:var(--fk-onboarding-guide-text, var(--fk-color-text, #1e293b))}.fk-onboarding-guide__head-actions{margin-left:auto;display:flex;gap:4px}.fk-onboarding-guide__icon-btn{display:grid;place-items:center;width:28px;height:28px;border:1px solid transparent;border-radius:7px;background:none;color:var(--fk-onboarding-guide-text-faint, var(--fk-color-muted, #94a3b8));cursor:pointer;transition:.14s}.fk-onboarding-guide__icon-btn:hover{background:var(--fk-onboarding-guide-surface-muted, var(--fk-color-surface-muted, #f8fafc));border-color:var(--fk-onboarding-guide-border, var(--fk-color-border, #e2e8f0));color:var(--fk-onboarding-guide-text, var(--fk-color-text, #1e293b))}.fk-onboarding-guide__edit{width:24px;height:24px;border-radius:6px}.fk-onboarding-guide__progress{display:flex;align-items:center;gap:11px;margin-top:13px}.fk-onboarding-guide__track{flex:1;height:7px;border-radius:5px;background:var(--fk-onboarding-guide-surface-muted, var(--fk-color-surface-muted, #f1f5f9));overflow:hidden}.fk-onboarding-guide__fill{height:100%;border-radius:5px;background:var(--fk-onboarding-guide-accent, var(--fk-color-text, #1a1a1a));transition:width .5s cubic-bezier(.4,0,.2,1)}.fk-onboarding-guide__pct{flex:none;font-family:var(--fk-onboarding-guide-font-mono, var(--fk-font-family-mono, ui-monospace, monospace));font-size:11px;font-weight:600;color:var(--fk-onboarding-guide-accent, var(--fk-color-text, #1a1a1a))}.fk-onboarding-guide__steps{padding:6px 8px 10px;max-height:400px;overflow-y:auto}.fk-onboarding-guide__step{border-radius:12px;overflow:hidden}.fk-onboarding-guide__step--open{background:var(--fk-onboarding-guide-surface-muted, var(--fk-color-surface-muted, #f8fafc))}.fk-onboarding-guide__step-row{display:flex;align-items:center;gap:12px;width:100%;padding:13px 12px;border:none;border-radius:12px;background:none;text-align:left;cursor:pointer;transition:.14s}.fk-onboarding-guide__step-row:hover{background:var(--fk-onboarding-guide-surface-muted, var(--fk-color-surface-muted, #f8fafc))}.fk-onboarding-guide__step--open .fk-onboarding-guide__step-row:hover{background:transparent}.fk-onboarding-guide__check{display:grid;place-items:center;flex:none;width:20px;height:20px;border-radius:50%;transition:.16s;color:var(--fk-onboarding-guide-accent-contrast, #fff)}.fk-onboarding-guide__check--done{background:var(--fk-onboarding-guide-accent, var(--fk-color-text, #1a1a1a))}.fk-onboarding-guide__check--todo{border:2px solid color-mix(in srgb,var(--fk-onboarding-guide-text-muted, var(--fk-color-muted, #64748b)) 45%,transparent)}.fk-onboarding-guide__check--active{border:2px solid var(--fk-onboarding-guide-accent, var(--fk-color-text, #1a1a1a));background:color-mix(in srgb,var(--fk-onboarding-guide-accent, var(--fk-color-text, #1a1a1a)) 10%,transparent)}.fk-onboarding-guide__dot{width:7px;height:7px;border-radius:50%;background:var(--fk-onboarding-guide-accent, var(--fk-color-text, #1a1a1a))}.fk-onboarding-guide__step-label{flex:1;min-width:0;font-size:14.5px;font-weight:600;color:var(--fk-onboarding-guide-text, var(--fk-color-text, #1e293b))}.fk-onboarding-guide__step--done .fk-onboarding-guide__step-label{color:var(--fk-onboarding-guide-text-muted, var(--fk-color-muted, #64748b));font-weight:500;text-decoration:line-through;text-decoration-color:color-mix(in srgb,var(--fk-onboarding-guide-text-muted, var(--fk-color-muted, #64748b)) 55%,transparent)}.fk-onboarding-guide__caret{display:grid;place-items:center;flex:none;color:var(--fk-onboarding-guide-text-faint, var(--fk-color-muted, #b6bfce));transition:transform .18s}.fk-onboarding-guide__step--open .fk-onboarding-guide__caret{transform:rotate(180deg);color:var(--fk-onboarding-guide-text, var(--fk-color-text, #1e293b))}.fk-onboarding-guide__step-body{padding:0 14px 14px 44px}.fk-onboarding-guide__desc{font-size:13px;line-height:1.55;color:var(--fk-onboarding-guide-text-muted, var(--fk-color-muted, #64748b));margin-bottom:12px}.fk-onboarding-guide__actions{display:flex;align-items:center;gap:8px}.fk-onboarding-guide__skip{font-size:13px;font-weight:600;color:var(--fk-onboarding-guide-text-muted, var(--fk-color-muted, #64748b));background:none;border:none;padding:6px;cursor:pointer}.fk-onboarding-guide__skip:hover{color:var(--fk-onboarding-guide-text, var(--fk-color-text, #1e293b))}.fk-onboarding-guide__sub{display:flex;align-items:center;gap:11px;width:100%;padding:8px 0;border:none;background:none;text-align:left;cursor:pointer}.fk-onboarding-guide__sub-check{display:grid;place-items:center;flex:none;width:18px;height:18px;border-radius:50%;color:var(--fk-onboarding-guide-accent-contrast, #fff);background:color-mix(in srgb,var(--fk-onboarding-guide-text-muted, var(--fk-color-muted, #64748b)) 22%,transparent)}.fk-onboarding-guide__sub--done .fk-onboarding-guide__sub-check{background:var(--fk-onboarding-guide-accent, var(--fk-color-text, #1a1a1a))}.fk-onboarding-guide__sub-label{font-size:14px;color:var(--fk-onboarding-guide-text, var(--fk-color-text, #36405a))}.fk-onboarding-guide__sub--done .fk-onboarding-guide__sub-label{color:var(--fk-onboarding-guide-text-muted, var(--fk-color-muted, #64748b))}.fk-onboarding-guide__foot{display:flex;align-items:center;gap:10px;padding:12px 18px 16px;border-top:1px solid var(--fk-onboarding-guide-divider, var(--fk-color-surface-dim, #f1f5f9))}.fk-onboarding-guide__foot-text{font-size:12.5px;color:var(--fk-onboarding-guide-text-muted, var(--fk-color-muted, #64748b))}.fk-onboarding-guide__foot-text b{color:var(--fk-onboarding-guide-text, var(--fk-color-text, #1e293b));font-weight:600}.fk-onboarding-guide__go{margin-left:auto;display:inline-flex;align-items:center;gap:6px;font-size:12.5px;font-weight:600;background:none;border:none;cursor:pointer;color:var(--fk-onboarding-guide-accent, var(--fk-color-text, #1a1a1a))}.fk-onboarding-guide__pill{display:none;align-items:center;gap:12px;padding:9px 15px 9px 10px;border:1px solid var(--fk-onboarding-guide-border, var(--fk-color-border, #e2e8f0));border-radius:999px;background:var(--fk-onboarding-guide-surface, var(--fk-color-surface, #fff));box-shadow:var(--fk-onboarding-guide-shadow, 0 24px 54px -18px rgba(15, 23, 42, .28));cursor:grab;animation:fk-onboarding-guide-pop .22s cubic-bezier(.2,.9,.3,1.1)}.fk-onboarding-guide__pill:active{cursor:grabbing}.fk-onboarding-guide__ring{position:relative;width:38px;height:38px;flex:none}.fk-onboarding-guide__ring svg{width:38px;height:38px;transform:rotate(-90deg)}.fk-onboarding-guide__ring-track{fill:none;stroke:var(--fk-onboarding-guide-surface-muted, var(--fk-color-surface-muted, #f1f5f9));stroke-width:4}.fk-onboarding-guide__ring-prog{fill:none;stroke:var(--fk-onboarding-guide-accent, var(--fk-color-text, #1a1a1a));stroke-width:4;stroke-linecap:round;transition:stroke-dashoffset .5s cubic-bezier(.4,0,.2,1)}.fk-onboarding-guide__ring-num{position:absolute;inset:0;display:grid;place-items:center;font-family:var(--fk-onboarding-guide-font-mono, var(--fk-font-family-mono, ui-monospace, monospace));font-size:10.5px;font-weight:600;color:var(--fk-onboarding-guide-accent, var(--fk-color-text, #1a1a1a))}.fk-onboarding-guide__pill-meta{display:flex;flex-direction:column;line-height:1.2;text-align:left}.fk-onboarding-guide__pill-title{font-family:var(--fk-onboarding-guide-font-display, var(--fk-font-family-display, inherit));font-size:13.5px;font-weight:700;white-space:nowrap;color:var(--fk-onboarding-guide-text, var(--fk-color-text, #1e293b))}.fk-onboarding-guide__pill-sub{margin-top:2px;font-size:11.5px;white-space:nowrap;color:var(--fk-onboarding-guide-text-muted, var(--fk-color-muted, #64748b))}.fk-onboarding-guide__pill-sub b{color:var(--fk-onboarding-guide-accent, var(--fk-color-text, #1a1a1a));font-weight:600}.fk-onboarding-guide__pill-expand{display:grid;place-items:center;width:28px;height:28px;flex:none;margin-left:2px;border-radius:50%;background:var(--fk-onboarding-guide-surface-muted, var(--fk-color-surface-muted, #f8fafc));color:var(--fk-onboarding-guide-text-muted, var(--fk-color-muted, #64748b))}.fk-onboarding-guide--complete .fk-onboarding-guide__ring-prog{stroke:var(--fk-onboarding-guide-complete, var(--fk-color-success, #16a34a))}.fk-onboarding-guide--complete .fk-onboarding-guide__ring-num{color:var(--fk-onboarding-guide-complete, var(--fk-color-success, #16a34a))}:host(.fk-onboarding-guide--collapsed) .fk-onboarding-guide__card{display:none}:host(.fk-onboarding-guide--collapsed) .fk-onboarding-guide__pill{display:flex}\n"], dependencies: [{ kind: "directive", type: CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "component", type: ButtonComponent, selector: "fk-button", inputs: ["variant", "size", "loading", "disabled", "type", "fullWidth", "id", "className", "ariaLabel", "ariaDescribedBy"] }, { kind: "component", type: IconComponent, selector: "fk-icon", inputs: ["name", "size", "color", "className", "id", "ariaLabel", "ariaHidden"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1200
+ }
1201
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: OnboardingGuideComponent, decorators: [{
1202
+ type: Component,
1203
+ args: [{ selector: 'fk-onboarding-guide', standalone: true, imports: [CdkDragHandle, ButtonComponent, IconComponent], hostDirectives: [CdkDrag], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- ===================== EXPANDED CARD ===================== -->\n<div class=\"fk-onboarding-guide__card\">\n <div class=\"fk-onboarding-guide__head\">\n <div class=\"fk-onboarding-guide__head-top\">\n <span class=\"fk-onboarding-guide__grip\" cdkDragHandle aria-hidden=\"true\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\">\n <circle cx=\"9\" cy=\"6\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"6\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"9\" cy=\"12\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"12\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"9\" cy=\"18\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"18\" r=\"1.5\" fill=\"currentColor\" />\n </svg>\n </span>\n\n <span class=\"fk-onboarding-guide__title\" cdkDragHandle>{{\n title()\n }}</span>\n\n <button\n type=\"button\"\n class=\"fk-onboarding-guide__icon-btn fk-onboarding-guide__edit\"\n [attr.aria-label]=\"renameLabel()\"\n (click)=\"onRename()\"\n >\n <fk-icon [name]=\"editIcon()\" size=\"sm\" />\n </button>\n\n <div class=\"fk-onboarding-guide__head-actions\">\n <button\n type=\"button\"\n class=\"fk-onboarding-guide__icon-btn\"\n [attr.aria-label]=\"collapseLabel()\"\n (click)=\"onCollapse()\"\n >\n <fk-icon [name]=\"collapseIcon()\" size=\"sm\" />\n </button>\n <button\n type=\"button\"\n class=\"fk-onboarding-guide__icon-btn\"\n [attr.aria-label]=\"dismissLabel()\"\n (click)=\"onDismiss()\"\n >\n <fk-icon [name]=\"dismissIcon()\" size=\"sm\" />\n </button>\n </div>\n </div>\n\n <div class=\"fk-onboarding-guide__progress\">\n <div\n class=\"fk-onboarding-guide__track\"\n role=\"progressbar\"\n [attr.aria-valuenow]=\"percent()\"\n aria-valuemin=\"0\"\n aria-valuemax=\"100\"\n >\n <div\n class=\"fk-onboarding-guide__fill\"\n [style.width.%]=\"percent()\"\n ></div>\n </div>\n <span class=\"fk-onboarding-guide__pct\">{{ percent() }}%</span>\n </div>\n </div>\n\n <div class=\"fk-onboarding-guide__steps\" role=\"list\">\n @for (step of steps(); track step.id) {\n @let done = isComplete(step);\n @let open = openStepId() === step.id;\n @let active = isActive(step);\n\n <div\n class=\"fk-onboarding-guide__step\"\n role=\"listitem\"\n [class.fk-onboarding-guide__step--done]=\"done\"\n [class.fk-onboarding-guide__step--open]=\"open\"\n >\n <button\n type=\"button\"\n class=\"fk-onboarding-guide__step-row\"\n [attr.aria-expanded]=\"open\"\n (click)=\"toggleStep(step.id)\"\n >\n <span\n class=\"fk-onboarding-guide__check\"\n [class.fk-onboarding-guide__check--done]=\"done\"\n [class.fk-onboarding-guide__check--active]=\"active\"\n [class.fk-onboarding-guide__check--todo]=\"!done && !active\"\n aria-hidden=\"true\"\n >\n @if (done) {\n <fk-icon [name]=\"checkIcon()\" size=\"xs\" />\n } @else if (active) {\n <i class=\"fk-onboarding-guide__dot\"></i>\n }\n </span>\n\n <span class=\"fk-onboarding-guide__step-label\">{{ step.label }}</span>\n\n <span class=\"fk-onboarding-guide__caret\" aria-hidden=\"true\">\n <fk-icon [name]=\"caretIcon()\" size=\"sm\" />\n </span>\n </button>\n\n @if (open) {\n <div class=\"fk-onboarding-guide__step-body\">\n @if (step.substeps && step.substeps.length > 0) {\n @for (sub of step.substeps; track sub.id) {\n <button\n type=\"button\"\n class=\"fk-onboarding-guide__sub\"\n [class.fk-onboarding-guide__sub--done]=\"sub.done\"\n (click)=\"onSubstep(step, sub)\"\n >\n <span\n class=\"fk-onboarding-guide__sub-check\"\n aria-hidden=\"true\"\n >\n @if (sub.done) {\n <fk-icon [name]=\"checkIcon()\" size=\"xs\" />\n }\n </span>\n <span class=\"fk-onboarding-guide__sub-label\">{{\n sub.label\n }}</span>\n </button>\n }\n } @else {\n @if (step.description) {\n <p class=\"fk-onboarding-guide__desc\">{{ step.description }}</p>\n }\n\n @if (!done) {\n <div class=\"fk-onboarding-guide__actions\">\n <fk-button\n variant=\"primary\"\n size=\"sm\"\n (click)=\"onAction(step)\"\n >\n {{ actionLabelFor(step) }}\n <fk-icon fkButtonIconEnd [name]=\"actionIcon()\" size=\"xs\" />\n </fk-button>\n <button\n type=\"button\"\n class=\"fk-onboarding-guide__skip\"\n (click)=\"onMarkDone(step)\"\n >\n {{ markDoneLabel() }}\n </button>\n </div>\n }\n }\n </div>\n }\n </div>\n }\n </div>\n\n <div class=\"fk-onboarding-guide__foot\">\n <span class=\"fk-onboarding-guide__foot-text\">\n <b>{{ doneCount() }}</b> / {{ total() }} {{ stepsWord() }}\n {{ doneWord() }}\n </span>\n <button type=\"button\" class=\"fk-onboarding-guide__go\" (click)=\"onGoLive()\">\n {{ goLiveLabel() }}\n <fk-icon [name]=\"actionIcon()\" size=\"xs\" />\n </button>\n </div>\n</div>\n\n<!-- ===================== COLLAPSED PILL ===================== -->\n<button\n type=\"button\"\n class=\"fk-onboarding-guide__pill\"\n cdkDragHandle\n [attr.aria-label]=\"expandLabel()\"\n (click)=\"onExpand()\"\n>\n <span class=\"fk-onboarding-guide__ring\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 38 38\">\n <circle class=\"fk-onboarding-guide__ring-track\" cx=\"19\" cy=\"19\" r=\"16\" />\n <circle\n class=\"fk-onboarding-guide__ring-prog\"\n cx=\"19\"\n cy=\"19\"\n r=\"16\"\n [style.stroke-dasharray]=\"ringCircumference\"\n [style.stroke-dashoffset]=\"ringOffset()\"\n />\n </svg>\n <span class=\"fk-onboarding-guide__ring-num\">{{ percent() }}%</span>\n </span>\n\n <span class=\"fk-onboarding-guide__pill-meta\">\n <span class=\"fk-onboarding-guide__pill-title\">{{ title() }}</span>\n <span class=\"fk-onboarding-guide__pill-sub\">\n @if (complete()) {\n {{ allDoneLabel() }}\n } @else {\n <b>{{ stepsLeft() }}</b> {{ stepsWord() }} {{ stepsLeftWord() }}\n }\n </span>\n </span>\n\n <span class=\"fk-onboarding-guide__pill-expand\" aria-hidden=\"true\">\n <fk-icon [name]=\"expandIcon()\" size=\"sm\" />\n </span>\n</button>\n", styles: ["@keyframes fk-onboarding-guide-pop{0%{opacity:0;transform:translateY(8px) scale(.97)}to{opacity:1;transform:none}}:host{position:fixed;top:0;left:0;z-index:var(--fk-onboarding-guide-z, 60);font-family:var(--fk-onboarding-guide-font-body, var(--fk-font-family-body, system-ui, sans-serif));color:var(--fk-onboarding-guide-text, var(--fk-color-text, #1e293b));touch-action:none}.fk-onboarding-guide__card,.fk-onboarding-guide__pill{--fk-button-primary-bg: var( --fk-onboarding-guide-accent, var(--fk-color-text, #1a1a1a) );--fk-button-primary-bg-hover: color-mix( in srgb, var(--fk-onboarding-guide-accent, var(--fk-color-text, #1a1a1a)) 88%, #000 );--fk-button-primary-color: var( --fk-onboarding-guide-accent-contrast, var(--fk-color-surface, #fff) )}.fk-onboarding-guide__card{width:var(--fk-onboarding-guide-width, 360px);max-width:calc(100vw - 2 * var(--fk-rhythm-4, 1rem));background:var(--fk-onboarding-guide-surface, var(--fk-color-surface, #fff));border:1px solid var(--fk-onboarding-guide-border, var(--fk-color-border, #e2e8f0));border-radius:var(--fk-onboarding-guide-radius, var(--fk-radius-lg, 16px));box-shadow:var(--fk-onboarding-guide-shadow, 0 24px 54px -18px rgba(15, 23, 42, .28));overflow:hidden;transform-origin:bottom right;animation:fk-onboarding-guide-pop .24s cubic-bezier(.2,.9,.3,1.1)}.fk-onboarding-guide__head{padding:16px 18px 14px}.fk-onboarding-guide__head-top{display:flex;align-items:center;gap:9px}.fk-onboarding-guide__grip,.fk-onboarding-guide__title{cursor:grab}.fk-onboarding-guide__grip:active,.fk-onboarding-guide__title:active{cursor:grabbing}.fk-onboarding-guide__grip{display:inline-flex;flex:none;margin-left:-3px;color:var(--fk-onboarding-guide-text-faint, var(--fk-color-muted, #94a3b8))}.fk-onboarding-guide__grip svg{width:15px;height:15px}.fk-onboarding-guide__title{font-family:var(--fk-onboarding-guide-font-display, var(--fk-font-family-display, inherit));font-size:16px;font-weight:700;color:var(--fk-onboarding-guide-text, var(--fk-color-text, #1e293b))}.fk-onboarding-guide__head-actions{margin-left:auto;display:flex;gap:4px}.fk-onboarding-guide__icon-btn{display:grid;place-items:center;width:28px;height:28px;border:1px solid transparent;border-radius:7px;background:none;color:var(--fk-onboarding-guide-text-faint, var(--fk-color-muted, #94a3b8));cursor:pointer;transition:.14s}.fk-onboarding-guide__icon-btn:hover{background:var(--fk-onboarding-guide-surface-muted, var(--fk-color-surface-muted, #f8fafc));border-color:var(--fk-onboarding-guide-border, var(--fk-color-border, #e2e8f0));color:var(--fk-onboarding-guide-text, var(--fk-color-text, #1e293b))}.fk-onboarding-guide__edit{width:24px;height:24px;border-radius:6px}.fk-onboarding-guide__progress{display:flex;align-items:center;gap:11px;margin-top:13px}.fk-onboarding-guide__track{flex:1;height:7px;border-radius:5px;background:var(--fk-onboarding-guide-surface-muted, var(--fk-color-surface-muted, #f1f5f9));overflow:hidden}.fk-onboarding-guide__fill{height:100%;border-radius:5px;background:var(--fk-onboarding-guide-accent, var(--fk-color-text, #1a1a1a));transition:width .5s cubic-bezier(.4,0,.2,1)}.fk-onboarding-guide__pct{flex:none;font-family:var(--fk-onboarding-guide-font-mono, var(--fk-font-family-mono, ui-monospace, monospace));font-size:11px;font-weight:600;color:var(--fk-onboarding-guide-accent, var(--fk-color-text, #1a1a1a))}.fk-onboarding-guide__steps{padding:6px 8px 10px;max-height:400px;overflow-y:auto}.fk-onboarding-guide__step{border-radius:12px;overflow:hidden}.fk-onboarding-guide__step--open{background:var(--fk-onboarding-guide-surface-muted, var(--fk-color-surface-muted, #f8fafc))}.fk-onboarding-guide__step-row{display:flex;align-items:center;gap:12px;width:100%;padding:13px 12px;border:none;border-radius:12px;background:none;text-align:left;cursor:pointer;transition:.14s}.fk-onboarding-guide__step-row:hover{background:var(--fk-onboarding-guide-surface-muted, var(--fk-color-surface-muted, #f8fafc))}.fk-onboarding-guide__step--open .fk-onboarding-guide__step-row:hover{background:transparent}.fk-onboarding-guide__check{display:grid;place-items:center;flex:none;width:20px;height:20px;border-radius:50%;transition:.16s;color:var(--fk-onboarding-guide-accent-contrast, #fff)}.fk-onboarding-guide__check--done{background:var(--fk-onboarding-guide-accent, var(--fk-color-text, #1a1a1a))}.fk-onboarding-guide__check--todo{border:2px solid color-mix(in srgb,var(--fk-onboarding-guide-text-muted, var(--fk-color-muted, #64748b)) 45%,transparent)}.fk-onboarding-guide__check--active{border:2px solid var(--fk-onboarding-guide-accent, var(--fk-color-text, #1a1a1a));background:color-mix(in srgb,var(--fk-onboarding-guide-accent, var(--fk-color-text, #1a1a1a)) 10%,transparent)}.fk-onboarding-guide__dot{width:7px;height:7px;border-radius:50%;background:var(--fk-onboarding-guide-accent, var(--fk-color-text, #1a1a1a))}.fk-onboarding-guide__step-label{flex:1;min-width:0;font-size:14.5px;font-weight:600;color:var(--fk-onboarding-guide-text, var(--fk-color-text, #1e293b))}.fk-onboarding-guide__step--done .fk-onboarding-guide__step-label{color:var(--fk-onboarding-guide-text-muted, var(--fk-color-muted, #64748b));font-weight:500;text-decoration:line-through;text-decoration-color:color-mix(in srgb,var(--fk-onboarding-guide-text-muted, var(--fk-color-muted, #64748b)) 55%,transparent)}.fk-onboarding-guide__caret{display:grid;place-items:center;flex:none;color:var(--fk-onboarding-guide-text-faint, var(--fk-color-muted, #b6bfce));transition:transform .18s}.fk-onboarding-guide__step--open .fk-onboarding-guide__caret{transform:rotate(180deg);color:var(--fk-onboarding-guide-text, var(--fk-color-text, #1e293b))}.fk-onboarding-guide__step-body{padding:0 14px 14px 44px}.fk-onboarding-guide__desc{font-size:13px;line-height:1.55;color:var(--fk-onboarding-guide-text-muted, var(--fk-color-muted, #64748b));margin-bottom:12px}.fk-onboarding-guide__actions{display:flex;align-items:center;gap:8px}.fk-onboarding-guide__skip{font-size:13px;font-weight:600;color:var(--fk-onboarding-guide-text-muted, var(--fk-color-muted, #64748b));background:none;border:none;padding:6px;cursor:pointer}.fk-onboarding-guide__skip:hover{color:var(--fk-onboarding-guide-text, var(--fk-color-text, #1e293b))}.fk-onboarding-guide__sub{display:flex;align-items:center;gap:11px;width:100%;padding:8px 0;border:none;background:none;text-align:left;cursor:pointer}.fk-onboarding-guide__sub-check{display:grid;place-items:center;flex:none;width:18px;height:18px;border-radius:50%;color:var(--fk-onboarding-guide-accent-contrast, #fff);background:color-mix(in srgb,var(--fk-onboarding-guide-text-muted, var(--fk-color-muted, #64748b)) 22%,transparent)}.fk-onboarding-guide__sub--done .fk-onboarding-guide__sub-check{background:var(--fk-onboarding-guide-accent, var(--fk-color-text, #1a1a1a))}.fk-onboarding-guide__sub-label{font-size:14px;color:var(--fk-onboarding-guide-text, var(--fk-color-text, #36405a))}.fk-onboarding-guide__sub--done .fk-onboarding-guide__sub-label{color:var(--fk-onboarding-guide-text-muted, var(--fk-color-muted, #64748b))}.fk-onboarding-guide__foot{display:flex;align-items:center;gap:10px;padding:12px 18px 16px;border-top:1px solid var(--fk-onboarding-guide-divider, var(--fk-color-surface-dim, #f1f5f9))}.fk-onboarding-guide__foot-text{font-size:12.5px;color:var(--fk-onboarding-guide-text-muted, var(--fk-color-muted, #64748b))}.fk-onboarding-guide__foot-text b{color:var(--fk-onboarding-guide-text, var(--fk-color-text, #1e293b));font-weight:600}.fk-onboarding-guide__go{margin-left:auto;display:inline-flex;align-items:center;gap:6px;font-size:12.5px;font-weight:600;background:none;border:none;cursor:pointer;color:var(--fk-onboarding-guide-accent, var(--fk-color-text, #1a1a1a))}.fk-onboarding-guide__pill{display:none;align-items:center;gap:12px;padding:9px 15px 9px 10px;border:1px solid var(--fk-onboarding-guide-border, var(--fk-color-border, #e2e8f0));border-radius:999px;background:var(--fk-onboarding-guide-surface, var(--fk-color-surface, #fff));box-shadow:var(--fk-onboarding-guide-shadow, 0 24px 54px -18px rgba(15, 23, 42, .28));cursor:grab;animation:fk-onboarding-guide-pop .22s cubic-bezier(.2,.9,.3,1.1)}.fk-onboarding-guide__pill:active{cursor:grabbing}.fk-onboarding-guide__ring{position:relative;width:38px;height:38px;flex:none}.fk-onboarding-guide__ring svg{width:38px;height:38px;transform:rotate(-90deg)}.fk-onboarding-guide__ring-track{fill:none;stroke:var(--fk-onboarding-guide-surface-muted, var(--fk-color-surface-muted, #f1f5f9));stroke-width:4}.fk-onboarding-guide__ring-prog{fill:none;stroke:var(--fk-onboarding-guide-accent, var(--fk-color-text, #1a1a1a));stroke-width:4;stroke-linecap:round;transition:stroke-dashoffset .5s cubic-bezier(.4,0,.2,1)}.fk-onboarding-guide__ring-num{position:absolute;inset:0;display:grid;place-items:center;font-family:var(--fk-onboarding-guide-font-mono, var(--fk-font-family-mono, ui-monospace, monospace));font-size:10.5px;font-weight:600;color:var(--fk-onboarding-guide-accent, var(--fk-color-text, #1a1a1a))}.fk-onboarding-guide__pill-meta{display:flex;flex-direction:column;line-height:1.2;text-align:left}.fk-onboarding-guide__pill-title{font-family:var(--fk-onboarding-guide-font-display, var(--fk-font-family-display, inherit));font-size:13.5px;font-weight:700;white-space:nowrap;color:var(--fk-onboarding-guide-text, var(--fk-color-text, #1e293b))}.fk-onboarding-guide__pill-sub{margin-top:2px;font-size:11.5px;white-space:nowrap;color:var(--fk-onboarding-guide-text-muted, var(--fk-color-muted, #64748b))}.fk-onboarding-guide__pill-sub b{color:var(--fk-onboarding-guide-accent, var(--fk-color-text, #1a1a1a));font-weight:600}.fk-onboarding-guide__pill-expand{display:grid;place-items:center;width:28px;height:28px;flex:none;margin-left:2px;border-radius:50%;background:var(--fk-onboarding-guide-surface-muted, var(--fk-color-surface-muted, #f8fafc));color:var(--fk-onboarding-guide-text-muted, var(--fk-color-muted, #64748b))}.fk-onboarding-guide--complete .fk-onboarding-guide__ring-prog{stroke:var(--fk-onboarding-guide-complete, var(--fk-color-success, #16a34a))}.fk-onboarding-guide--complete .fk-onboarding-guide__ring-num{color:var(--fk-onboarding-guide-complete, var(--fk-color-success, #16a34a))}:host(.fk-onboarding-guide--collapsed) .fk-onboarding-guide__card{display:none}:host(.fk-onboarding-guide--collapsed) .fk-onboarding-guide__pill{display:flex}\n"] }]
1204
+ }], ctorParameters: () => [], propDecorators: { steps: [{ type: i0.Input, args: [{ isSignal: true, alias: "steps", required: true }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], storageKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "storageKey", required: false }] }], startCollapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "startCollapsed", required: false }] }], startLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "startLabel", required: false }] }], markDoneLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "markDoneLabel", required: false }] }], goLiveLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "goLiveLabel", required: false }] }], stepsWord: [{ type: i0.Input, args: [{ isSignal: true, alias: "stepsWord", required: false }] }], doneWord: [{ type: i0.Input, args: [{ isSignal: true, alias: "doneWord", required: false }] }], stepsLeftWord: [{ type: i0.Input, args: [{ isSignal: true, alias: "stepsLeftWord", required: false }] }], allDoneLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "allDoneLabel", required: false }] }], renameLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "renameLabel", required: false }] }], collapseLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapseLabel", required: false }] }], dismissLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "dismissLabel", required: false }] }], expandLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandLabel", required: false }] }], checkIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "checkIcon", required: false }] }], caretIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "caretIcon", required: false }] }], editIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "editIcon", required: false }] }], collapseIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapseIcon", required: false }] }], dismissIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "dismissIcon", required: false }] }], expandIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandIcon", required: false }] }], actionIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "actionIcon", required: false }] }], stepAction: [{ type: i0.Output, args: ["stepAction"] }], stepMarkDone: [{ type: i0.Output, args: ["stepMarkDone"] }], substepToggle: [{ type: i0.Output, args: ["substepToggle"] }], goLive: [{ type: i0.Output, args: ["goLive"] }], renameClick: [{ type: i0.Output, args: ["renameClick"] }], dismiss: [{ type: i0.Output, args: ["dismiss"] }], collapsedChange: [{ type: i0.Output, args: ["collapsedChange"] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], hostClass: [{
1205
+ type: HostBinding,
1206
+ args: ['class']
1207
+ }], hostId: [{
1208
+ type: HostBinding,
1209
+ args: ['attr.id']
1210
+ }] } });
1211
+
927
1212
  /**
928
1213
  * Generated bundle index. Do not edit.
929
1214
  */
930
1215
 
931
- export { ColumnsComponent, ContentSplitLayoutComponent, DetailPanelComponent, DialogFooterComponent, DialogHeaderComponent, DialogShellComponent, PageHeaderComponent, SidebarNavComponent, SidebarNavItemDirective, TableEmptyStateComponent };
1216
+ export { ColumnsComponent, ContentSplitLayoutComponent, DetailPanelComponent, DialogFooterComponent, DialogHeaderComponent, DialogShellComponent, OnboardingGuideComponent, PageHeaderComponent, SidebarNavComponent, SidebarNavItemDirective, TableEmptyStateComponent };
932
1217
  //# sourceMappingURL=frame-kit-ui-ng-patterns-dashboard.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"frame-kit-ui-ng-patterns-dashboard.mjs","sources":["../../../../packages/ui-ng-patterns/dashboard/page-header/page-header.component.ts","../../../../packages/ui-ng-patterns/dashboard/page-header/page-header.component.html","../../../../packages/ui-ng-patterns/dashboard/table-empty-state/table-empty-state.component.ts","../../../../packages/ui-ng-patterns/dashboard/table-empty-state/table-empty-state.component.html","../../../../packages/ui-ng-patterns/dashboard/content-split-layout/content-split-layout.component.ts","../../../../packages/ui-ng-patterns/dashboard/content-split-layout/content-split-layout.component.html","../../../../packages/ui-ng-patterns/dashboard/columns/columns.component.ts","../../../../packages/ui-ng-patterns/dashboard/columns/columns.component.html","../../../../packages/ui-ng-patterns/dashboard/detail-panel/detail-panel.component.ts","../../../../packages/ui-ng-patterns/dashboard/detail-panel/detail-panel.component.html","../../../../packages/ui-ng-patterns/dashboard/sidebar-nav/sidebar-nav-item.directive.ts","../../../../packages/ui-ng-patterns/dashboard/sidebar-nav/sidebar-nav.component.ts","../../../../packages/ui-ng-patterns/dashboard/sidebar-nav/sidebar-nav.component.html","../../../../packages/ui-ng-patterns/dashboard/dialog-footer/dialog-footer.component.ts","../../../../packages/ui-ng-patterns/dashboard/dialog-footer/dialog-footer.component.html","../../../../packages/ui-ng-patterns/dashboard/dialog-header/dialog-header.component.ts","../../../../packages/ui-ng-patterns/dashboard/dialog-header/dialog-header.component.html","../../../../packages/ui-ng-patterns/dashboard/dialog-shell/dialog-shell.component.ts","../../../../packages/ui-ng-patterns/dashboard/dialog-shell/dialog-shell.component.html","../../../../packages/ui-ng-patterns/dashboard/frame-kit-ui-ng-patterns-dashboard.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n input,\n ViewEncapsulation,\n} from '@angular/core';\n\nimport type { HeadlineLevel } from '@frame-kit/ui-ng/core/headline';\nimport { HeadlineComponent } from '@frame-kit/ui-ng/core/headline';\nimport { TextComponent } from '@frame-kit/ui-ng/core/text';\n\n/**\n * Page-level dashboard header: title + optional description on the left, up to\n * ~3 actions on the right.\n *\n * When the header's own width gets tight, the actions drop below the text and\n * go full-width (mobile-style). The break is driven by a CSS container query on\n * the host, so it responds to the content region's width — not the viewport,\n * which means it behaves correctly inside a narrow panel.\n *\n * Project actions by tagging each button with `pageHeaderActions`:\n *\n * <fk-page-header title=\"Users\" description=\"...\">\n * <fk-button pageHeaderActions variant=\"outline\" size=\"sm\">Import</fk-button>\n * <fk-button pageHeaderActions variant=\"primary\" size=\"sm\">Create user</fk-button>\n * </fk-page-header>\n *\n * Tagging each button (rather than wrapping them in a div) makes every button a\n * direct flex child, so full-width stacking falls out of `align-items: stretch`\n * with no `::ng-deep` reach-in.\n *\n * The title row has two projected slots — `[pageHeaderLeading]` before the\n * title and `[pageHeaderTrailing]` after it. Project a plain `fk-icon` for a\n * decorative mark, or a `button` for a clickable one (the consumer owns the\n * interaction, focus ring, and aria-label):\n *\n * <fk-page-header title=\"Permissions\">\n * <fk-icon pageHeaderLeading name=\"key-outline\" />\n * <button pageHeaderTrailing type=\"button\" aria-label=\"Docs\" (click)=\"openDocs()\">\n * <fk-icon name=\"view-api\" />\n * </button>\n * </fk-page-header>\n */\n@Component({\n selector: 'fk-page-header',\n standalone: true,\n imports: [HeadlineComponent, TextComponent],\n // Emulated (not None) so `:host` works — `:host { display: block }` is what\n // keeps the custom element from defaulting to `display: inline` and\n // collapsing to min-content under the container query below.\n encapsulation: ViewEncapsulation.Emulated,\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './page-header.component.html',\n styleUrl: './page-header.component.scss',\n})\nexport class PageHeaderComponent {\n readonly title = input.required<string>();\n readonly description = input<string | null>(null);\n readonly headingLevel = input<HeadlineLevel>(1);\n}\n","<header class=\"fk-page-header\">\n <div class=\"fk-page-header__text\">\n <div class=\"fk-page-header__title-row\">\n <ng-content select=\"[pageHeaderLeading]\" />\n\n <fk-headline [level]=\"headingLevel()\">{{ title() }}</fk-headline>\n\n <ng-content select=\"[pageHeaderTrailing]\" />\n </div>\n\n @if (description()) {\n <fk-text class=\"fk-page-header__description\" tone=\"muted\">{{\n description()\n }}</fk-text>\n }\n </div>\n\n <div class=\"fk-page-header__actions\">\n <ng-content select=\"[pageHeaderActions]\" />\n </div>\n</header>\n","import {\n ChangeDetectionStrategy,\n Component,\n computed,\n HostBinding,\n input,\n ViewEncapsulation,\n} from '@angular/core';\n\nimport { IconComponent } from '@frame-kit/ui-ng/core/icon';\n\n/**\n * Empty-state panel for dashboard tables and lists: a centered icon, a title,\n * an optional description, and a projected actions slot (typically one primary\n * fk-button). Bordered-card styling, meant to stand in for a table body when\n * there are no rows.\n *\n * The action row flips from a horizontal row to a centered vertical stack on\n * narrow widths, driven by a container query on the host — so it reacts to the\n * empty-state's own width (e.g. inside a split column) rather than the viewport.\n *\n * <fk-table-empty-state\n * icon=\"globe\"\n * title=\"No webhooks configured\"\n * description=\"Add a webhook to receive events.\"\n * >\n * <fk-button variant=\"primary\" size=\"sm\">Add webhook</fk-button>\n * </fk-table-empty-state>\n *\n * The actions slot is an open `ng-content`, so project as many actions as the\n * design needs (one primary is the norm; two reads cleanly).\n */\n@Component({\n selector: 'fk-table-empty-state',\n standalone: true,\n imports: [IconComponent],\n // Emulated (default) so `:host` works — the host is the bordered flex card\n // and establishes the container-query context the actions break against.\n encapsulation: ViewEncapsulation.Emulated,\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './table-empty-state.component.html',\n styleUrl: './table-empty-state.component.scss',\n})\nexport class TableEmptyStateComponent {\n // ===== INPUTS =====\n readonly icon = input<string | null>(null);\n readonly title = input.required<string>();\n readonly description = input<string | null>(null);\n\n // ===== BASE PROPS =====\n readonly className = input<string>('');\n readonly id = input<string | null>(null);\n readonly ariaLabel = input<string | null>(null);\n\n // ===== COMPUTED =====\n readonly classes = computed(() =>\n ['fk-table-empty-state', this.className()].filter(Boolean).join(' '),\n );\n\n @HostBinding('class')\n get hostClass(): string {\n return this.classes();\n }\n\n @HostBinding('attr.id')\n get hostId(): string | null {\n return this.id();\n }\n\n @HostBinding('attr.aria-label')\n get hostAriaLabel(): string | null {\n return this.ariaLabel();\n }\n}\n","@if (icon()) {\n <div class=\"fk-table-empty-state__icon\">\n <fk-icon [name]=\"icon()!\" size=\"lg\" />\n </div>\n}\n\n<h3 class=\"fk-table-empty-state__title\">{{ title() }}</h3>\n\n@if (description()) {\n <p class=\"fk-table-empty-state__description\">{{ description() }}</p>\n}\n\n<div class=\"fk-table-empty-state__actions\">\n <ng-content />\n</div>\n","import {\n ChangeDetectionStrategy,\n Component,\n HostBinding,\n input,\n} from '@angular/core';\n\n/**\n * Two-column split layout with container-query responsive stacking.\n *\n * Projects content into `[start]` (grows to fill) and `[end]` (content-sized or\n * fixed width). Below 700px container width, columns stack vertically.\n *\n * A standalone layout primitive for custom dashboard rows.\n */\n@Component({\n selector: 'fk-content-split-layout',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './content-split-layout.component.html',\n styleUrl: './content-split-layout.component.scss',\n})\nexport class ContentSplitLayoutComponent {\n readonly endWidth = input<string | null>(null);\n readonly gap = input<string>('var(--fk-rhythm-4, 1rem)');\n\n @HostBinding('class')\n readonly hostClass = 'fk-content-split-layout';\n}\n","<div\n class=\"fk-content-split-layout__row\"\n [style.--fk-content-split-gap]=\"gap()\"\n>\n <div class=\"fk-content-split-layout__start\">\n <ng-content select=\"[start]\" />\n </div>\n\n <div\n class=\"fk-content-split-layout__end\"\n [class.fk-content-split-layout__end--fixed]=\"endWidth()\"\n [style.--fk-content-split-end-width]=\"endWidth()\"\n >\n <ng-content select=\"[end]\" />\n </div>\n</div>\n","import {\n ChangeDetectionStrategy,\n Component,\n computed,\n HostBinding,\n input,\n} from '@angular/core';\n\n/**\n * Responsive column layout for dashboard content. Lays projected children out\n * in equal-width columns that wrap — and ultimately collapse to a single\n * stacked column — based on the layout's *own* available width, never the\n * viewport. So it reacts correctly when the dashboard content region is\n * squeezed (sidenav open, a drawer pushed in, a split pane) while the viewport\n * still reports \"desktop\".\n *\n * Implemented with an intrinsic CSS grid — `repeat(auto-fit, minmax(min, 1fr))`\n * — so there is no container query, no JS, and no viewport breakpoint to keep\n * in sync. `minColumnWidth` is the smallest a column may shrink to before the\n * grid drops a column; empty tracks collapse, so N children never produce more\n * than N columns. Spacing on both axes is a single `gutter` gap, so wrapped\n * rows and side-by-side columns separate consistently with no edge artifacts.\n *\n * <fk-columns minColumnWidth=\"18rem\">\n * <fk-field-group>…</fk-field-group>\n * <fk-field-group>…</fk-field-group>\n * </fk-columns>\n *\n * By default columns grow to fill the row (`1fr`). Set `maxColumnWidth` to cap\n * how wide a column may get — past that, columns stay that width and the extra\n * space is left empty (columns aligned to the start) rather than stretching.\n */\n@Component({\n selector: 'fk-columns',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './columns.component.html',\n styleUrl: './columns.component.scss',\n})\nexport class ColumnsComponent {\n // ===== INPUTS =====\n /**\n * The smallest width a column may shrink to before the grid drops to fewer\n * columns. This is the single knob that controls when columns wrap/stack.\n */\n readonly minColumnWidth = input<string>('16rem');\n /**\n * Optional cap on how wide a column may grow. Unset (default), columns fill\n * the row (`1fr`); when set (e.g. `'22rem'`), columns size between\n * `minColumnWidth` and this value and don't stretch past it — leftover space\n * stays empty, columns aligned to the start.\n */\n readonly maxColumnWidth = input<string | null>(null);\n /** Gap between side-by-side columns and between wrapped rows. */\n readonly gutter = input<string>('var(--fk-rhythm-4, 1rem)');\n\n // ===== BASE PROPS =====\n readonly className = input<string>('');\n readonly id = input<string | null>(null);\n readonly ariaLabel = input<string | null>(null);\n\n // ===== COMPUTED =====\n readonly classes = computed(() =>\n ['fk-columns', this.className()].filter(Boolean).join(' '),\n );\n\n @HostBinding('class')\n get hostClass(): string {\n return this.classes();\n }\n\n @HostBinding('attr.id')\n get hostId(): string | null {\n return this.id();\n }\n\n @HostBinding('attr.aria-label')\n get hostAriaLabel(): string | null {\n return this.ariaLabel();\n }\n\n @HostBinding('style.--fk-columns-min')\n get hostMin(): string {\n return this.minColumnWidth();\n }\n\n // Null leaves the property unset, so the SCSS falls back to `1fr` (fill).\n @HostBinding('style.--fk-columns-max')\n get hostMax(): string | null {\n return this.maxColumnWidth();\n }\n\n @HostBinding('style.--fk-columns-gutter')\n get hostGutter(): string {\n return this.gutter();\n }\n}\n","<ng-content />\n","import {\n ChangeDetectionStrategy,\n Component,\n computed,\n HostBinding,\n input,\n} from '@angular/core';\n\n/**\n * Padded container for an expanded dashboard detail region — typically the body\n * of a data-table row expansion, holding an `fk-columns` of form controls.\n *\n * The `disabled` input greys the panel and makes its entire subtree `inert`\n * (non-interactive, unfocusable, hidden from assistive technology) — for\n * controls gated behind a feature toggle that must not be editable until the\n * feature is enabled.\n *\n * <fk-detail-panel [disabled]=\"!feature.enabled\">\n * <fk-columns>…</fk-columns>\n * </fk-detail-panel>\n */\n@Component({\n selector: 'fk-detail-panel',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './detail-panel.component.html',\n styleUrl: './detail-panel.component.scss',\n})\nexport class DetailPanelComponent {\n // ===== INPUTS =====\n /**\n * Greys the panel and makes its content inert (locked) — for feature-gated\n * controls that should not be editable until the feature is enabled.\n */\n readonly disabled = input<boolean>(false);\n\n // ===== BASE PROPS =====\n readonly className = input<string>('');\n readonly id = input<string | null>(null);\n readonly ariaLabel = input<string | null>(null);\n\n // ===== COMPUTED =====\n readonly classes = computed(() =>\n [\n 'fk-detail-panel',\n this.disabled() ? 'fk-detail-panel--disabled' : '',\n this.className(),\n ]\n .filter(Boolean)\n .join(' '),\n );\n\n @HostBinding('class')\n get hostClass(): string {\n return this.classes();\n }\n\n @HostBinding('attr.id')\n get hostId(): string | null {\n return this.id();\n }\n\n @HostBinding('attr.aria-label')\n get hostAriaLabel(): string | null {\n return this.ariaLabel();\n }\n\n /**\n * Lock the whole subtree when disabled. `inert` blocks pointer interaction,\n * focus, and assistive-tech access in one attribute — stronger and more\n * correct than `pointer-events: none`, which only blocks the mouse.\n */\n @HostBinding('attr.inert')\n get hostInert(): '' | null {\n return this.disabled() ? '' : null;\n }\n}\n","<ng-content />\n","import { Directive, inject, TemplateRef } from '@angular/core';\n\nimport type { SidebarNavLink } from './sidebar-nav.types';\n\n/**\n * Marks an `<ng-template>` whose content `fk-sidebar-nav` renders as an item's\n * leading content — e.g. a method badge or any custom adornment — receiving the\n * item as `$implicit`. The component still owns the row, label, disclosure,\n * active/branch state, collapse, and flyout; this only customizes what sits\n * before the label.\n *\n * The template is applied to any item whose `data` is set; items without `data`\n * fall back to their `icon`.\n *\n * <fk-sidebar-nav [model]=\"nav\">\n * <ng-template fkSidebarNavItem let-item>\n * <fk-method-badge [method]=\"item.data\" />\n * </ng-template>\n * </fk-sidebar-nav>\n */\n@Directive({\n selector: 'ng-template[fkSidebarNavItem]',\n standalone: true,\n})\nexport class SidebarNavItemDirective {\n readonly template =\n inject<TemplateRef<{ $implicit: SidebarNavLink }>>(TemplateRef);\n\n /** Types `let-item` as a `SidebarNavLink` in the consumer's template. */\n static ngTemplateContextGuard(\n _directive: SidebarNavItemDirective,\n _context: unknown,\n ): _context is { $implicit: SidebarNavLink } {\n return true;\n }\n}\n","import { Overlay, OverlayRef } from '@angular/cdk/overlay';\nimport { TemplatePortal } from '@angular/cdk/portal';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n afterNextRender,\n ChangeDetectionStrategy,\n Component,\n computed,\n contentChild,\n DestroyRef,\n effect,\n HostBinding,\n inject,\n Injector,\n input,\n signal,\n TemplateRef,\n viewChild,\n ViewContainerRef,\n} from '@angular/core';\nimport { toSignal } from '@angular/core/rxjs-interop';\nimport {\n ActivatedRoute,\n NavigationEnd,\n Router,\n RouterLink,\n} from '@angular/router';\nimport { filter, map, Subscription } from 'rxjs';\n\nimport { IconComponent } from '@frame-kit/ui-ng/core/icon';\nimport { TooltipDirective } from '@frame-kit/ui-ng/directives/tooltip';\nimport { AppShellComponent } from '@frame-kit/ui-ng/layouts/app-shell';\n\nimport { SidebarNavItemDirective } from './sidebar-nav-item.directive';\nimport type {\n SidebarNavItem,\n SidebarNavLink,\n SidebarNavModel,\n} from './sidebar-nav.types';\n\n/**\n * Model-driven dashboard sidebar navigation.\n *\n * Renders a sidebar from a {@link SidebarNavModel}: labelled groups of items,\n * where each item is either a leaf link or a parent with children. The pattern\n * owns the two-state behavior that makes a dashboard rail usable:\n *\n * - **Expanded** — parents disclose their children inline; the section\n * containing the active route stays open and reads as active (tinted).\n * - **Collapsed (icon rail)** — labels collapse to icons with hover tooltips;\n * a parent click opens a **flyout** beside the rail (anchored via CDK\n * Overlay) listing its children, so nested pages stay reachable without\n * expanding the whole sidebar.\n *\n * Drop it into an `fk-app-shell` sidenav slot — it reads the shell's collapse\n * state automatically. Pass `[collapsed]` explicitly to drive the rail without\n * a shell.\n */\n@Component({\n selector: 'fk-sidebar-nav',\n standalone: true,\n imports: [RouterLink, IconComponent, TooltipDirective, NgTemplateOutlet],\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './sidebar-nav.component.html',\n styleUrl: './sidebar-nav.component.scss',\n})\nexport class SidebarNavComponent {\n // ===== INPUTS =====\n /** The navigation model — ordered groups of items. */\n readonly model = input<SidebarNavModel>([]);\n /**\n * Collapsed (icon-rail) state. Left `null`, the component reads the collapse\n * state of an ancestor `fk-app-shell`. Set explicitly to drive the rail\n * without a shell present.\n */\n readonly collapsed = input<boolean | null>(null);\n\n // ===== BASE PROPS =====\n readonly className = input<string>('');\n\n // ===== DEPENDENCIES =====\n private readonly shell = inject(AppShellComponent, { optional: true });\n private readonly router = inject(Router);\n private readonly route = inject(ActivatedRoute);\n private readonly overlay = inject(Overlay);\n private readonly vcr = inject(ViewContainerRef);\n private readonly destroyRef = inject(DestroyRef);\n private readonly injector = inject(Injector);\n\n // ===== REFS =====\n private readonly flyoutTpl =\n viewChild.required<TemplateRef<unknown>>('flyoutTpl');\n /** Optional consumer template for an item's leading content (e.g. a badge). */\n private readonly itemTpl = contentChild(SidebarNavItemDirective);\n private readonly itemTemplate = computed(\n () => this.itemTpl()?.template ?? null,\n );\n\n /**\n * The leading-content template for an item, or null. Only items carrying\n * `data` use it; others fall back to their `icon`.\n */\n protected leadingTemplate(\n item: SidebarNavLink,\n ): TemplateRef<{ $implicit: SidebarNavLink }> | null {\n return item.data !== undefined && item.data !== null\n ? this.itemTemplate()\n : null;\n }\n\n // ===== STATE =====\n /** Active URL, recomputed on every navigation — drives section-active styling. */\n private readonly currentUrl = toSignal(\n this.router.events.pipe(\n filter((e): e is NavigationEnd => e instanceof NavigationEnd),\n map(() => stripUrl(this.router.url)),\n ),\n { initialValue: stripUrl(this.router.url) },\n );\n /** Parent ids the user has explicitly opened (the active section is always open). */\n private readonly openIds = signal<ReadonlySet<string>>(new Set());\n\n private overlayRef: OverlayRef | null = null;\n /** Overlay-scoped event subscriptions — torn down with the overlay in closeFlyout(). */\n private flyoutSubs: Subscription | null = null;\n /** The trigger row the open flyout is anchored to — used to ignore its own re-click. */\n private flyoutOrigin: HTMLElement | null = null;\n /** The parent whose flyout is currently open (collapsed rail), or null. */\n protected readonly flyoutItem = signal<SidebarNavItem | null>(null);\n\n constructor() {\n // Tear down an open flyout the moment the rail expands. Clicking the shell\n // toggle would close it via the outside-pointer handler, but a programmatic\n // `[collapsed]` change, a responsive breakpoint flip, or a keyboard toggle\n // produces no pointer event — so the overlay would otherwise linger beside\n // the now-expanded sidebar.\n effect(() => {\n if (!this.isCollapsed()) {\n this.closeFlyout();\n }\n });\n\n // Close on any navigation (covers programmatic router.navigate, which\n // disposeOnNavigation does not catch, and keeps internal state in sync).\n effect(() => {\n this.currentUrl();\n this.closeFlyout();\n });\n\n // Auto-open the section that holds the active route — on first load and\n // whenever navigation lands inside a (possibly different, or previously\n // collapsed) section. This only ever *adds* to openIds, so a section the\n // user collapses by hand stays closed until they navigate back into it.\n effect(() => {\n this.currentUrl();\n\n const activeIds = this.model()\n .flatMap((group) => group.items)\n .filter((item) => this.isParent(item) && this.sectionActive(item))\n .map((item) => item.id);\n\n if (activeIds.length === 0) {\n return;\n }\n\n this.openIds.update((set) => {\n const next = new Set(set);\n activeIds.forEach((id) => next.add(id));\n\n return next;\n });\n });\n\n this.destroyRef.onDestroy(() => this.closeFlyout());\n }\n\n // ===== COMPUTED =====\n readonly isCollapsed = computed(\n () => this.collapsed() ?? this.shell?.isCollapsed() ?? false,\n );\n\n readonly classes = computed(() =>\n [\n 'fk-sidebar-nav',\n this.isCollapsed() ? 'fk-sidebar-nav--collapsed' : '',\n this.className(),\n ]\n .filter(Boolean)\n .join(' '),\n );\n\n @HostBinding('class')\n get hostClass(): string {\n return this.classes();\n }\n\n // ===== ACTIVE / EXPANSION =====\n protected isParent(item: SidebarNavItem): boolean {\n return (item.children?.length ?? 0) > 0;\n }\n\n protected linkActive(link: SidebarNavLink): boolean {\n const routerLink = link.routerLink;\n\n if (!routerLink) {\n return false;\n }\n\n // Touch currentUrl so the check re-evaluates on every navigation (OnPush).\n this.currentUrl();\n\n // Resolve through the Router rather than string-joining: this handles array\n // commands, relative segments, leading slashes, and matrix/query params\n // correctly — a naive join silently mismatched for array routerLinks.\n const tree = this.router.createUrlTree(\n Array.isArray(routerLink) ? routerLink : [routerLink],\n { relativeTo: this.route },\n );\n\n return this.router.isActive(tree, {\n paths: link.exact ? 'exact' : 'subset',\n queryParams: 'ignored',\n fragment: 'ignored',\n matrixParams: 'ignored',\n });\n }\n\n /** True when the item itself, or any of its children, is the active route. */\n protected sectionActive(item: SidebarNavItem): boolean {\n if (this.linkActive(item)) {\n return true;\n }\n\n return (item.children ?? []).some((child) => this.linkActive(child));\n }\n\n /**\n * Whether a parent discloses its children inline (expanded rail only).\n * Disclosure is owned entirely by `openIds` — the active section is seeded\n * into it by the auto-open effect, so it starts open yet can still be\n * collapsed by clicking the parent (the effect only re-opens on navigation).\n */\n protected isOpen(item: SidebarNavItem): boolean {\n return this.openIds().has(item.id);\n }\n\n // ===== INTERACTIONS =====\n /** Parent row click: flyout in the rail, inline disclosure when expanded. */\n protected onParentClick(item: SidebarNavItem, rowEl: HTMLElement): void {\n if (this.isCollapsed()) {\n this.toggleFlyout(item, rowEl);\n\n return;\n }\n\n this.openIds.update((set) => {\n const next = new Set(set);\n\n if (next.has(item.id)) {\n next.delete(item.id);\n } else {\n next.add(item.id);\n }\n\n return next;\n });\n }\n\n /** Leaf / child / flyout link click — navigation is via routerLink; tidy up. */\n protected onLinkClick(): void {\n this.closeFlyout();\n this.shell?.dismissSidenav();\n }\n\n // ===== FLYOUT (collapsed parent) =====\n private toggleFlyout(item: SidebarNavItem, rowEl: HTMLElement): void {\n if (this.flyoutItem()?.id === item.id) {\n this.closeFlyout();\n\n return;\n }\n\n this.openFlyout(item, rowEl);\n }\n\n private openFlyout(item: SidebarNavItem, rowEl: HTMLElement): void {\n this.closeFlyout();\n\n const positionStrategy = this.overlay\n .position()\n .flexibleConnectedTo(rowEl)\n // Nudge the panel back into the viewport when a low trigger row would push\n // its (now height-capped) box off the bottom edge.\n .withPush(true)\n .withPositions([\n {\n originX: 'end',\n originY: 'top',\n overlayX: 'start',\n overlayY: 'top',\n offsetX: 8,\n },\n {\n originX: 'start',\n originY: 'top',\n overlayX: 'end',\n overlayY: 'top',\n offsetX: -8,\n },\n ]);\n\n const overlayRef = this.overlay.create({\n positionStrategy,\n scrollStrategy: this.overlay.scrollStrategies.reposition(),\n panelClass: 'fk-sidebar-nav__flyout',\n // Dispose on browser back/forward so the flyout can't linger over a new\n // page (matches fk-drawer). Programmatic navigation is covered by the\n // route-change effect in the constructor.\n disposeOnNavigation: true,\n });\n\n this.overlayRef = overlayRef;\n this.flyoutOrigin = rowEl;\n this.flyoutItem.set(item);\n overlayRef.attach(\n new TemplatePortal(this.flyoutTpl(), this.vcr, { $implicit: item }),\n );\n\n // After the panel renders: bring the active item into view (so a selection\n // deep in a long, scrolled list is visible on reopen, matching a native\n // select), and point the caret at the trigger's center now that CDK has\n // applied (and possibly pushed) the panel's final position.\n afterNextRender(\n () => {\n this.scrollActiveItemIntoView(overlayRef.overlayElement);\n this.positionFlyoutCaret(overlayRef.overlayElement);\n },\n { injector: this.injector },\n );\n\n // Scope the event subscriptions to this overlay's lifetime via a\n // Subscription torn down in closeFlyout() — not to the component lifetime,\n // and not relying on CDK completing the streams on dispose.\n const subscriptions = new Subscription();\n\n // Re-point the caret whenever CDK repositions the panel (push on open, or a\n // reposition while scrolling) so it keeps tracking the trigger's center.\n subscriptions.add(\n positionStrategy.positionChanges.subscribe(() =>\n this.positionFlyoutCaret(overlayRef.overlayElement),\n ),\n );\n\n subscriptions.add(\n overlayRef.outsidePointerEvents().subscribe((event) => {\n // Ignore clicks on the trigger row itself — the row's own click handler\n // toggles the flyout, so closing here would just let it reopen.\n const target = event.target as Node | null;\n\n if (target && this.flyoutOrigin?.contains(target)) {\n return;\n }\n\n this.closeFlyout();\n }),\n );\n\n subscriptions.add(\n overlayRef.keydownEvents().subscribe((event) => {\n if (event.key === 'Escape') {\n this.closeFlyout();\n }\n }),\n );\n\n this.flyoutSubs = subscriptions;\n }\n\n private closeFlyout(): void {\n this.flyoutSubs?.unsubscribe();\n this.flyoutSubs = null;\n this.overlayRef?.dispose();\n this.overlayRef = null;\n this.flyoutOrigin = null;\n this.flyoutItem.set(null);\n }\n\n /**\n * Center the active flyout item within its scroll viewport. No-op when there\n * is no active item (nothing selected) or the list isn't scrolled — the\n * `scrollTop` write clamps, so a short list simply stays at the top. Operates\n * only on the items container's own `scrollTop`, never `scrollIntoView`, so it\n * can't perturb the page or the overlay position.\n */\n private scrollActiveItemIntoView(overlayEl: HTMLElement): void {\n const container = overlayEl.querySelector<HTMLElement>(\n '.fk-sidebar-nav__flyout-items',\n );\n const active = container?.querySelector<HTMLElement>(\n '.fk-sidebar-nav__flyout-item--active',\n );\n\n if (!container || !active) {\n return;\n }\n\n const containerBox = container.getBoundingClientRect();\n const activeBox = active.getBoundingClientRect();\n const delta =\n activeBox.top -\n containerBox.top -\n (container.clientHeight - activeBox.height) / 2;\n\n container.scrollTop += delta;\n }\n\n /**\n * Point the flyout caret at the trigger row's vertical center. The caret is\n * absolutely positioned on the panel, so a fixed `top` drifts off the icon as\n * soon as `withPush` (or a flip) shifts the panel; deriving it from the live\n * trigger and panel boxes keeps it aligned. Clamped to the panel so it can't\n * ride off the rounded corners when the trigger sits beyond the panel's span.\n */\n private positionFlyoutCaret(overlayEl: HTMLElement): void {\n const origin = this.flyoutOrigin;\n const panel = overlayEl.querySelector<HTMLElement>(\n '.fk-sidebar-nav__flyout-panel',\n );\n\n if (!origin || !panel) {\n return;\n }\n\n const originBox = origin.getBoundingClientRect();\n const panelBox = panel.getBoundingClientRect();\n\n const caretSize = 11; // px — matches the ::before square\n const edge = 12; // keep the caret clear of the panel's rounded corners\n const center = originBox.top + originBox.height / 2 - panelBox.top;\n const top = Math.max(\n edge,\n Math.min(center - caretSize / 2, panelBox.height - edge - caretSize),\n );\n\n panel.style.setProperty('--fk-sidebar-nav-flyout-caret-top', `${top}px`);\n }\n}\n\n/** Strip query string and fragment so URL comparison matches route paths. */\nfunction stripUrl(url: string): string {\n return url.split('?')[0].split('#')[0];\n}\n\n","@for (group of model(); track $index) {\n <div class=\"fk-sidebar-nav__group\">\n @if (group.label) {\n <div class=\"fk-sidebar-nav__group-label\">{{ group.label }}</div>\n }\n <div class=\"fk-sidebar-nav__divider\" aria-hidden=\"true\"></div>\n\n <ul class=\"fk-sidebar-nav__list\">\n @for (item of group.items; track item.id) {\n <li class=\"fk-sidebar-nav__item\">\n @if (isParent(item)) {\n <!-- PARENT — disclosure row -->\n <button\n #row\n type=\"button\"\n class=\"fk-sidebar-nav__row fk-sidebar-nav__row--parent\"\n [class.fk-sidebar-nav__row--branch]=\"sectionActive(item)\"\n [attr.aria-expanded]=\"\n isCollapsed() ? flyoutItem()?.id === item.id : isOpen(item)\n \"\n [attr.aria-haspopup]=\"isCollapsed() ? 'true' : null\"\n [attr.aria-label]=\"isCollapsed() ? item.label : null\"\n [fkTooltip]=\"item.label\"\n [fkTooltipDisabled]=\"!isCollapsed()\"\n fkTooltipPosition=\"right\"\n (click)=\"onParentClick(item, row)\"\n >\n @if (leadingTemplate(item); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: item }\"\n />\n } @else if (item.icon) {\n <fk-icon\n class=\"fk-sidebar-nav__icon\"\n [name]=\"item.icon\"\n size=\"sm\"\n />\n }\n <span class=\"fk-sidebar-nav__label\">{{ item.label }}</span>\n <span\n class=\"fk-sidebar-nav__chevron\"\n [class.fk-sidebar-nav__chevron--open]=\"isOpen(item)\"\n aria-hidden=\"true\"\n >\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 18 18\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M6.75 4.5L11.25 9L6.75 13.5\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n fill=\"none\"\n />\n </svg>\n </span>\n </button>\n\n @if (!isCollapsed() && isOpen(item)) {\n <ul class=\"fk-sidebar-nav__children\">\n @for (child of item.children; track child.id) {\n @if (child.heading) {\n <li class=\"fk-sidebar-nav__subgroup\">\n <span class=\"fk-sidebar-nav__subgroup-title\">{{\n child.label\n }}</span>\n </li>\n } @else {\n <li>\n <a\n class=\"fk-sidebar-nav__child\"\n [class.fk-sidebar-nav__child--active]=\"linkActive(child)\"\n [attr.aria-current]=\"linkActive(child) ? 'page' : null\"\n [routerLink]=\"child.routerLink\"\n (click)=\"onLinkClick()\"\n >\n @if (leadingTemplate(child); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: child }\"\n />\n }\n <span class=\"fk-sidebar-nav__label\">{{\n child.label\n }}</span>\n </a>\n </li>\n }\n }\n </ul>\n }\n } @else {\n <!-- LEAF — direct link -->\n <a\n class=\"fk-sidebar-nav__row\"\n [class.fk-sidebar-nav__row--active]=\"linkActive(item)\"\n [attr.aria-current]=\"linkActive(item) ? 'page' : null\"\n [routerLink]=\"item.routerLink\"\n [attr.aria-label]=\"isCollapsed() ? item.label : null\"\n [fkTooltip]=\"item.label\"\n [fkTooltipDisabled]=\"!isCollapsed()\"\n fkTooltipPosition=\"right\"\n (click)=\"onLinkClick()\"\n >\n @if (leadingTemplate(item); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: item }\"\n />\n } @else if (item.icon) {\n <fk-icon\n class=\"fk-sidebar-nav__icon\"\n [name]=\"item.icon\"\n size=\"sm\"\n />\n }\n <span class=\"fk-sidebar-nav__label\">{{ item.label }}</span>\n </a>\n }\n </li>\n }\n </ul>\n </div>\n}\n\n<!-- Flyout panel for a collapsed parent (anchored beside the rail via CDK Overlay) -->\n<ng-template #flyoutTpl let-item>\n <!--\n A labelled group of navigation links — not an ARIA `menu`. Menu semantics\n promise roving arrow-key focus we don't implement (these are Tab-navigated\n links), so `role=\"group\"` + `aria-label` is the honest, valid structure.\n -->\n <div\n class=\"fk-sidebar-nav__flyout-panel\"\n role=\"group\"\n [attr.aria-label]=\"item.label\"\n >\n <!-- Decorative: the group is already named by aria-label, so the visual\n title/icon would only repeat it to assistive tech. -->\n <div class=\"fk-sidebar-nav__flyout-head\" aria-hidden=\"true\">\n @if (item.icon) {\n <span class=\"fk-sidebar-nav__flyout-icon\">\n <fk-icon [name]=\"item.icon\" size=\"sm\" />\n </span>\n }\n <span class=\"fk-sidebar-nav__flyout-title\">{{ item.label }}</span>\n </div>\n\n <!--\n The items scroll inside their own bounded container, not the panel: the\n panel hosts the caret (::before) which sits outside its left edge, so\n putting overflow on the panel itself would clip it.\n -->\n <div class=\"fk-sidebar-nav__flyout-items\">\n @for (child of item.children; track child.id) {\n @if (child.heading) {\n <span class=\"fk-sidebar-nav__flyout-subgroup\">{{ child.label }}</span>\n } @else {\n <a\n class=\"fk-sidebar-nav__flyout-item\"\n [class.fk-sidebar-nav__flyout-item--active]=\"linkActive(child)\"\n [attr.aria-current]=\"linkActive(child) ? 'page' : null\"\n [routerLink]=\"child.routerLink\"\n (click)=\"onLinkClick()\"\n >\n @if (leadingTemplate(child); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: child }\"\n />\n }\n <span class=\"fk-sidebar-nav__label\">{{ child.label }}</span>\n </a>\n }\n }\n </div>\n </div>\n</ng-template>\n","import {\n ChangeDetectionStrategy,\n Component,\n computed,\n HostBinding,\n input,\n} from '@angular/core';\n\nimport { IconComponent } from '@frame-kit/ui-ng/core/icon';\n\n/**\n * The fixed footer chrome for {@link DialogShellComponent} — an optional muted\n * note on the left, then the projected action buttons pushed to the right,\n * above a top divider. Paired with {@link DialogHeaderComponent} so every\n * dialog shares the same chrome.\n *\n * The note icon is optional and degrades gracefully — an empty `noteIcon`\n * simply renders no glyph.\n *\n * ```html\n * <fk-dialog-footer note=\"Takes effect immediately\" noteIcon=\"power\">\n * <fk-button variant=\"outline\" (click)=\"cancel()\">Cancel</fk-button>\n * <fk-button variant=\"primary\" type=\"submit\">Save</fk-button>\n * </fk-dialog-footer>\n * ```\n */\n@Component({\n selector: 'fk-dialog-footer',\n standalone: true,\n imports: [IconComponent],\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './dialog-footer.component.html',\n styleUrl: './dialog-footer.component.scss',\n})\nexport class DialogFooterComponent {\n // ===== INPUTS =====\n /** Optional muted note shown on the left (e.g. \"Takes effect immediately\"). */\n readonly note = input<string>('');\n /** Optional icon glyph rendered before the note. Empty renders no glyph. */\n readonly noteIcon = input<string>('');\n\n // ===== BASE PROPS =====\n readonly className = input<string>('');\n readonly id = input<string | null>(null);\n readonly ariaLabel = input<string | null>(null);\n\n // ===== COMPUTED =====\n readonly classes = computed(() =>\n ['fk-dialog-footer', this.className()].filter(Boolean).join(' '),\n );\n\n @HostBinding('class')\n get hostClass(): string {\n return this.classes();\n }\n\n @HostBinding('attr.id')\n get hostId(): string | null {\n return this.id();\n }\n\n @HostBinding('attr.aria-label')\n get hostAriaLabel(): string | null {\n return this.ariaLabel();\n }\n}\n","@if (note()) {\n <span class=\"fk-dialog-footer__note\">\n @if (noteIcon()) {\n <fk-icon\n class=\"fk-dialog-footer__note-icon\"\n [name]=\"noteIcon()\"\n size=\"sm\"\n />\n }\n {{ note() }}\n </span>\n}\n\n<span class=\"fk-dialog-footer__spacer\"></span>\n\n<ng-content />\n","import {\n ChangeDetectionStrategy,\n Component,\n computed,\n HostBinding,\n input,\n output,\n} from '@angular/core';\n\nimport { HeadlineComponent } from '@frame-kit/ui-ng/core/headline';\nimport { IconComponent } from '@frame-kit/ui-ng/core/icon';\nimport { TextComponent } from '@frame-kit/ui-ng/core/text';\nimport { IconBadgeComponent } from '@frame-kit/ui-ng/ui/icon-badge';\n\nimport type { DialogHeaderTint } from './dialog-header.types';\n\n/** The tint tone → the CSS-variable pair driving the icon tile + title accent.\n * Each reference is two-tier (component token → semantic token) so the header\n * renders correctly with no theme loaded and can be retinted per theme. */\nconst TINTS: Record<DialogHeaderTint, { color: string; background: string }> = {\n brand: {\n color:\n 'var(--fk-dialog-header-tint-brand-color, var(--fk-color-primary, #2563eb))',\n background:\n 'var(--fk-dialog-header-tint-brand-bg, var(--fk-color-primary-light, #eff6ff))',\n },\n warning: {\n color:\n 'var(--fk-dialog-header-tint-warning-color, var(--fk-color-warning, #d97706))',\n background:\n 'var(--fk-dialog-header-tint-warning-bg, var(--fk-color-warning-subtle, #fffbeb))',\n },\n success: {\n color:\n 'var(--fk-dialog-header-tint-success-color, var(--fk-color-success, #16a34a))',\n background:\n 'var(--fk-dialog-header-tint-success-bg, var(--fk-color-success-subtle, #f0fdf4))',\n },\n danger: {\n color:\n 'var(--fk-dialog-header-tint-danger-color, var(--fk-color-danger, #dc2626))',\n background:\n 'var(--fk-dialog-header-tint-danger-bg, var(--fk-color-danger-light, #fee2e2))',\n },\n accent: {\n color: 'var(--fk-dialog-header-tint-accent-color, #7c3aed)',\n background: 'var(--fk-dialog-header-tint-accent-bg, #f5f3ff)',\n },\n};\n\n/**\n * The fixed header chrome for {@link DialogShellComponent} — a tinted icon\n * tile, a title with an optional trailing accent, an optional mono subtitle,\n * and a close button. Every dialog wears the same chrome; only the icon, tint,\n * and text differ, so this centralises it instead of each dialog hand-rolling\n * the markup.\n *\n * Text is passed in as plain inputs (no i18n dependency), and the icon is\n * optional — an empty `icon` simply renders no tile, so the header degrades\n * gracefully rather than showing a broken glyph.\n *\n * ```html\n * <fk-dialog-header\n * icon=\"user-ban\"\n * tint=\"warning\"\n * title=\"Deactivate identity\"\n * subtitle=\"Acme Inc. · Members\"\n * (dismiss)=\"close()\"\n * />\n * ```\n */\n@Component({\n selector: 'fk-dialog-header',\n standalone: true,\n imports: [\n HeadlineComponent,\n IconBadgeComponent,\n IconComponent,\n TextComponent,\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './dialog-header.component.html',\n styleUrl: './dialog-header.component.scss',\n})\nexport class DialogHeaderComponent {\n // ===== INPUTS =====\n /** Icon glyph name for the tile. Empty renders no tile. */\n readonly icon = input<string>('');\n /** Colour accent for the icon tile + title accent. */\n readonly tint = input<DialogHeaderTint>('brand');\n /** Dialog title. */\n readonly title = input.required<string>();\n /** Optional trailing accent appended to the title, rendered in the tint colour. */\n readonly titleAccent = input<string>('');\n /** Optional mono subtitle under the title. */\n readonly subtitle = input<string>('');\n /** Accessible label for the close button. */\n readonly closeLabel = input<string>('Close');\n\n // ===== OUTPUTS =====\n /** Fires when the close button is clicked. */\n readonly dismiss = output<void>();\n\n // ===== BASE PROPS =====\n readonly className = input<string>('');\n readonly id = input<string | null>(null);\n readonly ariaLabel = input<string | null>(null);\n\n // ===== COMPUTED =====\n /** The tint's `{ color, background }` CSS-variable pair. */\n protected readonly tintVars = computed(() => TINTS[this.tint()]);\n\n readonly classes = computed(() =>\n ['fk-dialog-header', `fk-dialog-header--${this.tint()}`, this.className()]\n .filter(Boolean)\n .join(' '),\n );\n\n @HostBinding('class')\n get hostClass(): string {\n return this.classes();\n }\n\n @HostBinding('attr.id')\n get hostId(): string | null {\n return this.id();\n }\n\n @HostBinding('attr.aria-label')\n get hostAriaLabel(): string | null {\n return this.ariaLabel();\n }\n}\n","@if (icon()) {\n <fk-icon-badge\n class=\"fk-dialog-header__icon\"\n [name]=\"icon()\"\n [color]=\"tintVars().color\"\n [backgroundColor]=\"tintVars().background\"\n shape=\"rounded\"\n size=\"md\"\n />\n}\n\n<div class=\"fk-dialog-header__titles\">\n <fk-headline\n class=\"fk-dialog-header__title\"\n [level]=\"2\"\n fontSize=\"var(--fk-dialog-header-title-font-size, 1.25rem)\"\n >\n {{ title() }}\n @if (titleAccent()) {\n <span class=\"fk-dialog-header__accent\" [style.color]=\"tintVars().color\">\n {{ titleAccent() }}</span\n >\n }\n </fk-headline>\n @if (subtitle()) {\n <fk-text class=\"fk-dialog-header__subtitle\" variant=\"small\">\n {{ subtitle() }}\n </fk-text>\n }\n</div>\n\n<button\n type=\"button\"\n class=\"fk-dialog-header__close\"\n [attr.aria-label]=\"closeLabel()\"\n (click)=\"dismiss.emit()\"\n>\n <fk-icon name=\"close\" size=\"sm\" />\n</button>\n","import {\n ChangeDetectionStrategy,\n Component,\n computed,\n HostBinding,\n input,\n output,\n} from '@angular/core';\n\nimport { IconComponent } from '@frame-kit/ui-ng/core/icon';\nimport { ButtonComponent } from '@frame-kit/ui-ng/ui/button';\n\nimport { DialogFooterComponent } from '../dialog-footer/dialog-footer.component';\nimport type { DialogHeaderTint } from '../dialog-header/dialog-header.types';\nimport { DialogHeaderComponent } from '../dialog-header/dialog-header.component';\nimport type { DialogConfirmVariant } from './dialog-shell.types';\n\n/**\n * The one dialog shell every dashboard dialog is built from. It owns the fixed\n * chrome — the tinted icon-tile header (title / accent / subtitle + close) and\n * the footer (muted note + the standard Cancel/confirm buttons) — so individual\n * dialogs stop re-declaring any of it. Everything unique to a dialog lives in\n * the projected **content region**.\n *\n * The shell carries no i18n dependency and no domain data: every label is a\n * plain input (with English defaults for the built-in Cancel button), and the\n * icons are inputs that degrade gracefully when empty. Render it inside the\n * consuming app's own `fk-dialog` (opened bare — `header: null, closable:\n * false` — with an `ariaLabel` for an accessible name).\n *\n * The common case needs zero footer markup — set the confirm label/variant and\n * handle the outputs:\n *\n * ```html\n * <fk-dialog-shell\n * icon=\"user-ban\"\n * tint=\"warning\"\n * title=\"Deactivate identity\"\n * [subtitle]=\"subtitle\"\n * footerNote=\"Sign-in blocked\"\n * footerNoteIcon=\"power\"\n * confirmLabel=\"Deactivate\"\n * confirmIcon=\"user-ban\"\n * confirmVariant=\"warning\"\n * [confirmDisabled]=\"!ready()\"\n * (confirm)=\"onConfirm()\"\n * (dismiss)=\"onCancel()\"\n * >\n * <!-- content region: lead, description, cards, callouts … -->\n * </fk-dialog-shell>\n * ```\n *\n * Escape hatches for the exceptions:\n * - leave `confirmLabel` empty and project buttons into the `dialogFooter` slot\n * to keep the footer chrome but use custom buttons (e.g. a form submit);\n * - set `[customFooter]=\"true\"` and project into the `footer` slot to replace\n * the whole footer.\n */\n@Component({\n selector: 'fk-dialog-shell',\n standalone: true,\n imports: [\n ButtonComponent,\n IconComponent,\n DialogFooterComponent,\n DialogHeaderComponent,\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './dialog-shell.component.html',\n styleUrl: './dialog-shell.component.scss',\n})\nexport class DialogShellComponent {\n // ===== INPUTS =====\n /** Icon glyph for the header tile. Empty renders no tile. */\n readonly icon = input<string>('');\n /** Colour accent for the header tile. */\n readonly tint = input<DialogHeaderTint>('brand');\n /** Header title. */\n readonly title = input.required<string>();\n /** Optional trailing accent appended to the title in the tint colour. */\n readonly titleAccent = input<string>('');\n /** Optional mono subtitle under the title. */\n readonly subtitle = input<string>('');\n /** Optional muted footer note on the left (e.g. \"Permanent\"). */\n readonly footerNote = input<string>('');\n /** Optional icon rendered before the footer note. */\n readonly footerNoteIcon = input<string>('');\n /**\n * Confirm-button label. When set, the shell renders the standard\n * Cancel + confirm pair; leave empty to project custom buttons into the\n * `dialogFooter` slot instead.\n */\n readonly confirmLabel = input<string>('');\n /** Optional leading icon on the confirm button. */\n readonly confirmIcon = input<string>('');\n /** Confirm-button colour — `primary` (default), `danger`, or `warning`. */\n readonly confirmVariant = input<DialogConfirmVariant>('primary');\n /** Disables the confirm button (e.g. while a type-to-confirm is unmet). */\n readonly confirmDisabled = input<boolean>(false);\n /** Cancel-button label. Defaults to `Cancel`. */\n readonly cancelLabel = input<string>('Cancel');\n /** Accessible label for the header's close button. */\n readonly closeLabel = input<string>('Close');\n /**\n * Escape hatch for the rare dialog that needs a bespoke footer. When true,\n * the default `fk-dialog-footer` (note + buttons) is suppressed and whatever\n * is projected into the `footer` slot is rendered raw instead.\n */\n readonly customFooter = input<boolean>(false);\n\n // ===== OUTPUTS =====\n /** Fires when the header close button OR the Cancel button is clicked. */\n readonly dismiss = output<void>();\n /** Fires when the confirm button is clicked. */\n readonly confirm = output<void>();\n\n // ===== BASE PROPS =====\n readonly className = input<string>('');\n readonly id = input<string | null>(null);\n\n // ===== COMPUTED =====\n /** `warning` renders as a retinted `danger` fk-button; others map directly. */\n protected readonly confirmButtonVariant = computed<'primary' | 'danger'>(\n () => {\n const variant = this.confirmVariant();\n\n return variant === 'warning' ? 'danger' : variant;\n },\n );\n\n readonly classes = computed(() =>\n ['fk-dialog-shell', this.className()].filter(Boolean).join(' '),\n );\n\n @HostBinding('class')\n get hostClass(): string {\n return this.classes();\n }\n\n @HostBinding('attr.id')\n get hostId(): string | null {\n return this.id();\n }\n}\n","<fk-dialog-header\n class=\"fk-dialog-shell__header\"\n [icon]=\"icon()\"\n [tint]=\"tint()\"\n [title]=\"title()\"\n [titleAccent]=\"titleAccent()\"\n [subtitle]=\"subtitle()\"\n [closeLabel]=\"closeLabel()\"\n (dismiss)=\"dismiss.emit()\"\n/>\n\n<div class=\"fk-dialog-shell__body\">\n <ng-content />\n</div>\n\n@if (customFooter()) {\n <ng-content select=\"[footer]\" />\n} @else {\n <fk-dialog-footer [note]=\"footerNote()\" [noteIcon]=\"footerNoteIcon()\">\n @if (confirmLabel()) {\n <fk-button variant=\"outline\" type=\"button\" (click)=\"dismiss.emit()\">\n {{ cancelLabel() }}\n </fk-button>\n <fk-button\n class=\"fk-dialog-shell__confirm\"\n [class.fk-dialog-shell__confirm--danger]=\"confirmVariant() === 'danger'\"\n [class.fk-dialog-shell__confirm--warning]=\"\n confirmVariant() === 'warning'\n \"\n [variant]=\"confirmButtonVariant()\"\n type=\"button\"\n [disabled]=\"confirmDisabled()\"\n (click)=\"confirm.emit()\"\n >\n @if (confirmIcon()) {\n <fk-icon fkButtonIconStart [name]=\"confirmIcon()\" size=\"sm\" />\n }\n {{ confirmLabel() }}\n </fk-button>\n } @else {\n <ng-content select=\"[dialogFooter]\" />\n }\n </fk-dialog-footer>\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"frame-kit-ui-ng-patterns-dashboard.mjs","sources":["../../../../packages/ui-ng-patterns/dashboard/page-header/page-header.component.ts","../../../../packages/ui-ng-patterns/dashboard/page-header/page-header.component.html","../../../../packages/ui-ng-patterns/dashboard/table-empty-state/table-empty-state.component.ts","../../../../packages/ui-ng-patterns/dashboard/table-empty-state/table-empty-state.component.html","../../../../packages/ui-ng-patterns/dashboard/content-split-layout/content-split-layout.component.ts","../../../../packages/ui-ng-patterns/dashboard/content-split-layout/content-split-layout.component.html","../../../../packages/ui-ng-patterns/dashboard/columns/columns.component.ts","../../../../packages/ui-ng-patterns/dashboard/columns/columns.component.html","../../../../packages/ui-ng-patterns/dashboard/detail-panel/detail-panel.component.ts","../../../../packages/ui-ng-patterns/dashboard/detail-panel/detail-panel.component.html","../../../../packages/ui-ng-patterns/dashboard/sidebar-nav/sidebar-nav-item.directive.ts","../../../../packages/ui-ng-patterns/dashboard/sidebar-nav/sidebar-nav.component.ts","../../../../packages/ui-ng-patterns/dashboard/sidebar-nav/sidebar-nav.component.html","../../../../packages/ui-ng-patterns/dashboard/dialog-footer/dialog-footer.component.ts","../../../../packages/ui-ng-patterns/dashboard/dialog-footer/dialog-footer.component.html","../../../../packages/ui-ng-patterns/dashboard/dialog-header/dialog-header.component.ts","../../../../packages/ui-ng-patterns/dashboard/dialog-header/dialog-header.component.html","../../../../packages/ui-ng-patterns/dashboard/dialog-shell/dialog-shell.component.ts","../../../../packages/ui-ng-patterns/dashboard/dialog-shell/dialog-shell.component.html","../../../../packages/ui-ng-patterns/dashboard/onboarding-guide/onboarding-guide.component.ts","../../../../packages/ui-ng-patterns/dashboard/onboarding-guide/onboarding-guide.component.html","../../../../packages/ui-ng-patterns/dashboard/frame-kit-ui-ng-patterns-dashboard.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n input,\n ViewEncapsulation,\n} from '@angular/core';\n\nimport type { HeadlineLevel } from '@frame-kit/ui-ng/core/headline';\nimport { HeadlineComponent } from '@frame-kit/ui-ng/core/headline';\nimport { TextComponent } from '@frame-kit/ui-ng/core/text';\n\n/**\n * Page-level dashboard header: title + optional description on the left, up to\n * ~3 actions on the right.\n *\n * When the header's own width gets tight, the actions drop below the text and\n * go full-width (mobile-style). The break is driven by a CSS container query on\n * the host, so it responds to the content region's width — not the viewport,\n * which means it behaves correctly inside a narrow panel.\n *\n * Project actions by tagging each button with `pageHeaderActions`:\n *\n * <fk-page-header title=\"Users\" description=\"...\">\n * <fk-button pageHeaderActions variant=\"outline\" size=\"sm\">Import</fk-button>\n * <fk-button pageHeaderActions variant=\"primary\" size=\"sm\">Create user</fk-button>\n * </fk-page-header>\n *\n * Tagging each button (rather than wrapping them in a div) makes every button a\n * direct flex child, so full-width stacking falls out of `align-items: stretch`\n * with no `::ng-deep` reach-in.\n *\n * The title row has two projected slots — `[pageHeaderLeading]` before the\n * title and `[pageHeaderTrailing]` after it. Project a plain `fk-icon` for a\n * decorative mark, or a `button` for a clickable one (the consumer owns the\n * interaction, focus ring, and aria-label):\n *\n * <fk-page-header title=\"Permissions\">\n * <fk-icon pageHeaderLeading name=\"key-outline\" />\n * <button pageHeaderTrailing type=\"button\" aria-label=\"Docs\" (click)=\"openDocs()\">\n * <fk-icon name=\"view-api\" />\n * </button>\n * </fk-page-header>\n */\n@Component({\n selector: 'fk-page-header',\n standalone: true,\n imports: [HeadlineComponent, TextComponent],\n // Emulated (not None) so `:host` works — `:host { display: block }` is what\n // keeps the custom element from defaulting to `display: inline` and\n // collapsing to min-content under the container query below.\n encapsulation: ViewEncapsulation.Emulated,\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './page-header.component.html',\n styleUrl: './page-header.component.scss',\n})\nexport class PageHeaderComponent {\n readonly title = input.required<string>();\n readonly description = input<string | null>(null);\n readonly headingLevel = input<HeadlineLevel>(1);\n}\n","<header class=\"fk-page-header\">\n <div class=\"fk-page-header__text\">\n <div class=\"fk-page-header__title-row\">\n <ng-content select=\"[pageHeaderLeading]\" />\n\n <fk-headline [level]=\"headingLevel()\">{{ title() }}</fk-headline>\n\n <ng-content select=\"[pageHeaderTrailing]\" />\n </div>\n\n @if (description()) {\n <fk-text class=\"fk-page-header__description\" tone=\"muted\">{{\n description()\n }}</fk-text>\n }\n </div>\n\n <div class=\"fk-page-header__actions\">\n <ng-content select=\"[pageHeaderActions]\" />\n </div>\n</header>\n","import {\n ChangeDetectionStrategy,\n Component,\n computed,\n HostBinding,\n input,\n ViewEncapsulation,\n} from '@angular/core';\n\nimport { IconComponent } from '@frame-kit/ui-ng/core/icon';\n\n/**\n * Empty-state panel for dashboard tables and lists: a centered icon, a title,\n * an optional description, and a projected actions slot (typically one primary\n * fk-button). Bordered-card styling, meant to stand in for a table body when\n * there are no rows.\n *\n * The action row flips from a horizontal row to a centered vertical stack on\n * narrow widths, driven by a container query on the host — so it reacts to the\n * empty-state's own width (e.g. inside a split column) rather than the viewport.\n *\n * <fk-table-empty-state\n * icon=\"globe\"\n * title=\"No webhooks configured\"\n * description=\"Add a webhook to receive events.\"\n * >\n * <fk-button variant=\"primary\" size=\"sm\">Add webhook</fk-button>\n * </fk-table-empty-state>\n *\n * The actions slot is an open `ng-content`, so project as many actions as the\n * design needs (one primary is the norm; two reads cleanly).\n */\n@Component({\n selector: 'fk-table-empty-state',\n standalone: true,\n imports: [IconComponent],\n // Emulated (default) so `:host` works — the host is the bordered flex card\n // and establishes the container-query context the actions break against.\n encapsulation: ViewEncapsulation.Emulated,\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './table-empty-state.component.html',\n styleUrl: './table-empty-state.component.scss',\n})\nexport class TableEmptyStateComponent {\n // ===== INPUTS =====\n readonly icon = input<string | null>(null);\n readonly title = input.required<string>();\n readonly description = input<string | null>(null);\n\n // ===== BASE PROPS =====\n readonly className = input<string>('');\n readonly id = input<string | null>(null);\n readonly ariaLabel = input<string | null>(null);\n\n // ===== COMPUTED =====\n readonly classes = computed(() =>\n ['fk-table-empty-state', this.className()].filter(Boolean).join(' '),\n );\n\n @HostBinding('class')\n get hostClass(): string {\n return this.classes();\n }\n\n @HostBinding('attr.id')\n get hostId(): string | null {\n return this.id();\n }\n\n @HostBinding('attr.aria-label')\n get hostAriaLabel(): string | null {\n return this.ariaLabel();\n }\n}\n","@if (icon()) {\n <div class=\"fk-table-empty-state__icon\">\n <fk-icon [name]=\"icon()!\" size=\"lg\" />\n </div>\n}\n\n<h3 class=\"fk-table-empty-state__title\">{{ title() }}</h3>\n\n@if (description()) {\n <p class=\"fk-table-empty-state__description\">{{ description() }}</p>\n}\n\n<div class=\"fk-table-empty-state__actions\">\n <ng-content />\n</div>\n","import {\n ChangeDetectionStrategy,\n Component,\n HostBinding,\n input,\n} from '@angular/core';\n\n/**\n * Two-column split layout with container-query responsive stacking.\n *\n * Projects content into `[start]` (grows to fill) and `[end]` (content-sized or\n * fixed width). Below 700px container width, columns stack vertically.\n *\n * A standalone layout primitive for custom dashboard rows.\n */\n@Component({\n selector: 'fk-content-split-layout',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './content-split-layout.component.html',\n styleUrl: './content-split-layout.component.scss',\n})\nexport class ContentSplitLayoutComponent {\n readonly endWidth = input<string | null>(null);\n readonly gap = input<string>('var(--fk-rhythm-4, 1rem)');\n\n @HostBinding('class')\n readonly hostClass = 'fk-content-split-layout';\n}\n","<div\n class=\"fk-content-split-layout__row\"\n [style.--fk-content-split-gap]=\"gap()\"\n>\n <div class=\"fk-content-split-layout__start\">\n <ng-content select=\"[start]\" />\n </div>\n\n <div\n class=\"fk-content-split-layout__end\"\n [class.fk-content-split-layout__end--fixed]=\"endWidth()\"\n [style.--fk-content-split-end-width]=\"endWidth()\"\n >\n <ng-content select=\"[end]\" />\n </div>\n</div>\n","import {\n ChangeDetectionStrategy,\n Component,\n computed,\n HostBinding,\n input,\n} from '@angular/core';\n\n/**\n * Responsive column layout for dashboard content. Lays projected children out\n * in equal-width columns that wrap — and ultimately collapse to a single\n * stacked column — based on the layout's *own* available width, never the\n * viewport. So it reacts correctly when the dashboard content region is\n * squeezed (sidenav open, a drawer pushed in, a split pane) while the viewport\n * still reports \"desktop\".\n *\n * Implemented with an intrinsic CSS grid — `repeat(auto-fit, minmax(min, 1fr))`\n * — so there is no container query, no JS, and no viewport breakpoint to keep\n * in sync. `minColumnWidth` is the smallest a column may shrink to before the\n * grid drops a column; empty tracks collapse, so N children never produce more\n * than N columns. Spacing on both axes is a single `gutter` gap, so wrapped\n * rows and side-by-side columns separate consistently with no edge artifacts.\n *\n * <fk-columns minColumnWidth=\"18rem\">\n * <fk-field-group>…</fk-field-group>\n * <fk-field-group>…</fk-field-group>\n * </fk-columns>\n *\n * By default columns grow to fill the row (`1fr`). Set `maxColumnWidth` to cap\n * how wide a column may get — past that, columns stay that width and the extra\n * space is left empty (columns aligned to the start) rather than stretching.\n */\n@Component({\n selector: 'fk-columns',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './columns.component.html',\n styleUrl: './columns.component.scss',\n})\nexport class ColumnsComponent {\n // ===== INPUTS =====\n /**\n * The smallest width a column may shrink to before the grid drops to fewer\n * columns. This is the single knob that controls when columns wrap/stack.\n */\n readonly minColumnWidth = input<string>('16rem');\n /**\n * Optional cap on how wide a column may grow. Unset (default), columns fill\n * the row (`1fr`); when set (e.g. `'22rem'`), columns size between\n * `minColumnWidth` and this value and don't stretch past it — leftover space\n * stays empty, columns aligned to the start.\n */\n readonly maxColumnWidth = input<string | null>(null);\n /** Gap between side-by-side columns and between wrapped rows. */\n readonly gutter = input<string>('var(--fk-rhythm-4, 1rem)');\n\n // ===== BASE PROPS =====\n readonly className = input<string>('');\n readonly id = input<string | null>(null);\n readonly ariaLabel = input<string | null>(null);\n\n // ===== COMPUTED =====\n readonly classes = computed(() =>\n ['fk-columns', this.className()].filter(Boolean).join(' '),\n );\n\n @HostBinding('class')\n get hostClass(): string {\n return this.classes();\n }\n\n @HostBinding('attr.id')\n get hostId(): string | null {\n return this.id();\n }\n\n @HostBinding('attr.aria-label')\n get hostAriaLabel(): string | null {\n return this.ariaLabel();\n }\n\n @HostBinding('style.--fk-columns-min')\n get hostMin(): string {\n return this.minColumnWidth();\n }\n\n // Null leaves the property unset, so the SCSS falls back to `1fr` (fill).\n @HostBinding('style.--fk-columns-max')\n get hostMax(): string | null {\n return this.maxColumnWidth();\n }\n\n @HostBinding('style.--fk-columns-gutter')\n get hostGutter(): string {\n return this.gutter();\n }\n}\n","<ng-content />\n","import {\n ChangeDetectionStrategy,\n Component,\n computed,\n HostBinding,\n input,\n} from '@angular/core';\n\n/**\n * Padded container for an expanded dashboard detail region — typically the body\n * of a data-table row expansion, holding an `fk-columns` of form controls.\n *\n * The `disabled` input greys the panel and makes its entire subtree `inert`\n * (non-interactive, unfocusable, hidden from assistive technology) — for\n * controls gated behind a feature toggle that must not be editable until the\n * feature is enabled.\n *\n * <fk-detail-panel [disabled]=\"!feature.enabled\">\n * <fk-columns>…</fk-columns>\n * </fk-detail-panel>\n */\n@Component({\n selector: 'fk-detail-panel',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './detail-panel.component.html',\n styleUrl: './detail-panel.component.scss',\n})\nexport class DetailPanelComponent {\n // ===== INPUTS =====\n /**\n * Greys the panel and makes its content inert (locked) — for feature-gated\n * controls that should not be editable until the feature is enabled.\n */\n readonly disabled = input<boolean>(false);\n\n // ===== BASE PROPS =====\n readonly className = input<string>('');\n readonly id = input<string | null>(null);\n readonly ariaLabel = input<string | null>(null);\n\n // ===== COMPUTED =====\n readonly classes = computed(() =>\n [\n 'fk-detail-panel',\n this.disabled() ? 'fk-detail-panel--disabled' : '',\n this.className(),\n ]\n .filter(Boolean)\n .join(' '),\n );\n\n @HostBinding('class')\n get hostClass(): string {\n return this.classes();\n }\n\n @HostBinding('attr.id')\n get hostId(): string | null {\n return this.id();\n }\n\n @HostBinding('attr.aria-label')\n get hostAriaLabel(): string | null {\n return this.ariaLabel();\n }\n\n /**\n * Lock the whole subtree when disabled. `inert` blocks pointer interaction,\n * focus, and assistive-tech access in one attribute — stronger and more\n * correct than `pointer-events: none`, which only blocks the mouse.\n */\n @HostBinding('attr.inert')\n get hostInert(): '' | null {\n return this.disabled() ? '' : null;\n }\n}\n","<ng-content />\n","import { Directive, inject, TemplateRef } from '@angular/core';\n\nimport type { SidebarNavLink } from './sidebar-nav.types';\n\n/**\n * Marks an `<ng-template>` whose content `fk-sidebar-nav` renders as an item's\n * leading content — e.g. a method badge or any custom adornment — receiving the\n * item as `$implicit`. The component still owns the row, label, disclosure,\n * active/branch state, collapse, and flyout; this only customizes what sits\n * before the label.\n *\n * The template is applied to any item whose `data` is set; items without `data`\n * fall back to their `icon`.\n *\n * <fk-sidebar-nav [model]=\"nav\">\n * <ng-template fkSidebarNavItem let-item>\n * <fk-method-badge [method]=\"item.data\" />\n * </ng-template>\n * </fk-sidebar-nav>\n */\n@Directive({\n selector: 'ng-template[fkSidebarNavItem]',\n standalone: true,\n})\nexport class SidebarNavItemDirective {\n readonly template =\n inject<TemplateRef<{ $implicit: SidebarNavLink }>>(TemplateRef);\n\n /** Types `let-item` as a `SidebarNavLink` in the consumer's template. */\n static ngTemplateContextGuard(\n _directive: SidebarNavItemDirective,\n _context: unknown,\n ): _context is { $implicit: SidebarNavLink } {\n return true;\n }\n}\n","import { Overlay, OverlayRef } from '@angular/cdk/overlay';\nimport { TemplatePortal } from '@angular/cdk/portal';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n afterNextRender,\n ChangeDetectionStrategy,\n Component,\n computed,\n contentChild,\n DestroyRef,\n effect,\n HostBinding,\n inject,\n Injector,\n input,\n signal,\n TemplateRef,\n viewChild,\n ViewContainerRef,\n} from '@angular/core';\nimport { toSignal } from '@angular/core/rxjs-interop';\nimport {\n ActivatedRoute,\n NavigationEnd,\n Router,\n RouterLink,\n} from '@angular/router';\nimport { filter, map, Subscription } from 'rxjs';\n\nimport { IconComponent } from '@frame-kit/ui-ng/core/icon';\nimport { TooltipDirective } from '@frame-kit/ui-ng/directives/tooltip';\nimport { AppShellComponent } from '@frame-kit/ui-ng/layouts/app-shell';\n\nimport { SidebarNavItemDirective } from './sidebar-nav-item.directive';\nimport type {\n SidebarNavItem,\n SidebarNavLink,\n SidebarNavModel,\n} from './sidebar-nav.types';\n\n/**\n * Model-driven dashboard sidebar navigation.\n *\n * Renders a sidebar from a {@link SidebarNavModel}: labelled groups of items,\n * where each item is either a leaf link or a parent with children. The pattern\n * owns the two-state behavior that makes a dashboard rail usable:\n *\n * - **Expanded** — parents disclose their children inline; the section\n * containing the active route stays open and reads as active (tinted).\n * - **Collapsed (icon rail)** — labels collapse to icons with hover tooltips;\n * a parent click opens a **flyout** beside the rail (anchored via CDK\n * Overlay) listing its children, so nested pages stay reachable without\n * expanding the whole sidebar.\n *\n * Drop it into an `fk-app-shell` sidenav slot — it reads the shell's collapse\n * state automatically. Pass `[collapsed]` explicitly to drive the rail without\n * a shell.\n */\n@Component({\n selector: 'fk-sidebar-nav',\n standalone: true,\n imports: [RouterLink, IconComponent, TooltipDirective, NgTemplateOutlet],\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './sidebar-nav.component.html',\n styleUrl: './sidebar-nav.component.scss',\n})\nexport class SidebarNavComponent {\n // ===== INPUTS =====\n /** The navigation model — ordered groups of items. */\n readonly model = input<SidebarNavModel>([]);\n /**\n * Collapsed (icon-rail) state. Left `null`, the component reads the collapse\n * state of an ancestor `fk-app-shell`. Set explicitly to drive the rail\n * without a shell present.\n */\n readonly collapsed = input<boolean | null>(null);\n\n // ===== BASE PROPS =====\n readonly className = input<string>('');\n\n // ===== DEPENDENCIES =====\n private readonly shell = inject(AppShellComponent, { optional: true });\n private readonly router = inject(Router);\n private readonly route = inject(ActivatedRoute);\n private readonly overlay = inject(Overlay);\n private readonly vcr = inject(ViewContainerRef);\n private readonly destroyRef = inject(DestroyRef);\n private readonly injector = inject(Injector);\n\n // ===== REFS =====\n private readonly flyoutTpl =\n viewChild.required<TemplateRef<unknown>>('flyoutTpl');\n /** Optional consumer template for an item's leading content (e.g. a badge). */\n private readonly itemTpl = contentChild(SidebarNavItemDirective);\n private readonly itemTemplate = computed(\n () => this.itemTpl()?.template ?? null,\n );\n\n /**\n * The leading-content template for an item, or null. Only items carrying\n * `data` use it; others fall back to their `icon`.\n */\n protected leadingTemplate(\n item: SidebarNavLink,\n ): TemplateRef<{ $implicit: SidebarNavLink }> | null {\n return item.data !== undefined && item.data !== null\n ? this.itemTemplate()\n : null;\n }\n\n // ===== STATE =====\n /** Active URL, recomputed on every navigation — drives section-active styling. */\n private readonly currentUrl = toSignal(\n this.router.events.pipe(\n filter((e): e is NavigationEnd => e instanceof NavigationEnd),\n map(() => stripUrl(this.router.url)),\n ),\n { initialValue: stripUrl(this.router.url) },\n );\n /** Parent ids the user has explicitly opened (the active section is always open). */\n private readonly openIds = signal<ReadonlySet<string>>(new Set());\n\n private overlayRef: OverlayRef | null = null;\n /** Overlay-scoped event subscriptions — torn down with the overlay in closeFlyout(). */\n private flyoutSubs: Subscription | null = null;\n /** The trigger row the open flyout is anchored to — used to ignore its own re-click. */\n private flyoutOrigin: HTMLElement | null = null;\n /** The parent whose flyout is currently open (collapsed rail), or null. */\n protected readonly flyoutItem = signal<SidebarNavItem | null>(null);\n\n constructor() {\n // Tear down an open flyout the moment the rail expands. Clicking the shell\n // toggle would close it via the outside-pointer handler, but a programmatic\n // `[collapsed]` change, a responsive breakpoint flip, or a keyboard toggle\n // produces no pointer event — so the overlay would otherwise linger beside\n // the now-expanded sidebar.\n effect(() => {\n if (!this.isCollapsed()) {\n this.closeFlyout();\n }\n });\n\n // Close on any navigation (covers programmatic router.navigate, which\n // disposeOnNavigation does not catch, and keeps internal state in sync).\n effect(() => {\n this.currentUrl();\n this.closeFlyout();\n });\n\n // Auto-open the section that holds the active route — on first load and\n // whenever navigation lands inside a (possibly different, or previously\n // collapsed) section. This only ever *adds* to openIds, so a section the\n // user collapses by hand stays closed until they navigate back into it.\n effect(() => {\n this.currentUrl();\n\n const activeIds = this.model()\n .flatMap((group) => group.items)\n .filter((item) => this.isParent(item) && this.sectionActive(item))\n .map((item) => item.id);\n\n if (activeIds.length === 0) {\n return;\n }\n\n this.openIds.update((set) => {\n const next = new Set(set);\n activeIds.forEach((id) => next.add(id));\n\n return next;\n });\n });\n\n this.destroyRef.onDestroy(() => this.closeFlyout());\n }\n\n // ===== COMPUTED =====\n readonly isCollapsed = computed(\n () => this.collapsed() ?? this.shell?.isCollapsed() ?? false,\n );\n\n readonly classes = computed(() =>\n [\n 'fk-sidebar-nav',\n this.isCollapsed() ? 'fk-sidebar-nav--collapsed' : '',\n this.className(),\n ]\n .filter(Boolean)\n .join(' '),\n );\n\n @HostBinding('class')\n get hostClass(): string {\n return this.classes();\n }\n\n // ===== ACTIVE / EXPANSION =====\n protected isParent(item: SidebarNavItem): boolean {\n return (item.children?.length ?? 0) > 0;\n }\n\n protected linkActive(link: SidebarNavLink): boolean {\n const routerLink = link.routerLink;\n\n if (!routerLink) {\n return false;\n }\n\n // Touch currentUrl so the check re-evaluates on every navigation (OnPush).\n this.currentUrl();\n\n // Resolve through the Router rather than string-joining: this handles array\n // commands, relative segments, leading slashes, and matrix/query params\n // correctly — a naive join silently mismatched for array routerLinks.\n const tree = this.router.createUrlTree(\n Array.isArray(routerLink) ? routerLink : [routerLink],\n { relativeTo: this.route },\n );\n\n return this.router.isActive(tree, {\n paths: link.exact ? 'exact' : 'subset',\n queryParams: 'ignored',\n fragment: 'ignored',\n matrixParams: 'ignored',\n });\n }\n\n /** True when the item itself, or any of its children, is the active route. */\n protected sectionActive(item: SidebarNavItem): boolean {\n if (this.linkActive(item)) {\n return true;\n }\n\n return (item.children ?? []).some((child) => this.linkActive(child));\n }\n\n /**\n * Whether a parent discloses its children inline (expanded rail only).\n * Disclosure is owned entirely by `openIds` — the active section is seeded\n * into it by the auto-open effect, so it starts open yet can still be\n * collapsed by clicking the parent (the effect only re-opens on navigation).\n */\n protected isOpen(item: SidebarNavItem): boolean {\n return this.openIds().has(item.id);\n }\n\n // ===== INTERACTIONS =====\n /** Parent row click: flyout in the rail, inline disclosure when expanded. */\n protected onParentClick(item: SidebarNavItem, rowEl: HTMLElement): void {\n if (this.isCollapsed()) {\n this.toggleFlyout(item, rowEl);\n\n return;\n }\n\n this.openIds.update((set) => {\n const next = new Set(set);\n\n if (next.has(item.id)) {\n next.delete(item.id);\n } else {\n next.add(item.id);\n }\n\n return next;\n });\n }\n\n /** Leaf / child / flyout link click — navigation is via routerLink; tidy up. */\n protected onLinkClick(): void {\n this.closeFlyout();\n this.shell?.dismissSidenav();\n }\n\n // ===== FLYOUT (collapsed parent) =====\n private toggleFlyout(item: SidebarNavItem, rowEl: HTMLElement): void {\n if (this.flyoutItem()?.id === item.id) {\n this.closeFlyout();\n\n return;\n }\n\n this.openFlyout(item, rowEl);\n }\n\n private openFlyout(item: SidebarNavItem, rowEl: HTMLElement): void {\n this.closeFlyout();\n\n const positionStrategy = this.overlay\n .position()\n .flexibleConnectedTo(rowEl)\n // Nudge the panel back into the viewport when a low trigger row would push\n // its (now height-capped) box off the bottom edge.\n .withPush(true)\n .withPositions([\n {\n originX: 'end',\n originY: 'top',\n overlayX: 'start',\n overlayY: 'top',\n offsetX: 8,\n },\n {\n originX: 'start',\n originY: 'top',\n overlayX: 'end',\n overlayY: 'top',\n offsetX: -8,\n },\n ]);\n\n const overlayRef = this.overlay.create({\n positionStrategy,\n scrollStrategy: this.overlay.scrollStrategies.reposition(),\n panelClass: 'fk-sidebar-nav__flyout',\n // Dispose on browser back/forward so the flyout can't linger over a new\n // page (matches fk-drawer). Programmatic navigation is covered by the\n // route-change effect in the constructor.\n disposeOnNavigation: true,\n });\n\n this.overlayRef = overlayRef;\n this.flyoutOrigin = rowEl;\n this.flyoutItem.set(item);\n overlayRef.attach(\n new TemplatePortal(this.flyoutTpl(), this.vcr, { $implicit: item }),\n );\n\n // After the panel renders: bring the active item into view (so a selection\n // deep in a long, scrolled list is visible on reopen, matching a native\n // select), and point the caret at the trigger's center now that CDK has\n // applied (and possibly pushed) the panel's final position.\n afterNextRender(\n () => {\n this.scrollActiveItemIntoView(overlayRef.overlayElement);\n this.positionFlyoutCaret(overlayRef.overlayElement);\n },\n { injector: this.injector },\n );\n\n // Scope the event subscriptions to this overlay's lifetime via a\n // Subscription torn down in closeFlyout() — not to the component lifetime,\n // and not relying on CDK completing the streams on dispose.\n const subscriptions = new Subscription();\n\n // Re-point the caret whenever CDK repositions the panel (push on open, or a\n // reposition while scrolling) so it keeps tracking the trigger's center.\n subscriptions.add(\n positionStrategy.positionChanges.subscribe(() =>\n this.positionFlyoutCaret(overlayRef.overlayElement),\n ),\n );\n\n subscriptions.add(\n overlayRef.outsidePointerEvents().subscribe((event) => {\n // Ignore clicks on the trigger row itself — the row's own click handler\n // toggles the flyout, so closing here would just let it reopen.\n const target = event.target as Node | null;\n\n if (target && this.flyoutOrigin?.contains(target)) {\n return;\n }\n\n this.closeFlyout();\n }),\n );\n\n subscriptions.add(\n overlayRef.keydownEvents().subscribe((event) => {\n if (event.key === 'Escape') {\n this.closeFlyout();\n }\n }),\n );\n\n this.flyoutSubs = subscriptions;\n }\n\n private closeFlyout(): void {\n this.flyoutSubs?.unsubscribe();\n this.flyoutSubs = null;\n this.overlayRef?.dispose();\n this.overlayRef = null;\n this.flyoutOrigin = null;\n this.flyoutItem.set(null);\n }\n\n /**\n * Center the active flyout item within its scroll viewport. No-op when there\n * is no active item (nothing selected) or the list isn't scrolled — the\n * `scrollTop` write clamps, so a short list simply stays at the top. Operates\n * only on the items container's own `scrollTop`, never `scrollIntoView`, so it\n * can't perturb the page or the overlay position.\n */\n private scrollActiveItemIntoView(overlayEl: HTMLElement): void {\n const container = overlayEl.querySelector<HTMLElement>(\n '.fk-sidebar-nav__flyout-items',\n );\n const active = container?.querySelector<HTMLElement>(\n '.fk-sidebar-nav__flyout-item--active',\n );\n\n if (!container || !active) {\n return;\n }\n\n const containerBox = container.getBoundingClientRect();\n const activeBox = active.getBoundingClientRect();\n const delta =\n activeBox.top -\n containerBox.top -\n (container.clientHeight - activeBox.height) / 2;\n\n container.scrollTop += delta;\n }\n\n /**\n * Point the flyout caret at the trigger row's vertical center. The caret is\n * absolutely positioned on the panel, so a fixed `top` drifts off the icon as\n * soon as `withPush` (or a flip) shifts the panel; deriving it from the live\n * trigger and panel boxes keeps it aligned. Clamped to the panel so it can't\n * ride off the rounded corners when the trigger sits beyond the panel's span.\n */\n private positionFlyoutCaret(overlayEl: HTMLElement): void {\n const origin = this.flyoutOrigin;\n const panel = overlayEl.querySelector<HTMLElement>(\n '.fk-sidebar-nav__flyout-panel',\n );\n\n if (!origin || !panel) {\n return;\n }\n\n const originBox = origin.getBoundingClientRect();\n const panelBox = panel.getBoundingClientRect();\n\n const caretSize = 11; // px — matches the ::before square\n const edge = 12; // keep the caret clear of the panel's rounded corners\n const center = originBox.top + originBox.height / 2 - panelBox.top;\n const top = Math.max(\n edge,\n Math.min(center - caretSize / 2, panelBox.height - edge - caretSize),\n );\n\n panel.style.setProperty('--fk-sidebar-nav-flyout-caret-top', `${top}px`);\n }\n}\n\n/** Strip query string and fragment so URL comparison matches route paths. */\nfunction stripUrl(url: string): string {\n return url.split('?')[0].split('#')[0];\n}\n\n","@for (group of model(); track $index) {\n <div class=\"fk-sidebar-nav__group\">\n @if (group.label) {\n <div class=\"fk-sidebar-nav__group-label\">{{ group.label }}</div>\n }\n <div class=\"fk-sidebar-nav__divider\" aria-hidden=\"true\"></div>\n\n <ul class=\"fk-sidebar-nav__list\">\n @for (item of group.items; track item.id) {\n <li class=\"fk-sidebar-nav__item\">\n @if (isParent(item)) {\n <!-- PARENT — disclosure row -->\n <button\n #row\n type=\"button\"\n class=\"fk-sidebar-nav__row fk-sidebar-nav__row--parent\"\n [class.fk-sidebar-nav__row--branch]=\"sectionActive(item)\"\n [attr.aria-expanded]=\"\n isCollapsed() ? flyoutItem()?.id === item.id : isOpen(item)\n \"\n [attr.aria-haspopup]=\"isCollapsed() ? 'true' : null\"\n [attr.aria-label]=\"isCollapsed() ? item.label : null\"\n [fkTooltip]=\"item.label\"\n [fkTooltipDisabled]=\"!isCollapsed()\"\n fkTooltipPosition=\"right\"\n (click)=\"onParentClick(item, row)\"\n >\n @if (leadingTemplate(item); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: item }\"\n />\n } @else if (item.icon) {\n <fk-icon\n class=\"fk-sidebar-nav__icon\"\n [name]=\"item.icon\"\n size=\"sm\"\n />\n }\n <span class=\"fk-sidebar-nav__label\">{{ item.label }}</span>\n <span\n class=\"fk-sidebar-nav__chevron\"\n [class.fk-sidebar-nav__chevron--open]=\"isOpen(item)\"\n aria-hidden=\"true\"\n >\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 18 18\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M6.75 4.5L11.25 9L6.75 13.5\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n fill=\"none\"\n />\n </svg>\n </span>\n </button>\n\n @if (!isCollapsed() && isOpen(item)) {\n <ul class=\"fk-sidebar-nav__children\">\n @for (child of item.children; track child.id) {\n @if (child.heading) {\n <li class=\"fk-sidebar-nav__subgroup\">\n <span class=\"fk-sidebar-nav__subgroup-title\">{{\n child.label\n }}</span>\n </li>\n } @else {\n <li>\n <a\n class=\"fk-sidebar-nav__child\"\n [class.fk-sidebar-nav__child--active]=\"linkActive(child)\"\n [attr.aria-current]=\"linkActive(child) ? 'page' : null\"\n [routerLink]=\"child.routerLink\"\n (click)=\"onLinkClick()\"\n >\n @if (leadingTemplate(child); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: child }\"\n />\n }\n <span class=\"fk-sidebar-nav__label\">{{\n child.label\n }}</span>\n </a>\n </li>\n }\n }\n </ul>\n }\n } @else {\n <!-- LEAF — direct link -->\n <a\n class=\"fk-sidebar-nav__row\"\n [class.fk-sidebar-nav__row--active]=\"linkActive(item)\"\n [attr.aria-current]=\"linkActive(item) ? 'page' : null\"\n [routerLink]=\"item.routerLink\"\n [attr.aria-label]=\"isCollapsed() ? item.label : null\"\n [fkTooltip]=\"item.label\"\n [fkTooltipDisabled]=\"!isCollapsed()\"\n fkTooltipPosition=\"right\"\n (click)=\"onLinkClick()\"\n >\n @if (leadingTemplate(item); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: item }\"\n />\n } @else if (item.icon) {\n <fk-icon\n class=\"fk-sidebar-nav__icon\"\n [name]=\"item.icon\"\n size=\"sm\"\n />\n }\n <span class=\"fk-sidebar-nav__label\">{{ item.label }}</span>\n </a>\n }\n </li>\n }\n </ul>\n </div>\n}\n\n<!-- Flyout panel for a collapsed parent (anchored beside the rail via CDK Overlay) -->\n<ng-template #flyoutTpl let-item>\n <!--\n A labelled group of navigation links — not an ARIA `menu`. Menu semantics\n promise roving arrow-key focus we don't implement (these are Tab-navigated\n links), so `role=\"group\"` + `aria-label` is the honest, valid structure.\n -->\n <div\n class=\"fk-sidebar-nav__flyout-panel\"\n role=\"group\"\n [attr.aria-label]=\"item.label\"\n >\n <!-- Decorative: the group is already named by aria-label, so the visual\n title/icon would only repeat it to assistive tech. -->\n <div class=\"fk-sidebar-nav__flyout-head\" aria-hidden=\"true\">\n @if (item.icon) {\n <span class=\"fk-sidebar-nav__flyout-icon\">\n <fk-icon [name]=\"item.icon\" size=\"sm\" />\n </span>\n }\n <span class=\"fk-sidebar-nav__flyout-title\">{{ item.label }}</span>\n </div>\n\n <!--\n The items scroll inside their own bounded container, not the panel: the\n panel hosts the caret (::before) which sits outside its left edge, so\n putting overflow on the panel itself would clip it.\n -->\n <div class=\"fk-sidebar-nav__flyout-items\">\n @for (child of item.children; track child.id) {\n @if (child.heading) {\n <span class=\"fk-sidebar-nav__flyout-subgroup\">{{ child.label }}</span>\n } @else {\n <a\n class=\"fk-sidebar-nav__flyout-item\"\n [class.fk-sidebar-nav__flyout-item--active]=\"linkActive(child)\"\n [attr.aria-current]=\"linkActive(child) ? 'page' : null\"\n [routerLink]=\"child.routerLink\"\n (click)=\"onLinkClick()\"\n >\n @if (leadingTemplate(child); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: child }\"\n />\n }\n <span class=\"fk-sidebar-nav__label\">{{ child.label }}</span>\n </a>\n }\n }\n </div>\n </div>\n</ng-template>\n","import {\n ChangeDetectionStrategy,\n Component,\n computed,\n HostBinding,\n input,\n} from '@angular/core';\n\nimport { IconComponent } from '@frame-kit/ui-ng/core/icon';\n\n/**\n * The fixed footer chrome for {@link DialogShellComponent} — an optional muted\n * note on the left, then the projected action buttons pushed to the right,\n * above a top divider. Paired with {@link DialogHeaderComponent} so every\n * dialog shares the same chrome.\n *\n * The note icon is optional and degrades gracefully — an empty `noteIcon`\n * simply renders no glyph.\n *\n * ```html\n * <fk-dialog-footer note=\"Takes effect immediately\" noteIcon=\"power\">\n * <fk-button variant=\"outline\" (click)=\"cancel()\">Cancel</fk-button>\n * <fk-button variant=\"primary\" type=\"submit\">Save</fk-button>\n * </fk-dialog-footer>\n * ```\n */\n@Component({\n selector: 'fk-dialog-footer',\n standalone: true,\n imports: [IconComponent],\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './dialog-footer.component.html',\n styleUrl: './dialog-footer.component.scss',\n})\nexport class DialogFooterComponent {\n // ===== INPUTS =====\n /** Optional muted note shown on the left (e.g. \"Takes effect immediately\"). */\n readonly note = input<string>('');\n /** Optional icon glyph rendered before the note. Empty renders no glyph. */\n readonly noteIcon = input<string>('');\n\n // ===== BASE PROPS =====\n readonly className = input<string>('');\n readonly id = input<string | null>(null);\n readonly ariaLabel = input<string | null>(null);\n\n // ===== COMPUTED =====\n readonly classes = computed(() =>\n ['fk-dialog-footer', this.className()].filter(Boolean).join(' '),\n );\n\n @HostBinding('class')\n get hostClass(): string {\n return this.classes();\n }\n\n @HostBinding('attr.id')\n get hostId(): string | null {\n return this.id();\n }\n\n @HostBinding('attr.aria-label')\n get hostAriaLabel(): string | null {\n return this.ariaLabel();\n }\n}\n","@if (note()) {\n <span class=\"fk-dialog-footer__note\">\n @if (noteIcon()) {\n <fk-icon\n class=\"fk-dialog-footer__note-icon\"\n [name]=\"noteIcon()\"\n size=\"sm\"\n />\n }\n {{ note() }}\n </span>\n}\n\n<span class=\"fk-dialog-footer__spacer\"></span>\n\n<ng-content />\n","import {\n ChangeDetectionStrategy,\n Component,\n computed,\n HostBinding,\n input,\n output,\n} from '@angular/core';\n\nimport { HeadlineComponent } from '@frame-kit/ui-ng/core/headline';\nimport { IconComponent } from '@frame-kit/ui-ng/core/icon';\nimport { TextComponent } from '@frame-kit/ui-ng/core/text';\nimport { IconBadgeComponent } from '@frame-kit/ui-ng/ui/icon-badge';\n\nimport type { DialogHeaderTint } from './dialog-header.types';\n\n/** The tint tone → the CSS-variable pair driving the icon tile + title accent.\n * Each reference is two-tier (component token → semantic token) so the header\n * renders correctly with no theme loaded and can be retinted per theme. */\nconst TINTS: Record<DialogHeaderTint, { color: string; background: string }> = {\n brand: {\n color:\n 'var(--fk-dialog-header-tint-brand-color, var(--fk-color-primary, #2563eb))',\n background:\n 'var(--fk-dialog-header-tint-brand-bg, var(--fk-color-primary-light, #eff6ff))',\n },\n warning: {\n color:\n 'var(--fk-dialog-header-tint-warning-color, var(--fk-color-warning, #d97706))',\n background:\n 'var(--fk-dialog-header-tint-warning-bg, var(--fk-color-warning-subtle, #fffbeb))',\n },\n success: {\n color:\n 'var(--fk-dialog-header-tint-success-color, var(--fk-color-success, #16a34a))',\n background:\n 'var(--fk-dialog-header-tint-success-bg, var(--fk-color-success-subtle, #f0fdf4))',\n },\n danger: {\n color:\n 'var(--fk-dialog-header-tint-danger-color, var(--fk-color-danger, #dc2626))',\n background:\n 'var(--fk-dialog-header-tint-danger-bg, var(--fk-color-danger-light, #fee2e2))',\n },\n accent: {\n color: 'var(--fk-dialog-header-tint-accent-color, #7c3aed)',\n background: 'var(--fk-dialog-header-tint-accent-bg, #f5f3ff)',\n },\n};\n\n/**\n * The fixed header chrome for {@link DialogShellComponent} — a tinted icon\n * tile, a title with an optional trailing accent, an optional mono subtitle,\n * and a close button. Every dialog wears the same chrome; only the icon, tint,\n * and text differ, so this centralises it instead of each dialog hand-rolling\n * the markup.\n *\n * Text is passed in as plain inputs (no i18n dependency), and the icon is\n * optional — an empty `icon` simply renders no tile, so the header degrades\n * gracefully rather than showing a broken glyph.\n *\n * ```html\n * <fk-dialog-header\n * icon=\"user-ban\"\n * tint=\"warning\"\n * title=\"Deactivate identity\"\n * subtitle=\"Acme Inc. · Members\"\n * (dismiss)=\"close()\"\n * />\n * ```\n */\n@Component({\n selector: 'fk-dialog-header',\n standalone: true,\n imports: [\n HeadlineComponent,\n IconBadgeComponent,\n IconComponent,\n TextComponent,\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './dialog-header.component.html',\n styleUrl: './dialog-header.component.scss',\n})\nexport class DialogHeaderComponent {\n // ===== INPUTS =====\n /** Icon glyph name for the tile. Empty renders no tile. */\n readonly icon = input<string>('');\n /** Colour accent for the icon tile + title accent. */\n readonly tint = input<DialogHeaderTint>('brand');\n /** Dialog title. */\n readonly title = input.required<string>();\n /** Optional trailing accent appended to the title, rendered in the tint colour. */\n readonly titleAccent = input<string>('');\n /** Optional mono subtitle under the title. */\n readonly subtitle = input<string>('');\n /** Accessible label for the close button. */\n readonly closeLabel = input<string>('Close');\n\n // ===== OUTPUTS =====\n /** Fires when the close button is clicked. */\n readonly dismiss = output<void>();\n\n // ===== BASE PROPS =====\n readonly className = input<string>('');\n readonly id = input<string | null>(null);\n readonly ariaLabel = input<string | null>(null);\n\n // ===== COMPUTED =====\n /** The tint's `{ color, background }` CSS-variable pair. */\n protected readonly tintVars = computed(() => TINTS[this.tint()]);\n\n readonly classes = computed(() =>\n ['fk-dialog-header', `fk-dialog-header--${this.tint()}`, this.className()]\n .filter(Boolean)\n .join(' '),\n );\n\n @HostBinding('class')\n get hostClass(): string {\n return this.classes();\n }\n\n @HostBinding('attr.id')\n get hostId(): string | null {\n return this.id();\n }\n\n @HostBinding('attr.aria-label')\n get hostAriaLabel(): string | null {\n return this.ariaLabel();\n }\n}\n","@if (icon()) {\n <fk-icon-badge\n class=\"fk-dialog-header__icon\"\n [name]=\"icon()\"\n [color]=\"tintVars().color\"\n [backgroundColor]=\"tintVars().background\"\n shape=\"rounded\"\n size=\"md\"\n />\n}\n\n<div class=\"fk-dialog-header__titles\">\n <fk-headline\n class=\"fk-dialog-header__title\"\n [level]=\"2\"\n fontSize=\"var(--fk-dialog-header-title-font-size, 1.25rem)\"\n >\n {{ title() }}\n @if (titleAccent()) {\n <span class=\"fk-dialog-header__accent\" [style.color]=\"tintVars().color\">\n {{ titleAccent() }}</span\n >\n }\n </fk-headline>\n @if (subtitle()) {\n <fk-text class=\"fk-dialog-header__subtitle\" variant=\"small\">\n {{ subtitle() }}\n </fk-text>\n }\n</div>\n\n<button\n type=\"button\"\n class=\"fk-dialog-header__close\"\n [attr.aria-label]=\"closeLabel()\"\n (click)=\"dismiss.emit()\"\n>\n <fk-icon name=\"close\" size=\"sm\" />\n</button>\n","import {\n ChangeDetectionStrategy,\n Component,\n computed,\n HostBinding,\n input,\n output,\n} from '@angular/core';\n\nimport { IconComponent } from '@frame-kit/ui-ng/core/icon';\nimport { ButtonComponent } from '@frame-kit/ui-ng/ui/button';\n\nimport { DialogFooterComponent } from '../dialog-footer/dialog-footer.component';\nimport type { DialogHeaderTint } from '../dialog-header/dialog-header.types';\nimport { DialogHeaderComponent } from '../dialog-header/dialog-header.component';\nimport type { DialogConfirmVariant } from './dialog-shell.types';\n\n/**\n * The one dialog shell every dashboard dialog is built from. It owns the fixed\n * chrome — the tinted icon-tile header (title / accent / subtitle + close) and\n * the footer (muted note + the standard Cancel/confirm buttons) — so individual\n * dialogs stop re-declaring any of it. Everything unique to a dialog lives in\n * the projected **content region**.\n *\n * The shell carries no i18n dependency and no domain data: every label is a\n * plain input (with English defaults for the built-in Cancel button), and the\n * icons are inputs that degrade gracefully when empty. Render it inside the\n * consuming app's own `fk-dialog` (opened bare — `header: null, closable:\n * false` — with an `ariaLabel` for an accessible name).\n *\n * The common case needs zero footer markup — set the confirm label/variant and\n * handle the outputs:\n *\n * ```html\n * <fk-dialog-shell\n * icon=\"user-ban\"\n * tint=\"warning\"\n * title=\"Deactivate identity\"\n * [subtitle]=\"subtitle\"\n * footerNote=\"Sign-in blocked\"\n * footerNoteIcon=\"power\"\n * confirmLabel=\"Deactivate\"\n * confirmIcon=\"user-ban\"\n * confirmVariant=\"warning\"\n * [confirmDisabled]=\"!ready()\"\n * (confirm)=\"onConfirm()\"\n * (dismiss)=\"onCancel()\"\n * >\n * <!-- content region: lead, description, cards, callouts … -->\n * </fk-dialog-shell>\n * ```\n *\n * Escape hatches for the exceptions:\n * - leave `confirmLabel` empty and project buttons into the `dialogFooter` slot\n * to keep the footer chrome but use custom buttons (e.g. a form submit);\n * - set `[customFooter]=\"true\"` and project into the `footer` slot to replace\n * the whole footer.\n */\n@Component({\n selector: 'fk-dialog-shell',\n standalone: true,\n imports: [\n ButtonComponent,\n IconComponent,\n DialogFooterComponent,\n DialogHeaderComponent,\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './dialog-shell.component.html',\n styleUrl: './dialog-shell.component.scss',\n})\nexport class DialogShellComponent {\n // ===== INPUTS =====\n /** Icon glyph for the header tile. Empty renders no tile. */\n readonly icon = input<string>('');\n /** Colour accent for the header tile. */\n readonly tint = input<DialogHeaderTint>('brand');\n /** Header title. */\n readonly title = input.required<string>();\n /** Optional trailing accent appended to the title in the tint colour. */\n readonly titleAccent = input<string>('');\n /** Optional mono subtitle under the title. */\n readonly subtitle = input<string>('');\n /** Optional muted footer note on the left (e.g. \"Permanent\"). */\n readonly footerNote = input<string>('');\n /** Optional icon rendered before the footer note. */\n readonly footerNoteIcon = input<string>('');\n /**\n * Confirm-button label. When set, the shell renders the standard\n * Cancel + confirm pair; leave empty to project custom buttons into the\n * `dialogFooter` slot instead.\n */\n readonly confirmLabel = input<string>('');\n /** Optional leading icon on the confirm button. */\n readonly confirmIcon = input<string>('');\n /** Confirm-button colour — `primary` (default), `danger`, or `warning`. */\n readonly confirmVariant = input<DialogConfirmVariant>('primary');\n /** Disables the confirm button (e.g. while a type-to-confirm is unmet). */\n readonly confirmDisabled = input<boolean>(false);\n /** Cancel-button label. Defaults to `Cancel`. */\n readonly cancelLabel = input<string>('Cancel');\n /** Accessible label for the header's close button. */\n readonly closeLabel = input<string>('Close');\n /**\n * Escape hatch for the rare dialog that needs a bespoke footer. When true,\n * the default `fk-dialog-footer` (note + buttons) is suppressed and whatever\n * is projected into the `footer` slot is rendered raw instead.\n */\n readonly customFooter = input<boolean>(false);\n\n // ===== OUTPUTS =====\n /** Fires when the header close button OR the Cancel button is clicked. */\n readonly dismiss = output<void>();\n /** Fires when the confirm button is clicked. */\n readonly confirm = output<void>();\n\n // ===== BASE PROPS =====\n readonly className = input<string>('');\n readonly id = input<string | null>(null);\n\n // ===== COMPUTED =====\n /** `warning` renders as a retinted `danger` fk-button; others map directly. */\n protected readonly confirmButtonVariant = computed<'primary' | 'danger'>(\n () => {\n const variant = this.confirmVariant();\n\n return variant === 'warning' ? 'danger' : variant;\n },\n );\n\n readonly classes = computed(() =>\n ['fk-dialog-shell', this.className()].filter(Boolean).join(' '),\n );\n\n @HostBinding('class')\n get hostClass(): string {\n return this.classes();\n }\n\n @HostBinding('attr.id')\n get hostId(): string | null {\n return this.id();\n }\n}\n","<fk-dialog-header\n class=\"fk-dialog-shell__header\"\n [icon]=\"icon()\"\n [tint]=\"tint()\"\n [title]=\"title()\"\n [titleAccent]=\"titleAccent()\"\n [subtitle]=\"subtitle()\"\n [closeLabel]=\"closeLabel()\"\n (dismiss)=\"dismiss.emit()\"\n/>\n\n<div class=\"fk-dialog-shell__body\">\n <ng-content />\n</div>\n\n@if (customFooter()) {\n <ng-content select=\"[footer]\" />\n} @else {\n <fk-dialog-footer [note]=\"footerNote()\" [noteIcon]=\"footerNoteIcon()\">\n @if (confirmLabel()) {\n <fk-button variant=\"outline\" type=\"button\" (click)=\"dismiss.emit()\">\n {{ cancelLabel() }}\n </fk-button>\n <fk-button\n class=\"fk-dialog-shell__confirm\"\n [class.fk-dialog-shell__confirm--danger]=\"confirmVariant() === 'danger'\"\n [class.fk-dialog-shell__confirm--warning]=\"\n confirmVariant() === 'warning'\n \"\n [variant]=\"confirmButtonVariant()\"\n type=\"button\"\n [disabled]=\"confirmDisabled()\"\n (click)=\"confirm.emit()\"\n >\n @if (confirmIcon()) {\n <fk-icon fkButtonIconStart [name]=\"confirmIcon()\" size=\"sm\" />\n }\n {{ confirmLabel() }}\n </fk-button>\n } @else {\n <ng-content select=\"[dialogFooter]\" />\n }\n </fk-dialog-footer>\n}\n","import {\n afterNextRender,\n ChangeDetectionStrategy,\n Component,\n computed,\n DestroyRef,\n ElementRef,\n HostBinding,\n inject,\n input,\n linkedSignal,\n output,\n signal,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport type { CdkDragEnd } from '@angular/cdk/drag-drop';\nimport { CdkDrag, CdkDragHandle } from '@angular/cdk/drag-drop';\n\nimport { IconComponent } from '@frame-kit/ui-ng/core/icon';\nimport { ButtonComponent } from '@frame-kit/ui-ng/ui/button';\n\nimport type {\n OnboardingStep,\n OnboardingSubstep,\n OnboardingSubstepToggle,\n} from './onboarding-guide.types';\n\ninterface Point {\n x: number;\n y: number;\n}\n\ninterface PersistedState {\n collapsed?: boolean;\n pos?: Point;\n}\n\nconst VIEWPORT_MARGIN = 24;\n\n/**\n * A floating, draggable onboarding-progress widget. It presents a checklist of\n * steps with a progress bar, collapses to a compact pill with a progress ring,\n * and can be dragged anywhere on screen (CDK drag). It renders over the app in\n * a fixed layer — drop it once near the app root.\n *\n * **Controlled model, no domain data.** The `steps` model is a required,\n * reactive input: the widget is a pure view of it and emits events when the\n * user acts (`stepAction`, `stepMarkDone`, `substepToggle`, `goLive`). The\n * consumer owns the step state — so if it is keyed by, say, the active account\n * or environment, swapping the input re-renders the widget instantly. The\n * widget never persists step state.\n *\n * **Presentation state is internal + persisted.** Collapsed and drag position\n * live in the widget and persist to `localStorage` under `storageKey` — these\n * are UI preferences, not part of the model.\n *\n * **Appearance-agnostic.** All colour flows through `--fk-*` tokens with neutral\n * (near-black / grey) raw fallbacks, so with no theme it renders monochrome;\n * point the tokens at a brand scale to colour it.\n *\n * ```html\n * <fk-onboarding-guide\n * [steps]=\"steps()\"\n * title=\"Setup guide\"\n * (stepAction)=\"onStart($event)\"\n * (substepToggle)=\"onToggle($event)\"\n * (goLive)=\"onGoLive()\"\n * (dismiss)=\"onDismiss()\"\n * />\n * ```\n */\n@Component({\n selector: 'fk-onboarding-guide',\n standalone: true,\n imports: [CdkDragHandle, ButtonComponent, IconComponent],\n hostDirectives: [CdkDrag],\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './onboarding-guide.component.html',\n styleUrl: './onboarding-guide.component.scss',\n})\nexport class OnboardingGuideComponent {\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly drag = inject(CdkDrag);\n private readonly destroyRef = inject(DestroyRef);\n\n // ===== INPUTS =====\n /** The step model. Controlled by the consumer; the widget is a view of it. */\n readonly steps = input.required<OnboardingStep[]>();\n /** Widget title. */\n readonly title = input<string>('Setup guide');\n /** `localStorage` key for the collapsed + drag-position preferences. */\n readonly storageKey = input<string>('fk-onboarding-guide');\n /** Initial collapsed state, used only when nothing is persisted yet. */\n readonly startCollapsed = input<boolean>(false);\n\n // --- Text (English defaults; pass translated strings as needed) ---\n /** Default CTA label when a step doesn't supply its own `actionLabel`. */\n readonly startLabel = input<string>('Start');\n /** Secondary \"mark this step done\" action label. */\n readonly markDoneLabel = input<string>('Mark done');\n /** Footer / final go-live action label. */\n readonly goLiveLabel = input<string>('Go live');\n /** Footer noun for the \"{done} of {total} {stepsWord} {doneWord}\" summary. */\n readonly stepsWord = input<string>('steps');\n /** Footer verb for the summary. */\n readonly doneWord = input<string>('done');\n /** Collapsed-pill suffix, e.g. \"3 steps left\". */\n readonly stepsLeftWord = input<string>('left');\n /** Collapsed-pill copy shown when everything is complete. */\n readonly allDoneLabel = input<string>('All set');\n /** ARIA labels for the icon-only header controls. */\n readonly renameLabel = input<string>('Rename');\n readonly collapseLabel = input<string>('Collapse');\n readonly dismissLabel = input<string>('Dismiss');\n readonly expandLabel = input<string>('Expand');\n\n // --- Icon glyph names (resolved by the app's icon registry) ---\n readonly checkIcon = input<string>('check');\n readonly caretIcon = input<string>('chevron-down');\n readonly editIcon = input<string>('pen');\n readonly collapseIcon = input<string>('collapse');\n readonly dismissIcon = input<string>('close');\n readonly expandIcon = input<string>('expand');\n readonly actionIcon = input<string>('arrow-right');\n\n // ===== OUTPUTS =====\n /** A step's primary CTA was clicked. Emits the step id. */\n readonly stepAction = output<string>();\n /** A step's \"mark done\" was clicked. Emits the step id. */\n readonly stepMarkDone = output<string>();\n /** A substep checkbox was toggled. */\n readonly substepToggle = output<OnboardingSubstepToggle>();\n /** The final go-live action was invoked (footer or the go-live step CTA). */\n readonly goLive = output<void>();\n /** The rename (edit) affordance was clicked; the consumer owns renaming. */\n readonly renameClick = output<void>();\n /** The dismiss control was clicked; the consumer decides whether to hide it. */\n readonly dismiss = output<void>();\n /** Fires when the collapsed state changes. */\n readonly collapsedChange = output<boolean>();\n\n // ===== BASE PROPS =====\n readonly className = input<string>('');\n readonly id = input<string | null>(null);\n\n // ===== PRESENTATION STATE =====\n protected readonly collapsed = signal(false);\n protected readonly dragPosition = signal<Point>({ x: 0, y: 0 });\n\n /** True immediately after a real drag, so the drag-handle's click (e.g. the\n * pill's expand) is suppressed rather than firing at the drop point. */\n private justDragged = false;\n\n /**\n * The expanded step. A `linkedSignal` over `steps` so that whenever the model\n * changes (e.g. the consumer swaps in another account/environment's steps) it\n * resets to the first incomplete step; user toggles override until the next\n * model change.\n */\n protected readonly openStepId = linkedSignal<OnboardingStep[], string | null>(\n {\n source: this.steps,\n computation: (steps) =>\n steps.find((s) => !this.isComplete(s))?.id ?? null,\n },\n );\n\n // ===== DERIVED =====\n protected readonly total = computed(() => this.steps().length);\n protected readonly doneCount = computed(\n () => this.steps().filter((s) => this.isComplete(s)).length,\n );\n protected readonly percent = computed(() => {\n const total = this.total();\n\n return total === 0 ? 0 : Math.round((this.doneCount() / total) * 100);\n });\n protected readonly stepsLeft = computed(\n () => this.total() - this.doneCount(),\n );\n protected readonly complete = computed(\n () => this.total() > 0 && this.stepsLeft() === 0,\n );\n\n /** Circumference for the pill's progress ring (r = 16). */\n protected readonly ringCircumference = 2 * Math.PI * 16;\n protected readonly ringOffset = computed(() => {\n const total = this.total();\n const fraction = total === 0 ? 0 : this.doneCount() / total;\n\n return this.ringCircumference * (1 - fraction);\n });\n\n readonly classes = computed(() =>\n [\n 'fk-onboarding-guide',\n this.collapsed() ? 'fk-onboarding-guide--collapsed' : '',\n this.complete() ? 'fk-onboarding-guide--complete' : '',\n this.className(),\n ]\n .filter(Boolean)\n .join(' '),\n );\n\n @HostBinding('class')\n get hostClass(): string {\n return this.classes();\n }\n\n @HostBinding('attr.id')\n get hostId(): string | null {\n return this.id();\n }\n\n constructor() {\n this.drag.ended\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe((event) => this.onDragEnded(event));\n\n afterNextRender(() => this.hydrate());\n }\n\n // ===== COMPLETION LOGIC =====\n isComplete(step: OnboardingStep): boolean {\n if (step.substeps && step.substeps.length > 0) {\n return step.substeps.every((sub) => sub.done);\n }\n\n return step.done;\n }\n\n protected isActive(step: OnboardingStep): boolean {\n return !this.isComplete(step) && this.openStepId() === step.id;\n }\n\n protected actionLabelFor(step: OnboardingStep): string {\n return step.actionLabel || this.startLabel();\n }\n\n // ===== INTERACTIONS =====\n protected toggleStep(stepId: string): void {\n this.openStepId.update((cur) => (cur === stepId ? null : stepId));\n }\n\n protected onAction(step: OnboardingStep): void {\n this.stepAction.emit(step.id);\n }\n\n protected onMarkDone(step: OnboardingStep): void {\n this.stepMarkDone.emit(step.id);\n }\n\n protected onSubstep(step: OnboardingStep, substep: OnboardingSubstep): void {\n this.substepToggle.emit({ stepId: step.id, substepId: substep.id });\n }\n\n protected onCollapse(): void {\n this.setCollapsed(true);\n }\n\n protected onExpand(): void {\n if (this.justDragged) {\n return;\n }\n\n this.setCollapsed(false);\n }\n\n protected onRename(): void {\n this.renameClick.emit();\n }\n\n protected onDismiss(): void {\n this.dismiss.emit();\n }\n\n protected onGoLive(): void {\n this.goLive.emit();\n }\n\n private setCollapsed(value: boolean): void {\n this.collapsed.set(value);\n this.collapsedChange.emit(value);\n this.persist();\n }\n\n // ===== DRAG =====\n private onDragEnded(event: CdkDragEnd): void {\n const clamped = this.clamp(this.drag.getFreeDragPosition());\n\n this.dragPosition.set(clamped);\n this.drag.setFreeDragPosition(clamped);\n this.persist();\n\n const moved =\n Math.abs(event.distance.x) > 3 || Math.abs(event.distance.y) > 3;\n\n if (moved) {\n this.justDragged = true;\n setTimeout(() => (this.justDragged = false));\n }\n }\n\n private clamp(point: Point): Point {\n if (typeof window === 'undefined') {\n return point;\n }\n\n const rect = this.host.nativeElement.getBoundingClientRect();\n const maxX = window.innerWidth - rect.width - VIEWPORT_MARGIN;\n const maxY = window.innerHeight - rect.height - VIEWPORT_MARGIN;\n\n return {\n x: Math.max(VIEWPORT_MARGIN, Math.min(point.x, maxX)),\n y: Math.max(VIEWPORT_MARGIN, Math.min(point.y, maxY)),\n };\n }\n\n // ===== PERSISTENCE =====\n private hydrate(): void {\n const saved = this.read();\n\n this.collapsed.set(saved.collapsed ?? this.startCollapsed());\n\n const pos = saved.pos ? this.clamp(saved.pos) : this.defaultBottomRight();\n\n this.dragPosition.set(pos);\n this.drag.setFreeDragPosition(pos);\n }\n\n private defaultBottomRight(): Point {\n if (typeof window === 'undefined') {\n return { x: 0, y: 0 };\n }\n\n const rect = this.host.nativeElement.getBoundingClientRect();\n\n return {\n x: Math.max(\n VIEWPORT_MARGIN,\n window.innerWidth - rect.width - VIEWPORT_MARGIN,\n ),\n y: Math.max(\n VIEWPORT_MARGIN,\n window.innerHeight - rect.height - VIEWPORT_MARGIN,\n ),\n };\n }\n\n private read(): PersistedState {\n const store = this.storage();\n\n if (!store) {\n return {};\n }\n\n try {\n return JSON.parse(store.getItem(this.storageKey()) || '{}');\n } catch {\n return {};\n }\n }\n\n private persist(): void {\n const store = this.storage();\n\n if (!store) {\n return;\n }\n\n const state: PersistedState = {\n collapsed: this.collapsed(),\n pos: this.dragPosition(),\n };\n\n try {\n store.setItem(this.storageKey(), JSON.stringify(state));\n } catch {\n // Storage unavailable (private mode / quota) — preferences just don't stick.\n }\n }\n\n private storage(): Storage | null {\n try {\n return typeof window === 'undefined' ? null : window.localStorage;\n } catch {\n return null;\n }\n }\n}\n","<!-- ===================== EXPANDED CARD ===================== -->\n<div class=\"fk-onboarding-guide__card\">\n <div class=\"fk-onboarding-guide__head\">\n <div class=\"fk-onboarding-guide__head-top\">\n <span class=\"fk-onboarding-guide__grip\" cdkDragHandle aria-hidden=\"true\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\">\n <circle cx=\"9\" cy=\"6\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"6\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"9\" cy=\"12\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"12\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"9\" cy=\"18\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"18\" r=\"1.5\" fill=\"currentColor\" />\n </svg>\n </span>\n\n <span class=\"fk-onboarding-guide__title\" cdkDragHandle>{{\n title()\n }}</span>\n\n <button\n type=\"button\"\n class=\"fk-onboarding-guide__icon-btn fk-onboarding-guide__edit\"\n [attr.aria-label]=\"renameLabel()\"\n (click)=\"onRename()\"\n >\n <fk-icon [name]=\"editIcon()\" size=\"sm\" />\n </button>\n\n <div class=\"fk-onboarding-guide__head-actions\">\n <button\n type=\"button\"\n class=\"fk-onboarding-guide__icon-btn\"\n [attr.aria-label]=\"collapseLabel()\"\n (click)=\"onCollapse()\"\n >\n <fk-icon [name]=\"collapseIcon()\" size=\"sm\" />\n </button>\n <button\n type=\"button\"\n class=\"fk-onboarding-guide__icon-btn\"\n [attr.aria-label]=\"dismissLabel()\"\n (click)=\"onDismiss()\"\n >\n <fk-icon [name]=\"dismissIcon()\" size=\"sm\" />\n </button>\n </div>\n </div>\n\n <div class=\"fk-onboarding-guide__progress\">\n <div\n class=\"fk-onboarding-guide__track\"\n role=\"progressbar\"\n [attr.aria-valuenow]=\"percent()\"\n aria-valuemin=\"0\"\n aria-valuemax=\"100\"\n >\n <div\n class=\"fk-onboarding-guide__fill\"\n [style.width.%]=\"percent()\"\n ></div>\n </div>\n <span class=\"fk-onboarding-guide__pct\">{{ percent() }}%</span>\n </div>\n </div>\n\n <div class=\"fk-onboarding-guide__steps\" role=\"list\">\n @for (step of steps(); track step.id) {\n @let done = isComplete(step);\n @let open = openStepId() === step.id;\n @let active = isActive(step);\n\n <div\n class=\"fk-onboarding-guide__step\"\n role=\"listitem\"\n [class.fk-onboarding-guide__step--done]=\"done\"\n [class.fk-onboarding-guide__step--open]=\"open\"\n >\n <button\n type=\"button\"\n class=\"fk-onboarding-guide__step-row\"\n [attr.aria-expanded]=\"open\"\n (click)=\"toggleStep(step.id)\"\n >\n <span\n class=\"fk-onboarding-guide__check\"\n [class.fk-onboarding-guide__check--done]=\"done\"\n [class.fk-onboarding-guide__check--active]=\"active\"\n [class.fk-onboarding-guide__check--todo]=\"!done && !active\"\n aria-hidden=\"true\"\n >\n @if (done) {\n <fk-icon [name]=\"checkIcon()\" size=\"xs\" />\n } @else if (active) {\n <i class=\"fk-onboarding-guide__dot\"></i>\n }\n </span>\n\n <span class=\"fk-onboarding-guide__step-label\">{{ step.label }}</span>\n\n <span class=\"fk-onboarding-guide__caret\" aria-hidden=\"true\">\n <fk-icon [name]=\"caretIcon()\" size=\"sm\" />\n </span>\n </button>\n\n @if (open) {\n <div class=\"fk-onboarding-guide__step-body\">\n @if (step.substeps && step.substeps.length > 0) {\n @for (sub of step.substeps; track sub.id) {\n <button\n type=\"button\"\n class=\"fk-onboarding-guide__sub\"\n [class.fk-onboarding-guide__sub--done]=\"sub.done\"\n (click)=\"onSubstep(step, sub)\"\n >\n <span\n class=\"fk-onboarding-guide__sub-check\"\n aria-hidden=\"true\"\n >\n @if (sub.done) {\n <fk-icon [name]=\"checkIcon()\" size=\"xs\" />\n }\n </span>\n <span class=\"fk-onboarding-guide__sub-label\">{{\n sub.label\n }}</span>\n </button>\n }\n } @else {\n @if (step.description) {\n <p class=\"fk-onboarding-guide__desc\">{{ step.description }}</p>\n }\n\n @if (!done) {\n <div class=\"fk-onboarding-guide__actions\">\n <fk-button\n variant=\"primary\"\n size=\"sm\"\n (click)=\"onAction(step)\"\n >\n {{ actionLabelFor(step) }}\n <fk-icon fkButtonIconEnd [name]=\"actionIcon()\" size=\"xs\" />\n </fk-button>\n <button\n type=\"button\"\n class=\"fk-onboarding-guide__skip\"\n (click)=\"onMarkDone(step)\"\n >\n {{ markDoneLabel() }}\n </button>\n </div>\n }\n }\n </div>\n }\n </div>\n }\n </div>\n\n <div class=\"fk-onboarding-guide__foot\">\n <span class=\"fk-onboarding-guide__foot-text\">\n <b>{{ doneCount() }}</b> / {{ total() }} {{ stepsWord() }}\n {{ doneWord() }}\n </span>\n <button type=\"button\" class=\"fk-onboarding-guide__go\" (click)=\"onGoLive()\">\n {{ goLiveLabel() }}\n <fk-icon [name]=\"actionIcon()\" size=\"xs\" />\n </button>\n </div>\n</div>\n\n<!-- ===================== COLLAPSED PILL ===================== -->\n<button\n type=\"button\"\n class=\"fk-onboarding-guide__pill\"\n cdkDragHandle\n [attr.aria-label]=\"expandLabel()\"\n (click)=\"onExpand()\"\n>\n <span class=\"fk-onboarding-guide__ring\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 38 38\">\n <circle class=\"fk-onboarding-guide__ring-track\" cx=\"19\" cy=\"19\" r=\"16\" />\n <circle\n class=\"fk-onboarding-guide__ring-prog\"\n cx=\"19\"\n cy=\"19\"\n r=\"16\"\n [style.stroke-dasharray]=\"ringCircumference\"\n [style.stroke-dashoffset]=\"ringOffset()\"\n />\n </svg>\n <span class=\"fk-onboarding-guide__ring-num\">{{ percent() }}%</span>\n </span>\n\n <span class=\"fk-onboarding-guide__pill-meta\">\n <span class=\"fk-onboarding-guide__pill-title\">{{ title() }}</span>\n <span class=\"fk-onboarding-guide__pill-sub\">\n @if (complete()) {\n {{ allDoneLabel() }}\n } @else {\n <b>{{ stepsLeft() }}</b> {{ stepsWord() }} {{ stepsLeftWord() }}\n }\n </span>\n </span>\n\n <span class=\"fk-onboarding-guide__pill-expand\" aria-hidden=\"true\">\n <fk-icon [name]=\"expandIcon()\" size=\"sm\" />\n </span>\n</button>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@frame-kit/ui-ng-patterns",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "Opinionated, dashboard-ready Angular component patterns composed from @frame-kit/ui-ng.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -17,7 +17,7 @@
17
17
  "@angular/forms": "^21.2.0",
18
18
  "@angular/platform-browser": "^21.2.0",
19
19
  "@angular/router": "^21.2.0",
20
- "@frame-kit/ui-ng": "0.1.6",
20
+ "@frame-kit/ui-ng": "0.1.7",
21
21
  "rxjs": "^7.0.0"
22
22
  },
23
23
  "sideEffects": false,
@@ -1,6 +1,7 @@
1
1
  import * as _angular_core from '@angular/core';
2
2
  import { TemplateRef } from '@angular/core';
3
3
  import { HeadlineLevel } from '@frame-kit/ui-ng/core/headline';
4
+ import * as i1 from '@angular/cdk/drag-drop';
4
5
 
5
6
  /**
6
7
  * Page-level dashboard header: title + optional description on the left, up to
@@ -579,5 +580,186 @@ declare class DialogFooterComponent {
579
580
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<DialogFooterComponent, "fk-dialog-footer", never, { "note": { "alias": "note"; "required": false; "isSignal": true; }; "noteIcon": { "alias": "noteIcon"; "required": false; "isSignal": true; }; "className": { "alias": "className"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
580
581
  }
581
582
 
582
- export { ColumnsComponent, ContentSplitLayoutComponent, DetailPanelComponent, DialogFooterComponent, DialogHeaderComponent, DialogShellComponent, PageHeaderComponent, SidebarNavComponent, SidebarNavItemDirective, TableEmptyStateComponent };
583
- export type { DialogConfirmVariant, DialogHeaderTint, SidebarNavChild, SidebarNavGroup, SidebarNavItem, SidebarNavLink, SidebarNavModel };
583
+ /**
584
+ * A single item inside a grouped step's sub-checklist. The consumer owns the
585
+ * `done` state — the widget only reflects it and emits toggles.
586
+ */
587
+ interface OnboardingSubstep {
588
+ /** Stable identifier, unique within the parent step. */
589
+ id: string;
590
+ /** Human-readable label. */
591
+ label: string;
592
+ /** Whether this substep is complete. */
593
+ done: boolean;
594
+ }
595
+ /**
596
+ * A step in the onboarding guide. A step is either:
597
+ *
598
+ * - a **leaf** step — has an optional `description` + a call-to-action, and its
599
+ * completion is driven by the `done` flag, or
600
+ * - a **group** step — carries `substeps`, and is considered complete once every
601
+ * substep is `done` (the top-level `done` flag is ignored for group steps).
602
+ *
603
+ * All state (`done`) is owned by the consumer; the widget is a controlled view
604
+ * of the `steps` model and emits events when the user acts.
605
+ */
606
+ interface OnboardingStep {
607
+ /** Stable identifier, unique within the guide. */
608
+ id: string;
609
+ /** Human-readable label shown on the step row. */
610
+ label: string;
611
+ /** Whether a leaf step is complete. Ignored when `substeps` is set. */
612
+ done: boolean;
613
+ /** Optional supporting copy shown when the step is expanded. */
614
+ description?: string;
615
+ /** Optional call-to-action label (defaults to a generic "Start"). */
616
+ actionLabel?: string;
617
+ /** When set, the step renders a sub-checklist and auto-completes when all are done. */
618
+ substeps?: OnboardingSubstep[];
619
+ }
620
+ /** Payload emitted when a substep checkbox is toggled. */
621
+ interface OnboardingSubstepToggle {
622
+ stepId: string;
623
+ substepId: string;
624
+ }
625
+
626
+ interface Point {
627
+ x: number;
628
+ y: number;
629
+ }
630
+ /**
631
+ * A floating, draggable onboarding-progress widget. It presents a checklist of
632
+ * steps with a progress bar, collapses to a compact pill with a progress ring,
633
+ * and can be dragged anywhere on screen (CDK drag). It renders over the app in
634
+ * a fixed layer — drop it once near the app root.
635
+ *
636
+ * **Controlled model, no domain data.** The `steps` model is a required,
637
+ * reactive input: the widget is a pure view of it and emits events when the
638
+ * user acts (`stepAction`, `stepMarkDone`, `substepToggle`, `goLive`). The
639
+ * consumer owns the step state — so if it is keyed by, say, the active account
640
+ * or environment, swapping the input re-renders the widget instantly. The
641
+ * widget never persists step state.
642
+ *
643
+ * **Presentation state is internal + persisted.** Collapsed and drag position
644
+ * live in the widget and persist to `localStorage` under `storageKey` — these
645
+ * are UI preferences, not part of the model.
646
+ *
647
+ * **Appearance-agnostic.** All colour flows through `--fk-*` tokens with neutral
648
+ * (near-black / grey) raw fallbacks, so with no theme it renders monochrome;
649
+ * point the tokens at a brand scale to colour it.
650
+ *
651
+ * ```html
652
+ * <fk-onboarding-guide
653
+ * [steps]="steps()"
654
+ * title="Setup guide"
655
+ * (stepAction)="onStart($event)"
656
+ * (substepToggle)="onToggle($event)"
657
+ * (goLive)="onGoLive()"
658
+ * (dismiss)="onDismiss()"
659
+ * />
660
+ * ```
661
+ */
662
+ declare class OnboardingGuideComponent {
663
+ private readonly host;
664
+ private readonly drag;
665
+ private readonly destroyRef;
666
+ /** The step model. Controlled by the consumer; the widget is a view of it. */
667
+ readonly steps: _angular_core.InputSignal<OnboardingStep[]>;
668
+ /** Widget title. */
669
+ readonly title: _angular_core.InputSignal<string>;
670
+ /** `localStorage` key for the collapsed + drag-position preferences. */
671
+ readonly storageKey: _angular_core.InputSignal<string>;
672
+ /** Initial collapsed state, used only when nothing is persisted yet. */
673
+ readonly startCollapsed: _angular_core.InputSignal<boolean>;
674
+ /** Default CTA label when a step doesn't supply its own `actionLabel`. */
675
+ readonly startLabel: _angular_core.InputSignal<string>;
676
+ /** Secondary "mark this step done" action label. */
677
+ readonly markDoneLabel: _angular_core.InputSignal<string>;
678
+ /** Footer / final go-live action label. */
679
+ readonly goLiveLabel: _angular_core.InputSignal<string>;
680
+ /** Footer noun for the "{done} of {total} {stepsWord} {doneWord}" summary. */
681
+ readonly stepsWord: _angular_core.InputSignal<string>;
682
+ /** Footer verb for the summary. */
683
+ readonly doneWord: _angular_core.InputSignal<string>;
684
+ /** Collapsed-pill suffix, e.g. "3 steps left". */
685
+ readonly stepsLeftWord: _angular_core.InputSignal<string>;
686
+ /** Collapsed-pill copy shown when everything is complete. */
687
+ readonly allDoneLabel: _angular_core.InputSignal<string>;
688
+ /** ARIA labels for the icon-only header controls. */
689
+ readonly renameLabel: _angular_core.InputSignal<string>;
690
+ readonly collapseLabel: _angular_core.InputSignal<string>;
691
+ readonly dismissLabel: _angular_core.InputSignal<string>;
692
+ readonly expandLabel: _angular_core.InputSignal<string>;
693
+ readonly checkIcon: _angular_core.InputSignal<string>;
694
+ readonly caretIcon: _angular_core.InputSignal<string>;
695
+ readonly editIcon: _angular_core.InputSignal<string>;
696
+ readonly collapseIcon: _angular_core.InputSignal<string>;
697
+ readonly dismissIcon: _angular_core.InputSignal<string>;
698
+ readonly expandIcon: _angular_core.InputSignal<string>;
699
+ readonly actionIcon: _angular_core.InputSignal<string>;
700
+ /** A step's primary CTA was clicked. Emits the step id. */
701
+ readonly stepAction: _angular_core.OutputEmitterRef<string>;
702
+ /** A step's "mark done" was clicked. Emits the step id. */
703
+ readonly stepMarkDone: _angular_core.OutputEmitterRef<string>;
704
+ /** A substep checkbox was toggled. */
705
+ readonly substepToggle: _angular_core.OutputEmitterRef<OnboardingSubstepToggle>;
706
+ /** The final go-live action was invoked (footer or the go-live step CTA). */
707
+ readonly goLive: _angular_core.OutputEmitterRef<void>;
708
+ /** The rename (edit) affordance was clicked; the consumer owns renaming. */
709
+ readonly renameClick: _angular_core.OutputEmitterRef<void>;
710
+ /** The dismiss control was clicked; the consumer decides whether to hide it. */
711
+ readonly dismiss: _angular_core.OutputEmitterRef<void>;
712
+ /** Fires when the collapsed state changes. */
713
+ readonly collapsedChange: _angular_core.OutputEmitterRef<boolean>;
714
+ readonly className: _angular_core.InputSignal<string>;
715
+ readonly id: _angular_core.InputSignal<string | null>;
716
+ protected readonly collapsed: _angular_core.WritableSignal<boolean>;
717
+ protected readonly dragPosition: _angular_core.WritableSignal<Point>;
718
+ /** True immediately after a real drag, so the drag-handle's click (e.g. the
719
+ * pill's expand) is suppressed rather than firing at the drop point. */
720
+ private justDragged;
721
+ /**
722
+ * The expanded step. A `linkedSignal` over `steps` so that whenever the model
723
+ * changes (e.g. the consumer swaps in another account/environment's steps) it
724
+ * resets to the first incomplete step; user toggles override until the next
725
+ * model change.
726
+ */
727
+ protected readonly openStepId: _angular_core.WritableSignal<string | null>;
728
+ protected readonly total: _angular_core.Signal<number>;
729
+ protected readonly doneCount: _angular_core.Signal<number>;
730
+ protected readonly percent: _angular_core.Signal<number>;
731
+ protected readonly stepsLeft: _angular_core.Signal<number>;
732
+ protected readonly complete: _angular_core.Signal<boolean>;
733
+ /** Circumference for the pill's progress ring (r = 16). */
734
+ protected readonly ringCircumference: number;
735
+ protected readonly ringOffset: _angular_core.Signal<number>;
736
+ readonly classes: _angular_core.Signal<string>;
737
+ get hostClass(): string;
738
+ get hostId(): string | null;
739
+ constructor();
740
+ isComplete(step: OnboardingStep): boolean;
741
+ protected isActive(step: OnboardingStep): boolean;
742
+ protected actionLabelFor(step: OnboardingStep): string;
743
+ protected toggleStep(stepId: string): void;
744
+ protected onAction(step: OnboardingStep): void;
745
+ protected onMarkDone(step: OnboardingStep): void;
746
+ protected onSubstep(step: OnboardingStep, substep: OnboardingSubstep): void;
747
+ protected onCollapse(): void;
748
+ protected onExpand(): void;
749
+ protected onRename(): void;
750
+ protected onDismiss(): void;
751
+ protected onGoLive(): void;
752
+ private setCollapsed;
753
+ private onDragEnded;
754
+ private clamp;
755
+ private hydrate;
756
+ private defaultBottomRight;
757
+ private read;
758
+ private persist;
759
+ private storage;
760
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<OnboardingGuideComponent, never>;
761
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<OnboardingGuideComponent, "fk-onboarding-guide", never, { "steps": { "alias": "steps"; "required": true; "isSignal": true; }; "title": { "alias": "title"; "required": false; "isSignal": true; }; "storageKey": { "alias": "storageKey"; "required": false; "isSignal": true; }; "startCollapsed": { "alias": "startCollapsed"; "required": false; "isSignal": true; }; "startLabel": { "alias": "startLabel"; "required": false; "isSignal": true; }; "markDoneLabel": { "alias": "markDoneLabel"; "required": false; "isSignal": true; }; "goLiveLabel": { "alias": "goLiveLabel"; "required": false; "isSignal": true; }; "stepsWord": { "alias": "stepsWord"; "required": false; "isSignal": true; }; "doneWord": { "alias": "doneWord"; "required": false; "isSignal": true; }; "stepsLeftWord": { "alias": "stepsLeftWord"; "required": false; "isSignal": true; }; "allDoneLabel": { "alias": "allDoneLabel"; "required": false; "isSignal": true; }; "renameLabel": { "alias": "renameLabel"; "required": false; "isSignal": true; }; "collapseLabel": { "alias": "collapseLabel"; "required": false; "isSignal": true; }; "dismissLabel": { "alias": "dismissLabel"; "required": false; "isSignal": true; }; "expandLabel": { "alias": "expandLabel"; "required": false; "isSignal": true; }; "checkIcon": { "alias": "checkIcon"; "required": false; "isSignal": true; }; "caretIcon": { "alias": "caretIcon"; "required": false; "isSignal": true; }; "editIcon": { "alias": "editIcon"; "required": false; "isSignal": true; }; "collapseIcon": { "alias": "collapseIcon"; "required": false; "isSignal": true; }; "dismissIcon": { "alias": "dismissIcon"; "required": false; "isSignal": true; }; "expandIcon": { "alias": "expandIcon"; "required": false; "isSignal": true; }; "actionIcon": { "alias": "actionIcon"; "required": false; "isSignal": true; }; "className": { "alias": "className"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; }, { "stepAction": "stepAction"; "stepMarkDone": "stepMarkDone"; "substepToggle": "substepToggle"; "goLive": "goLive"; "renameClick": "renameClick"; "dismiss": "dismiss"; "collapsedChange": "collapsedChange"; }, never, never, true, [{ directive: typeof i1.CdkDrag; inputs: {}; outputs: {}; }]>;
762
+ }
763
+
764
+ export { ColumnsComponent, ContentSplitLayoutComponent, DetailPanelComponent, DialogFooterComponent, DialogHeaderComponent, DialogShellComponent, OnboardingGuideComponent, PageHeaderComponent, SidebarNavComponent, SidebarNavItemDirective, TableEmptyStateComponent };
765
+ export type { DialogConfirmVariant, DialogHeaderTint, OnboardingStep, OnboardingSubstep, OnboardingSubstepToggle, SidebarNavChild, SidebarNavGroup, SidebarNavItem, SidebarNavLink, SidebarNavModel };