@frame-kit/ui-ng-patterns 0.1.19 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { input, computed, HostBinding, ChangeDetectionStrategy, ViewEncapsulation, Component, inject, TemplateRef, Directive, ViewContainerRef, DestroyRef, Injector, viewChild, contentChild, signal, effect, afterNextRender, output, ElementRef,
|
|
2
|
+
import { input, computed, HostBinding, ChangeDetectionStrategy, ViewEncapsulation, Component, inject, TemplateRef, Directive, ViewContainerRef, DestroyRef, Injector, viewChild, contentChild, signal, effect, afterNextRender, output, ElementRef, model, untracked } 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';
|
|
@@ -967,23 +967,46 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
967
967
|
args: ['attr.id']
|
|
968
968
|
}] } });
|
|
969
969
|
|
|
970
|
-
|
|
970
|
+
/** Pointer travel below this is a click, not a drag. */
|
|
971
|
+
const DRAG_THRESHOLD = 3;
|
|
971
972
|
/**
|
|
972
973
|
* A floating, draggable onboarding-progress widget. It presents a checklist of
|
|
973
974
|
* steps with a progress bar, collapses to a compact pill with a progress ring,
|
|
974
|
-
* and can be dragged
|
|
975
|
-
*
|
|
975
|
+
* and can be dragged around (CDK drag). It renders over the app in a fixed
|
|
976
|
+
* layer — drop it once near the app root.
|
|
977
|
+
*
|
|
978
|
+
* **Presentational, not clever.** It renders exactly what it is given and
|
|
979
|
+
* reports what the user did — it derives no step state of its own. Which step
|
|
980
|
+
* is open (`openStepId`), which are done or pending (`steps`), whether it is
|
|
981
|
+
* collapsed (`collapsed`): all inputs. When a step should advance, when a
|
|
982
|
+
* context switch should re-focus the guide, when a choice has gone stale —
|
|
983
|
+
* all consumer decisions, because the consumer knows *what changed*, while
|
|
984
|
+
* the widget only ever sees a new array.
|
|
976
985
|
*
|
|
977
986
|
* **Controlled model, no domain data.** The `steps` model is a required,
|
|
978
987
|
* reactive input: the widget is a pure view of it and emits events when the
|
|
979
|
-
* user acts (`stepAction`, `stepMarkDone`, `
|
|
980
|
-
* consumer owns the step state — so if
|
|
981
|
-
*
|
|
982
|
-
* widget never persists step state.
|
|
988
|
+
* user acts (`stepAction`, `stepMarkDone`, `stepSecondaryAction`,
|
|
989
|
+
* `substepToggle`, `footerAction`). The consumer owns the step state — so if
|
|
990
|
+
* it is keyed by, say, the active account or environment, swapping the input
|
|
991
|
+
* re-renders the widget instantly. The widget never persists step state.
|
|
992
|
+
*
|
|
993
|
+
* **Collapsed and openStepId are two-way models.** Bind `[(collapsed)]` /
|
|
994
|
+
* `[(openStepId)]` to drive the card ↔ pill swap and the expanded row from
|
|
995
|
+
* outside; the widget writes them only in response to a direct user action.
|
|
996
|
+
*
|
|
997
|
+
* **Container-aware.** `boundary` (a selector or element) confines both
|
|
998
|
+
* dragging and the widget's resting position to a region of the app — e.g. a
|
|
999
|
+
* dashboard's content area, so the widget can never cover navigation or a
|
|
1000
|
+
* footer. The default resting spot is the boundary's bottom-right corner, and
|
|
1001
|
+
* the widget re-clamps itself whenever its own footprint changes (pill ↔ card
|
|
1002
|
+
* swap, a step expanding) or the viewport resizes — a corner-parked pill that
|
|
1003
|
+
* expands into a large card pulls itself fully back into view. Until the user
|
|
1004
|
+
* actually drags it, it stays anchored to the bottom-right corner.
|
|
983
1005
|
*
|
|
984
|
-
* **Presentation state is internal + persisted.** Collapsed and
|
|
985
|
-
*
|
|
986
|
-
*
|
|
1006
|
+
* **Presentation state is internal + optionally persisted.** Collapsed and
|
|
1007
|
+
* drag position persist to `localStorage` under `storageKey`; pass
|
|
1008
|
+
* `storageKey = null` for session-only behavior (e.g. when a consumer-side
|
|
1009
|
+
* store owns presentation policy).
|
|
987
1010
|
*
|
|
988
1011
|
* **Opinionated but themeable.** It ships a house look out of the box; all
|
|
989
1012
|
* colour flows through `--fk-onboarding-guide-*` tokens, so overriding those
|
|
@@ -993,9 +1016,12 @@ const VIEWPORT_MARGIN = 24;
|
|
|
993
1016
|
* <fk-onboarding-guide
|
|
994
1017
|
* [steps]="steps()"
|
|
995
1018
|
* title="Setup guide"
|
|
1019
|
+
* boundary=".app-content"
|
|
1020
|
+
* [storageKey]="null"
|
|
1021
|
+
* [(collapsed)]="collapsed"
|
|
996
1022
|
* (stepAction)="onStart($event)"
|
|
997
1023
|
* (substepToggle)="onToggle($event)"
|
|
998
|
-
* (
|
|
1024
|
+
* (footerAction)="onGoLive()"
|
|
999
1025
|
* (dismiss)="onDismiss()"
|
|
1000
1026
|
* />
|
|
1001
1027
|
* ```
|
|
@@ -1009,17 +1035,31 @@ class OnboardingGuideComponent {
|
|
|
1009
1035
|
steps = input.required(...(ngDevMode ? [{ debugName: "steps" }] : /* istanbul ignore next */ []));
|
|
1010
1036
|
/** Widget title. */
|
|
1011
1037
|
title = input('Setup guide', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
|
|
1012
|
-
/**
|
|
1038
|
+
/**
|
|
1039
|
+
* `localStorage` key for the collapsed + drag-position preferences.
|
|
1040
|
+
* `null` disables persistence entirely — presentation state then lives and
|
|
1041
|
+
* dies with the component instance (or with whatever the consumer binds).
|
|
1042
|
+
*/
|
|
1013
1043
|
storageKey = input('fk-onboarding-guide', ...(ngDevMode ? [{ debugName: "storageKey" }] : /* istanbul ignore next */ []));
|
|
1014
|
-
/**
|
|
1015
|
-
|
|
1044
|
+
/**
|
|
1045
|
+
* Region the widget is confined to: a CSS selector or an element. Both
|
|
1046
|
+
* dragging and the widget's resting position are clamped inside it. `null`
|
|
1047
|
+
* (the default) confines to the viewport.
|
|
1048
|
+
*/
|
|
1049
|
+
boundary = input(null, ...(ngDevMode ? [{ debugName: "boundary" }] : /* istanbul ignore next */ []));
|
|
1050
|
+
/** Breathing room kept between the widget and the boundary's edges. */
|
|
1051
|
+
boundaryMargin = input(24, ...(ngDevMode ? [{ debugName: "boundaryMargin" }] : /* istanbul ignore next */ []));
|
|
1052
|
+
/** Shows the rename (edit) affordance next to the title. */
|
|
1053
|
+
renamable = input(false, ...(ngDevMode ? [{ debugName: "renamable" }] : /* istanbul ignore next */ []));
|
|
1054
|
+
/** Shows the secondary "mark this step done" action on leaf steps. */
|
|
1055
|
+
showMarkDone = input(true, ...(ngDevMode ? [{ debugName: "showMarkDone" }] : /* istanbul ignore next */ []));
|
|
1016
1056
|
// --- Text (English defaults; pass translated strings as needed) ---
|
|
1017
1057
|
/** Default CTA label when a step doesn't supply its own `actionLabel`. */
|
|
1018
1058
|
startLabel = input('Start', ...(ngDevMode ? [{ debugName: "startLabel" }] : /* istanbul ignore next */ []));
|
|
1019
1059
|
/** Secondary "mark this step done" action label. */
|
|
1020
1060
|
markDoneLabel = input('Mark done', ...(ngDevMode ? [{ debugName: "markDoneLabel" }] : /* istanbul ignore next */ []));
|
|
1021
|
-
/** Footer
|
|
1022
|
-
|
|
1061
|
+
/** Footer action label (e.g. "Go live"). `null` hides the footer action. */
|
|
1062
|
+
footerActionLabel = input('Go live', ...(ngDevMode ? [{ debugName: "footerActionLabel" }] : /* istanbul ignore next */ []));
|
|
1023
1063
|
/** Footer noun for the "{done} of {total} {stepsWord} {doneWord}" summary. */
|
|
1024
1064
|
stepsWord = input('steps', ...(ngDevMode ? [{ debugName: "stepsWord" }] : /* istanbul ignore next */ []));
|
|
1025
1065
|
/** Footer verb for the summary. */
|
|
@@ -1041,38 +1081,59 @@ class OnboardingGuideComponent {
|
|
|
1041
1081
|
dismissIcon = input('close', ...(ngDevMode ? [{ debugName: "dismissIcon" }] : /* istanbul ignore next */ []));
|
|
1042
1082
|
expandIcon = input('expand', ...(ngDevMode ? [{ debugName: "expandIcon" }] : /* istanbul ignore next */ []));
|
|
1043
1083
|
actionIcon = input('arrow-right', ...(ngDevMode ? [{ debugName: "actionIcon" }] : /* istanbul ignore next */ []));
|
|
1084
|
+
// ===== MODEL =====
|
|
1085
|
+
/**
|
|
1086
|
+
* Whether the widget is collapsed to the pill. Two-way bindable so a
|
|
1087
|
+
* consumer-side policy (auto-open on context switches, banner-triggered
|
|
1088
|
+
* opens) can drive the card ↔ pill swap; unbound, the widget manages it.
|
|
1089
|
+
*/
|
|
1090
|
+
collapsed = model(false, ...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
|
|
1044
1091
|
// ===== OUTPUTS =====
|
|
1045
1092
|
/** A step's primary CTA was clicked. Emits the step id. */
|
|
1046
1093
|
stepAction = output();
|
|
1047
1094
|
/** A step's "mark done" was clicked. Emits the step id. */
|
|
1048
1095
|
stepMarkDone = output();
|
|
1096
|
+
/** A step's secondary text-action was clicked. Emits the step id. */
|
|
1097
|
+
stepSecondaryAction = output();
|
|
1049
1098
|
/** A substep checkbox was toggled. */
|
|
1050
1099
|
substepToggle = output();
|
|
1051
|
-
/** The
|
|
1052
|
-
|
|
1100
|
+
/** The footer action was invoked. */
|
|
1101
|
+
footerAction = output();
|
|
1053
1102
|
/** The rename (edit) affordance was clicked; the consumer owns renaming. */
|
|
1054
1103
|
renameClick = output();
|
|
1055
1104
|
/** The dismiss control was clicked; the consumer decides whether to hide it. */
|
|
1056
1105
|
dismiss = output();
|
|
1057
|
-
/** Fires when the collapsed state changes. */
|
|
1058
|
-
collapsedChange = output();
|
|
1059
1106
|
// ===== BASE PROPS =====
|
|
1060
1107
|
className = input('', ...(ngDevMode ? [{ debugName: "className" }] : /* istanbul ignore next */ []));
|
|
1061
1108
|
id = input(null, ...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
|
|
1062
1109
|
// ===== PRESENTATION STATE =====
|
|
1063
|
-
collapsed = signal(false, ...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
|
|
1064
1110
|
dragPosition = signal({ x: 0, y: 0 }, ...(ngDevMode ? [{ debugName: "dragPosition" }] : /* istanbul ignore next */ []));
|
|
1065
1111
|
/** True immediately after a real drag, so the drag-handle's click (e.g. the
|
|
1066
1112
|
* pill's expand) is suppressed rather than firing at the drop point. */
|
|
1067
1113
|
justDragged = false;
|
|
1068
1114
|
/**
|
|
1069
|
-
*
|
|
1070
|
-
*
|
|
1071
|
-
*
|
|
1072
|
-
*
|
|
1115
|
+
* True once the user has deliberately placed the widget (a real drag now,
|
|
1116
|
+
* or a persisted position from a previous session). Until then the widget
|
|
1117
|
+
* re-anchors to the boundary's bottom-right corner on every viewport or
|
|
1118
|
+
* footprint change instead of merely clamping its current spot.
|
|
1119
|
+
*/
|
|
1120
|
+
userMoved = false;
|
|
1121
|
+
footprintObserver = null;
|
|
1122
|
+
/** Guards the one-time preference restore in `hydrateOnce`. */
|
|
1123
|
+
hydrated = false;
|
|
1124
|
+
/** True between CDK's drag start and drop — `reposition` stands down. */
|
|
1125
|
+
dragging = false;
|
|
1126
|
+
/** The boundary element currently under observation (if any). */
|
|
1127
|
+
observedBoundary = null;
|
|
1128
|
+
/**
|
|
1129
|
+
* The expanded step, or `null` for none. Fully controlled: the widget
|
|
1130
|
+
* writes it only when the user toggles a row, and never infers a value
|
|
1131
|
+
* of its own — which step should be open, when to advance to the next
|
|
1132
|
+
* one, and whether a context switch should re-focus the guide are all
|
|
1133
|
+
* decisions the consumer owns (it knows what changed; the widget only
|
|
1134
|
+
* sees a new array).
|
|
1073
1135
|
*/
|
|
1074
|
-
openStepId =
|
|
1075
|
-
computation: (steps) => steps.find((s) => !this.isComplete(s))?.id ?? null });
|
|
1136
|
+
openStepId = model(null, ...(ngDevMode ? [{ debugName: "openStepId" }] : /* istanbul ignore next */ []));
|
|
1076
1137
|
// ===== DERIVED =====
|
|
1077
1138
|
total = computed(() => this.steps().length, ...(ngDevMode ? [{ debugName: "total" }] : /* istanbul ignore next */ []));
|
|
1078
1139
|
doneCount = computed(() => this.steps().filter((s) => this.isComplete(s)).length, ...(ngDevMode ? [{ debugName: "doneCount" }] : /* istanbul ignore next */ []));
|
|
@@ -1104,10 +1165,59 @@ class OnboardingGuideComponent {
|
|
|
1104
1165
|
return this.id();
|
|
1105
1166
|
}
|
|
1106
1167
|
constructor() {
|
|
1168
|
+
this.drag.started
|
|
1169
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
1170
|
+
.subscribe(() => (this.dragging = true));
|
|
1107
1171
|
this.drag.ended
|
|
1108
1172
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
1109
1173
|
.subscribe((event) => this.onDragEnded(event));
|
|
1110
|
-
|
|
1174
|
+
// The card ↔ pill swap changes the footprint drastically; reposition
|
|
1175
|
+
// right after the swap renders. The ResizeObserver covers the same
|
|
1176
|
+
// case, but its deliveries ride the rendering loop — which pauses in
|
|
1177
|
+
// occluded/backgrounded tabs — so the swap gets a deterministic,
|
|
1178
|
+
// task-scheduled companion (layout can be forced without frames).
|
|
1179
|
+
effect(() => {
|
|
1180
|
+
this.collapsed();
|
|
1181
|
+
untracked(() => {
|
|
1182
|
+
if (typeof window !== 'undefined') {
|
|
1183
|
+
setTimeout(() => this.reposition());
|
|
1184
|
+
}
|
|
1185
|
+
});
|
|
1186
|
+
});
|
|
1187
|
+
// Confine live dragging to the boundary — CDK enforces it during the
|
|
1188
|
+
// drag, and `clamp` applies the same region to programmatic placement.
|
|
1189
|
+
// The assignment is unconditional so clearing the input releases CDK's
|
|
1190
|
+
// constraint too (an empty string disables it), and the position
|
|
1191
|
+
// re-clamps immediately so a runtime boundary change moves the widget
|
|
1192
|
+
// into the new region instead of waiting for the next geometry trigger.
|
|
1193
|
+
// `boundaryMargin` is tracked alongside `boundary` so a runtime margin
|
|
1194
|
+
// change re-clamps immediately instead of waiting for the next
|
|
1195
|
+
// geometry trigger. Hydration runs first, synchronously, on the very
|
|
1196
|
+
// first execution — during initial change detection, BEFORE the first
|
|
1197
|
+
// paint — so a returning user's saved position and collapsed state
|
|
1198
|
+
// apply without a visible jump from the automatic anchor.
|
|
1199
|
+
effect(() => {
|
|
1200
|
+
const boundary = this.boundary();
|
|
1201
|
+
this.boundaryMargin();
|
|
1202
|
+
untracked(() => {
|
|
1203
|
+
this.hydrateOnce();
|
|
1204
|
+
this.drag.boundaryElement = boundary ?? '';
|
|
1205
|
+
this.syncBoundaryObservation();
|
|
1206
|
+
this.reposition();
|
|
1207
|
+
});
|
|
1208
|
+
});
|
|
1209
|
+
afterNextRender(() => {
|
|
1210
|
+
this.watchGeometry();
|
|
1211
|
+
// Re-clamp once real layout has settled — first-CD measurements are
|
|
1212
|
+
// forced synchronously and can differ slightly (fonts, late styles).
|
|
1213
|
+
this.reposition();
|
|
1214
|
+
});
|
|
1215
|
+
this.destroyRef.onDestroy(() => {
|
|
1216
|
+
this.footprintObserver?.disconnect();
|
|
1217
|
+
if (typeof window !== 'undefined') {
|
|
1218
|
+
window.removeEventListener('resize', this.onViewportResize);
|
|
1219
|
+
}
|
|
1220
|
+
});
|
|
1111
1221
|
}
|
|
1112
1222
|
// ===== COMPLETION LOGIC =====
|
|
1113
1223
|
isComplete(step) {
|
|
@@ -1116,6 +1226,9 @@ class OnboardingGuideComponent {
|
|
|
1116
1226
|
}
|
|
1117
1227
|
return step.done;
|
|
1118
1228
|
}
|
|
1229
|
+
isPending(step) {
|
|
1230
|
+
return !this.isComplete(step) && step.pending === true;
|
|
1231
|
+
}
|
|
1119
1232
|
isActive(step) {
|
|
1120
1233
|
return !this.isComplete(step) && this.openStepId() === step.id;
|
|
1121
1234
|
}
|
|
@@ -1124,7 +1237,7 @@ class OnboardingGuideComponent {
|
|
|
1124
1237
|
}
|
|
1125
1238
|
// ===== INTERACTIONS =====
|
|
1126
1239
|
toggleStep(stepId) {
|
|
1127
|
-
this.openStepId.
|
|
1240
|
+
this.openStepId.set(this.openStepId() === stepId ? null : stepId);
|
|
1128
1241
|
}
|
|
1129
1242
|
onAction(step) {
|
|
1130
1243
|
this.stepAction.emit(step.id);
|
|
@@ -1132,6 +1245,9 @@ class OnboardingGuideComponent {
|
|
|
1132
1245
|
onMarkDone(step) {
|
|
1133
1246
|
this.stepMarkDone.emit(step.id);
|
|
1134
1247
|
}
|
|
1248
|
+
onSecondaryAction(step) {
|
|
1249
|
+
this.stepSecondaryAction.emit(step.id);
|
|
1250
|
+
}
|
|
1135
1251
|
onSubstep(step, substep) {
|
|
1136
1252
|
this.substepToggle.emit({ stepId: step.id, substepId: substep.id });
|
|
1137
1253
|
}
|
|
@@ -1150,63 +1266,211 @@ class OnboardingGuideComponent {
|
|
|
1150
1266
|
onDismiss() {
|
|
1151
1267
|
this.dismiss.emit();
|
|
1152
1268
|
}
|
|
1153
|
-
|
|
1154
|
-
this.
|
|
1269
|
+
onFooterAction() {
|
|
1270
|
+
this.footerAction.emit();
|
|
1155
1271
|
}
|
|
1156
1272
|
setCollapsed(value) {
|
|
1157
1273
|
this.collapsed.set(value);
|
|
1158
|
-
this.collapsedChange.emit(value);
|
|
1159
1274
|
this.persist();
|
|
1160
1275
|
}
|
|
1161
1276
|
// ===== DRAG =====
|
|
1162
1277
|
onDragEnded(event) {
|
|
1278
|
+
this.dragging = false;
|
|
1163
1279
|
const clamped = this.clamp(this.drag.getFreeDragPosition());
|
|
1164
1280
|
this.dragPosition.set(clamped);
|
|
1165
1281
|
this.drag.setFreeDragPosition(clamped);
|
|
1166
|
-
|
|
1167
|
-
|
|
1282
|
+
const moved = Math.abs(event.distance.x) > DRAG_THRESHOLD ||
|
|
1283
|
+
Math.abs(event.distance.y) > DRAG_THRESHOLD;
|
|
1168
1284
|
if (moved) {
|
|
1285
|
+
this.userMoved = true;
|
|
1169
1286
|
this.justDragged = true;
|
|
1170
1287
|
setTimeout(() => (this.justDragged = false));
|
|
1288
|
+
this.persist();
|
|
1171
1289
|
}
|
|
1172
1290
|
}
|
|
1291
|
+
// ===== GEOMETRY =====
|
|
1292
|
+
/**
|
|
1293
|
+
* Keep the resting position valid as the world changes around it. Two
|
|
1294
|
+
* signals feed the same repositioning: the viewport resizing, and the
|
|
1295
|
+
* widget's own footprint changing (pill ↔ card swap, a step expanding) —
|
|
1296
|
+
* the latter is what stops a corner-parked pill from reopening as a card
|
|
1297
|
+
* that's mostly off-screen.
|
|
1298
|
+
*/
|
|
1299
|
+
watchGeometry() {
|
|
1300
|
+
if (typeof window === 'undefined') {
|
|
1301
|
+
return;
|
|
1302
|
+
}
|
|
1303
|
+
window.addEventListener('resize', this.onViewportResize);
|
|
1304
|
+
// Environments without ResizeObserver (some test runners, older
|
|
1305
|
+
// runtimes) keep the viewport-resize path; footprint tracking is a
|
|
1306
|
+
// progressive enhancement.
|
|
1307
|
+
if (typeof ResizeObserver === 'undefined') {
|
|
1308
|
+
return;
|
|
1309
|
+
}
|
|
1310
|
+
this.footprintObserver = new ResizeObserver(() => this.reposition());
|
|
1311
|
+
this.footprintObserver.observe(this.host.nativeElement);
|
|
1312
|
+
this.syncBoundaryObservation();
|
|
1313
|
+
}
|
|
1314
|
+
/**
|
|
1315
|
+
* The boundary region can resize without a viewport resize — a side
|
|
1316
|
+
* panel opening, chrome banners toggling — so the confining element is
|
|
1317
|
+
* observed alongside the widget's own footprint. Re-synced whenever the
|
|
1318
|
+
* `boundary` input changes.
|
|
1319
|
+
*/
|
|
1320
|
+
syncBoundaryObservation() {
|
|
1321
|
+
if (!this.footprintObserver) {
|
|
1322
|
+
return;
|
|
1323
|
+
}
|
|
1324
|
+
const next = this.resolveBoundaryElement();
|
|
1325
|
+
if (next === this.observedBoundary) {
|
|
1326
|
+
return;
|
|
1327
|
+
}
|
|
1328
|
+
if (this.observedBoundary) {
|
|
1329
|
+
this.footprintObserver.unobserve(this.observedBoundary);
|
|
1330
|
+
}
|
|
1331
|
+
if (next) {
|
|
1332
|
+
this.footprintObserver.observe(next);
|
|
1333
|
+
}
|
|
1334
|
+
this.observedBoundary = next;
|
|
1335
|
+
}
|
|
1336
|
+
resolveBoundaryElement() {
|
|
1337
|
+
const boundary = this.boundary();
|
|
1338
|
+
if (typeof window === 'undefined' || !boundary) {
|
|
1339
|
+
return null;
|
|
1340
|
+
}
|
|
1341
|
+
return typeof boundary === 'string'
|
|
1342
|
+
? document.querySelector(boundary)
|
|
1343
|
+
: boundary;
|
|
1344
|
+
}
|
|
1345
|
+
onViewportResize = () => this.reposition();
|
|
1346
|
+
reposition() {
|
|
1347
|
+
if (typeof window === 'undefined') {
|
|
1348
|
+
return;
|
|
1349
|
+
}
|
|
1350
|
+
// Never fight a drag in flight: CDK owns the transform until the
|
|
1351
|
+
// pointer is released, and writing a position here (a resize or an
|
|
1352
|
+
// observer callback can land mid-drag) would tear the widget away
|
|
1353
|
+
// from the pointer. `onDragEnded` clamps the drop point anyway.
|
|
1354
|
+
if (this.dragging) {
|
|
1355
|
+
return;
|
|
1356
|
+
}
|
|
1357
|
+
// A selector boundary may not have matched at mount — re-resolve on
|
|
1358
|
+
// every geometry trigger so a late-appearing element gets observed.
|
|
1359
|
+
this.syncBoundaryObservation();
|
|
1360
|
+
const current = this.drag.getFreeDragPosition();
|
|
1361
|
+
const target = this.userMoved
|
|
1362
|
+
? this.clamp(current)
|
|
1363
|
+
: this.defaultBottomRight();
|
|
1364
|
+
if (target.x !== current.x || target.y !== current.y) {
|
|
1365
|
+
this.dragPosition.set(target);
|
|
1366
|
+
this.drag.setFreeDragPosition(target);
|
|
1367
|
+
// A deliberate placement that just got re-clamped (e.g. the card ↔
|
|
1368
|
+
// pill swap) supersedes whatever was stored moments earlier.
|
|
1369
|
+
if (this.userMoved) {
|
|
1370
|
+
this.persist();
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
/** The confining region: the `boundary` element's rect, or the viewport. */
|
|
1375
|
+
boundaryRect() {
|
|
1376
|
+
const el = this.resolveBoundaryElement();
|
|
1377
|
+
if (el) {
|
|
1378
|
+
return el.getBoundingClientRect();
|
|
1379
|
+
}
|
|
1380
|
+
return {
|
|
1381
|
+
left: 0,
|
|
1382
|
+
top: 0,
|
|
1383
|
+
right: typeof window === 'undefined' ? 0 : window.innerWidth,
|
|
1384
|
+
bottom: typeof window === 'undefined' ? 0 : window.innerHeight,
|
|
1385
|
+
};
|
|
1386
|
+
}
|
|
1387
|
+
/**
|
|
1388
|
+
* Constrain one axis to `[start + margin, end - size - margin]`.
|
|
1389
|
+
*
|
|
1390
|
+
* When the region can't fit the widget plus both margins that range is
|
|
1391
|
+
* inverted, so the margin is dropped and the widget is fitted to the
|
|
1392
|
+
* region's own edges instead — keeping it inside the boundary rather
|
|
1393
|
+
* than letting the inset push it out. A widget genuinely larger than
|
|
1394
|
+
* its region still overflows (the card has a fixed width and something
|
|
1395
|
+
* has to give); it pins to the start edge.
|
|
1396
|
+
*/
|
|
1397
|
+
clampAxis(value, start, end, size, margin) {
|
|
1398
|
+
const min = start + margin;
|
|
1399
|
+
const max = end - size - margin;
|
|
1400
|
+
if (min <= max) {
|
|
1401
|
+
return Math.max(min, Math.min(value, max));
|
|
1402
|
+
}
|
|
1403
|
+
const tightMax = end - size;
|
|
1404
|
+
if (start <= tightMax) {
|
|
1405
|
+
return Math.max(start, Math.min(value, tightMax));
|
|
1406
|
+
}
|
|
1407
|
+
return start;
|
|
1408
|
+
}
|
|
1173
1409
|
clamp(point) {
|
|
1174
1410
|
if (typeof window === 'undefined') {
|
|
1175
1411
|
return point;
|
|
1176
1412
|
}
|
|
1177
1413
|
const rect = this.host.nativeElement.getBoundingClientRect();
|
|
1178
|
-
const
|
|
1179
|
-
const
|
|
1414
|
+
const bounds = this.boundaryRect();
|
|
1415
|
+
const margin = this.boundaryMargin();
|
|
1180
1416
|
return {
|
|
1181
|
-
x:
|
|
1182
|
-
y:
|
|
1417
|
+
x: this.clampAxis(point.x, bounds.left, bounds.right, rect.width, margin),
|
|
1418
|
+
y: this.clampAxis(point.y, bounds.top, bounds.bottom, rect.height, margin),
|
|
1183
1419
|
};
|
|
1184
1420
|
}
|
|
1185
|
-
// ===== PERSISTENCE =====
|
|
1186
|
-
hydrate() {
|
|
1187
|
-
const saved = this.read();
|
|
1188
|
-
this.collapsed.set(saved.collapsed ?? this.startCollapsed());
|
|
1189
|
-
const pos = saved.pos ? this.clamp(saved.pos) : this.defaultBottomRight();
|
|
1190
|
-
this.dragPosition.set(pos);
|
|
1191
|
-
this.drag.setFreeDragPosition(pos);
|
|
1192
|
-
}
|
|
1193
1421
|
defaultBottomRight() {
|
|
1194
1422
|
if (typeof window === 'undefined') {
|
|
1195
1423
|
return { x: 0, y: 0 };
|
|
1196
1424
|
}
|
|
1197
1425
|
const rect = this.host.nativeElement.getBoundingClientRect();
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1426
|
+
const bounds = this.boundaryRect();
|
|
1427
|
+
const margin = this.boundaryMargin();
|
|
1428
|
+
// Aim at the bottom-right inset and let the shared clamp resolve it —
|
|
1429
|
+
// including the too-narrow-region fallbacks.
|
|
1430
|
+
return this.clamp({
|
|
1431
|
+
x: bounds.right - rect.width - margin,
|
|
1432
|
+
y: bounds.bottom - rect.height - margin,
|
|
1433
|
+
});
|
|
1434
|
+
}
|
|
1435
|
+
// ===== PERSISTENCE =====
|
|
1436
|
+
/**
|
|
1437
|
+
* One-time restore of the persisted preferences, run from the first
|
|
1438
|
+
* execution of the boundary effect — inputs are set by then, storage
|
|
1439
|
+
* reads are synchronous, and it lands during initial change detection
|
|
1440
|
+
* so the restored state is what the first paint shows. The caller's
|
|
1441
|
+
* `reposition()` clamps the raw restored position right afterwards.
|
|
1442
|
+
*/
|
|
1443
|
+
hydrateOnce() {
|
|
1444
|
+
if (this.hydrated) {
|
|
1445
|
+
return;
|
|
1446
|
+
}
|
|
1447
|
+
this.hydrated = true;
|
|
1448
|
+
const saved = this.read();
|
|
1449
|
+
// The stored collapsed preference restores only when the model still
|
|
1450
|
+
// holds its default — a consumer that mounted the widget with a bound,
|
|
1451
|
+
// non-default `collapsed` gave an explicit instruction, and storage
|
|
1452
|
+
// must not overwrite it (or echo the stale value back out through
|
|
1453
|
+
// `collapsedChange`). Fully controlled usage should disable
|
|
1454
|
+
// persistence with `storageKey: null`.
|
|
1455
|
+
if (saved.collapsed != null && this.collapsed() === false) {
|
|
1456
|
+
this.collapsed.set(saved.collapsed);
|
|
1457
|
+
}
|
|
1458
|
+
if (saved.pos) {
|
|
1459
|
+
// A persisted position is a deliberate placement from a previous
|
|
1460
|
+
// session — keep honouring it instead of re-anchoring bottom-right.
|
|
1461
|
+
this.userMoved = true;
|
|
1462
|
+
this.dragPosition.set(saved.pos);
|
|
1463
|
+
this.drag.setFreeDragPosition(saved.pos);
|
|
1464
|
+
}
|
|
1202
1465
|
}
|
|
1203
1466
|
read() {
|
|
1204
1467
|
const store = this.storage();
|
|
1205
|
-
|
|
1468
|
+
const key = this.storageKey();
|
|
1469
|
+
if (!store || !key) {
|
|
1206
1470
|
return {};
|
|
1207
1471
|
}
|
|
1208
1472
|
try {
|
|
1209
|
-
return JSON.parse(store.getItem(
|
|
1473
|
+
return JSON.parse(store.getItem(key) || '{}');
|
|
1210
1474
|
}
|
|
1211
1475
|
catch {
|
|
1212
1476
|
return {};
|
|
@@ -1214,15 +1478,20 @@ class OnboardingGuideComponent {
|
|
|
1214
1478
|
}
|
|
1215
1479
|
persist() {
|
|
1216
1480
|
const store = this.storage();
|
|
1217
|
-
|
|
1481
|
+
const key = this.storageKey();
|
|
1482
|
+
if (!store || !key) {
|
|
1218
1483
|
return;
|
|
1219
1484
|
}
|
|
1485
|
+
// Position is a preference only once the user has actually dragged —
|
|
1486
|
+
// persisting the automatic bottom-right anchor would make the next
|
|
1487
|
+
// load's hydrate treat it as a deliberate placement and stop the
|
|
1488
|
+
// widget from re-anchoring on geometry changes.
|
|
1220
1489
|
const state = {
|
|
1221
1490
|
collapsed: this.collapsed(),
|
|
1222
|
-
pos: this.dragPosition(),
|
|
1491
|
+
pos: this.userMoved ? this.dragPosition() : undefined,
|
|
1223
1492
|
};
|
|
1224
1493
|
try {
|
|
1225
|
-
store.setItem(
|
|
1494
|
+
store.setItem(key, JSON.stringify(state));
|
|
1226
1495
|
}
|
|
1227
1496
|
catch {
|
|
1228
1497
|
// Storage unavailable (private mode / quota) — preferences just don't stick.
|
|
@@ -1237,12 +1506,12 @@ class OnboardingGuideComponent {
|
|
|
1237
1506
|
}
|
|
1238
1507
|
}
|
|
1239
1508
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: OnboardingGuideComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1240
|
-
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 });
|
|
1509
|
+
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 }, boundary: { classPropertyName: "boundary", publicName: "boundary", isSignal: true, isRequired: false, transformFunction: null }, boundaryMargin: { classPropertyName: "boundaryMargin", publicName: "boundaryMargin", isSignal: true, isRequired: false, transformFunction: null }, renamable: { classPropertyName: "renamable", publicName: "renamable", isSignal: true, isRequired: false, transformFunction: null }, showMarkDone: { classPropertyName: "showMarkDone", publicName: "showMarkDone", 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 }, footerActionLabel: { classPropertyName: "footerActionLabel", publicName: "footerActionLabel", 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 }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", 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 }, openStepId: { classPropertyName: "openStepId", publicName: "openStepId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { collapsed: "collapsedChange", stepAction: "stepAction", stepMarkDone: "stepMarkDone", stepSecondaryAction: "stepSecondaryAction", substepToggle: "substepToggle", footerAction: "footerAction", renameClick: "renameClick", dismiss: "dismiss", openStepId: "openStepIdChange" }, 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 @if (renamable()) {\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\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 pending = isPending(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--pending]=\"pending\"\n [class.fk-onboarding-guide__check--active]=\"active && !pending\"\n [class.fk-onboarding-guide__check--todo]=\"\n !done && !active && !pending\n \"\n aria-hidden=\"true\"\n >\n @if (done) {\n <fk-icon [name]=\"checkIcon()\" size=\"xs\" />\n } @else if (active || pending) {\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 (pending && step.pendingNote) {\n <p class=\"fk-onboarding-guide__pending-note\">\n {{ step.pendingNote }}\n </p>\n }\n\n @if (!done || step.secondaryActionLabel) {\n <div class=\"fk-onboarding-guide__actions\">\n @if (!done) {\n <fk-button\n variant=\"primary\"\n size=\"sm\"\n (click)=\"onAction(step)\"\n >\n {{ actionLabelFor(step) }}\n <fk-icon\n fkButtonIconEnd\n [name]=\"actionIcon()\"\n size=\"xs\"\n />\n </fk-button>\n\n @if (showMarkDone()) {\n <button\n type=\"button\"\n class=\"fk-onboarding-guide__skip\"\n (click)=\"onMarkDone(step)\"\n >\n {{ markDoneLabel() }}\n </button>\n }\n }\n\n @if (step.secondaryActionLabel) {\n <button\n type=\"button\"\n class=\"fk-onboarding-guide__secondary\"\n (click)=\"onSecondaryAction(step)\"\n >\n {{ step.secondaryActionLabel }}\n </button>\n }\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\n @if (footerActionLabel(); as footerLabel) {\n <button\n type=\"button\"\n class=\"fk-onboarding-guide__go\"\n (click)=\"onFooterAction()\"\n >\n {{ footerLabel }}\n <fk-icon [name]=\"actionIcon()\" size=\"xs\" />\n </button>\n }\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__icon-btn:focus-visible,.fk-onboarding-guide__step-row:focus-visible,.fk-onboarding-guide__sub:focus-visible,.fk-onboarding-guide__skip:focus-visible,.fk-onboarding-guide__secondary:focus-visible,.fk-onboarding-guide__go:focus-visible,.fk-onboarding-guide__pill:focus-visible{outline:none;box-shadow:var(--fk-focus-ring, 0 0 0 3px rgba(37, 99, 235, .18))}.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__check--pending{border:2px solid var(--fk-onboarding-guide-pending, var(--fk-color-warning, #d97706));background:color-mix(in srgb,var(--fk-onboarding-guide-pending, var(--fk-color-warning, #d97706)) 12%,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__check--pending .fk-onboarding-guide__dot{background:var(--fk-onboarding-guide-pending, var(--fk-color-warning, #d97706))}.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__pending-note{font-size:12.5px;line-height:1.5;color:var(--fk-onboarding-guide-pending-strong, var(--fk-onboarding-guide-pending, var(--fk-color-warning, #92400e)));margin-bottom:12px}.fk-onboarding-guide__actions{display:flex;align-items:center;gap:8px}.fk-onboarding-guide__skip,.fk-onboarding-guide__secondary{font-size:13px;font-weight:600;color:var(--fk-onboarding-guide-text-muted, var(--fk-color-muted, #64748b));background:none;border:none;border-radius:6px;padding:6px;cursor:pointer}.fk-onboarding-guide__skip:hover,.fk-onboarding-guide__secondary: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 });
|
|
1241
1510
|
}
|
|
1242
1511
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: OnboardingGuideComponent, decorators: [{
|
|
1243
1512
|
type: Component,
|
|
1244
|
-
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"] }]
|
|
1245
|
-
}], 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 }] }],
|
|
1513
|
+
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 @if (renamable()) {\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\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 pending = isPending(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--pending]=\"pending\"\n [class.fk-onboarding-guide__check--active]=\"active && !pending\"\n [class.fk-onboarding-guide__check--todo]=\"\n !done && !active && !pending\n \"\n aria-hidden=\"true\"\n >\n @if (done) {\n <fk-icon [name]=\"checkIcon()\" size=\"xs\" />\n } @else if (active || pending) {\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 (pending && step.pendingNote) {\n <p class=\"fk-onboarding-guide__pending-note\">\n {{ step.pendingNote }}\n </p>\n }\n\n @if (!done || step.secondaryActionLabel) {\n <div class=\"fk-onboarding-guide__actions\">\n @if (!done) {\n <fk-button\n variant=\"primary\"\n size=\"sm\"\n (click)=\"onAction(step)\"\n >\n {{ actionLabelFor(step) }}\n <fk-icon\n fkButtonIconEnd\n [name]=\"actionIcon()\"\n size=\"xs\"\n />\n </fk-button>\n\n @if (showMarkDone()) {\n <button\n type=\"button\"\n class=\"fk-onboarding-guide__skip\"\n (click)=\"onMarkDone(step)\"\n >\n {{ markDoneLabel() }}\n </button>\n }\n }\n\n @if (step.secondaryActionLabel) {\n <button\n type=\"button\"\n class=\"fk-onboarding-guide__secondary\"\n (click)=\"onSecondaryAction(step)\"\n >\n {{ step.secondaryActionLabel }}\n </button>\n }\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\n @if (footerActionLabel(); as footerLabel) {\n <button\n type=\"button\"\n class=\"fk-onboarding-guide__go\"\n (click)=\"onFooterAction()\"\n >\n {{ footerLabel }}\n <fk-icon [name]=\"actionIcon()\" size=\"xs\" />\n </button>\n }\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__icon-btn:focus-visible,.fk-onboarding-guide__step-row:focus-visible,.fk-onboarding-guide__sub:focus-visible,.fk-onboarding-guide__skip:focus-visible,.fk-onboarding-guide__secondary:focus-visible,.fk-onboarding-guide__go:focus-visible,.fk-onboarding-guide__pill:focus-visible{outline:none;box-shadow:var(--fk-focus-ring, 0 0 0 3px rgba(37, 99, 235, .18))}.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__check--pending{border:2px solid var(--fk-onboarding-guide-pending, var(--fk-color-warning, #d97706));background:color-mix(in srgb,var(--fk-onboarding-guide-pending, var(--fk-color-warning, #d97706)) 12%,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__check--pending .fk-onboarding-guide__dot{background:var(--fk-onboarding-guide-pending, var(--fk-color-warning, #d97706))}.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__pending-note{font-size:12.5px;line-height:1.5;color:var(--fk-onboarding-guide-pending-strong, var(--fk-onboarding-guide-pending, var(--fk-color-warning, #92400e)));margin-bottom:12px}.fk-onboarding-guide__actions{display:flex;align-items:center;gap:8px}.fk-onboarding-guide__skip,.fk-onboarding-guide__secondary{font-size:13px;font-weight:600;color:var(--fk-onboarding-guide-text-muted, var(--fk-color-muted, #64748b));background:none;border:none;border-radius:6px;padding:6px;cursor:pointer}.fk-onboarding-guide__skip:hover,.fk-onboarding-guide__secondary: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"] }]
|
|
1514
|
+
}], 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 }] }], boundary: [{ type: i0.Input, args: [{ isSignal: true, alias: "boundary", required: false }] }], boundaryMargin: [{ type: i0.Input, args: [{ isSignal: true, alias: "boundaryMargin", required: false }] }], renamable: [{ type: i0.Input, args: [{ isSignal: true, alias: "renamable", required: false }] }], showMarkDone: [{ type: i0.Input, args: [{ isSignal: true, alias: "showMarkDone", required: false }] }], startLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "startLabel", required: false }] }], markDoneLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "markDoneLabel", required: false }] }], footerActionLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "footerActionLabel", 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 }] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }, { type: i0.Output, args: ["collapsedChange"] }], stepAction: [{ type: i0.Output, args: ["stepAction"] }], stepMarkDone: [{ type: i0.Output, args: ["stepMarkDone"] }], stepSecondaryAction: [{ type: i0.Output, args: ["stepSecondaryAction"] }], substepToggle: [{ type: i0.Output, args: ["substepToggle"] }], footerAction: [{ type: i0.Output, args: ["footerAction"] }], renameClick: [{ type: i0.Output, args: ["renameClick"] }], dismiss: [{ type: i0.Output, args: ["dismiss"] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], openStepId: [{ type: i0.Input, args: [{ isSignal: true, alias: "openStepId", required: false }] }, { type: i0.Output, args: ["openStepIdChange"] }], hostClass: [{
|
|
1246
1515
|
type: HostBinding,
|
|
1247
1516
|
args: ['class']
|
|
1248
1517
|
}], hostId: [{
|